Skip to content

fix: publish credential-login removal (#76) #224

fix: publish credential-login removal (#76)

fix: publish credential-login removal (#76) #224

Workflow file for this run

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"