name: Publish to npm

env:
  GH_TOKEN: ${{ github.token }}

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:

permissions:
  id-token: write
  contents: write

jobs:
  publish:
    environment: release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Setup Bun
        uses: oven-sh/setup-bun@v2

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: '24'
          registry-url: 'https://registry.npmjs.org'

      # Because GitHub & NPM can't figure out their shit
      - name: Update NPM
        run: npm install -g npm@latest

      - name: Install dependencies
        run: bun install

      - name: Build
        run: bun dev:build

      - name: Publish sandstone-cli
        run: npm publish --provenance

      - name: Publish create-sandstone
        run: |
          sed -i 's/"sandstone-cli"/"create-sandstone"/g' package.json
          npm publish --provenance

      - name: Prepare release metadata
        id: release
        run: |
          TAG="${GITHUB_REF_NAME}"
          PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${TAG}$" | head -n1)
          echo "prev_tag=${PREV_TAG}" >> $GITHUB_OUTPUT

          # Get commit message
          COMMIT_MSG=$(git log -1 --format=%B)
          COMMIT_TITLE=$(echo "$COMMIT_MSG" | head -n1)
          COMMIT_BODY=$(echo "$COMMIT_MSG" | tail -n +3)

          # Remove emoji prefix from title
          CLEAN_TITLE=$(echo "$COMMIT_TITLE" | sed -E 's/^[^ ]+ //')

          # Release title
          # Written to a file (not $GITHUB_OUTPUT) so backticks in the user's
          # title aren't lost when the title round-trips through GitHub
          # Actions' output interpolation into the next step's `--title`.
          echo "${TAG} - ${CLEAN_TITLE}" > release_title.txt

          # Build release body
          {
            if [[ -n "$COMMIT_BODY" ]]; then
              echo "$COMMIT_BODY"
              echo ""
            fi

            if [[ -n "$PREV_TAG" ]]; then
              echo "<details>"
              echo "<summary>Commits since ${PREV_TAG}</summary>"
              echo ""
              for COMMIT in $(git log --format="%H" "${PREV_TAG}..${TAG}"); do
                SUBJECT=$(git log -1 --format="%s" "$COMMIT")
                # Resolve GitHub login via API so @mention links correctly
                # even when the commit's author name differs from the login
                # (e.g. commits made via the github.com web editor use the
                # user's display name, not their handle).
                LOGIN=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${COMMIT}" --jq '.author.login // empty')
                if [[ -z "$LOGIN" ]]; then
                  EMAIL=$(git log -1 --format="%ae" "$COMMIT")
                  LOGIN=$(gh api "search/users?q=${EMAIL}+in:email" --jq '.items[0].login // empty' 2>/dev/null || true)
                fi
                if [[ -n "$LOGIN" ]]; then
                  AUTHOR="@${LOGIN}"
                else
                  AUTHOR="@$(git log -1 --format="%an" "$COMMIT")"
                fi
                COAUTHORS=$(git log -1 --format="%(trailers:key=Co-authored-by,valueonly)" "$COMMIT" | sed -n 's/\(.*\) <.*/\1/p' | sed 's/^/, @/')
                echo "- $COMMIT $SUBJECT (${AUTHOR}${COAUTHORS})"
              done
              echo ""
              echo "</details>"
              echo ""
              echo "**Full Changelog**: [${PREV_TAG}...${TAG}](https://github.com/sandstone-mc/sandstone-cli/compare/${PREV_TAG}...${TAG})"
            fi
          } > release_body.md

      - name: Create GitHub Release
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh release create "${{ github.ref_name }}" \
            --title "$(cat release_title.txt)" \
            --notes-file release_body.md

      # Fetch the release payload via the GitHub API so the Discord action
      # receives the same raw name / body / url that a `release: published`
      # event would carry. The action handles its own formatting downstream
      # (whitespace, head reduction, mention links), so feeding it identical
      # raw input guarantees identical output regardless of how this workflow
      # was triggered (push tag, manual dispatch, or release event).
      - name: Fetch release payload
        id: release_payload
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh release view "${{ github.ref_name }}" \
            --repo sandstone-mc/sandstone-cli \
            --json name,body,url > release.json

          {
            echo "name<<EOF_NAME"
            jq -r .name release.json
            echo "EOF_NAME"
            echo "body<<EOF_BODY"
            jq -r .body release.json
            echo "EOF_BODY"
            echo "url<<EOF_URL"
            jq -r .url release.json
            echo "EOF_URL"
          } >> "$GITHUB_OUTPUT"

      - name: Notify Discord
        if: success()
        uses: SethCohen/github-releases-to-discord@v1
        with:
          webhook_url: ${{ secrets.WEBHOOK_URL }}
          # Sandstone tan — `0xC2A878` = 12757112. Tweak to taste.
          color: 12757112
          username: "Sandstone CLI"
          footer_title: Changelog
          reduce_headings: true
          footer_timestamp: true
          release_name: ${{ steps.release_payload.outputs.name }}
          release_body: ${{ steps.release_payload.outputs.body }}
          release_html_url: ${{ steps.release_payload.outputs.url }}
