Skip to content

feat(ci): add automated npm publish pipeline via semantic-release - #38

Draft
gmenher wants to merge 1 commit into
Gkrumbach07:mainfrom
gmenher:feat/npm-publish-pipeline
Draft

feat(ci): add automated npm publish pipeline via semantic-release#38
gmenher wants to merge 1 commit into
Gkrumbach07:mainfrom
gmenher:feat/npm-publish-pipeline

Conversation

@gmenher

@gmenher gmenher commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Closes #11

Description

Adds an automated npm publish pipeline so that openshell-dashboard is published to the npm registry on every merge to main that passes CI. This enables odh-dashboard (and any other consumer) to install the package directly from npm instead of relying on git dependencies or local symlinks.

Currently, publishing is manual and error-prone — the version is hardcoded and there's no CI gate ensuring tests pass before a release goes out. This PR automates the entire flow using semantic-release, which determines the next version from conventional commit messages, generates release notes, and publishes atomically.

What changed

  • .github/workflows/publish.yml (new): Publish workflow triggered via workflow_run after the CI workflow completes successfully on main. Pins semantic-release@25.0.9 via npx. Installs frontend deps, builds the library, and runs semantic-release.
  • .releaserc.json (new): semantic-release configuration — commit-analyzer, release-notes-generator, npm (targeting frontend/ as pkgRoot), and github plugin for creating GitHub Releases.
  • frontend/package.json (1 line): Version changed to 0.0.0-semantically-released — semantic-release manages the actual version at publish time.
  • .gitattributes (new): Marks package-lock.json files as linguist-generated so GitHub collapses them in future PR diffs.

Design decisions

1. workflow_run instead of on: push with paths:

The publish workflow does NOT trigger directly on push. Instead, it listens for the CI workflow to complete successfully. This guarantees that lint, typecheck, and unit tests all pass before any package is published. A paths: filter can't enforce this — it would race with CI.

2. Pinned npx semantic-release@25.0.9 instead of root package.json

Alternative considered: adding a root package.json with semantic-release as a devDependency. This was rejected because it introduces a 5,600-line package-lock.json for a single CI tool. Pinning in the npx call gives version stability without bloating the repo. The plugins are resolved by semantic-release itself from .releaserc.json.

3. 0.0.0-semantically-released version placeholder

Standard pattern for semantic-release managed packages. The actual version is written by the @semantic-release/npm plugin during publish. The placeholder prevents accidental manual publishes with a stale version.

4. No id-token: write permission (OIDC provenance)

npm provenance requires id-token: write. This can be added later when the package is established. For now, we keep permissions minimal.

Dependencies

  • PR fix(packaging): make npm package publishable #36 (fix/npm-package-publishable) must merge first — it fixes the exports map and files field so the published tarball actually works.
  • Secret NPM_TOKEN must be configured in repo Settings → Secrets → Actions before the first publish will succeed.
  • After both are in place, the next merge to main with a feat: or fix: commit will trigger the first release.

How Has This Been Tested?

1. Local build validation

cd frontend && npm run build:lib

Build succeeds. All 10 export paths verified:

✓ dist/pages/index.js
✓ dist/pages/index.d.ts
✓ dist/components/index.js
✓ dist/components/index.d.ts
✓ dist/api/index.js
✓ dist/api/index.d.ts
✓ dist/types/index.js
✓ dist/types/index.d.ts
✓ dist/slots/index.js
✓ dist/slots/index.d.ts

2. semantic-release dry run

npx semantic-release --dry-run --no-ci

Result — all plugins loaded correctly:

[semantic-release] › ✔  Loaded plugin "verifyConditions" from "@semantic-release/npm"
[semantic-release] › ✔  Loaded plugin "verifyConditions" from "@semantic-release/github"
[semantic-release] › ✔  Loaded plugin "analyzeCommits" from "@semantic-release/commit-analyzer"
[semantic-release] › ✔  Loaded plugin "generateNotes" from "@semantic-release/release-notes-generator"
[semantic-release] › ✔  Loaded plugin "prepare" from "@semantic-release/npm"
[semantic-release] › ✔  Loaded plugin "publish" from "@semantic-release/npm"
[semantic-release] › ✔  Loaded plugin "publish" from "@semantic-release/github"
[semantic-release] › ℹ  This test run was triggered on the branch feat/npm-publish-pipeline, while semantic-release is configured to only publish from main, therefore a new version won't be published.

3. Export map resolution

node -e "
const fs = require('fs');
const pkg = require('./package.json');
for (const [key, val] of Object.entries(pkg.exports)) {
  const js = fs.existsSync(val.default);
  const ts = fs.existsSync(val.types);
  console.log((js && ts ? '✓' : '✗') + ' ' + key);
}
"

Result:

✓ ./pages
✓ ./components
✓ ./api
✓ ./types
✓ ./slots

4. Why this testing approach

Full end-to-end validation (actual npm publish) is not possible without the NPM_TOKEN secret configured and a merge to main. The local validation confirms:

  • The build pipeline produces the expected output structure
  • semantic-release recognizes and loads the configuration
  • The package exports resolve correctly post-build
  • The workflow YAML is syntactically valid

@gmenher
gmenher force-pushed the feat/npm-publish-pipeline branch 2 times, most recently from d2e3cdd to 2598af0 Compare August 13, 2026 14:14
Adds a publish workflow gated on CI success via workflow_run trigger.
Uses semantic-release to automate versioning and npm publishing based
on conventional commits.

Prerequisite: NPM_TOKEN secret must be configured in repo settings.
@gmenher
gmenher force-pushed the feat/npm-publish-pipeline branch from 2598af0 to 6069a53 Compare August 13, 2026 14:23
@gmenher

gmenher commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

This PR will move to ready-for-review once someone with admin access adds the NPM_TOKEN secret to the repo with publish scope for openshell-dashboard.

Feel free to mark it ready and merge once that's in place (after #36 lands).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Set up automated npm publish pipeline

1 participant