Skip to content

Commit 3f82114

Browse files
Bring in release changes
1 parent 56c9475 commit 3f82114

3 files changed

Lines changed: 212 additions & 0 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: First Package Release
2+
3+
# Bootstrap workflow for brand-new npm packages.
4+
#
5+
# npm Trusted Publishing cannot be configured until a package already exists on
6+
# the registry. This manual workflow handles that one-time gap by using a short
7+
# lived NPM_TOKEN secret to publish only public workspace packages whose package
8+
# name is not on npm yet. It skips packages that already exist, even when the
9+
# local version has not been published.
10+
#
11+
# This runs through changesets/action so successful first publishes get the
12+
# same tag and GitHub Release behavior as the normal Release workflow. It must
13+
# run on a versioned checkout with no pending changeset files; otherwise
14+
# changesets/action would create/update a release PR instead of publishing.
15+
# Newly published packages must already have a CHANGELOG.md entry for their
16+
# current version, because changesets/action uses that entry as the GitHub
17+
# Release body.
18+
#
19+
# Before running:
20+
# - Create a temporary npm granular access token with read/write access to the
21+
# relevant scope, a short expiration, and 2FA bypass for automation.
22+
# Command-line equivalent:
23+
# npm token create \
24+
# --name "first-package-release" \
25+
# --expires 1 \
26+
# --scopes @fujocoded \
27+
# --packages-and-scopes-permission read-write \
28+
# --bypass-2fa
29+
# - Add it to this repository's Actions secrets as NPM_TOKEN.
30+
# Command-line equivalent:
31+
# gh secret set NPM_TOKEN \
32+
# --repo FujoWebDev/fujocoded-plugins \
33+
# --body "<temporary-npm-token>"
34+
# - Run this workflow manually.
35+
# Command-line equivalent:
36+
# gh workflow run first-release.yaml \
37+
# --repo FujoWebDev/fujocoded-plugins \
38+
# --ref <branch-or-tag>
39+
#
40+
# After a successful first release:
41+
# - Configure Trusted Publishing for each newly published package, using this
42+
# repository and the normal release.yaml workflow file.
43+
# Command-line equivalent:
44+
# npm trust github <package-name> \
45+
# --repo FujoWebDev/fujocoded-plugins \
46+
# --file release.yaml \
47+
# --allow-publish
48+
# - Delete the NPM_TOKEN repository secret and revoke the npm token.
49+
# Command-line equivalent:
50+
# gh secret delete NPM_TOKEN \
51+
# --repo FujoWebDev/fujocoded-plugins
52+
# npm token revoke <token-id-or-token>
53+
# - Use the normal Release workflow for future package versions.
54+
55+
on:
56+
workflow_dispatch:
57+
58+
concurrency: ${{ github.workflow }}-${{ github.ref }}
59+
60+
permissions:
61+
id-token: write
62+
contents: write
63+
64+
jobs:
65+
first-release:
66+
name: First Package Release
67+
runs-on: ubuntu-latest
68+
steps:
69+
- name: Checkout
70+
uses: actions/checkout@v6
71+
72+
- name: Setup Node.js
73+
uses: actions/setup-node@v6
74+
with:
75+
node-version: 24
76+
registry-url: "https://registry.npmjs.org"
77+
78+
- name: Install dependencies
79+
run: npm ci
80+
81+
- name: Refuse pending changesets
82+
run: |
83+
if find .changeset -maxdepth 1 -type f -name '*.md' ! -name README.md | grep -q .; then
84+
echo "::error::First Package Release must run on a versioned checkout with no pending changeset files."
85+
exit 1
86+
fi
87+
88+
- name: Build
89+
run: npm run build
90+
91+
- name: Publish first-release packages
92+
uses: changesets/action@v1
93+
with:
94+
publish: node .github/workflows/scripts/first-release-publish.mjs
95+
createGithubReleases: true
96+
env:
97+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
98+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { existsSync, readdirSync, readFileSync } from "node:fs";
2+
import { join } from "node:path";
3+
import { spawnSync } from "node:child_process";
4+
5+
if (!process.env.NPM_TOKEN) {
6+
console.error("NPM_TOKEN is required for first package releases.");
7+
process.exit(1);
8+
}
9+
10+
const root = JSON.parse(readFileSync("package.json", "utf8"));
11+
const workspaces = Array.isArray(root.workspaces)
12+
? root.workspaces
13+
: (root.workspaces?.packages ?? []);
14+
15+
const packages = [];
16+
17+
for (const workspace of workspaces) {
18+
if (workspace !== "*/") {
19+
continue;
20+
}
21+
22+
for (const entry of readdirSync(".", { withFileTypes: true })) {
23+
if (!entry.isDirectory() || entry.name.startsWith(".")) {
24+
continue;
25+
}
26+
27+
try {
28+
const manifest = JSON.parse(
29+
readFileSync(join(entry.name, "package.json"), "utf8"),
30+
);
31+
if (!manifest.private && manifest.name && manifest.version) {
32+
packages.push({
33+
dir: entry.name,
34+
name: manifest.name,
35+
version: manifest.version,
36+
});
37+
}
38+
} catch {
39+
// Not a workspace package.
40+
}
41+
}
42+
}
43+
44+
const missingPackages = [];
45+
46+
for (const pkg of packages) {
47+
const result = spawnSync("npm", ["view", pkg.name, "version"], {
48+
encoding: "utf8",
49+
});
50+
51+
if (result.status === 0) {
52+
continue;
53+
}
54+
55+
const error = `${result.stderr}\n${result.stdout}`;
56+
if (/E404|404 Not Found/.test(error)) {
57+
console.log(`${pkg.name} is not published yet.`);
58+
missingPackages.push(pkg);
59+
continue;
60+
}
61+
62+
process.stderr.write(error);
63+
process.exit(result.status ?? 1);
64+
}
65+
66+
if (missingPackages.length === 0) {
67+
console.error("No unpublished public workspace packages found.");
68+
process.exit(1);
69+
}
70+
71+
for (const pkg of missingPackages) {
72+
const changelogPath = join(pkg.dir, "CHANGELOG.md");
73+
if (!existsSync(changelogPath)) {
74+
console.error(
75+
`${pkg.name} is missing CHANGELOG.md. Create the first version changelog before publishing so changesets/action can create the GitHub Release.`,
76+
);
77+
process.exit(1);
78+
}
79+
80+
const changelog = readFileSync(changelogPath, "utf8");
81+
const versionHeading = new RegExp(`^#{1,6}\\s+${pkg.version}\\s*$`, "m");
82+
if (!versionHeading.test(changelog)) {
83+
console.error(
84+
`${pkg.name} CHANGELOG.md is missing a ${pkg.version} entry. Create the first version changelog before publishing so changesets/action can create the GitHub Release.`,
85+
);
86+
process.exit(1);
87+
}
88+
}
89+
90+
for (const pkg of missingPackages) {
91+
const result = spawnSync("npm", ["publish", pkg.dir, "--provenance"], {
92+
encoding: "utf8",
93+
stdio: ["inherit", "pipe", "pipe"],
94+
});
95+
96+
process.stdout.write(result.stdout);
97+
process.stderr.write(result.stderr);
98+
99+
if (result.status !== 0) {
100+
process.exit(result.status ?? 1);
101+
}
102+
103+
console.log(`New tag: ${pkg.name}@${pkg.version}`);
104+
}

msw-atproto/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# @fujocoded/astro-smooth-action
2+
3+
## 0.0.1
4+
5+
First release, yay!
6+
7+
As said in the README: `@fujocoded/msw-atproto` uses the power of
8+
[MSW](https://mswjs.io/) to give you(r tests) fake, <u>stateful</u> ATproto
9+
accounts that respond to HTTP requests exactly like real PDSes on the real
10+
network would!

0 commit comments

Comments
 (0)