Skip to content

Latest commit

 

History

History
335 lines (291 loc) · 13.6 KB

File metadata and controls

335 lines (291 loc) · 13.6 KB

Solidos Release Orchestrator - How To

Quick Summary

The Solidos monorepo uses a centralized release orchestrator to publish all dependent packages at once.

solidos/ (main branch)
├── .github/workflows/
│   └── release.yml                 ← Manual GitHub Actions trigger
├── scripts/
│   └── release-orchestrator.js     ← Does the actual work
├── release.config.json             ← Lists repos to publish (stable mode)
├── release.config.test.json        ← Lists repos to publish (test mode)
└── workspaces/
    ├── solid-panes/                ← Nothing special needed
    ├── folder-pane/                ← Nothing special needed
    └── (other repos)               ← Nothing special needed

Org Owner Setup (5 Minutes)

Before the release workflow can publish stable versions from GitHub Actions:

  1. Create a fine-grained PAT for release automation.
  2. Grant it Contents: Read and write and Metadata: Read on the SolidOS repos to be released.
  3. In solidos/solidos → Settings → Secrets and variables → Actions, add:
  • GIT_PUSH_TOKEN
  • NPM_TOKEN
  1. For protected branches on main: Use mode=stable-publish (no extra config needed—it auto-merges PRs)
  2. For unprotected main branch: Use mode=stable (requires direct push access)
  3. Run the Solidos Release workflow manually with:
  • mode=test for prerelease publishing
  • mode=stable-publish for @latest (protected branch)
  • mode=stable for @latest (direct push)

How It Works

Three execution modes:

Scenario Command Where Publishes?
Local Testing node scripts/release-orchestrator.js --dry-run=true Your computer ❌ No (prints what would happen)
Test Release Manual trigger: mode=test GitHub Actions ✅ Yes (@test tag)
Stable Release (Direct Push) Manual trigger: mode=stable GitHub Actions ✅ Yes (@latest tag)
Stable Release (Protected Branch) Manual trigger: mode=stable-publish GitHub Actions ✅ Yes (@latest tag, auto-merges PR)

Workflow (stable-publish mode with protected branches):

You click "Run workflow" → mode=stable-publish
          ↓ Step 1/3: Create Release PR
Creates release branch from dev → Merges dev into main → Pushes branch → Opens PR
          ↓ Step 2/3: Auto-Merge PR
Waits for CI checks to pass → Auto-merges PR with --squash → Fetches updated main
          ↓ Step 3/3: Publish
For each repo listed:
  - npm install
  - npm version (bump patch/minor/major)
  - npm publish (@latest tag)
  - git push + tags all at once

Old two-step flow (still supported for manual workflows):

  • Step 1: mode=stable-prepare-pr - creates PR, human reviews/merges
  • Step 2: mode=stable-publish - requires manual merge first

New unified flow (recommended):

  • Single mode=stable-publish - does all three: create PR, auto-merge, publish

Key Points

  • Individual repos need nothing special — they just need package.json and npm scripts
  • All repos already exist in GitHub — clone-missing is a fallback only
  • Branches are configurable — typically main for stable, develop for test
  • Both test and stable default to main — configure in release.config.json if you want different branches
  • PR workflow is unaffected — each repo's ci.yml still runs for PRs
  • Waiting PRs won't auto-publish — you manually trigger the release

Overview

  • This repository uses a multi-repo release orchestrator to publish dependent packages.
  • Publishing is only allowed in GitHub Actions; local runs must use --dry-run.
  • Test publishes use a prerelease version and the npm dist-tag "test" so @latest is unaffected.

Files

  • release.config.json: repo list and per-repo overrides.
  • scripts/release-orchestrator.js: the release runner.
  • .github/workflows/release.yml: GitHub Actions workflow.

Three Execution Scenarios

Scenario 1: Local Dry-Run (Testing)

cd d:\github\solidos
node scripts/release-orchestrator.js --mode test --dry-run=true
  • Runs on your computer
  • Prints commands without executing them (prefixed with [dry-run])
  • Creates release-summary.json locally
  • No publishing occurs
  • Use case: See exactly what would happen before running for real

Scenario 2: GitHub Test Release

  • Click Actions → "Solidos Release" → Run workflow
  • Inputs: mode=test, dry_run=false
  • Publishes to npm with @test tag
  • Does NOT create git tags
  • Results in GitHub Actions logs and artifacts
  • Always publishes (no skip logic)
  • Use case: Pre-release versions for testing from dev branch

