mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
Merge pull request #13 from heygen-com/03-23-ci_add_tag-triggered_npm_publish_workflow_with_oidc_provenance
ci: add CI pipeline, npm publish workflow, and release tooling
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm build
|
||||
|
||||
typecheck:
|
||||
name: Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm build
|
||||
- run: pnpm -r typecheck
|
||||
|
||||
test-core:
|
||||
name: "Test: core"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm --filter @hyperframes/core test -- --coverage
|
||||
|
||||
test-engine:
|
||||
name: "Test: engine"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm --filter @hyperframes/engine test
|
||||
|
||||
test-runtime-contract:
|
||||
name: "Test: runtime contract"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm --filter @hyperframes/core test:hyperframe-runtime-ci
|
||||
|
||||
semantic-pr-title:
|
||||
name: Semantic PR title
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
build
|
||||
ci
|
||||
chore
|
||||
revert
|
||||
@@ -0,0 +1,53 @@
|
||||
name: Publish to npm
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
environment: npm-publish
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm build
|
||||
|
||||
- name: Publish @hyperframes/core
|
||||
run: pnpm --filter @hyperframes/core publish --access public --provenance --no-git-checks
|
||||
env:
|
||||
NPM_CONFIG_PROVENANCE: "true"
|
||||
|
||||
- name: Publish @hyperframes/engine
|
||||
run: pnpm --filter @hyperframes/engine publish --access public --provenance --no-git-checks
|
||||
env:
|
||||
NPM_CONFIG_PROVENANCE: "true"
|
||||
|
||||
- name: Publish @hyperframes/producer
|
||||
run: pnpm --filter @hyperframes/producer publish --access public --provenance --no-git-checks
|
||||
env:
|
||||
NPM_CONFIG_PROVENANCE: "true"
|
||||
|
||||
- name: Publish @hyperframes/studio
|
||||
run: pnpm --filter @hyperframes/studio publish --access public --provenance --no-git-checks
|
||||
env:
|
||||
NPM_CONFIG_PROVENANCE: "true"
|
||||
|
||||
- name: Publish hyperframes (CLI)
|
||||
run: pnpm --filter hyperframes publish --access public --provenance --no-git-checks
|
||||
env:
|
||||
NPM_CONFIG_PROVENANCE: "true"
|
||||
+61
-1
@@ -9,7 +9,67 @@ Thanks for your interest in contributing to Hyperframes! This guide will help yo
|
||||
3. Install dependencies: `pnpm install`
|
||||
4. Create a branch: `git checkout -b my-feature`
|
||||
|
||||
<!-- TODO: Fill in development setup details once packages are ported -->
|
||||
## Development
|
||||
|
||||
```bash
|
||||
pnpm install # Install all dependencies
|
||||
pnpm dev # Run the studio (composition editor)
|
||||
pnpm build # Build all packages
|
||||
pnpm -r typecheck # Type-check all packages
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
pnpm --filter @hyperframes/core test # Core unit tests (vitest)
|
||||
pnpm --filter @hyperframes/engine test # Engine unit tests (vitest)
|
||||
pnpm --filter @hyperframes/core test:hyperframe-runtime-ci # Runtime contract tests
|
||||
```
|
||||
|
||||
## Pull Requests
|
||||
|
||||
- Use [conventional commit](https://www.conventionalcommits.org/) format for PR titles (e.g., `feat: add timeline export`, `fix: resolve seek overflow`)
|
||||
- CI must pass before merge (build, typecheck, tests, semantic PR title)
|
||||
- PRs require at least 1 approval
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | Description |
|
||||
|---|---|
|
||||
| `@hyperframes/core` | Types, HTML generation, runtime, linter |
|
||||
| `@hyperframes/engine` | Seekable page-to-video capture engine |
|
||||
| `@hyperframes/producer` | Full rendering pipeline (capture + encode) |
|
||||
| `@hyperframes/studio` | Composition editor UI |
|
||||
| `hyperframes` | CLI for creating, previewing, and rendering |
|
||||
|
||||
## Releasing (Maintainers)
|
||||
|
||||
All packages use **fixed versioning** — every release bumps all packages to the same version.
|
||||
|
||||
### Steps
|
||||
|
||||
```bash
|
||||
# 1. Bump version, commit, and tag
|
||||
pnpm set-version 0.1.1 --tag
|
||||
|
||||
# 2. Push to trigger the publish workflow
|
||||
git push origin main --tags
|
||||
```
|
||||
|
||||
The `v*` tag triggers CI, which validates (build + typecheck + tests) then publishes all packages to npm with provenance attestation.
|
||||
|
||||
### Without `--tag` (manual control)
|
||||
|
||||
```bash
|
||||
# 1. Bump versions only (no commit/tag)
|
||||
pnpm set-version 0.1.1
|
||||
|
||||
# 2. Review changes, commit yourself
|
||||
git add -A
|
||||
git commit -m "chore: release v0.1.1"
|
||||
git tag v0.1.1
|
||||
git push origin main --tags
|
||||
```
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@
|
||||
"build:producer": "pnpm --filter @hyperframes/producer build",
|
||||
"studio": "pnpm --filter @hyperframes/studio dev",
|
||||
"build:hyperframes-runtime": "pnpm --filter @hyperframes/core build:hyperframes-runtime",
|
||||
"build:hyperframes-runtime:modular": "pnpm --filter @hyperframes/core build:hyperframes-runtime:modular"
|
||||
"build:hyperframes-runtime:modular": "pnpm --filter @hyperframes/core build:hyperframes-runtime:modular",
|
||||
"set-version": "tsx scripts/set-version.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.0.10",
|
||||
|
||||
Generated
+3
-3
@@ -128,7 +128,7 @@ importers:
|
||||
specifier: ^1.13.0
|
||||
version: 1.19.11(hono@4.12.8)
|
||||
'@hyperframes/core':
|
||||
specifier: workspace:*
|
||||
specifier: workspace:^
|
||||
version: link:../core
|
||||
hono:
|
||||
specifier: ^4.6.0
|
||||
@@ -192,10 +192,10 @@ importers:
|
||||
specifier: ^1.13.0
|
||||
version: 1.19.11(hono@4.12.8)
|
||||
'@hyperframes/core':
|
||||
specifier: workspace:*
|
||||
specifier: workspace:^
|
||||
version: link:../core
|
||||
'@hyperframes/engine':
|
||||
specifier: workspace:*
|
||||
specifier: workspace:^
|
||||
version: link:../engine
|
||||
hono:
|
||||
specifier: ^4.6.0
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env tsx
|
||||
/**
|
||||
* Set the version across all publishable packages in the monorepo.
|
||||
*
|
||||
* Usage:
|
||||
* pnpm set-version 0.1.1
|
||||
* pnpm set-version 0.1.1 --tag # also creates a git commit and tag
|
||||
*
|
||||
* All packages share a single version number (fixed versioning).
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { execSync } from "child_process";
|
||||
|
||||
const PACKAGES = [
|
||||
"packages/core",
|
||||
"packages/engine",
|
||||
"packages/producer",
|
||||
"packages/studio",
|
||||
"packages/cli",
|
||||
];
|
||||
|
||||
const ROOT = join(import.meta.dirname, "..");
|
||||
|
||||
function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const version = args.find((a) => !a.startsWith("--"));
|
||||
const shouldTag = args.includes("--tag");
|
||||
|
||||
if (!version) {
|
||||
console.error("Usage: pnpm set-version <version> [--tag]");
|
||||
console.error("Example: pnpm set-version 0.1.1 --tag");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(version)) {
|
||||
console.error(`Invalid semver: ${version}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Update each package.json
|
||||
for (const pkg of PACKAGES) {
|
||||
const pkgPath = join(ROOT, pkg, "package.json");
|
||||
const content = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
||||
const oldVersion = content.version;
|
||||
content.version = version;
|
||||
writeFileSync(pkgPath, JSON.stringify(content, null, 2) + "\n");
|
||||
console.log(` ${content.name}: ${oldVersion} -> ${version}`);
|
||||
}
|
||||
|
||||
console.log(`\nSet ${PACKAGES.length} packages to v${version}`);
|
||||
|
||||
if (shouldTag) {
|
||||
// Verify working tree is clean (aside from the version bumps we just made)
|
||||
const status = execSync("git status --porcelain", {
|
||||
cwd: ROOT,
|
||||
encoding: "utf-8",
|
||||
}).trim();
|
||||
const unexpected = status
|
||||
.split("\n")
|
||||
.filter((line) => line && !PACKAGES.some((pkg) => line.includes(pkg)));
|
||||
if (unexpected.length > 0) {
|
||||
console.error("\nUnexpected uncommitted changes:");
|
||||
unexpected.forEach((line) => console.error(` ${line}`));
|
||||
console.error("Commit or stash these before tagging.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
execSync(`git add ${PACKAGES.map((p) => join(p, "package.json")).join(" ")}`, { cwd: ROOT, stdio: "inherit" });
|
||||
execSync(`git commit -m "chore: release v${version}"`, { cwd: ROOT, stdio: "inherit" });
|
||||
execSync(`git tag v${version}`, { cwd: ROOT, stdio: "inherit" });
|
||||
console.log(`\nCreated commit and tag v${version}`);
|
||||
console.log(`Run 'git push origin main --tags' to trigger the publish workflow.`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user