diff --git a/.github/aw/releases.json b/.github/aw/releases.json index b7e6bdee713..b9a4f1194fa 100644 --- a/.github/aw/releases.json +++ b/.github/aw/releases.json @@ -2,9 +2,5 @@ "$schema": "./releases.schema.json", "blockedVersions": [], "minimumVersion": "v0.64.4", - "minRecommendedVersion": "v0.64.4", - "aliases": { - "latest": "latest", - "stable": "v0.64.5" - } + "minRecommendedVersion": "v0.64.4" } diff --git a/.github/aw/releases.schema.json b/.github/aw/releases.schema.json index 0ea8b5e8ffb..c1ebba7027d 100644 --- a/.github/aw/releases.schema.json +++ b/.github/aw/releases.schema.json @@ -31,16 +31,6 @@ "description": "The minimum recommended compile-agentic version in vMAJOR.MINOR.PATCH format. Workflows compiled with a version below this will emit a warning (but not fail) at activation, nudging users to upgrade. Use an empty string to disable this check.", "pattern": "^(v[0-9]+\\.[0-9]+\\.[0-9]+)?$", "default": "" - }, - "aliases": { - "type": "object", - "description": "A map of release alias names to version strings. The special value 'latest' resolves to the most recent release. Other values must be a version string in vMAJOR.MINOR.PATCH format.", - "additionalProperties": { - "type": "string", - "pattern": "^(latest|v[0-9]+\\.[0-9]+\\.[0-9]+)$", - "description": "A version string in vMAJOR.MINOR.PATCH format or the special value 'latest'" - }, - "default": {} } } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d908d2946dd..f9edd03b2f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -870,30 +870,13 @@ jobs: const errors = []; // Check additionalProperties (only allow known keys) - const allowedKeys = new Set(['$schema', 'blockedVersions', 'minimumVersion', 'minRecommendedVersion', 'aliases']); + const allowedKeys = new Set(['$schema', 'blockedVersions', 'minimumVersion', 'minRecommendedVersion']); for (const key of Object.keys(config)) { if (!allowedKeys.has(key)) { errors.push(`Unknown property: '${key}'`); } } - // Validate aliases - if ('aliases' in config) { - const aliases = config.aliases; - if (typeof aliases !== 'object' || aliases === null || Array.isArray(aliases)) { - errors.push("'aliases' must be an object"); - } else { - const aliasValuePattern = /^(latest|v[0-9]+\.[0-9]+\.[0-9]+)$/; - for (const [alias, value] of Object.entries(aliases)) { - if (typeof value !== 'string') { - errors.push(`'aliases.${alias}' must be a string`); - } else if (!aliasValuePattern.test(value)) { - errors.push(`'aliases.${alias}' ('${value}') must be 'latest' or a version in vMAJOR.MINOR.PATCH format (e.g. 'v1.2.3')`); - } - } - } - } - // Validate blockedVersions if ('blockedVersions' in config) { const bv = config.blockedVersions; @@ -2801,66 +2784,6 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY - install-script: - name: Install Script (stable) - runs-on: ubuntu-latest - timeout-minutes: 10 - permissions: - contents: read - concurrency: - group: ci-${{ github.ref }}-install-script - cancel-in-progress: true - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Validate stable alias in releases.json - id: validate-stable - run: | - STABLE=$(jq -r '.aliases.stable // empty' .github/aw/releases.json) - echo "stable_version=$STABLE" >> $GITHUB_OUTPUT - - if [ -z "$STABLE" ]; then - echo "❌ 'stable' alias is not set in releases.json" - exit 1 - fi - - if [ "$STABLE" = "stable" ]; then - echo "❌ 'stable' alias points to itself - misconfiguration in releases.json" - exit 1 - fi - - if ! echo "$STABLE" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then - echo "❌ 'stable' alias '$STABLE' is not a valid semver version (expected vMAJOR.MINOR.PATCH)" - exit 1 - fi - - echo "✅ 'stable' alias resolves to a valid version: $STABLE" - - - name: Run install-gh-aw.sh with stable version - run: bash install-gh-aw.sh stable - - - name: Verify installation - run: | - BINARY="$HOME/.local/share/gh/extensions/gh-aw/gh-aw" - EXPECTED="${{ steps.validate-stable.outputs.stable_version }}" - - if [ ! -f "$BINARY" ]; then - echo "❌ Binary not found at $BINARY" - exit 1 - fi - - INSTALLED_VERSION=$("$BINARY" version 2>&1 | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1) - echo "Installed version: $INSTALLED_VERSION" - echo "Expected version: $EXPECTED" - - if [ "$INSTALLED_VERSION" != "$EXPECTED" ]; then - echo "❌ Version mismatch: installed $INSTALLED_VERSION but expected $EXPECTED" - exit 1 - fi - - echo "✅ install-gh-aw.sh successfully installed stable release: $INSTALLED_VERSION" >> $GITHUB_STEP_SUMMARY - sh-difc-proxy: name: DIFC Proxy sh Integration Test runs-on: ubuntu-latest diff --git a/.github/workflows/update-stable-release.yml b/.github/workflows/update-stable-release.yml deleted file mode 100644 index 6f947c27f62..00000000000 --- a/.github/workflows/update-stable-release.yml +++ /dev/null @@ -1,151 +0,0 @@ -name: Release Punter - -on: - workflow_dispatch: - inputs: - version: - description: "Version to set as stable (e.g., v1.2.3). Defaults to the latest published release." - required: false - type: string - -# Prevent concurrent runs that could produce conflicting commits -concurrency: - group: update-stable-release - cancel-in-progress: false - -jobs: - update-stable: - name: Release Punter - runs-on: ubuntu-latest - # Never run on forks — they cannot push to the upstream repository - if: ${{ !github.event.repository.fork }} - permissions: - contents: write - - steps: - - name: Validate actor permissions - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ - owner: context.repo.owner, - repo: context.repo.repo, - username: context.actor, - }); - const role = data.role_name; - core.info(`Actor ${context.actor} has role: ${role}`); - if (role !== 'admin' && role !== 'maintain') { - core.setFailed( - `❌ ${context.actor} must be a repository admin or maintainer to update the stable release (current role: ${role})` - ); - } else { - core.info(`✅ ${context.actor} is authorized (role: ${role})`); - } - - - name: Resolve version - id: version - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - INPUT_VERSION: ${{ inputs.version }} - with: - script: | - let version = (process.env.INPUT_VERSION || '').trim(); - if (!version) { - const { data: release } = await github.rest.repos.getLatestRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - }); - version = release.tag_name; - core.info(`ℹ️ No version specified, resolved to latest: ${version}`); - } - core.setOutput('version', version); - - - name: Validate release tag - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - RELEASE_VERSION: ${{ steps.version.outputs.version }} - with: - script: | - const version = process.env.RELEASE_VERSION; - - // Only exact vMAJOR.MINOR.PATCH versions are valid for the stable alias - // (pre-release suffixes such as -beta.1 are intentionally rejected) - if (!/^v\d+\.\d+\.\d+$/.test(version)) { - core.setFailed( - `❌ Invalid version format: "${version}". Expected vMAJOR.MINOR.PATCH (e.g., v1.2.3). ` + - `Pre-release versions cannot be set as stable.` - ); - return; - } - - let release; - try { - ({ data: release } = await github.rest.repos.getReleaseByTag({ - owner: context.repo.owner, - repo: context.repo.repo, - tag: version, - })); - } catch (err) { - core.setFailed(`❌ No published release found for tag ${version}: ${err.message}`); - return; - } - - if (release.draft) { - core.setFailed(`❌ ${version} is a draft release and cannot be set as stable`); - return; - } - - if (release.prerelease) { - core.warning(`⚠️ ${version} is marked as a pre-release`); - } - - core.info(`✅ Validated: ${version} is a published release`); - - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Update stable alias in releases.json - id: update - env: - VERSION: ${{ steps.version.outputs.version }} - run: | - FILE=".github/aw/releases.json" - - CURRENT=$(jq -r '.aliases.stable // ""' "$FILE") - - if [ -z "$CURRENT" ]; then - echo "ℹ️ No existing stable alias found; will create one." - fi - - if [ "$CURRENT" = "$VERSION" ]; then - echo "ℹ️ stable is already set to $VERSION — no change needed." - echo "changed=false" >> "$GITHUB_OUTPUT" - else - echo "Updating stable alias: $CURRENT → $VERSION" - jq --arg v "$VERSION" '.aliases.stable = $v' "$FILE" > /tmp/releases.json - mv /tmp/releases.json "$FILE" - echo "✅ Updated $FILE" - cat "$FILE" - echo "changed=true" >> "$GITHUB_OUTPUT" - fi - - - name: Validate releases.json - if: steps.update.outputs.changed == 'true' - run: | - FILE=".github/aw/releases.json" - if ! jq empty "$FILE" 2>&1; then - echo "❌ $FILE is not valid JSON after update" - exit 1 - fi - echo "✅ $FILE is valid JSON" - - - name: Commit and push - if: steps.update.outputs.changed == 'true' - env: - VERSION: ${{ steps.version.outputs.version }} - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add .github/aw/releases.json - git commit -m "chore: update stable release to $VERSION" - git push diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f74dc5d67c9..52d40bebf92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -545,6 +545,8 @@ This project follows the GitHub Community Guidelines. Please be respectful and i Releases are triggered manually by a core team member using the GitHub Actions release workflow. +> **Note:** The release workflow publishes the new version as a **prerelease** on GitHub. Once the release is verified, a maintainer must **manually promote it to a full release and move the `latest` tag** so that users installing with `version: latest` receive the new version. + ### Steps 1. **Launch the release action** @@ -563,7 +565,17 @@ Releases are triggered manually by a core team member using the GitHub Actions r 3. **Approve the environment gate** - Return to the paused release run in [`github/gh-aw`](https://github.com/github/gh-aw/actions). Approve the **`gh-aw-actions-release`** environment gate. The workflow will verify that the new tag exists in `github/gh-aw-actions` and then publish the GitHub release. + Return to the paused release run in [`github/gh-aw`](https://github.com/github/gh-aw/actions). Approve the **`gh-aw-actions-release`** environment gate. The workflow will verify that the new tag exists in `github/gh-aw-actions` and then publish the GitHub release as a **prerelease**. + +4. **Promote to latest** _(manual step)_ + + After verifying the prerelease is working correctly: + + a. **Edit the GitHub release** — go to the [Releases page](https://github.com/github/gh-aw/releases), open the new prerelease, uncheck **This is a pre-release**, and save. This promotes the release to a stable full release. + + b. **Move the `latest` tag** — GitHub's release API resolves `latest` to the most recent non-prerelease release. Promoting the release in step (a) is sufficient for the `latest` resolution to update automatically. + + Users who install with `version: latest` (the default) will now receive the new release. ### Summary @@ -583,7 +595,13 @@ Merge the sync-actions PR Approve the gh-aw-actions-release environment gate │ ▼ -Release published 🎉 +Release published as prerelease 🎉 + │ + ▼ (manual) +Promote prerelease → full release on GitHub Releases page + │ + ▼ +'latest' now resolves to the new version ✅ ``` ## 🎯 Why This Contribution Model? diff --git a/actions/setup-cli/install.sh b/actions/setup-cli/install.sh index 445c99fc008..9e529ff4332 100755 --- a/actions/setup-cli/install.sh +++ b/actions/setup-cli/install.sh @@ -2,16 +2,15 @@ # Script to download and install gh-aw binary for the current OS and architecture # Supports: Linux, macOS (Darwin), FreeBSD, Windows (Git Bash/MSYS/Cygwin) -# Usage: ./install-gh-aw.sh [version] [options] -# If no version is specified, it will use "stable" (resolved from .github/aw/releases.json) -# Version aliases (e.g. "stable", "latest") are resolved via .github/aw/releases.json before download. +# If no version is specified, it will use "latest" # Note: Checksum validation is currently skipped by default (will be enabled in future releases) # +# Usage: ./install.sh [version] [options] +# # Examples: -# ./install-gh-aw.sh # Install stable version -# ./install-gh-aw.sh latest # Install latest version -# ./install-gh-aw.sh v1.0.0 # Install specific version -# ./install-gh-aw.sh --skip-checksum # Skip checksum validation +# ./install.sh # Install latest version +# ./install.sh v1.0.0 # Install specific version +# ./install.sh --skip-checksum # Skip checksum validation # # Options: # --skip-checksum Skip checksum verification @@ -83,12 +82,6 @@ if ! command -v curl &> /dev/null; then exit 1 fi -# Check if jq is available (optional, we'll use grep/sed as fallback) -HAS_JQ=false -if command -v jq &> /dev/null; then - HAS_JQ=true -fi - # Check if sha256sum or shasum is available (for checksum verification) HAS_CHECKSUM_TOOL=false CHECKSUM_CMD="" @@ -170,105 +163,17 @@ print_info "Detected OS: $OS -> $OS_NAME" print_info "Detected architecture: $ARCH -> $ARCH_NAME" print_info "Platform: $PLATFORM" -# Function to fetch release data with fallback for invalid token and retry logic -fetch_release_data() { - local url=$1 - local max_retries=3 - local retry_delay=2 - local use_auth=false - - # Try with authentication if GH_TOKEN is set - if [ -n "$GH_TOKEN" ]; then - use_auth=true - fi - - # Retry loop - for attempt in $(seq 1 $max_retries); do - local curl_args=("-s" "-f") - - # Add auth header if using authentication - if [ "$use_auth" = true ]; then - curl_args+=("-H" "Authorization: Bearer $GH_TOKEN") - fi - - print_info "Fetching release data (attempt $attempt/$max_retries)..." >&2 - - # Make the API call - local response - response=$(curl "${curl_args[@]}" "$url" 2>/dev/null) - local exit_code=$? - - # Success - if [ $exit_code -eq 0 ] && [ -n "$response" ]; then - echo "$response" - return 0 - fi - - # If this was the first attempt with auth and it failed, try without auth - if [ "$attempt" -eq 1 ] && [ "$use_auth" = true ]; then - print_warning "API call with GH_TOKEN failed. Retrying without authentication..." >&2 - print_warning "Your GH_TOKEN may be incompatible (typically SSO) with this request." >&2 - use_auth=false - # Don't count this as a retry attempt, just switch auth mode - continue - fi - - # If we haven't exhausted retries, wait and try again - if [ "$attempt" -lt "$max_retries" ]; then - print_warning "Fetch attempt $attempt failed (exit code: $exit_code). Retrying in ${retry_delay}s..." >&2 - sleep $retry_delay - retry_delay=$((retry_delay * 2)) - else - print_error "Failed to fetch release data after $max_retries attempts" >&2 - fi - done - - return 1 -} - -# Get version (use provided version or default to "stable") +# Get version (use provided version or default to "latest") # VERSION is already set from argument parsing REPO="github/gh-aw" if [ -z "$VERSION" ]; then - print_info "No version specified, using 'stable'..." - VERSION="stable" + print_info "No version specified, using 'latest'..." + VERSION="latest" else print_info "Using specified version: $VERSION" fi -# Resolve version aliases from releases.json -RELEASES_JSON_URL="https://raw.githubusercontent.com/$REPO/main/.github/aw/releases.json" -print_info "Resolving version alias '$VERSION' from $RELEASES_JSON_URL..." - -releases_json="" -releases_json=$(curl -s -f "$RELEASES_JSON_URL" 2>/dev/null) || true - -if [ -n "$releases_json" ]; then - resolved_version="" - if [ "$HAS_JQ" = true ]; then - resolved_version=$(echo "$releases_json" | jq -r ".aliases[\"$VERSION\"] // empty" 2>/dev/null) || { - print_info "jq failed to parse releases.json; alias resolution skipped" - } - else - # Fallback: extract alias value using grep/sed - # Escape regex special characters in VERSION to avoid unintended matches - version_escaped=$(printf '%s' "$VERSION" | sed 's/[.[\*^$]/\\&/g') - resolved_version=$(echo "$releases_json" | grep -o "\"${version_escaped}\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" | sed 's/.*:[[:space:]]*"\([^"]*\)"/\1/' | head -1) || true - fi - - if [ -n "$resolved_version" ] && [ "$resolved_version" != "$VERSION" ]; then - print_info "Resolved alias '$VERSION' -> '$resolved_version'" - VERSION="$resolved_version" - elif [ -n "$resolved_version" ]; then - print_warning "Version '$VERSION' is an alias for itself in releases.json (no change); this may indicate a misconfiguration" - else - print_info "No alias found for '$VERSION', using it as-is" - fi -else - print_warning "Could not fetch releases.json; proceeding with version '$VERSION' as-is" -fi - # Try gh extension install if requested (and gh is available) if [ "$TRY_GH_INSTALL" = true ] && command -v gh &> /dev/null; then print_info "Attempting to install gh-aw using 'gh extension install'..." diff --git a/docs/src/content/docs/reference/releases.md b/docs/src/content/docs/reference/releases.md index af0899672a9..d56ecfc5158 100644 --- a/docs/src/content/docs/reference/releases.md +++ b/docs/src/content/docs/reference/releases.md @@ -1,6 +1,6 @@ --- title: Releases and Versioning -description: How to pin the gh-aw CLI to a release channel, what stable vs latest means, how compiled lock.yml files are versioned, and when to use upgrade vs update. +description: How to pin the gh-aw CLI to a specific release, how compiled lock.yml files are versioned, and when to use upgrade vs update. sidebar: order: 520 --- @@ -9,23 +9,19 @@ GitHub Agentic Workflows uses a two-layer versioning model: the **CLI extension* ## Release Channels -The gh-aw installer resolves version aliases from [`.github/aw/releases.json`](https://github.com/github/gh-aw/blob/main/.github/aw/releases.json) before downloading a binary. Three options are available: +Two options are available when installing gh-aw: | Channel | Alias | Behavior | |---------|-------|----------| -| **Stable** (default) | `stable` | Resolves to the latest fully-vetted release — recommended for most users | -| **Latest** | `latest` | Always resolves to the most recent GitHub release, including recently shipped features | +| **Latest** (default) | `latest` | Always resolves to the most recent GitHub release | | **Pinned** | `vMAJOR.MINOR.PATCH` | A fixed release tag — use when you need exact reproducibility | ### Installing a channel ```bash -# Stable (default — no version flag needed) +# Latest (default — no version flag needed) curl -sL https://raw.githubusercontent.com/github/gh-aw/main/install-gh-aw.sh | bash -# Latest -curl -sL https://raw.githubusercontent.com/github/gh-aw/main/install-gh-aw.sh | bash -s latest - # Specific version curl -sL https://raw.githubusercontent.com/github/gh-aw/main/install-gh-aw.sh | bash -s v0.64.5 ``` @@ -33,13 +29,10 @@ curl -sL https://raw.githubusercontent.com/github/gh-aw/main/install-gh-aw.sh | Via the GitHub CLI extension manager: ```bash -gh extension install github/gh-aw # stable (default) +gh extension install github/gh-aw # latest (default) gh extension install github/gh-aw@v0.64.5 # pinned version ``` -> [!TIP] -> Use `stable` for production repositories and CI. Use `latest` when you want to try new features as soon as they ship. - ### Checking and updating your version ```bash diff --git a/install-gh-aw.sh b/install-gh-aw.sh index 445c99fc008..9e529ff4332 100755 --- a/install-gh-aw.sh +++ b/install-gh-aw.sh @@ -2,16 +2,15 @@ # Script to download and install gh-aw binary for the current OS and architecture # Supports: Linux, macOS (Darwin), FreeBSD, Windows (Git Bash/MSYS/Cygwin) -# Usage: ./install-gh-aw.sh [version] [options] -# If no version is specified, it will use "stable" (resolved from .github/aw/releases.json) -# Version aliases (e.g. "stable", "latest") are resolved via .github/aw/releases.json before download. +# If no version is specified, it will use "latest" # Note: Checksum validation is currently skipped by default (will be enabled in future releases) # +# Usage: ./install.sh [version] [options] +# # Examples: -# ./install-gh-aw.sh # Install stable version -# ./install-gh-aw.sh latest # Install latest version -# ./install-gh-aw.sh v1.0.0 # Install specific version -# ./install-gh-aw.sh --skip-checksum # Skip checksum validation +# ./install.sh # Install latest version +# ./install.sh v1.0.0 # Install specific version +# ./install.sh --skip-checksum # Skip checksum validation # # Options: # --skip-checksum Skip checksum verification @@ -83,12 +82,6 @@ if ! command -v curl &> /dev/null; then exit 1 fi -# Check if jq is available (optional, we'll use grep/sed as fallback) -HAS_JQ=false -if command -v jq &> /dev/null; then - HAS_JQ=true -fi - # Check if sha256sum or shasum is available (for checksum verification) HAS_CHECKSUM_TOOL=false CHECKSUM_CMD="" @@ -170,105 +163,17 @@ print_info "Detected OS: $OS -> $OS_NAME" print_info "Detected architecture: $ARCH -> $ARCH_NAME" print_info "Platform: $PLATFORM" -# Function to fetch release data with fallback for invalid token and retry logic -fetch_release_data() { - local url=$1 - local max_retries=3 - local retry_delay=2 - local use_auth=false - - # Try with authentication if GH_TOKEN is set - if [ -n "$GH_TOKEN" ]; then - use_auth=true - fi - - # Retry loop - for attempt in $(seq 1 $max_retries); do - local curl_args=("-s" "-f") - - # Add auth header if using authentication - if [ "$use_auth" = true ]; then - curl_args+=("-H" "Authorization: Bearer $GH_TOKEN") - fi - - print_info "Fetching release data (attempt $attempt/$max_retries)..." >&2 - - # Make the API call - local response - response=$(curl "${curl_args[@]}" "$url" 2>/dev/null) - local exit_code=$? - - # Success - if [ $exit_code -eq 0 ] && [ -n "$response" ]; then - echo "$response" - return 0 - fi - - # If this was the first attempt with auth and it failed, try without auth - if [ "$attempt" -eq 1 ] && [ "$use_auth" = true ]; then - print_warning "API call with GH_TOKEN failed. Retrying without authentication..." >&2 - print_warning "Your GH_TOKEN may be incompatible (typically SSO) with this request." >&2 - use_auth=false - # Don't count this as a retry attempt, just switch auth mode - continue - fi - - # If we haven't exhausted retries, wait and try again - if [ "$attempt" -lt "$max_retries" ]; then - print_warning "Fetch attempt $attempt failed (exit code: $exit_code). Retrying in ${retry_delay}s..." >&2 - sleep $retry_delay - retry_delay=$((retry_delay * 2)) - else - print_error "Failed to fetch release data after $max_retries attempts" >&2 - fi - done - - return 1 -} - -# Get version (use provided version or default to "stable") +# Get version (use provided version or default to "latest") # VERSION is already set from argument parsing REPO="github/gh-aw" if [ -z "$VERSION" ]; then - print_info "No version specified, using 'stable'..." - VERSION="stable" + print_info "No version specified, using 'latest'..." + VERSION="latest" else print_info "Using specified version: $VERSION" fi -# Resolve version aliases from releases.json -RELEASES_JSON_URL="https://raw.githubusercontent.com/$REPO/main/.github/aw/releases.json" -print_info "Resolving version alias '$VERSION' from $RELEASES_JSON_URL..." - -releases_json="" -releases_json=$(curl -s -f "$RELEASES_JSON_URL" 2>/dev/null) || true - -if [ -n "$releases_json" ]; then - resolved_version="" - if [ "$HAS_JQ" = true ]; then - resolved_version=$(echo "$releases_json" | jq -r ".aliases[\"$VERSION\"] // empty" 2>/dev/null) || { - print_info "jq failed to parse releases.json; alias resolution skipped" - } - else - # Fallback: extract alias value using grep/sed - # Escape regex special characters in VERSION to avoid unintended matches - version_escaped=$(printf '%s' "$VERSION" | sed 's/[.[\*^$]/\\&/g') - resolved_version=$(echo "$releases_json" | grep -o "\"${version_escaped}\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" | sed 's/.*:[[:space:]]*"\([^"]*\)"/\1/' | head -1) || true - fi - - if [ -n "$resolved_version" ] && [ "$resolved_version" != "$VERSION" ]; then - print_info "Resolved alias '$VERSION' -> '$resolved_version'" - VERSION="$resolved_version" - elif [ -n "$resolved_version" ]; then - print_warning "Version '$VERSION' is an alias for itself in releases.json (no change); this may indicate a misconfiguration" - else - print_info "No alias found for '$VERSION', using it as-is" - fi -else - print_warning "Could not fetch releases.json; proceeding with version '$VERSION' as-is" -fi - # Try gh extension install if requested (and gh is available) if [ "$TRY_GH_INSTALL" = true ] && command -v gh &> /dev/null; then print_info "Attempting to install gh-aw using 'gh extension install'..." diff --git a/pkg/cli/setup_cli_action_integration_test.go b/pkg/cli/setup_cli_action_integration_test.go index 9267854a7e5..cd3c04d2ff8 100644 --- a/pkg/cli/setup_cli_action_integration_test.go +++ b/pkg/cli/setup_cli_action_integration_test.go @@ -50,9 +50,9 @@ func TestSetupCLIAction(t *testing.T) { if err != nil { t.Fatalf("Failed to read install.sh: %v", err) } - // Verify script has fallback to use stable version - if !strings.Contains(string(content), "No version specified") || !strings.Contains(string(content), "using 'stable'") { - t.Errorf("Script should support fetching stable release when no version is provided") + // Verify script has fallback to use latest version + if !strings.Contains(string(content), "No version specified") || !strings.Contains(string(content), "using 'latest'") { + t.Errorf("Script should support fetching latest release when no version is provided") } }) diff --git a/scripts/test-install-script.sh b/scripts/test-install-script.sh index 90c62f5c337..dda5793f6fd 100755 --- a/scripts/test-install-script.sh +++ b/scripts/test-install-script.sh @@ -187,85 +187,9 @@ else exit 1 fi -# Test 8: Verify fetch_release_data function exists and has correct logic +# Test 8: Verify retry logic for downloads echo "" -echo "Test 8: Verify fetch_release_data function logic" - -# Extract and test the function -if grep -q "fetch_release_data()" "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: fetch_release_data function exists" -else - echo " ✗ FAIL: fetch_release_data function not found" - exit 1 -fi - -# Verify the function checks for GH_TOKEN -if grep -q 'if \[ -n "\$GH_TOKEN" \]; then' "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Function checks for GH_TOKEN" -else - echo " ✗ FAIL: Function does not check for GH_TOKEN" - exit 1 -fi - -# Verify the function includes fallback logic -if grep -q "Retrying without authentication" "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Function includes retry fallback with warning" -else - echo " ✗ FAIL: Function does not include retry fallback" - exit 1 -fi - -# Verify the warning mentions incompatible token -if grep -q "incompatible" "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Warning message mentions incompatible token" -else - echo " ✗ FAIL: Warning message does not mention incompatible token" - exit 1 -fi - -# Verify the function uses Authorization header with Bearer -if grep -q 'Authorization: Bearer' "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Function uses proper Authorization header with Bearer" -else - echo " ✗ FAIL: Function does not use Authorization header with Bearer" - exit 1 -fi - -# Verify the function has retry logic with max_retries -if grep -q 'local max_retries=3' "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Function has max_retries=3 variable" -else - echo " ✗ FAIL: Function does not have max_retries variable" - exit 1 -fi - -# Verify the function has retry loop -if grep -q 'for attempt in $(seq 1 $max_retries)' "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Function has retry loop" -else - echo " ✗ FAIL: Function does not have retry loop" - exit 1 -fi - -# Verify the function logs fetch attempts -if grep -q 'Fetching release data (attempt' "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Function logs fetch attempts" -else - echo " ✗ FAIL: Function does not log fetch attempts" - exit 1 -fi - -# Verify the function has exponential backoff for retries -if grep -q 'retry_delay=\$((retry_delay \* 2))' "$PROJECT_ROOT/install-gh-aw.sh"; then - echo " ✓ PASS: Function has exponential backoff for retries" -else - echo " ✗ FAIL: Function does not have exponential backoff" - exit 1 -fi - -# Test 9: Verify retry logic for downloads -echo "" -echo "Test 9: Verify download retry logic" +echo "Test 8: Verify download retry logic" # Check for MAX_RETRIES variable if grep -q "MAX_RETRIES=" "$PROJECT_ROOT/install-gh-aw.sh"; then @@ -291,9 +215,9 @@ else exit 1 fi -# Test 10: Verify checksum validation functionality +# Test 9: Verify checksum validation functionality echo "" -echo "Test 10: Verify checksum validation functionality" +echo "Test 9: Verify checksum validation functionality" # Check for --skip-checksum flag if grep -q "\-\-skip-checksum" "$PROJECT_ROOT/install-gh-aw.sh"; then @@ -351,9 +275,9 @@ else exit 1 fi -# Test 11: Verify "latest" version functionality +# Test 10: Verify "latest" version functionality echo "" -echo "Test 11: Verify 'latest' version functionality" +echo "Test 10: Verify 'latest' version functionality" # Check for "latest" as default version if grep -q "using 'latest'" "$PROJECT_ROOT/install-gh-aw.sh"; then