Scenario 3: GitHub Stable Release (Protected Branches)

  • Click Actions → "Solidos Release" → Run workflow
  • Inputs: mode=stable-publish, dry_run=false
  • Single command that does everything:
    1. Creates release branch from dev
    2. Opens PR to main
    3. Waits for CI checks to pass
    4. Auto-merges PR (squash merge)
    5. Publishes all packages to npm with @latest tag
    6. Pushes git tags to main
  • Eliminates manual PR merge step
  • Perfect for: Organizations with branch protection rules on main
  • Use case: Automated stable releases without human intervention on PR merge

Scenario 4: GitHub Stable Release (Direct Push)

  • Click Actions → "Solidos Release" → Run workflow
  • Inputs: mode=stable, dry_run=false
  • Automatically merges origin/dev → main if dev has new commits
  • Publishes to npm with @latest tag
  • Creates git tags and pushes to GitHub
  • Results in GitHub Actions logs and artifacts
  • Skips if dev has no new commits (unless --branch=main specified)
  • WARNING: Requires write access to protected branches, may fail with 403
  • Use case: Repositories without branch protection on main

Local dry-run

  • Show the exact commands without running them: node scripts/release-orchestrator.js --mode test --dry-run
  • Override the branch: node scripts/release-orchestrator.js --mode test --dry-run --branch develop
  • Force stable publish regardless of changes: node scripts/release-orchestrator.js --mode stable --branch main
  • Dry-run allows untracked files (ignored for convenience)

CI runs (GitHub Actions)

  • Trigger workflow "Solidos Release" with inputs:

    • mode: test or stable
    • config: release.config.json (or another config file)
    • dry_run: true or false
    • clone_missing: true or false
    • branch: optional branch name override

    Fine-Grained PAT for Git Push (GIT_PUSH_TOKEN)

    • Stable mode needs to push commits/tags to multiple SolidOS repos.
    • GITHUB_TOKEN is often limited to the current repository.
    • Configure GIT_PUSH_TOKEN as a repository secret in solidos/solidos.

    Recommended setup (fine-grained PAT):

    1. Create a new fine-grained PAT in GitHub (do not reuse a broad personal token).
    2. Resource owner: SolidOS organization.
    3. Repository access:
    • Prefer "Only select repositories" and include repos listed in release.config.json.
    • "All repositories" also works if needed.
    1. Permissions:
    • Contents: Read and write (required for clone/push/tags)
    • Metadata: Read (required)
    • Actions: Read (optional)
    1. If branch protection blocks direct push to main, allow this token/account to bypass rules, or switch to a PR-based merge flow.
    2. Save token as secret:
    • Repo: solidos/solidos
    • Secret name: GIT_PUSH_TOKEN

    Security notes:

    • Do not use high-risk scopes like delete_repo or delete:packages.
    • Use a dedicated token for release automation.
    • Rotate regularly and immediately on suspected exposure.

Command-line Options

  • --mode: test or stable (default: stable)
  • --config: path to config file (default: release.config.json)
  • --dry-run: true or false (default: false)
  • --clone-missing: true or false (default: false)
  • --branch: override branch for all repos (optional)
    • Also disables skip logic in stable mode (forces publish)
  • --summary-path: path to output summary file (default: release-summary.json)

Branch Configuration

By default, both test and stable modes use the main branch. To use different branches:

Example release.config.json with separate branches:

{
  "defaultBranch": "main",
  "modes": [
    {
      "name": "test",
      "branch": "dev",
      "versionBump": "prerelease",
      "preid": "test",
      "npmTag": "test"
    },
    {
      "name": "stable",
      "branch": "main",
      "versionBump": "patch",
      "npmTag": "latest"
    }
  ],
  "repos": [
    {
      "name": "solid-panes",
      "path": "./workspaces/solid-panes",
      "afterInstall": [
        "npm install profile-pane"
      ]
    }
  ]
}

Behavior:

  • Test mode:
    • Pulls from dev branch
    • Always publishes (no skip)
    • afterInstall npm install profile-pane becomes npm install profile-pane@test || npm install profile-pane@latest
  • Stable mode:
    • Pulls from main branch
    • Auto-merges origin/dev if it has new commits
    • Skips if no changes (unless --branch=main specified)

