Improve CLI auth UX and logout revocation #63
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: bkper-cli-delivery | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| jobs: | |
| build-and-unit-test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Install optional peer required for type-checking | |
| run: npm install miniflare@^4 --no-save | |
| - name: Build | |
| run: bun run build | |
| - name: Unit tests | |
| run: bun run test:unit | |
| release: | |
| needs: build-and-unit-test | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: release-main | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| pull-requests: read | |
| id-token: write | |
| steps: | |
| - name: Determine release level from PR labels associated with this commit | |
| id: release_level | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const commitSha = context.sha; | |
| const levelByLabel = { | |
| 'release:patch': 'patch', | |
| 'release:minor': 'minor', | |
| 'release:major': 'major', | |
| }; | |
| const orderedLabels = ['release:major', 'release:minor', 'release:patch']; | |
| const { data: pulls } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ | |
| owner, | |
| repo, | |
| commit_sha: commitSha, | |
| }); | |
| const mergedPr = pulls.find(pr => pr.merged_at && pr.base?.ref === 'main'); | |
| if (!mergedPr) { | |
| core.info('No merged PR associated with this commit. Skipping release.'); | |
| core.setOutput('level', 'none'); | |
| return; | |
| } | |
| const labels = (mergedPr.labels ?? []) | |
| .map(label => typeof label === 'string' ? label : label.name) | |
| .filter(Boolean); | |
| const selectedLabel = orderedLabels.find(label => labels.includes(label)) ?? null; | |
| const level = selectedLabel ? levelByLabel[selectedLabel] : 'none'; | |
| core.info(`Merged PR: #${mergedPr.number} (${mergedPr.html_url})`); | |
| core.info(`Labels: ${labels.join(', ') || '(none)'}`); | |
| core.info(`Selected release level: ${level}`); | |
| core.setOutput('level', level); | |
| - name: Skip release (no release label) | |
| if: steps.release_level.outputs.level == 'none' | |
| run: echo "Skipping release due to missing release label" | |
| - name: Checkout main | |
| if: steps.release_level.outputs.level != 'none' | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: main | |
| fetch-depth: 0 | |
| - name: Setup Bun | |
| if: steps.release_level.outputs.level != 'none' | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Setup Node | |
| if: steps.release_level.outputs.level != 'none' | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| - name: Install dependencies | |
| if: steps.release_level.outputs.level != 'none' | |
| run: bun install | |
| - name: Install optional peer required for type-checking | |
| if: steps.release_level.outputs.level != 'none' | |
| run: npm install miniflare@^4 --no-save | |
| - name: Build and unit test | |
| if: steps.release_level.outputs.level != 'none' | |
| run: | | |
| bun run build | |
| bun run test:unit | |
| - name: Validate package version for this release | |
| if: steps.release_level.outputs.level != 'none' | |
| env: | |
| RELEASE_LEVEL: ${{ steps.release_level.outputs.level }} | |
| run: | | |
| set -euo pipefail | |
| git fetch --tags origin | |
| LATEST_TAG="$(git tag --list 'v*' --sort=-version:refname | head -n1)" | |
| PACKAGE_VERSION="$(node -p "require('./package.json').version")" | |
| EXPECTED_VERSION="$(node --input-type=module - "$LATEST_TAG" "$PACKAGE_VERSION" "$RELEASE_LEVEL" <<'NODE' | |
| import { resolveNextVersion } from './lib/release/versioning.js'; | |
| const [latestTag, packageVersion, level] = process.argv.slice(2); | |
| process.stdout.write(resolveNextVersion(latestTag || null, packageVersion, level)); | |
| NODE | |
| )" | |
| if [[ "$PACKAGE_VERSION" != "$EXPECTED_VERSION" ]]; then | |
| echo "package.json version $PACKAGE_VERSION does not match expected next $EXPECTED_VERSION for release level $RELEASE_LEVEL" | |
| exit 1 | |
| fi | |
| echo "VERSION=v${PACKAGE_VERSION}" >> "$GITHUB_ENV" | |
| - name: Upgrade npm | |
| if: steps.release_level.outputs.level != 'none' | |
| run: | | |
| npm install -g npm@11.11.0 | |
| npm install -g npm@11.12.1 | |
| - name: Print tool versions | |
| if: steps.release_level.outputs.level != 'none' | |
| run: | | |
| node -v | |
| npm -v | |
| - name: Ensure tokenless OIDC publishing context | |
| if: steps.release_level.outputs.level != 'none' | |
| run: | | |
| rm -f .npmrc ~/.npmrc || true | |
| unset NODE_AUTH_TOKEN NPM_TOKEN || true | |
| - name: Create release tag | |
| if: steps.release_level.outputs.level != 'none' | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag -a "${VERSION}" -m "${VERSION}" | |
| - name: Publish to npm (Trusted Publishers) | |
| if: steps.release_level.outputs.level != 'none' | |
| run: npm publish --access public --provenance --verbose | |
| - name: Push release tag | |
| if: steps.release_level.outputs.level != 'none' | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| run: git push origin "${VERSION}" | |
| - name: Notify Slack | |
| if: always() && steps.release_level.outputs.level != 'none' | |
| uses: pioug/le-slack-message@v1.0.0 | |
| with: | |
| ACTION_NAME: release ${{ env.VERSION || '' }} | |
| JOB: ${{ toJson(job) }} | |
| SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} |