Skip to content

native release

native release #15

Workflow file for this run

name: native release
on:
workflow_dispatch:
inputs:
mode:
description: Stage assets, verify an unpublished draft, or publish and update Homebrew.
required: true
type: choice
options:
- preflight
- draft
- publish
default: preflight
concurrency:
group: native-release-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.release-source.outputs.version }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24.15.0
- name: Validate release source
id: release-source
env:
GH_TOKEN: ${{ github.token }}
IMMUTABLE_RELEASES_ENABLED: ${{ vars.IMMUTABLE_RELEASES_ENABLED }}
run: |
set -euo pipefail
if [[ "$GITHUB_REF" != refs/tags/v* ]]; then
echo "::error::Select a v<version> tag under 'Run workflow from'; branches cannot produce releases. Selected reference: $GITHUB_REF"
exit 1
fi
version="${GITHUB_REF#refs/tags/v}"
package_version="$(node -p "require('./packages/cli/package.json').version")"
if [ "$version" != "$package_version" ]; then
echo "::error::Selected tag v$version does not match package version $package_version."
exit 1
fi
tag_commit="$(git rev-list -n 1 "v$version")"
if [ "$tag_commit" != "$GITHUB_SHA" ]; then
echo "::error::Selected tag v$version does not resolve to the checked-out commit."
exit 1
fi
if [ "$IMMUTABLE_RELEASES_ENABLED" != 'true' ]; then
echo "::error::Immutable GitHub Releases must be enabled before publishing native artifacts."
exit 1
fi
if gh release view "v$version" >/dev/null 2>&1; then
echo "::error::v$version already has a GitHub Release"
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
macos:
needs: validate
uses: ./.github/workflows/macos-release.yml
with:
production: true
version: ${{ needs.validate.outputs.version }}
secrets: inherit
linux:
needs: validate
permissions:
attestations: write
contents: read
id-token: write
uses: ./.github/workflows/linux-release.yml
with:
production: true
version: ${{ needs.validate.outputs.version }}
secrets: inherit
windows:
needs: validate
permissions:
contents: read
id-token: write
uses: ./.github/workflows/windows-release.yml
with:
publish: false
sign: true
tag: v${{ needs.validate.outputs.version }}
secrets: inherit
stage:
needs:
- validate
- macos
- linux
- windows
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
with:
node-version: 24.15.0
cache: pnpm
- name: Install
run: pnpm install --frozen-lockfile
- name: Download macOS release stage
uses: actions/download-artifact@v7
with:
name: inflow-native-macos-${{ needs.validate.outputs.version }}
path: dist/native/macos
- name: Download Linux release stage
uses: actions/download-artifact@v7
with:
name: inflow-native-linux-${{ needs.validate.outputs.version }}
path: dist/native/linux
- name: Download Windows release stage
uses: actions/download-artifact@v7
with:
name: inflow-windows-signed-release
path: dist/native/windows
- name: Assemble and verify release assets
env:
VERSION: ${{ needs.validate.outputs.version }}
run: |
set -euo pipefail
node scripts/assemble-native-release-assets.mjs \
dist/native/assets \
dist/native/macos \
dist/native/linux \
dist/native/windows
node scripts/verify-native-release-assets.mjs dist/native/assets "$VERSION"
- name: Upload verified release stage
uses: actions/upload-artifact@v6
with:
name: inflow-native-release-${{ needs.validate.outputs.version }}
path: dist/native/assets
if-no-files-found: error
retention-days: 7
publish:
if: inputs.mode != 'preflight'
needs:
- validate
- stage
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
with:
node-version: 24.15.0
cache: pnpm
- name: Install
run: pnpm install --frozen-lockfile
- name: Download verified release stage
uses: actions/download-artifact@v7
with:
name: inflow-native-release-${{ needs.validate.outputs.version }}
path: dist/native/assets
- name: Verify release assets
env:
VERSION: ${{ needs.validate.outputs.version }}
run: node scripts/verify-native-release-assets.mjs dist/native/assets "$VERSION"
- name: Create draft release with complete asset set
id: release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.validate.outputs.version }}
run: |
set -euo pipefail
existing_release_ids="$(gh api "repos/$GITHUB_REPOSITORY/releases" \
--jq ".[] | select(.tag_name == \"v$VERSION\") | .id")"
if [ -n "$existing_release_ids" ]; then
echo "::error::v$VERSION already has a GitHub Release"
exit 1
fi
gh release create "v$VERSION" dist/native/assets/* \
--draft \
--generate-notes \
--title "InFlow $VERSION" \
--verify-tag
release_id="$(gh api "repos/$GITHUB_REPOSITORY/releases" \
--jq ".[] | select(.draft and .tag_name == \"v$VERSION\") | .id")"
test -n "$release_id"
test "$(printf '%s\n' "$release_id" | wc -l | tr -d ' ')" = '1'
echo "release_id=$release_id" >> "$GITHUB_OUTPUT"
- name: Verify draft release assets
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.validate.outputs.version }}
run: |
set -euo pipefail
gh api "repos/$GITHUB_REPOSITORY/releases/${{ steps.release.outputs.release_id }}" > dist/native/release.json
node scripts/verify-native-release-assets.mjs dist/native/assets "$VERSION" dist/native/release.json
- name: Publish release
if: inputs.mode == 'publish'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_ID: ${{ steps.release.outputs.release_id }}
run: gh api --method PATCH "repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID" -F draft=false -f make_latest=true
- name: Verify published immutable release
if: inputs.mode == 'publish'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_ID: ${{ steps.release.outputs.release_id }}
VERSION: ${{ needs.validate.outputs.version }}
run: |
set -euo pipefail
gh api "repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID" > dist/native/release.json
test "$(jq -r '.draft' dist/native/release.json)" = 'false'
test "$(jq -r '.immutable' dist/native/release.json)" = 'true'
test "$(jq -r '.tag_name' dist/native/release.json)" = "v$VERSION"
node scripts/verify-native-release-assets.mjs dist/native/assets "$VERSION" dist/native/release.json
- name: Remove unpublished draft
if: failure() || inputs.mode == 'draft'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_ID: ${{ steps.release.outputs.release_id }}
run: |
if [ -n "$RELEASE_ID" ] && [ "$(gh api "repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID" --jq '.draft' 2>/dev/null)" = 'true' ]; then
gh api --method DELETE "repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID"
fi
homebrew:
if: inputs.mode == 'publish'
needs:
- validate
- publish
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- name: Download macOS release stage
uses: actions/download-artifact@v7
with:
name: inflow-native-macos-${{ needs.validate.outputs.version }}
path: dist/native/macos
- name: Resolve Homebrew Cask
id: cask
run: |
set -euo pipefail
cask="$(find dist/native/macos -type f -name inflow.rb -print -quit)"
test -n "$cask"
echo "path=$cask" >> "$GITHUB_OUTPUT"
- name: Create Homebrew tap token
id: homebrew-tap-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ vars.HOMEBREW_TAP_APP_CLIENT_ID }}
private-key: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }}
owner: inflowpayai
repositories: homebrew-tap
permission-contents: write
- name: Update Homebrew tap
env:
CASK: ${{ steps.cask.outputs.path }}
HOMEBREW_TAP_TOKEN: ${{ steps.homebrew-tap-token.outputs.token }}
VERSION: ${{ needs.validate.outputs.version }}
run: |
set -euo pipefail
tap="$RUNNER_TEMP/homebrew-tap"
git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/inflowpayai/homebrew-tap.git" "$tap"
cp "$CASK" "$tap/Casks/inflow.rb"
git -C "$tap" config user.name github-actions
git -C "$tap" config user.email github-actions@github.com
git -C "$tap" add Casks/inflow.rb
if git -C "$tap" diff --cached --quiet; then
exit 0
fi
git -C "$tap" commit -m "Update inflow to $VERSION"
git -C "$tap" push origin HEAD:main