Skip to content

Commit 89a7403

Browse files
authored
Merge pull request #820 from Kitware/tagged-releases
Automate package publishing via CI/CD
2 parents a98b1c5 + f71c801 commit 89a7403

File tree

6 files changed

+111
-34
lines changed

6 files changed

+111
-34
lines changed

.github/workflows/release.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Unified workflow for both prerelease and stable releases
2+
# Prerelease: triggered on push to main
3+
# Stable: triggered on push of tag matching 'v*.*.*'
4+
# NOTE: The reason this is all done in one workflow is because npmjs.com only
5+
# allows one GH Actions file to be setup as a trusted publisher.
6+
name: Publish npm package
7+
8+
on:
9+
push:
10+
branches:
11+
- main
12+
tags:
13+
- 'v[0-9]+.[0-9]+.[0-9]+'
14+
15+
permissions:
16+
id-token: write
17+
18+
jobs:
19+
publish:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0
25+
26+
- uses: actions/setup-node@v4
27+
with:
28+
node-version: current
29+
registry-url: 'https://registry.npmjs.org/'
30+
31+
- name: Install dependencies
32+
run: npm ci
33+
34+
- name: Determine version and tag
35+
id: version
36+
run: |
37+
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
38+
# Stable release: use tag version
39+
VERSION=${GITHUB_REF#refs/tags/v}
40+
npm version "$VERSION" --no-git-tag-version
41+
TAG="latest"
42+
echo "version=$VERSION" >> $GITHUB_OUTPUT
43+
echo "tag=$TAG" >> $GITHUB_OUTPUT
44+
echo "Setting version to $VERSION for stable release"
45+
else
46+
# Prerelease: bump from latest stable tag
47+
LATEST_TAG=$(git tag --list "v*.*.*" --sort=-v:refname | grep -v '-' | head -n1)
48+
npm version "${LATEST_TAG#v}" --no-git-tag-version
49+
npm version prerelease --preid="dev.${{ github.sha }}" --no-git-tag-version
50+
VERSION=$(node -p "require('./package.json').version")
51+
TAG="dev"
52+
echo "version=$VERSION" >> $GITHUB_OUTPUT
53+
echo "tag=$TAG" >> $GITHUB_OUTPUT
54+
echo "Setting version to $VERSION for prerelease"
55+
fi
56+
57+
- name: Build with remote save enabled
58+
run: VITE_REMOTE_SERVER_URL= VITE_ENABLE_REMOTE_SAVE=true npm run build
59+
60+
- name: Publish to npm
61+
run: npm publish --tag ${{ steps.version.outputs.tag }} --access public --provenance

CONTRIBUTING.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Before you begin, make sure your environment matches the following versions:
66

7-
- **Node.js**: >= 18.20.0 (20.x LTS recommended)
7+
- **Node.js**: >= 18.20.0 (20.x LTS recommended)
88
- **npm**: >= 9.x (npm 10+ works with Node 20)
99

1010
Check your versions:
@@ -97,6 +97,27 @@ npm run test:e2e:dev -- -- --spec ./tests/specs/remote-manifest.e2e.ts
9797

9898
---
9999

100+
## Versioning
101+
102+
Merging to `main` automatically publishes prerelease packages to NPM:
103+
104+
1. Merge creates a prerelease tag (e.g. v4.4.0-dev.<sha>)
105+
2. Tag triggers automatic NPM publish with `@dev` dist-tag
106+
107+
```bash
108+
npm install volview # Gets latest stable release (e.g., 4.4.0)
109+
npm install volview@dev # Gets latest dev package (most recent commit to main branch)
110+
```
111+
112+
To publish a new release via CI/CD, manually create and push a tag, e.g.:
113+
114+
```bash
115+
git tag v4.5.0 # must match format 'v[0-9]+.[0-9]+.[0-9]+'
116+
git push origin --tags
117+
```
118+
119+
---
120+
100121
## Developing with VTK.js
101122

102123
Follow these steps to develop against a custom development branch of VTK.js:

package-lock.json

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
{
22
"name": "volview",
3-
"version": "4.4.0",
3+
"version": "0.0.0",
44
"type": "module",
5+
"files": [
6+
"dist",
7+
"src"
8+
],
59
"scripts": {
610
"dev": "cross-env VITE_SHOW_SAMPLE_DATA=true vite",
711
"preview": "vite preview",
@@ -19,7 +23,6 @@
1923
"build:resample": "itk-wasm -s src/io/resample/ build ",
2024
"build:resample:debug": "itk-wasm -s src/io/resample/ build -- -DCMAKE_BUILD_TYPE=Debug",
2125
"build:watch": "npm run build -- --watch",
22-
"postinstall": "patch-package",
2326
"prettify": "prettier --write src tests",
2427
"docs:dev": "vitepress dev docs",
2528
"docs:build": "vitepress build docs",

vite.config.ts

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="vitest" />
22
import * as path from 'node:path';
3+
import * as fs from 'node:fs';
34
import { createRequire } from 'node:module';
45
import { Plugin, defineConfig, normalizePath } from 'vite';
56
import vue from '@vitejs/plugin-vue';
@@ -10,35 +11,8 @@ import { visualizer } from 'rollup-plugin-visualizer';
1011
import { sentryVitePlugin } from '@sentry/vite-plugin';
1112
import replace from '@rollup/plugin-replace';
1213

13-
import pkgLock from './package-lock.json';
1414
import { config } from './wdio.shared.conf';
1515

16-
function getPackageInfo(lockInfo: typeof pkgLock) {
17-
if (lockInfo.lockfileVersion === 2) {
18-
return {
19-
versions: {
20-
volview: lockInfo.version,
21-
'vtk.js': lockInfo.dependencies['@kitware/vtk.js'].version,
22-
'itk-wasm': lockInfo.dependencies['itk-wasm'].version,
23-
},
24-
};
25-
}
26-
27-
if (lockInfo.lockfileVersion === 3) {
28-
return {
29-
versions: {
30-
volview: lockInfo.version,
31-
'vtk.js': lockInfo.packages['node_modules/@kitware/vtk.js'].version,
32-
'itk-wasm': lockInfo.packages['node_modules/itk-wasm'].version,
33-
},
34-
};
35-
}
36-
37-
throw new Error(
38-
'VolView build: your package-lock.json version is not 2 or 3. Cannot extract dependency versions.'
39-
);
40-
}
41-
4216
function resolveNodeModulePath(moduleName: string) {
4317
const require = createRequire(import.meta.url);
4418
let modulePath = normalizePath(require.resolve(moduleName));
@@ -55,13 +29,32 @@ function resolvePath(...args: string[]) {
5529
return normalizePath(path.resolve(...args));
5630
}
5731

32+
function getPackageInfo() {
33+
const mainPkgPath = path.resolve(__dirname, 'package.json');
34+
const mainPkg = JSON.parse(fs.readFileSync(mainPkgPath, 'utf-8'));
35+
36+
const vtkJsPath = path.join(resolveNodeModulePath('@kitware/vtk.js'), 'package.json');
37+
const vtkJsPkg = JSON.parse(fs.readFileSync(vtkJsPath, 'utf-8'));
38+
39+
const itkWasmPath = path.join(resolveNodeModulePath('itk-wasm'), 'package.json');
40+
const itkWasmPkg = JSON.parse(fs.readFileSync(itkWasmPath, 'utf-8'));
41+
42+
return {
43+
versions: {
44+
volview: mainPkg.version,
45+
'vtk.js': vtkJsPkg.version,
46+
'itk-wasm': itkWasmPkg.version,
47+
},
48+
};
49+
}
50+
5851
const rootDir = resolvePath(__dirname);
5952
const distDir = resolvePath(rootDir, 'dist');
6053

6154
const { ANALYZE_BUNDLE, SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT } =
6255
process.env;
6356

64-
const pkgInfo = getPackageInfo(pkgLock);
57+
const pkgInfo = getPackageInfo();
6558

6659
function configureSentryPlugin() {
6760
return SENTRY_AUTH_TOKEN && SENTRY_ORG && SENTRY_PROJECT

0 commit comments

Comments
 (0)