You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+51-8Lines changed: 51 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@ The aim of **uppt** is to make a very simple, secure release workflow for mainta
10
10
11
11
### Set up your package for trusted publishing on npmjs.com
12
12
13
-
1. Visit `https://npmjs.com/<package-name>/settings` and add a new trusted publisher entry, pointing at your repo and the `release.yml` workflow, with the `npm stage publish` permission chip. Set the 'Environment name' to 'npm'.
13
+
1. Visit `https://npmjs.com/<package-name>/settings` and add a new trusted publisher entry, pointing at your repo and the `release.yml` workflow, with the `npm stage publish` permission chip. Set the 'Environment name' to 'npm'. In a monorepo, repeat this once per published package, pointing each entry at the same workflow and environment.
14
14
15
15
> [!NOTE]
16
16
> [Staged publishing](https://docs.npmjs.com/staged-publishing/) requires you to approve the publish before it goes live.
@@ -81,10 +81,8 @@ jobs:
81
81
# The chained dispatch from `release` lands here as a `workflow_dispatch`
82
82
# event on a `vX.Y.Z` tag ref. The `pack` job installs deps, runs
83
83
# `pnpm pack` (or `npm pack`), and uploads the tarball as a workflow
84
-
# artifact. Lifecycle scripts (`prepack`, `prepare`, `postpack`) run
85
-
# here, in a job with `permissions: {}` and no `npm` environment.
86
-
# Manual recovery uses the same path.
87
-
# (Run workflow -> pick a `v*` tag).
84
+
# artifact. See "Lifecycle scripts" below for what runs where. Manual
85
+
# recovery uses the same path (Run workflow -> pick a `v*` tag).
@@ -137,6 +135,7 @@ Whenever you push to the default branch, this action parses conventional commits
137
135
| `base-branch` | default branch | Base branch for the release PR. |
138
136
| `node-version` | `24` | Node version for the scripts. Needs `--experimental-strip-types` (Node 22.6+, 24+ recommended). |
139
137
| `checkout` | `true` | Set to `false` if the caller has already checked out with `fetch-depth: 0`. |
138
+
| `packages` | _(unset)_ | Newline-separated list of publishable workspace directories (paths or globs, e.g. `packages/*`). When set, uppt operates in monorepo lockstep mode. See [Monorepo support](#monorepo-support). |
140
139
141
140
### Creates a release (`danielroe/uppt/release`)
142
141
@@ -158,6 +157,7 @@ This subaction installs the package's dependencies, runs `pnpm pack --json` (if
158
157
| `node-version` | `24` | Node version for the scripts. Needs `--experimental-strip-types` (Node 22.6+, 24+ recommended). Ignored when `install` is `false`. |
159
158
| `checkout` | `true` | Set to `false` if the caller has already checked out the tag ref. |
160
159
| `install` | `true` | Set to `false` to handle `actions/setup-node` and dependency installation yourself. Useful when you want a pinned package manager version, a cached `node_modules`, or a hardened install policy. When `false`, the caller must put `node`, `npm`, and any package manager on PATH before `uppt/pack` runs. |
160
+
| `packages` | _(unset)_ | Newline-separated list of publishable workspace directories (paths or globs). Must match the value passed to `uppt/pr`. See [Monorepo support](#monorepo-support). |
161
161
162
162
| Output | Description |
163
163
| --- | --- |
@@ -167,15 +167,58 @@ This subaction installs the package's dependencies, runs `pnpm pack --json` (if
167
167
168
168
This subaction downloads the tarball uploaded by `uppt/pack` in the same workflow run and runs `npm stage publish ./<tarball>.tgz` with OIDC authentication. The staged version then needs to be approved by a maintainer with 2FA on npmjs.com before it goes live.
169
169
170
-
> [!IMPORTANT]
171
-
> `prepublishOnly` is **not** invoked: `uppt/publish` publishes the prebuilt tarball with `--ignore-scripts`. Move any logic you previously had in `prepublishOnly` into `prepack` so it runs during `uppt/pack` and the output lands in the tarball.
172
-
173
170
| Input | Default | Description |
174
171
| --- | --- | --- |
175
172
| `node-version` | `24` | Node version for the scripts and for `npm stage publish`. Needs `--experimental-strip-types` (Node 22.6+, 24+ recommended). |
| `files` | _(scan artifact)_ | Optional JSON array of tarball filenames to publish, as emitted by `uppt/pack`'s `files` output. When omitted, every `*.tgz` in the downloaded artifact is published. |
178
175
176
+
## Lifecycle scripts
177
+
178
+
uppt runs your package's lifecycle scripts at one specific point and skips them everywhere else. The aim is to keep the runner that produces the tarball from executing more third-party code than it has to.
179
+
180
+
- **During install** (inside `uppt/pack`): runs with `--ignore-scripts`. Your dependencies' `preinstall` / `install` / `postinstall` hooks do **not** fire, and neither does your own repo's `prepare`. This is deliberate: it's why a compromised transitive dependency can't run code on the publish runner. If your build genuinely needs a dependency's `postinstall` to have run, set `install: false` on `uppt/pack` and install yourself before the action runs.
181
+
- **During pack** (inside `uppt/pack`, after install): `prepack`, `prepare`, and `postpack` run. This is where your build belongs.
182
+
- **During publish** (inside `uppt/publish`): nothing runs. `prepublishOnly` is **not** invoked; the prebuilt tarball is published with `--ignore-scripts`. Move any logic you previously had in `prepublishOnly` into `prepack` so it runs during `uppt/pack` and the output lands in the tarball.
183
+
184
+
## Monorepo support
185
+
186
+
uppt supports lockstep monorepos: every publishable package shares a single version, gets bumped together, lands under one `vX.Y.Z` tag, and is staged in one workflow run.
187
+
188
+
Declare the publishable workspaces by passing the same `packages:` input to both `uppt/pr` and `uppt/pack`. Each line is a directory path or a glob; `!`-prefixed entries are excluded; workspaces whose `package.json` has `"private": true` are silently skipped (even when listed by an exact path), so playgrounds and example apps stay out of npm.
189
+
190
+
```yaml
191
+
pr:
192
+
# ...
193
+
steps:
194
+
- uses: danielroe/uppt/pr@<sha>
195
+
with:
196
+
token: ${{ secrets.GITHUB_TOKEN }}
197
+
packages: |
198
+
packages/*
199
+
!packages/playground
200
+
201
+
pack:
202
+
# ...
203
+
steps:
204
+
- uses: danielroe/uppt/pack@<sha>
205
+
with:
206
+
packages: |
207
+
packages/*
208
+
!packages/playground
209
+
```
210
+
211
+
The lockstep version comes from the workspaces themselves: every listed package must agree on a single semver `version`, and that's the version uppt bumps from. The root `package.json#version` (if present) is only bumped when it already matches the lockstep version, so a `0.0.0` or absent root version is left untouched.
212
+
213
+
> [!IMPORTANT]
214
+
> The `packages:` value on `uppt/pr` and `uppt/pack` must match. If they diverge, the release PR and the published tarballs will cover different sets of packages.
215
+
216
+
> [!IMPORTANT]
217
+
> If you use pnpm, every workspace you list under `packages:` must also be listed in your `pnpm-workspace.yaml`. `pnpm pack` resolves `workspace:` and `catalog:` specifiers via the workspace graph, so a directory missing from `pnpm-workspace.yaml` will produce a tarball with unresolved specifiers (or fail outright).
218
+
219
+
> [!NOTE]
220
+
> Independent versioning (per-package tags and cadence) is not yet supported. Track [#9](https://github.com/danielroe/uppt/issues/9) if you need it.
Copy file name to clipboardExpand all lines: pack/action.yml
+5Lines changed: 5 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,10 @@ inputs:
19
19
description: 'Whether the action should install the package''s dependencies itself. Set to `false` if the caller has already installed (e.g. with a pinned package manager version, a cached `node_modules`, or a hardened install policy). When `false`, the action will not run `actions/setup-node` either; the caller is responsible for putting `node`, `npm`, and any package manager on PATH before `uppt/pack` runs.'
20
20
required: false
21
21
default: 'true'
22
+
packages:
23
+
description: 'Newline-separated list of publishable workspace directories, relative to the repo root. Each line is a path or glob (e.g. `packages/*`); `!`-prefixed entries are excluded; workspaces with `"private": true` are skipped. Must match the value passed to `uppt/pr`. Omit for single-package repos.'
0 commit comments