-
Notifications
You must be signed in to change notification settings - Fork 0
172 lines (155 loc) · 5.47 KB
/
Copy pathrelease.yml
File metadata and controls
172 lines (155 loc) · 5.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
name: release
# Publishes the npm package and attaches a standalone binary per platform to
# the GitHub release. Pushing a version tag (`git tag v0.1.0 && git push
# --tags`) runs the full release. A manual run builds binaries and creates the
# release only — tick `publish_npm` to also publish to npm.
#
# Authentication: npm Trusted Publishing (OIDC) — no NPM_TOKEN secret. The
# `npm` job mints a short-lived OIDC token via `id-token: write` and npm
# verifies it against the trusted publisher configured for the package.
#
# Gating, in layers:
# 1. `authorize` hard-fails unless the actor is the repo owner; every other
# job depends on it.
# 2. Tag pushes and workflow_dispatch already require repo write access.
# 3. The `npm` job runs in the `release` GitHub Environment — add a required
# reviewer to that environment for a manual approval gate.
#
# One-time setup (the package must exist before a trusted publisher can be
# configured, so the FIRST publish is manual):
# a. Locally: `npm login` then `npm publish` once.
# b. npmjs.com -> the package -> Settings -> Trusted Publisher -> GitHub
# Actions. Org: AirswitchAsa, Repo: exa-cli, Workflow: release.yml,
# Environment: release.
# c. GitHub repo -> Settings -> Environments -> create `release` (optionally
# add yourself as a required reviewer).
# Every tagged release after that publishes through this workflow.
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g. v0.1.0). Created if it does not exist."
required: true
type: string
publish_npm:
description: "Also publish to npm. Leave off for a binary-only (re)build."
type: boolean
default: false
push:
tags:
- "v*"
# No ambient permissions; each job is granted only what it needs.
permissions: {}
jobs:
authorize:
runs-on: ubuntu-latest
steps:
- name: Restrict to repo owner
env:
ACTOR: ${{ github.actor }}
OWNER: ${{ github.repository_owner }}
run: |
if [ "$ACTOR" != "$OWNER" ]; then
echo "::error::Release workflow is restricted to the repo owner ($OWNER); actor was $ACTOR"
exit 1
fi
npm:
name: Publish to npm
needs: authorize
# Tag pushes always publish; manual runs only when publish_npm is ticked.
if: github.event_name == 'push' || inputs.publish_npm
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write # mint the OIDC token for npm trusted publishing
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org
- name: Use a trusted-publishing-capable npm
run: npm install -g npm@latest # trusted publishing needs npm >= 11.5.1
- run: npm ci
# No NODE_AUTH_TOKEN: npm authenticates via OIDC. `npm publish` runs
# prepublishOnly (lint, typecheck, test, build) and, because the repo and
# package are public, auto-generates provenance attestations.
- run: npm publish
binaries:
name: Build ${{ matrix.target }}
needs: authorize
runs-on: ${{ matrix.runner }}
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- target: exa-cli-darwin-arm64
runner: macos-14
ext: ""
- target: exa-cli-linux-x64
runner: ubuntu-22.04
ext: ""
- target: exa-cli-linux-arm64
runner: ubuntu-22.04-arm
ext: ""
- target: exa-cli-windows-x64
runner: windows-latest
ext: ".exe"
steps:
- uses: actions/checkout@v5
- uses: oven-sh/setup-bun@v2
- run: bun install
- name: Build standalone binary
shell: bash
run: bun build src/cli.ts --compile --outfile "dist-bin/exa-cli${{ matrix.ext }}"
- name: Smoke test
shell: bash
run: "dist-bin/exa-cli${{ matrix.ext }} --help"
- name: Stage asset
shell: bash
run: |
mkdir -p artifacts
cp "dist-bin/exa-cli${{ matrix.ext }}" "artifacts/${{ matrix.target }}${{ matrix.ext }}"
- uses: actions/upload-artifact@v5
with:
name: ${{ matrix.target }}
path: artifacts/${{ matrix.target }}${{ matrix.ext }}
if-no-files-found: error
release:
name: Publish release
needs: [authorize, binaries]
runs-on: ubuntu-latest
permissions:
contents: write # create and upload to the GitHub release
steps:
- uses: actions/checkout@v5
- uses: actions/download-artifact@v5
with:
path: artifacts
merge-multiple: true
- name: Resolve tag
id: tag
shell: bash
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo "name=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
else
echo "name=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
fi
- name: Create or update release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.tag.outputs.name }}
shell: bash
run: |
set -euo pipefail
if ! gh release view "$TAG" >/dev/null 2>&1; then
gh release create "$TAG" \
--title "$TAG" \
--generate-notes \
--target "${GITHUB_SHA}"
fi
gh release upload "$TAG" artifacts/* --clobber