fix: publish credential-login removal (#76) #224
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: Existing stable tag to resume or reconcile, for example v1.5.1 | |
| required: true | |
| type: string | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| permissions: {} | |
| jobs: | |
| verify: | |
| if: github.event_name != 'push' || !contains(github.event.head_commit.message, '[skip ci]') | |
| name: Verify CLI | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Vite+ | |
| uses: ./.github/actions/setup-vp | |
| with: | |
| node-version-file: ".node-version" | |
| cache: true | |
| - name: Install dependencies | |
| run: vp install | |
| - name: Verify repository | |
| run: vp run verify | |
| release: | |
| if: >- | |
| ${{ | |
| github.ref == 'refs/heads/main' && | |
| ( | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name == 'push' && !contains(github.event.head_commit.message, '[skip ci]')) | |
| ) | |
| }} | |
| name: Release CLI | |
| needs: | |
| - verify | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| env: | |
| PUTIO_CLI_REQUIRE_SENTRY_DSN: "true" | |
| PUTIO_CLI_SENTRY_DSN: ${{ vars.PUTIO_CLI_SENTRY_DSN }} | |
| environment: | |
| name: release | |
| deployment: false | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| release_state: ${{ steps.release-target.outputs.state }} | |
| release_tag: ${{ steps.release-target.outputs.tag }} | |
| release_version: ${{ steps.release-target.outputs.version }} | |
| steps: | |
| - name: Create release bot token | |
| id: release-bot | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| client-id: ${{ vars.PUTIO_RELEASE_BOT_CLIENT_ID }} | |
| private-key: ${{ secrets.PUTIO_RELEASE_BOT_PRIVATE_KEY }} | |
| permission-contents: write | |
| permission-issues: write | |
| permission-pull-requests: write | |
| - name: Resolve release bot identity | |
| id: release-bot-identity | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ steps.release-bot.outputs.token }} | |
| APP_SLUG: ${{ steps.release-bot.outputs.app-slug }} | |
| run: | | |
| set -euo pipefail | |
| user_id="$(gh api "/users/${APP_SLUG}%5Bbot%5D" --jq .id)" | |
| if [[ ! "$user_id" =~ ^[0-9]+$ ]]; then | |
| echo "failed to resolve numeric bot user id for ${APP_SLUG}[bot]" >&2 | |
| exit 1 | |
| fi | |
| echo "user_id=${user_id}" >> "$GITHUB_OUTPUT" | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Vite+ | |
| uses: ./.github/actions/setup-vp | |
| with: | |
| node-version-file: ".node-version" | |
| cache: false | |
| - name: Install dependencies | |
| run: vp install | |
| - name: Build package | |
| if: github.event_name != 'workflow_dispatch' | |
| run: vp run build | |
| - name: Configure release bot remote | |
| if: github.event_name != 'workflow_dispatch' | |
| run: git remote set-url origin "https://x-access-token:${RELEASE_BOT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" | |
| env: | |
| RELEASE_BOT_TOKEN: ${{ steps.release-bot.outputs.token }} | |
| - name: Release package | |
| if: github.event_name != 'workflow_dispatch' | |
| id: semantic | |
| uses: cycjimmy/semantic-release-action@b12c8f6015dc215fe37bc154d4ad456dd3833c90 # v6.0.0 | |
| with: | |
| extra_plugins: | | |
| @semantic-release/commit-analyzer@13.0.1 | |
| @semantic-release/release-notes-generator@14.1.1 | |
| @semantic-release/npm@13.1.5 | |
| @semantic-release/github@12.0.8 | |
| @semantic-release/git@10.0.1 | |
| conventional-changelog-conventionalcommits@9.3.1 | |
| env: | |
| GITHUB_TOKEN: ${{ steps.release-bot.outputs.token }} | |
| GIT_AUTHOR_NAME: ${{ steps.release-bot.outputs.app-slug }}[bot] | |
| GIT_AUTHOR_EMAIL: ${{ steps.release-bot-identity.outputs.user_id }}+${{ steps.release-bot.outputs.app-slug }}[bot]@users.noreply.github.com | |
| GIT_COMMITTER_NAME: ${{ steps.release-bot.outputs.app-slug }}[bot] | |
| GIT_COMMITTER_EMAIL: ${{ steps.release-bot-identity.outputs.user_id }}+${{ steps.release-bot.outputs.app-slug }}[bot]@users.noreply.github.com | |
| - name: Resolve exact release target | |
| id: release-target | |
| env: | |
| GH_TOKEN: ${{ steps.release-bot.outputs.token }} | |
| NEW_RELEASE_TAG: ${{ steps.semantic.outputs.new_release_git_tag }} | |
| REQUESTED_RELEASE_TAG: ${{ inputs.release_tag }} | |
| run: | | |
| set -euo pipefail | |
| git fetch origin main --tags --force | |
| tag="${REQUESTED_RELEASE_TAG:-$NEW_RELEASE_TAG}" | |
| if [[ -z "$tag" ]]; then | |
| echo "state=absent" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "unsupported release tag: $tag" >&2 | |
| exit 1 | |
| fi | |
| if ! git merge-base --is-ancestor "$tag" origin/main; then | |
| echo "release tag is not on origin/main: $tag" >&2 | |
| exit 1 | |
| fi | |
| release="$(gh release view "$tag" --repo "$GITHUB_REPOSITORY" --json isDraft,isPrerelease,tagName)" | |
| if [[ "$(jq -r .tagName <<<"$release")" != "$tag" ]]; then | |
| echo "release lookup returned the wrong tag" >&2 | |
| exit 1 | |
| fi | |
| if [[ "$(jq -r .isPrerelease <<<"$release")" != "false" ]]; then | |
| echo "stable release tag resolved to a prerelease: $tag" >&2 | |
| exit 1 | |
| fi | |
| state="$([[ "$(jq -r .isDraft <<<"$release")" == "true" ]] && echo draft || echo published)" | |
| { | |
| echo "tag=$tag" | |
| echo "version=${tag#v}" | |
| echo "state=$state" | |
| } >> "$GITHUB_OUTPUT" | |
| build-unix-binaries: | |
| if: needs.release.outputs.release_state == 'draft' | |
| name: Build ${{ matrix.os }} release assets | |
| needs: | |
| - release | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 30 | |
| env: | |
| PUTIO_CLI_REQUIRE_SENTRY_DSN: "true" | |
| PUTIO_CLI_SENTRY_DSN: ${{ vars.PUTIO_CLI_SENTRY_DSN }} | |
| environment: | |
| name: release | |
| deployment: false | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| asset_os: linux | |
| asset_arch: amd64 | |
| - os: macos-latest | |
| asset_os: darwin | |
| asset_arch: arm64 | |
| steps: | |
| - name: Create release bot token | |
| id: release-bot | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| client-id: ${{ vars.PUTIO_RELEASE_BOT_CLIENT_ID }} | |
| private-key: ${{ secrets.PUTIO_RELEASE_BOT_PRIVATE_KEY }} | |
| permission-contents: write | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ needs.release.outputs.release_tag }} | |
| persist-credentials: false | |
| - name: Set up Vite+ | |
| uses: ./.github/actions/setup-vp | |
| with: | |
| node-version-file: ".node-version" | |
| cache: false | |
| - name: Install dependencies | |
| run: vp install | |
| - name: Build SEA binary | |
| run: vp run build:sea | |
| - name: Verify SEA binary | |
| run: vp run verify:sea | |
| - name: Package release assets | |
| shell: pwsh | |
| run: | | |
| $version = "${{ needs.release.outputs.release_version }}" | |
| $assetBase = "putio-cli-$version-${{ matrix.asset_os }}-${{ matrix.asset_arch }}" | |
| $releaseDir = ".artifacts/release" | |
| New-Item -ItemType Directory -Force -Path $releaseDir | Out-Null | |
| $binaryPath = ".artifacts/sea/putio" | |
| $stageDir = "$releaseDir/stage" | |
| New-Item -ItemType Directory -Force -Path $stageDir | Out-Null | |
| Copy-Item $binaryPath "$stageDir/putio" | |
| tar -czf "$releaseDir/$assetBase.tar.gz" -C $stageDir putio | |
| Remove-Item -Recurse -Force $stageDir | |
| $assetPath = "$releaseDir/$assetBase.tar.gz" | |
| $hash = (Get-FileHash -Algorithm SHA256 $assetPath).Hash.ToLower() | |
| "$hash $(Split-Path $assetPath -Leaf)" | Out-File "$assetPath.sha256" -Encoding ascii -NoNewline | |
| - name: Generate SHA-256 checksums | |
| shell: pwsh | |
| run: Get-ChildItem .artifacts/release | |
| - name: Upload binary assets to the GitHub release | |
| uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3 | |
| with: | |
| token: ${{ steps.release-bot.outputs.token }} | |
| tag_name: ${{ needs.release.outputs.release_tag }} | |
| draft: true | |
| files: | | |
| .artifacts/release/* | |
| build-windows-binary: | |
| if: needs.release.outputs.release_state == 'draft' | |
| name: Build windows-latest release assets | |
| needs: | |
| - release | |
| runs-on: windows-latest | |
| timeout-minutes: 30 | |
| env: | |
| PUTIO_CLI_REQUIRE_SENTRY_DSN: "true" | |
| PUTIO_CLI_SENTRY_DSN: ${{ vars.PUTIO_CLI_SENTRY_DSN }} | |
| environment: | |
| name: release | |
| deployment: false | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Create release bot token | |
| id: release-bot | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| client-id: ${{ vars.PUTIO_RELEASE_BOT_CLIENT_ID }} | |
| private-key: ${{ secrets.PUTIO_RELEASE_BOT_PRIVATE_KEY }} | |
| permission-contents: write | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ needs.release.outputs.release_tag }} | |
| persist-credentials: false | |
| - name: Set up Vite+ | |
| uses: ./.github/actions/setup-vp | |
| with: | |
| node-version-file: ".node-version" | |
| cache: false | |
| - name: Install dependencies | |
| run: vp install | |
| - name: Build SEA binary | |
| run: vp run build:sea | |
| - name: Verify SEA binary | |
| run: vp run verify:sea | |
| - name: Package release assets | |
| shell: pwsh | |
| run: | | |
| $version = "${{ needs.release.outputs.release_version }}" | |
| $assetBase = "putio-cli-$version-windows-amd64" | |
| $releaseDir = ".artifacts/release" | |
| New-Item -ItemType Directory -Force -Path $releaseDir | Out-Null | |
| $binaryPath = ".artifacts/sea/putio.exe" | |
| Compress-Archive -Path $binaryPath -DestinationPath "$releaseDir/$assetBase.zip" -Force | |
| $assetPath = "$releaseDir/$assetBase.zip" | |
| $hash = (Get-FileHash -Algorithm SHA256 $assetPath).Hash.ToLower() | |
| "$hash $(Split-Path $assetPath -Leaf)" | Out-File "$assetPath.sha256" -Encoding ascii -NoNewline | |
| - name: Generate SHA-256 checksums | |
| shell: pwsh | |
| run: Get-ChildItem .artifacts/release | |
| - name: Upload binary assets to the GitHub release | |
| uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3 | |
| with: | |
| token: ${{ steps.release-bot.outputs.token }} | |
| tag_name: ${{ needs.release.outputs.release_tag }} | |
| draft: true | |
| files: | | |
| .artifacts/release/* | |
| finalize-release: | |
| if: >- | |
| ${{ | |
| !cancelled() && | |
| needs.release.result == 'success' && | |
| needs.release.outputs.release_state != 'absent' && | |
| ( | |
| needs.release.outputs.release_state == 'published' || | |
| ( | |
| needs.release.outputs.release_state == 'draft' && | |
| needs.build-unix-binaries.result == 'success' && | |
| needs.build-windows-binary.result == 'success' | |
| ) | |
| ) | |
| }} | |
| name: Verify and publish GitHub release | |
| needs: | |
| - release | |
| - build-unix-binaries | |
| - build-windows-binary | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| environment: | |
| name: release | |
| deployment: false | |
| permissions: | |
| contents: read | |
| outputs: | |
| release_ready: ${{ steps.finalized.outputs.ready }} | |
| steps: | |
| - name: Create release bot token | |
| id: release-bot | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| client-id: ${{ vars.PUTIO_RELEASE_BOT_CLIENT_ID }} | |
| private-key: ${{ secrets.PUTIO_RELEASE_BOT_PRIVATE_KEY }} | |
| permission-contents: write | |
| - name: Verify asset manifest and finalize release | |
| id: finalized | |
| env: | |
| GH_TOKEN: ${{ steps.release-bot.outputs.token }} | |
| RELEASE_TAG: ${{ needs.release.outputs.release_tag }} | |
| RELEASE_VERSION: ${{ needs.release.outputs.release_version }} | |
| run: | | |
| set -euo pipefail | |
| release="$(gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --json assets,isDraft,isPrerelease)" | |
| [[ "$(jq -r .isPrerelease <<<"$release")" == "false" ]] | |
| expected="$(printf '%s\n' \ | |
| "putio-cli-${RELEASE_VERSION}-darwin-arm64.tar.gz" \ | |
| "putio-cli-${RELEASE_VERSION}-darwin-arm64.tar.gz.sha256" \ | |
| "putio-cli-${RELEASE_VERSION}-linux-amd64.tar.gz" \ | |
| "putio-cli-${RELEASE_VERSION}-linux-amd64.tar.gz.sha256" \ | |
| "putio-cli-${RELEASE_VERSION}-windows-amd64.zip" \ | |
| "putio-cli-${RELEASE_VERSION}-windows-amd64.zip.sha256" | sort)" | |
| actual="$(jq -r '.assets[].name' <<<"$release" | sort)" | |
| diff -u <(printf '%s\n' "$expected") <(printf '%s\n' "$actual") | |
| if [[ "$(jq -r .isDraft <<<"$release")" == "true" ]]; then | |
| gh release edit "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --draft=false --latest | |
| fi | |
| echo "ready=true" >> "$GITHUB_OUTPUT" | |
| update-homebrew-tap: | |
| if: needs.finalize-release.outputs.release_ready == 'true' | |
| name: Update Homebrew tap | |
| needs: | |
| - release | |
| - finalize-release | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| environment: | |
| name: release | |
| deployment: false | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Create Homebrew release bot token | |
| id: homebrew-release-bot | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| client-id: ${{ vars.PUTIO_RELEASE_BOT_CLIENT_ID }} | |
| private-key: ${{ secrets.PUTIO_RELEASE_BOT_PRIVATE_KEY }} | |
| owner: putdotio | |
| repositories: | | |
| putio-cli | |
| homebrew-tap | |
| permission-contents: write | |
| - name: Resolve Homebrew release bot user ID | |
| id: homebrew-release-bot-user | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ steps.homebrew-release-bot.outputs.token }} | |
| APP_SLUG: ${{ steps.homebrew-release-bot.outputs.app-slug }} | |
| run: | | |
| set -euo pipefail | |
| user_id="$(gh api "/users/${APP_SLUG}%5Bbot%5D" --jq .id)" | |
| if [[ ! "$user_id" =~ ^[0-9]+$ ]]; then | |
| echo "failed to resolve numeric bot user id for ${APP_SLUG}[bot]" >&2 | |
| exit 1 | |
| fi | |
| echo "user_id=${user_id}" >> "$GITHUB_OUTPUT" | |
| - name: Release to Homebrew tap | |
| uses: Justintime50/homebrew-releaser@a62d7a359683bfc047cdb2431f53ee58241464d1 # v3 | |
| with: | |
| homebrew_owner: putdotio | |
| homebrew_tap: homebrew-tap | |
| github_token: ${{ steps.homebrew-release-bot.outputs.token }} | |
| commit_owner: ${{ steps.homebrew-release-bot.outputs.app-slug }}[bot] | |
| commit_email: ${{ steps.homebrew-release-bot-user.outputs.user_id }}+${{ steps.homebrew-release-bot.outputs.app-slug }}[bot]@users.noreply.github.com | |
| branch: main | |
| formula_folder: Formula | |
| version: ${{ needs.release.outputs.release_tag }} | |
| install: 'bin.install "putio"' | |
| test: | | |
| output = shell_output("#{bin}/putio version") | |
| assert_match "putio", output | |
| assert_match version.to_s, output | |
| target_darwin_arm64: true | |
| target_linux_amd64: true | |
| skip_checksum: true | |
| ignore_warnings: true | |
| - name: Verify Homebrew tap points at the release | |
| env: | |
| GH_TOKEN: ${{ steps.homebrew-release-bot.outputs.token }} | |
| RELEASE_TAG: ${{ needs.release.outputs.release_tag }} | |
| RELEASE_VERSION: ${{ needs.release.outputs.release_version }} | |
| run: | | |
| set -euo pipefail | |
| formula="$(gh api repos/putdotio/homebrew-tap/contents/Formula/putio-cli.rb --jq .content | base64 --decode)" | |
| grep -Fq "/archive/refs/tags/${RELEASE_TAG}.tar.gz" <<<"$formula" | |
| grep -Fq "/releases/download/${RELEASE_TAG}/putio-cli-${RELEASE_VERSION}-darwin-arm64.tar.gz" <<<"$formula" | |
| grep -Fq "/releases/download/${RELEASE_TAG}/putio-cli-${RELEASE_VERSION}-linux-amd64.tar.gz" <<<"$formula" |