add: automated release of goodsdks packages - #58
Conversation
|
@copilot update PR description and review code |
Updated the PR description with full scope, motivation, and test details. I also reviewed the release automation changes in commit
Both checks passed. |
There was a problem hiding this comment.
Pull request overview
This PR introduces an automated, deterministic npm release pipeline for the publishable @goodsdks/* workspaces, backed by repo-local release tooling and manifest validation, and tightens deployment/security posture for Vercel workflows and browser bundling.
Changes:
- Added a GitHub Actions workflow to plan/version/tag/publish affected packages on
mainpushes, plus manualbootstrap/recovermodes. - Introduced release tooling under
scripts/release/(package allowlist + cascade rules, changed-file based selection, version planning, publish/verify helpers, and tests). - Standardized publishable package manifests for npm (MIT licensing, repository metadata,
files: ["dist"], and consistent workspace ranges), plus safer env handling in Vite/Vercel deploy flows.
Reviewed changes
Copilot reviewed 27 out of 29 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Align internal workspace dependency selectors to workspace:^ to support publishing/versioning invariants. |
| scripts/scan-build-secrets.mjs | New script to scan built assets for leaked CI/Vercel/npm secret values before deployment. |
| scripts/release/config.mjs | Defines the publishable package allowlist, topological order, and consumer cascade map. |
| scripts/release/release-lib.mjs | Implements release relevance detection, package selection/cascade logic, and semver helpers. |
| scripts/release/release.mjs | Release CLI implementing plan/prepare/verify/pack/tag/publish/bootstrap flows. |
| scripts/release/validate-packages.mjs | Central validation of publishable package.json invariants prior to release. |
| scripts/release/release.test.mjs | Node test runner coverage for selection/cascade, release marker, and semver helpers. |
| packages/ui-components/tsup.config.claim.ts | Enables DTS generation for the claim button bundle. |
| packages/ui-components/package.json | Adds exports/types, restricts shipped files to dist, and standardizes publish metadata. |
| packages/streaming-sdk/package.json | Adds MIT license + repository metadata + public publishConfig. |
| packages/savings-widget/tsup.config.savings.ts | Enables DTS generation for the savings widget bundle. |
| packages/savings-widget/package.json | Adds exports/types, restricts shipped files to dist, and standardizes publish metadata. |
| packages/savings-sdk/package.json | Restricts shipped files to dist and standardizes publish metadata. |
| packages/react-hooks/package.json | Restricts shipped files to dist, standardizes publish metadata, and uses workspace:^ for internal deps. |
| packages/invite-sdk/package.json | Switches lint script to tsc --noEmit, restricts shipped files to dist, and standardizes publish metadata. |
| packages/good-reserve/package.json | Restricts shipped files to dist and standardizes publish metadata. |
| packages/engagement-sdk/package.json | Restricts shipped files to dist and standardizes publish metadata. |
| packages/citizen-sdk/package.json | Adjusts test command for CI suitability, updates CJS types export path, restricts shipped files, and standardizes publish metadata. |
| packages/bridging-sdk/package.json | Restricts shipped files to dist and standardizes publish metadata. |
| package.json | Adds MIT license and root release scripts (release:plan, release:test, release:validate). |
| LICENSE | Adds MIT license text at repo root. |
| apps/demo-identity-app/vite.config.mts | Stops injecting full process.env into the browser bundle; only provides NODE_ENV. |
| .gitignore | Ignores .release/ artifacts and normalizes .npmrc entry formatting. |
| .github/workflows/vercel-preview-identity.yml | Pins checkout/setup-node SHAs, adds read-only permissions, and prevents fork PRs from running with secrets. |
| .github/workflows/vercel-preview-engagement.yml | Pins checkout/setup-node SHAs, adds read-only permissions, and prevents fork PRs from running with secrets. |
| .github/workflows/vercel-deploy-identity.yml | New production deploy workflow on prod, with pinned Vercel CLI and secret-leak scan gate. |
| .github/workflows/vercel-deploy-engagement.yml | Hardens production deploy on main (permissions, concurrency, pinned CLI, env var adjustments). |
| .github/workflows/release-packages.yml | New automated release workflow (plan/prepare/lockfile commit/tags/publish + manual recover/bootstrap). |
| .github/CODEOWNERS | Adds code ownership for workflows and release scripts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const buildDirectory = path.resolve(process.argv[2] ?? "") | ||
| if (!process.argv[2] || !statSync(buildDirectory).isDirectory()) { | ||
| throw new Error("Usage: scan-build-secrets.mjs <build-directory>") | ||
| } |
| import assert from "node:assert/strict" | ||
| import { readFileSync } from "node:fs" | ||
| import path from "node:path" | ||
| import { packageByName, packages } from "./config.mjs" | ||
|
|
||
| const root = path.resolve(import.meta.dirname, "../..") |
| const leaks = [] | ||
| for (const filename of files(buildDirectory)) { | ||
| const content = readFileSync(filename) | ||
| for (const [name, value] of candidates) { | ||
| if (content.includes(Buffer.from(value))) leaks.push(`${name} in ${path.relative(buildDirectory, filename)}`) | ||
| } | ||
| } | ||
| if (leaks.length) throw new Error(`Secret values found in production assets:\n${leaks.join("\n")}`) | ||
| console.log(`Scanned ${files(buildDirectory).length} production files for ${candidates.length} CI secrets`) |
| for (const group of ["dependencies", "devDependencies", "peerDependencies"]) { | ||
| for (const [name, range] of Object.entries(manifest[group] ?? {})) { | ||
| if (packageByName.has(name) && group !== "peerDependencies") { | ||
| assert.match(range, /^workspace:\^$/, `${manifest.name} has an unpinned workspace range`) |
| import { execFileSync } from "node:child_process" | ||
| import { mkdirSync, readFileSync, writeFileSync } from "node:fs" | ||
| import path from "node:path" | ||
| import process from "node:process" | ||
| import { packageByName, packages, RELEASE_MARKER } from "./config.mjs" | ||
| import { | ||
| cascadePackages, | ||
| changedFiles, | ||
| compareVersions, | ||
| directPackagesForFiles, | ||
| gitOutput, | ||
| isReleaseCommit, | ||
| packageVersion, | ||
| patchVersion, | ||
| } from "./release-lib.mjs" | ||
|
|
||
| const root = path.resolve(import.meta.dirname, "../..") |
Description
This PR adds automated npm release flow for the publishable
@goodsdks/*packages.What changed
.github/workflows/release-packages.yml:mainpushes (with release-loop guard).workflow_dispatchmodes forrecoverandbootstrap.scripts/release/:config.mjs: release allowlist + consumer cascade map.release-lib.mjs: changed-file detection, release relevance filters, dependency cascade, semver helpers.release.mjs: prepare/verify/pack/tag/publish/bootstrap/check-bootstrap commands.validate-packages.mjs: enforces publishable package manifest invariants.release.test.mjs: tests package selection, cascade behavior, and release marker handling.yarn release:planyarn release:testyarn release:validateMotivation
Automate safe, repeatable package publishing while keeping release decisions deterministic in git and recoverable after partial registry failures.
How has this been tested?
yarn release:testyarn release:validateChecklist