name: Prod Release

# Manual prod release. Click "Run workflow" in the Actions tab to cut @latest
# from main. Gated by the `prod` GitHub Environment approval before any
# publishing or commit-push side effects run.

on:
  workflow_dispatch: {}

concurrency:
  group: prod-release
  cancel-in-progress: false

permissions:
  contents: write
  packages: write
  pull-requests: write

jobs:
  prod-release:
    name: Production Release
    runs-on: ubuntu-latest
    environment: prod
    steps:
      - uses: actions/checkout@v6
        with:
          ref: main
          fetch-depth: 0
          token: ${{ secrets.RELEASE_PAT }}

      - uses: actions/setup-node@v6
        with:
          node-version: '26.1'
          registry-url: https://registry.npmjs.org
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Cache Next.js build
        uses: actions/cache@v4
        with:
          path: web/.next/cache
          key: nextjs-${{ runner.os }}-${{ hashFiles('web/package-lock.json') }}-${{ hashFiles('web/app/**', 'web/components/**', 'web/lib/**', 'web/hooks/**') }}
          restore-keys: |
            nextjs-${{ runner.os }}-${{ hashFiles('web/package-lock.json') }}-
            nextjs-${{ runner.os }}-

      - name: Run live LLM tests (optional)
        continue-on-error: true
        run: npm run test:live || echo "::warning::Live LLM tests failed — non-blocking, but worth investigating"
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          SF_LIVE_TESTS: "1"

      - name: Generate changelog and determine version
        id: release
        run: |
          OUTPUT=$(node scripts/generate-changelog.mjs)
          echo "$OUTPUT" | jq .
          echo "version=$(echo "$OUTPUT" | jq -r '.newVersion')" >> "$GITHUB_OUTPUT"
          echo "$OUTPUT" | jq -r '.changelogEntry' > /tmp/changelog-entry.md
          echo "$OUTPUT" | jq -r '.releaseNotes' > /tmp/release-notes.md

      - name: Bump version and sync packages
        env:
          RELEASE_VERSION: ${{ steps.release.outputs.version }}
        run: node scripts/bump-version.mjs "$RELEASE_VERSION"

      - name: Validate package files after version bump
        run: |
          node -e "require('./package.json')" && \
          node -e "require('./packages/pi-coding-agent/package.json')" && \
          node -e "require('./pkg/package.json')" && \
          echo "All package.json files are valid"

      - name: Update CHANGELOG.md
        run: node scripts/update-changelog.mjs /tmp/changelog-entry.md

      - name: Commit and tag release
        env:
          RELEASE_VERSION: ${{ steps.release.outputs.version }}
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add package.json package-lock.json web/package-lock.json CHANGELOG.md rust-engine/npm/*/package.json pkg/package.json packages/*/package.json
          git commit -m "release: v${RELEASE_VERSION}"
          git pull --rebase origin main
          git tag "v${RELEASE_VERSION}"

      - name: Build release
        run: npm run build

      - name: Publish release to npm @latest
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          RELEASE_VERSION: ${{ steps.release.outputs.version }}
        run: |
          OUTPUT=$(npm publish 2>&1) && echo "$OUTPUT" || {
            if echo "$OUTPUT" | grep -q "cannot publish over the previously published"; then
              echo "Version already published — promoting to latest"
              npm dist-tag add "singularity-forge@${RELEASE_VERSION}" latest
            else
              echo "$OUTPUT"
              exit 1
            fi
          }

      - name: Push release commit and tag
        env:
          RELEASE_VERSION: ${{ steps.release.outputs.version }}
        run: |
          git push origin main
          git push origin "v${RELEASE_VERSION}"

      - name: Create GitHub Release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          RELEASE_VERSION: ${{ steps.release.outputs.version }}
        run: |
          gh release create "v${RELEASE_VERSION}" \
            --title "v${RELEASE_VERSION}" \
            --notes-file /tmp/release-notes.md \
            --latest

      - name: Post to Discord
        if: ${{ env.DISCORD_WEBHOOK != '' }}
        env:
          DISCORD_WEBHOOK: ${{ secrets.DISCORD_CHANGELOG_WEBHOOK }}
          RELEASE_VERSION: ${{ steps.release.outputs.version }}
        run: |
          NOTES=$(cat /tmp/release-notes.md)
          curl -s -X POST "$DISCORD_WEBHOOK" \
            -H "Content-Type: application/json" \
            -d "$(jq -n --arg c "**SF v${RELEASE_VERSION} Released**\n\n${NOTES}\n\n\`npm i singularity-forge@${RELEASE_VERSION}\`" '{content:$c}')"

      # Docker publish disabled — no ghcr.io package configured yet
      # - name: Log in to GHCR
      #   uses: docker/login-action@v4
      #   with:
      #     registry: ghcr.io
      #     username: ${{ github.actor }}
      #     password: ${{ secrets.GITHUB_TOKEN }}
      #
      # - name: Build and push release Docker image
      #   env:
      #     RELEASE_VERSION: ${{ steps.release.outputs.version }}
      #   run: |
      #     docker build --target runtime \
      #       -t ghcr.io/singularity-ng/singularity-forge:latest \
      #       -t "ghcr.io/singularity-ng/singularity-forge:${RELEASE_VERSION}" \
      #       .
      #     docker push "ghcr.io/singularity-ng/singularity-forge:${RELEASE_VERSION}"
      #     docker push ghcr.io/singularity-ng/singularity-forge:latest

      - name: Open back-merge PR main→next if behind
        env:
          GH_TOKEN: ${{ secrets.RELEASE_PAT }}
          RELEASE_VERSION: ${{ steps.release.outputs.version }}
        run: |
          if ! git ls-remote --exit-code --heads origin next >/dev/null 2>&1; then
            echo "next branch does not exist yet; skipping back-merge"
            exit 0
          fi
          git fetch origin next main
          BEHIND=$(git rev-list --count origin/next..origin/main)
          if [ "$BEHIND" -gt 0 ]; then
            BRANCH="backmerge/main-to-next-v${RELEASE_VERSION}"
            git checkout -B "$BRANCH" origin/main
            git push origin "$BRANCH" --force-with-lease
            gh pr create --base next --head "$BRANCH" \
              --title "chore: back-merge main to next (v${RELEASE_VERSION})" \
              --body "Sync release commit and version bump from main into next." || true
          else
            echo "next is up to date with main; no back-merge needed"
          fi
