feat: Implement tag-based version synchronization and direct publishing for releases.
Some checks failed
Code Quality / lint-and-build (push) Failing after 46s
Release Packages / release (push) Failing after 32s

This commit is contained in:
2026-02-02 01:02:14 +01:00
parent 83b4ea8807
commit 10a6b5e11a
4 changed files with 105 additions and 22 deletions

View File

@@ -4,6 +4,8 @@ on:
push:
branches:
- main
tags:
- 'v*'
jobs:
release:
@@ -31,6 +33,13 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Create Release Pull Request or Publish
id: changesets
run: pnpm release
- name: Release Packages
run: |
if [[ "${{ github.ref_type }}" == "tag" ]]; then
echo "🏷️ Tag detected, performing sync release..."
pnpm sync-versions
pnpm release:tag
else
echo "🚀 Push detected, looking for changesets..."
pnpm release
fi

View File

@@ -9,7 +9,9 @@
"test": "pnpm -r test",
"changeset": "changeset",
"version-packages": "changeset version",
"sync-versions": "tsx scripts/sync-versions.ts",
"release": "pnpm build && changeset publish",
"release:tag": "pnpm build && pnpm -r publish --no-git-checks --access public",
"prepare": "husky"
},
"devDependencies": {
@@ -32,6 +34,7 @@
"jsdom": "^27.4.0",
"lint-staged": "^16.2.7",
"prettier": "^3.8.1",
"tsx": "^4.21.0",
"typescript": "^5.0.0",
"typescript-eslint": "^8.54.0",
"vitest": "^4.0.18"

56
pnpm-lock.yaml generated
View File

@@ -37,7 +37,7 @@ importers:
version: 19.2.3(@types/react@19.2.10)
'@vitejs/plugin-react':
specifier: ^5.1.2
version: 5.1.2(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))
version: 5.1.2(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
eslint:
specifier: ^9.39.2
version: 9.39.2(jiti@2.6.1)
@@ -65,6 +65,9 @@ importers:
prettier:
specifier: ^3.8.1
version: 3.8.1
tsx:
specifier: ^4.21.0
version: 4.21.0
typescript:
specifier: ^5.0.0
version: 5.9.3
@@ -73,7 +76,7 @@ importers:
version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
vitest:
specifier: ^4.0.18
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.30)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.4.0)(terser@5.46.0)(yaml@2.8.2)
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.30)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.4.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
apps/sample-website:
dependencies:
@@ -138,7 +141,7 @@ importers:
version: 2.4.9
tsup:
specifier: ^8.0.0
version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2)
version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
typescript:
specifier: ^5.0.0
version: 5.9.3
@@ -205,7 +208,7 @@ importers:
version: 8.5.6
tailwindcss:
specifier: ^3.4.17
version: 3.4.19(yaml@2.8.2)
version: 3.4.19(tsx@4.21.0)(yaml@2.8.2)
typescript:
specifier: ^5.0.0
version: 5.9.3
@@ -266,7 +269,7 @@ importers:
version: 9.39.2(jiti@2.6.1)
tsup:
specifier: ^8.0.0
version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2)
version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
typescript:
specifier: ^5.0.0
version: 5.9.3
@@ -4094,6 +4097,11 @@ packages:
typescript:
optional: true
tsx@4.21.0:
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
engines: {node: '>=18.0.0'}
hasBin: true
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -6045,7 +6053,7 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
'@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))':
'@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.28.6
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6)
@@ -6053,7 +6061,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.53
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
vite: 7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- supports-color
@@ -6066,13 +6074,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@4.0.18(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))':
'@vitest/mocker@4.0.18(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 4.0.18
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/pretty-format@4.0.18':
dependencies:
@@ -7994,20 +8002,22 @@ snapshots:
camelcase-css: 2.0.1
postcss: 8.5.6
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2):
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
lilconfig: 3.1.3
optionalDependencies:
jiti: 1.21.7
postcss: 8.5.6
tsx: 4.21.0
yaml: 2.8.2
postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(yaml@2.8.2):
postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
lilconfig: 3.1.3
optionalDependencies:
jiti: 2.6.1
postcss: 8.5.6
tsx: 4.21.0
yaml: 2.8.2
postcss-nested@6.2.0(postcss@8.5.6):
@@ -8520,7 +8530,7 @@ snapshots:
tailwind-merge@2.6.1: {}
tailwindcss@3.4.19(yaml@2.8.2):
tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -8539,7 +8549,7 @@ snapshots:
postcss: 8.5.6
postcss-import: 15.1.0(postcss@8.5.6)
postcss-js: 4.1.0(postcss@8.5.6)
postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2)
postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2)
postcss-nested: 6.2.0(postcss@8.5.6)
postcss-selector-parser: 6.1.2
resolve: 1.22.11
@@ -8626,7 +8636,7 @@ snapshots:
tslib@2.8.1: {}
tsup@8.5.1(jiti@2.6.1)(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2):
tsup@8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2):
dependencies:
bundle-require: 5.1.0(esbuild@0.27.2)
cac: 6.7.14
@@ -8637,7 +8647,7 @@ snapshots:
fix-dts-default-cjs-exports: 1.0.1
joycon: 3.1.1
picocolors: 1.1.1
postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(yaml@2.8.2)
postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2)
resolve-from: 5.0.0
rollup: 4.57.1
source-map: 0.7.6
@@ -8654,6 +8664,13 @@ snapshots:
- tsx
- yaml
tsx@4.21.0:
dependencies:
esbuild: 0.27.2
get-tsconfig: 4.13.1
optionalDependencies:
fsevents: 2.3.3
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
@@ -8772,7 +8789,7 @@ snapshots:
uuid@9.0.1: {}
vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2):
vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.27.2
fdir: 6.5.0(picomatch@4.0.3)
@@ -8785,12 +8802,13 @@ snapshots:
fsevents: 2.3.3
jiti: 2.6.1
terser: 5.46.0
tsx: 4.21.0
yaml: 2.8.2
vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.30)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.4.0)(terser@5.46.0)(yaml@2.8.2):
vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.30)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.4.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@vitest/expect': 4.0.18
'@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))
'@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/pretty-format': 4.0.18
'@vitest/runner': 4.0.18
'@vitest/snapshot': 4.0.18
@@ -8807,7 +8825,7 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vite: 7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@20.19.30)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@opentelemetry/api': 1.9.0

