Skip to content

Commit 32f1622

Browse files
committed
fix(repo): add recovery step for downstream notifications
1 parent 9bfaa80 commit 32f1622

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,85 @@ jobs:
107107
core.warning("Changeset in pre-mode should not prepare a ClerkJS production release")
108108
}
109109
110+
# Recovery: if the changesets action published to npm but then failed
111+
# (e.g. git push --follow-tags error), the `published` output is never
112+
# set and downstream repos are not notified. This step detects that
113+
# scenario by checking npm for the local package version and dispatches
114+
# if the packages are already live.
115+
- name: Recover downstream notifications
116+
if: always() && steps.changesets.conclusion == 'failure'
117+
continue-on-error: true
118+
uses: actions/github-script@v7
119+
with:
120+
result-encoding: string
121+
retries: 3
122+
retry-exempt-status-codes: 400,401
123+
github-token: ${{ secrets.CLERK_COOKIE_PAT }}
124+
script: |
125+
const { execSync } = require('child_process');
126+
127+
const clerkjsVersion = require('./packages/clerk-js/package.json').version;
128+
const clerkUiVersion = require('./packages/ui/package.json').version;
129+
130+
// Only recover stable releases
131+
const preReleases = [
132+
clerkjsVersion.includes('-') && `@clerk/clerk-js@${clerkjsVersion}`,
133+
clerkUiVersion.includes('-') && `@clerk/ui@${clerkUiVersion}`,
134+
].filter(Boolean);
135+
if (preReleases.length > 0) {
136+
console.log(`Skipping recovery: ${preReleases.join(', ')} is a pre-release`);
137+
return;
138+
}
139+
140+
const preMode = require("fs").existsSync("./.changeset/pre.json");
141+
if (preMode) {
142+
core.warning("Changeset in pre-mode, skipping recovery dispatch");
143+
return;
144+
}
145+
146+
// Check if either version was actually published to npm
147+
function isPublished(name, version) {
148+
try {
149+
return execSync(`npm view ${name}@${version} version`, { encoding: 'utf8' }).trim() === version;
150+
} catch {
151+
return false;
152+
}
153+
}
154+
155+
const clerkjsPublished = isPublished('@clerk/clerk-js', clerkjsVersion);
156+
const clerkUiPublished = isPublished('@clerk/ui', clerkUiVersion);
157+
158+
if (!clerkjsPublished && !clerkUiPublished) {
159+
console.log('Neither @clerk/clerk-js nor @clerk/ui were published to npm, no recovery needed');
160+
return;
161+
}
162+
163+
const published = [
164+
clerkjsPublished && `@clerk/clerk-js@${clerkjsVersion}`,
165+
clerkUiPublished && `@clerk/ui@${clerkUiVersion}`,
166+
].filter(Boolean).join(', ');
167+
core.warning(`Recovery: ${published} published to npm but downstream repos were not notified. Dispatching now.`);
168+
169+
const nextjsVersion = require('./packages/nextjs/package.json').version;
170+
171+
const targets = [
172+
{ repo: 'sdk-infra-workers', workflow_id: 'update-pkg-versions.yml', inputs: { clerkjsVersion, clerkUiVersion } },
173+
{ repo: 'dashboard', workflow_id: 'prepare-nextjs-sdk-update.yml', inputs: { version: nextjsVersion } },
174+
{ repo: 'clerk-docs', workflow_id: 'typedoc.yml' },
175+
];
176+
const results = await Promise.allSettled(
177+
targets.map(t => github.rest.actions.createWorkflowDispatch({ owner: 'clerk', ref: 'main', ...t }))
178+
);
179+
const failures = results
180+
.map((r, i) => r.status === 'rejected' ? { target: targets[i], reason: r.reason } : null)
181+
.filter(Boolean);
182+
if (failures.length) {
183+
failures.forEach(f => core.error(`Recovery dispatch to ${f.target.repo}/${f.target.workflow_id} failed: ${f.reason?.message ?? f.reason}`));
184+
core.setFailed(`${failures.length} recovery dispatch(es) failed`);
185+
} else {
186+
core.notice('Recovery dispatch completed successfully');
187+
}
188+
110189
- name: Generate notification payload
111190
id: notification
112191
if: steps.changesets.outputs.published == 'true'

0 commit comments

Comments
 (0)