Skip to content

Commit fa98fb3

Browse files
committed
Merge develop: fix CI publish pipeline
2 parents 2ac0de1 + d28c048 commit fa98fb3

4 files changed

Lines changed: 162 additions & 53 deletions

File tree

.github/workflows/publish.yml

Lines changed: 0 additions & 49 deletions
This file was deleted.

.github/workflows/release-please.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ on:
1010
permissions:
1111
contents: write
1212
pull-requests: write
13+
id-token: write
1314

1415
jobs:
1516
release-please:
1617
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
1718
runs-on: ubuntu-latest
19+
outputs:
20+
release_created: ${{ steps.release.outputs.release_created }}
1821
steps:
1922
- uses: googleapis/release-please-action@v4
2023
id: release
@@ -23,3 +26,43 @@ jobs:
2326
config-file: release-please-config.json
2427
manifest-file: .release-please-manifest.json
2528
target-branch: main
29+
30+
publish:
31+
name: Publish to npm
32+
needs: release-please
33+
if: ${{ needs.release-please.outputs.release_created == 'true' }}
34+
runs-on: ubuntu-latest
35+
steps:
36+
- uses: actions/checkout@v4
37+
38+
- name: Setup Bun
39+
uses: oven-sh/setup-bun@v1
40+
with:
41+
bun-version: latest
42+
43+
- name: Install dependencies
44+
run: bun install --frozen-lockfile
45+
46+
- name: Build workspace dependencies
47+
run: bun run build
48+
working-directory: packages/pg-introspection
49+
50+
- name: Build pg-sourcerer
51+
run: bun run build
52+
working-directory: packages/pg-sourcerer
53+
54+
- name: Publish pg-introspection to npm
55+
working-directory: packages/pg-introspection
56+
run: bun publish --access public --tolerate-republish
57+
env:
58+
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
59+
60+
- name: Publish pg-sourcerer to npm
61+
working-directory: packages/pg-sourcerer
62+
run: |
63+
cp ../../README.md ./README.md
64+
cp ../../LICENSE ./LICENSE
65+
bun publish --access public --tolerate-republish
66+
rm ./README.md ./LICENSE
67+
env:
68+
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}