53
scripts/sync-versions.ts Normal file
View File

@@ -0,0 +1,53 @@
import * as fs from "fs";
import * as path from "path";
import { execSync } from "child_process";
const tag = process.env.GITHUB_REF_NAME || process.env.TAG;
if (!tag || !tag.startsWith("v")) {
console.error("❌ No valid tag found (must start with v, e.g., v1.0.0)");
process.exit(1);
}
const version = tag.replace(/^v/, "");
console.log(`🚀 Syncing all packages to version: ${version}`);
const rootPkg = JSON.parse(fs.readFileSync("package.json", "utf-8"));
const packagesDir = "packages";
const appsDir = "apps";
function updatePkg(pkgPath: string) {
if (!fs.existsSync(pkgPath)) return;
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
pkg.version = version;
// Also update workspace dependencies if they match our packages
if (pkg.dependencies) {
for (const dep in pkg.dependencies) {
if (pkg.dependencies[dep].startsWith("workspace:")) {
pkg.dependencies[dep] = "workspace:*"; // Keep workspace protocol
}
}
}
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
console.log(`✅ Updated ${pkg.name} to ${version}`);
}
// Update root
rootPkg.version = version;
fs.writeFileSync("package.json", JSON.stringify(rootPkg, null, 2) + "\n");
// Update all packages
const packages = fs.readdirSync(packagesDir);
for (const p of packages) {
updatePkg(path.join(packagesDir, p, "package.json"));
}
// Update all apps
const apps = fs.readdirSync(appsDir);
for (const a of apps) {
updatePkg(path.join(appsDir, a, "package.json"));
}
console.log("✨ All versions synced!");