name: 'Release: Rollback change'

on:
  workflow_dispatch:
    inputs:
      rollback_origin:
        description: 'The package version to rollback FROM and delete (e.g., 0.5.0-preview-2)'
        required: true
        type: 'string'
      rollback_destination:
        description: 'The package version to rollback TO (e.g., 0.5.0-preview-2). This version must already exist on the npm registry.'
        required: false
        type: 'string'
      channel:
        description: 'The npm dist-tag to apply to rollback_destination (e.g., latest, preview, nightly). REQUIRED IF rollback_destination is set.'
        required: false
        type: 'choice'
        options:
          - 'latest'
          - 'preview'
          - 'nightly'
          - 'dev'
        default: 'dev'
      ref:
        description: 'The branch, tag, or SHA to run from.'
        required: false
        type: 'string'
        default: 'main'
      dry-run:
        description: 'Whether to run in dry-run mode.'
        required: false
        type: 'boolean'
        default: true
      environment:
        description: 'Environment'
        required: false
        type: 'choice'
        options:
          - 'prod'
          - 'dev'
        default: 'prod'

jobs:
  change-tags:
    if: "github.repository == 'google-gemini/gemini-cli'"
    environment: "${{ github.event.inputs.environment || 'prod' }}"
    runs-on: 'ubuntu-latest'
    permissions:
      packages: 'write'
      issues: 'write'
    steps:
      - name: 'Checkout repository'
        uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
        with:
          persist-credentials: false
          ref: '${{ github.event.inputs.ref }}'
          fetch-depth: 0

      - name: 'Setup Node.js'
        uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
        with:
          node-version-file: '.nvmrc'

      - name: 'configure .npmrc'
        uses: './.github/actions/setup-npmrc'
        with:
          github-token: '${{ secrets.GITHUB_TOKEN }}'

      - name: 'Get Origin Version Tag'
        id: 'origin_tag'
        shell: 'bash'
        env:
          ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
        run: |
          TAG_VALUE="v${ROLLBACK_ORIGIN}"
          echo "ORIGIN_TAG=$TAG_VALUE" >> "$GITHUB_OUTPUT"

      - name: 'Get Origin Commit Hash'
        id: 'origin_hash'
        env:
          GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
          ORIGIN_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
        shell: 'bash'
        run: |
          echo "ORIGIN_HASH=$(git rev-parse "${ORIGIN_TAG}")" >> "$GITHUB_OUTPUT"

      - name: 'Change tag'
        if: "${{ github.event.inputs.rollback_destination != '' }}"
        uses: './.github/actions/tag-npm-release'
        with:
          channel: '${{ github.event.inputs.channel }}'
          version: '${{ github.event.inputs.rollback_destination }}'
          dry-run: '${{ github.event.inputs.dry-run }}'
          wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
          wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
          wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
          github-token: '${{ secrets.GITHUB_TOKEN }}'
          cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
          core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
          a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'

      - name: 'Get cli Token'
        uses: './.github/actions/npm-auth-token'
        id: 'cli-token'
        with:
          package-name: '${{ vars.CLI_PACKAGE_NAME }}'
          github-token: '${{ secrets.GITHUB_TOKEN }}'
          wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
          wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
          wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'

      - name: 'Deprecate Cli Npm Package'
        if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod' }}"
        env:
          NODE_AUTH_TOKEN: '${{ steps.cli-token.outputs.auth-token }}'
          PACKAGE_NAME: '${{ vars.CLI_PACKAGE_NAME }}'
          ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
        shell: 'bash'
        run: |
          npm deprecate "${PACKAGE_NAME}@${ROLLBACK_ORIGIN}" "This version has been rolled back."

      - name: 'Get core Token'
        uses: './.github/actions/npm-auth-token'
        id: 'core-token'
        with:
          package-name: '${{ vars.CLI_PACKAGE_NAME }}'
          github-token: '${{ secrets.GITHUB_TOKEN }}'
          wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
          wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
          wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'

      - name: 'Deprecate Core Npm Package'
        if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod' }}"
        env:
          NODE_AUTH_TOKEN: '${{ steps.core-token.outputs.auth-token }}'
          PACKAGE_NAME: '${{ vars.CORE_PACKAGE_NAME }}'
          ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
        shell: 'bash'
        run: |
          npm deprecate "${PACKAGE_NAME}@${ROLLBACK_ORIGIN}" "This version has been rolled back."

      - name: 'Get a2a Token'
        uses: './.github/actions/npm-auth-token'
        id: 'a2a-token'
        with:
          package-name: '${{ vars.A2A_PACKAGE_NAME }}'
          github-token: '${{ secrets.GITHUB_TOKEN }}'
          wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
          wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
          wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'

      - name: 'Deprecate A2A Server Npm Package'
        if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod'  }}"
        env:
          NODE_AUTH_TOKEN: '${{ steps.a2a-token.outputs.auth-token }}'
          PACKAGE_NAME: '${{ vars.A2A_PACKAGE_NAME }}'
          ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
        shell: 'bash'
        run: |
          npm deprecate "${PACKAGE_NAME}@${ROLLBACK_ORIGIN}" "This version has been rolled back."

      - name: 'Delete Github Release'
        if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod'}}"
        env:
          GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
          ORIGIN_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
        shell: 'bash'
        run: |
          gh release delete "${ORIGIN_TAG}" --yes

      - name: 'Verify Origin Release Deletion'
        if: "${{ github.event.inputs.dry-run == 'false' }}"
        env:
          GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
          TARGET_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
        shell: 'bash'
        run: |
          RELEASE_TAG=$(gh release view "$TARGET_TAG" --json tagName --jq .tagName)
          if [ "$RELEASE_TAG" = "$TARGET_TAG" ]; then
            echo "❌ Failed to delete release with tag ${TARGET_TAG}"
            echo '❌ This means the release was not deleted, and the workflow should fail.'
            exit 1
          fi

      - name: 'Add Rollback Tag'
        id: 'rollback_tag'
        if: "${{ github.event.inputs.dry-run == 'false' }}"
        env:
          GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
          ROLLBACK_TAG_NAME: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}-rollback'
          ORIGIN_HASH: '${{ steps.origin_hash.outputs.ORIGIN_HASH }}'
        shell: 'bash'
        run: |
          echo "ROLLBACK_TAG=$ROLLBACK_TAG_NAME" >> "$GITHUB_OUTPUT"
          git tag "$ROLLBACK_TAG_NAME" "${ORIGIN_HASH}"
          git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" --tags

      - name: 'Verify Rollback Tag Added'
        if: "${{ github.event.inputs.dry-run == 'false' }}"
        env:
          GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
          TARGET_TAG: '${{ steps.rollback_tag.outputs.ROLLBACK_TAG }}'
          TARGET_HASH: '${{ steps.origin_hash.outputs.ORIGIN_HASH }}'
        shell: 'bash'
        run: |
          ROLLBACK_COMMIT=$(git rev-parse -q --verify "$TARGET_TAG")
          if [ "$ROLLBACK_COMMIT" != "$TARGET_HASH" ]; then
            echo "❌ Failed to add tag ${TARGET_TAG} to commit ${TARGET_HASH}"
            echo '❌ This means the tag was not added, and the workflow should fail.'
            exit 1
          fi

      - name: 'Log Dry run'
        if: "${{ github.event.inputs.dry-run == 'true' }}"
        env:
          ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
          ROLLBACK_DESTINATION: '${{ github.event.inputs.rollback_destination }}'
          CHANNEL: '${{ github.event.inputs.channel }}'
          REF_INPUT: '${{ github.event.inputs.ref }}'
          ORIGIN_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
          ORIGIN_HASH: '${{ steps.origin_hash.outputs.ORIGIN_HASH }}'
          ROLLBACK_TAG: '${{ steps.rollback_tag.outputs.ROLLBACK_TAG }}'
          CLI_PACKAGE_NAME: '${{ vars.CLI_PACKAGE_NAME }}'
          CORE_PACKAGE_NAME: '${{ vars.CORE_PACKAGE_NAME }}'
          A2A_PACKAGE_NAME: '${{ vars.A2A_PACKAGE_NAME }}'
        shell: 'bash'
        run: |
          echo "
          Inputs:
          - rollback_origin: '${ROLLBACK_ORIGIN}'
          - rollback_destination: '${ROLLBACK_DESTINATION}'
          - channel: '${CHANNEL}'
          - ref: '${REF_INPUT}'

          Outputs:
          - ORIGIN_TAG: '${ORIGIN_TAG}'
          - ORIGIN_HASH: '${ORIGIN_HASH}'
          - ROLLBACK_TAG: '${ROLLBACK_TAG}'

          Would have npm deprecate ${CLI_PACKAGE_NAME}@${ROLLBACK_ORIGIN}, ${CORE_PACKAGE_NAME}@${ROLLBACK_ORIGIN}, and ${A2A_PACKAGE_NAME}@${ROLLBACK_ORIGIN}
          Would have deleted the github release with tag ${ORIGIN_TAG}
          Would have added tag ${ORIGIN_TAG}-rollback to ${ORIGIN_HASH}
          "