Publish modes

  • test:
    • Runs on: dev branch (or configured branch)
    • npm version prerelease --preid test
    • npm publish --tag test --ignore-scripts
    • does NOT create git tags or push
    • Always publishes (no skip check)
    • If the prerelease version already exists, it auto-bumps again before publishing
    • Temporarily disables preversion/version/postversion scripts during version bump
    • afterInstall commands use @test tag with @latest fallback
  • stable:
    • Runs on: main branch (or configured branch)
    • Checks if origin/dev has commits that main doesn't
    • If yes: auto-merges origin/dev → main (may fail on conflicts)
    • npm version patch (or configured bump)
    • npm publish (latest) with --ignore-scripts
    • creates git tags and pushes by default
    • Skips if no changes (unless --branch explicitly specified)
    • afterInstall commands use @latest tag

Multiple configs

  • Create additional config files (for example):
    • release.config.json
    • release.config.test.json
    • release.config.hotfix.json
  • Use with: --config release.config.test.json

Skip logic

  • Test mode: Always publishes (no skip logic)
  • Stable mode:
    • Compares origin/dev vs main to detect unpublished changes
    • If origin/dev has commits that main doesn't: merges and publishes
    • If no changes: skips publishing
    • Override: --branch=main forces publish regardless of changes
    • Merge happens automatically before publish (fails if conflicts)
    • Merge commit includes [skip ci] to prevent redundant ci.yml runs

Summary output

  • A summary is printed at the end and written to release-summary.json.
  • Override with: --summary-path path/to/summary.json

npm install with dist-tags

  • Test mode: afterInstall commands automatically inject @test tags
    • Example: npm install solid-ui becomes npm install solid-ui@test
    • Fallback: If @test doesn't exist, tries @latest automatically
    • Command: npm install solid-ui@test || npm install solid-ui@latest
  • Stable mode: afterInstall commands use @latest tags (default npm behavior)
  • Manual install: npm install <pkg>@test to get test versions

Config options (release.config.json)

  • defaultBranch: branch name used if repo does not override.
  • skipIfNoDiff: skip publish if no diff vs origin.
  • defaultInstall / defaultTest / defaultBuild: commands for all repos.
  • modes: publish behavior for "stable" and "test".
  • repos: per repo configuration:
    • name (required)
    • path (required)
    • repo (optional, needed for CI clone)
    • branch (optional override)
    • install/test/build (optional overrides)
    • before*/after* arrays for custom steps

Notes

  • CI uses npm OIDC with NODE_AUTH_TOKEN set in GitHub Actions.
  • CI uses GIT_PUSH_TOKEN (preferred) or falls back to GITHUB_TOKEN for git clone/push authentication.
  • If a repo requires special install steps, add them under afterInstall in the config.

Individual Repos and Their CI Workflows

Each workspace repo (solid-panes, folder-pane, etc.) has its own ci.yml workflow for PR testing. This is independent of the release orchestrator:

Per-repo ci.yml (solid-panes/.github/workflows/ci.yml):

  • Triggers on: Push to main/develop, Pull requests
  • Runs: Tests, linting, building
  • Purpose: Verify code quality
  • Used by: PRs waiting to be merged
  • Does NOT publish to npm

Central release.yml (solidos/.github/workflows/release.yml):

  • Triggers on: Manual button click only
  • Runs: release-orchestrator.js
  • Purpose: Publish all repos to npm at once
  • Used by: Release maintainers
  • Does NOT run automatically on PRs or merges

Summary:

┌─ PR Created
│  └─ ci.yml runs in each repo → blocks merge if tests fail
│
└─ PR Merged to main/develop
   └─ ci.yml finishes
   └─ [waiting for manual release trigger]
   └─ You click "Run workflow" in Actions
      └─ release.yml runs → publishes to npm
         └─ (stable mode) auto-merges dev→main with [skip ci]
         └─ pushes version tags and commits
         └─ ci.yml does NOT run (prevented by [skip ci])

Important Notes:

  • Waiting PRs are NOT automatically published. You must manually trigger the release after merging.
  • When stable mode merges dev→main automatically, it uses [skip ci] in the commit message to prevent redundant ci.yml runs in individual repos.
  • Tests/builds already ran in the release orchestrator, so skipping ci.yml avoids duplicate work.