packages/example/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
"private": true,
55
"type": "module",
66
"scripts": {
7-
"dry": "bun --env-file=.env pgsourcerer generate --log-level debug --dry-run",
7+
"dry": "bun -b --env-file=.env pgsourcerer generate --log-level debug --dry-run",
88
"dev": "bun run-p db:watch generate:watch",
99
"start": "bun run generate",
10-
"generate": "bun --env-file=.env pgsourcerer generate --log-level debug",
10+
"generate": "bun -b --env-file=.env pgsourcerer generate --log-level debug",
1111
"generate:watch": "bun --env-file=.env --watch pgsourcerer generate --log-level debug",
1212
"predev": "bun db:ensure",
13-
"gm": "bun --env-file=.env ../../node_modules/.bin/graphile-migrate",
13+
"gm": "bun -b graphile-migrate",
1414
"db:ensure": "bun scripts/dbEnsure.ts",
1515
"db:setup": "bun scripts/dbSetup.ts",
1616
"db:latest": "bun run gm watch --once",

scripts/release.ts

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { $ } from "bun";
1+
/// <reference types="bun" />
22

33
const version = process.argv[2];
44
if (!version) {
@@ -40,8 +40,42 @@ const runCapture = async (command: string[], cwd?: string) => {
4040
return stdout;
4141
};
4242

43+
const runCaptureOptional = async (command: string[], cwd?: string) => {
44+
const proc = Bun.spawn(command, {
45+
cwd,
46+
stdout: "pipe",
47+
stderr: "pipe",
48+
});
49+
const stdout = await new Response(proc.stdout).text();
50+
const stderr = await new Response(proc.stderr).text();
51+
const exitCode = await proc.exited;
52+
return { exitCode, stdout, stderr };
53+
};
54+
55+
const runCheck = async (command: string[], cwd?: string) => {
56+
const proc = Bun.spawn(command, {
57+
cwd,
58+
stdout: "ignore",
59+
stderr: "ignore",
60+
});
61+
return (await proc.exited) === 0;
62+
};
63+
4364
const readText = async (path: string) => Bun.file(path).text();
4465

66+
const parseVersion = (input: string) => {
67+
const [major = 0, minor = 0, patch = 0] = input.split(".").map(Number);
68+
return [major, minor, patch] as const;
69+
};
70+
71+
const compareSemver = (left: string, right: string) => {
72+
const [lMajor, lMinor, lPatch] = parseVersion(left);
73+
const [rMajor, rMinor, rPatch] = parseVersion(right);
74+
if (lMajor !== rMajor) return lMajor - rMajor;
75+
if (lMinor !== rMinor) return lMinor - rMinor;
76+
return lPatch - rPatch;
77+
};
78+
4579
const ensureClean = async () => {
4680
const status = (await runCapture(["git", "status", "--porcelain"])).trim();
4781
if (status.length > 0) {
@@ -72,6 +106,83 @@ const ensureTagAvailable = async (tag: string) => {
72106
}
73107
};
74108

109+
const ensureReleasePleasePrClosed = async () => {
110+
const result = await runCaptureOptional([
111+
"gh",
112+
"pr",
113+
"list",
114+
"--state",
115+
"open",
116+
"--search",
117+
"release-please",
118+
"--json",
119+
"number,title",
120+
]);
121+
if (result.exitCode !== 0) {
122+
console.warn("Warning: unable to check release-please PR status.");
123+
return;
124+
}
125+
126+
const prs = JSON.parse(result.stdout) as Array<{ number: number; title: string }>;
127+
if (prs.length > 0) {
128+
console.error(
129+
[
130+
"Release-please PR already open:",
131+
...prs.map(pr => `#${pr.number} ${pr.title}`),
132+
].join("\n"),
133+
);
134+
process.exit(1);
135+
}
136+
};
137+
138+
const ensureDevelopContainsMain = async () => {
139+
await run(["git", "fetch", "origin"]);
140+
const hasMain = await runCheck(["git", "merge-base", "--is-ancestor", "origin/main", "develop"]);
141+
if (!hasMain) {
142+
console.error("Develop is missing commits from main. Merge main into develop first.");
143+
process.exit(1);
144+
}
145+
};
146+
147+
const ensureDevelopUpToDate = async () => {
148+
const output = await runCapture([
149+
"git",
150+
"rev-list",
151+
"--left-right",
152+
"--count",
153+
"origin/develop...develop",
154+
]);
155+
const [behind = 0] = output.trim().split("\t").map(Number);
156+
if (behind > 0) {
157+
console.error("Develop is behind origin/develop. Pull first.");
158+
process.exit(1);
159+
}
160+
};
161+
162+
const ensureVersionAdvances = async () => {
163+
const manifest = JSON.parse(
164+
await readText(".release-please-manifest.json"),
165+
) as Record<string, string>;
166+
const current = manifest["packages/pg-sourcerer"];
167+
if (!current) {
168+
console.error("Release-please manifest missing packages/pg-sourcerer version.");
169+
process.exit(1);
170+
}
171+
172+
if (compareSemver(version, current) <= 0) {
173+
console.error(`Version must be greater than ${current}.`);
174+
process.exit(1);
175+
}
176+
177+
const pkg = JSON.parse(
178+
await readText("packages/pg-sourcerer/package.json"),
179+
) as { version: string };
180+
if (pkg.version !== current) {
181+
console.error("Package version and release-please manifest are out of sync.");
182+
process.exit(1);
183+
}
184+
};
185+
75186
const bumpVersion = async () => {
76187
const pkgPath = "packages/pg-sourcerer/package.json";
77188
const manifestPath = ".release-please-manifest.json";
@@ -116,6 +227,10 @@ const pushDevelop = async () => {
116227
const main = async () => {
117228
await ensureClean();
118229
await ensureBranch("develop");
230+
await ensureDevelopContainsMain();
231+
await ensureDevelopUpToDate();
232+
await ensureReleasePleasePrClosed();
233+
await ensureVersionAdvances();
119234
await ensureTagAvailable(`v${version}`);
120235
await bumpVersion();
121236
await runTests();

0 commit comments

Comments
 (0)