1 name: NPM Release
2
3 on:
4 push:
5 tags:
6 - "v*.*.*"
7 workflow_dispatch:
8 inputs:
9 tag:
10 description: "Release tag (e.g. v0.1.1)"
11 required: true
12
13 permissions:
14 id-token: write
15 contents: read
16
17 env:
18 CARGO_TERM_COLOR: always
19
20 jobs:
21 publish-npm-binaries:
22 name: Publish NPM platform packages
23 runs-on: ${{ matrix.build.OS }}
24 strategy:
25 fail-fast: false
26 matrix:
27 build:
28 - {
29 NAME: linux-x64-glibc,
30 OS: ubuntu-latest,
31 TARGET: x86_64-unknown-linux-gnu,
32 }
33 - {
34 NAME: linux-arm64-glibc,
35 OS: ubuntu-24.04-arm,
36 TARGET: aarch64-unknown-linux-gnu,
37 }
38 - {
39 NAME: win32-x64-msvc,
40 OS: windows-2022,
41 TARGET: x86_64-pc-windows-msvc,
42 }
43 - {
44 NAME: win32-arm64-msvc,
45 OS: windows-2022,
46 TARGET: aarch64-pc-windows-msvc,
47 }
48 - { NAME: darwin-x64, OS: macos-26, TARGET: x86_64-apple-darwin }
49 - { NAME: darwin-arm64, OS: macos-26, TARGET: aarch64-apple-darwin }
50
51 steps:
52 - name: Checkout
53 uses: actions/checkout@v6
54 with:
55 ref: ${{ github.event.inputs.tag || github.ref }}
56
57 - name: Set the release version
58 shell: bash
59 run: |
60 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
61 release_version="${GITHUB_REF_NAME#v}"
62 else
63 release_version="${{ github.event.inputs.tag }}"
64 release_version="${release_version#v}"
65 fi
66 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
67
68 - name: Read Rust toolchain
69 shell: bash
70 run: |
71 rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
72 if [ -z "$rust_toolchain" ]; then
73 echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
74 exit 1
75 fi
76 echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
77
78 - name: Install Rust toolchain
79 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
80 with:
81 toolchain: ${{ env.RUST_TOOLCHAIN }}
82
83 - name: Install Rust target
84 shell: bash
85 run: |
86 rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }}
87 rustup target list --installed
88
89 - name: Setup Rust cache
90 uses: Swatinem/rust-cache@v2
91 with:
92 key: npm-${{ matrix.build.TARGET }}
93
94 - name: Build binary
95 shell: bash
96 run: cargo build --locked --release --target ${{ matrix.build.TARGET }}
97
98 - name: Install Node
99 uses: actions/setup-node@v6
100 with:
101 node-version-file: .nvmrc
102 registry-url: "https://registry.npmjs.org"
103
104 - name: Publish platform package to NPM
105 env:
106 NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
107 shell: bash
108 run: |
109 cd npm
110
111 # Binary name from Cargo.toml
112 cargo_bin="sigit"
113
114 # Prefix used for optional dependency package names
115 node_pkg_prefix="sigit"
116
117 # Derive OS and architecture from the build matrix name
118 # Matrix name format: <os>-<arch>[-<extra>]
119 node_os=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f1)
120 export node_os
121 node_arch=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f2)
122 export node_arch
123
124 # Set the version
125 export node_version="${{ env.RELEASE_VERSION }}"
126
127 # Build the platform package name; normalise win32 → windows
128 if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
129 export node_pkg="${node_pkg_prefix}-windows-${node_arch}"
130 else
131 export node_pkg="${node_pkg_prefix}-${node_os}-${node_arch}"
132 fi
133
134 # Create the package directory
135 mkdir -p "${node_pkg}/bin"
136
137 # Generate package.json + README for this platform slice
138 node ./scripts/render-platform-package.cjs \
139 "${node_pkg}" \
140 "${node_version}" \
141 "${node_os}" \
142 "${node_arch}"
143
144 # Windows binaries carry a .exe extension
145 if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
146 cargo_bin="${cargo_bin}.exe"
147 fi
148
149 cp "../target/${{ matrix.build.TARGET }}/release/${cargo_bin}" "${node_pkg}/bin"
150
151 cd "${node_pkg}"
152
153 npm_package_name="@smbcloud/${node_pkg}"
154 if npm view "${npm_package_name}@${node_version}" version >/dev/null 2>&1; then
155 echo "${npm_package_name}@${node_version} already exists on npm, skipping publish"
156 exit 0
157 fi
158
159 npm publish --access public --provenance
160
161 publish-npm-base:
162 name: Publish base NPM package (@smbcloud/sigit)
163 needs: publish-npm-binaries
164 runs-on: ubuntu-latest
165
166 steps:
167 - name: Checkout
168 uses: actions/checkout@v6
169 with:
170 ref: ${{ github.event.inputs.tag || github.ref }}
171
172 - name: Set the release version
173 shell: bash
174 run: |
175 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
176 release_version="${GITHUB_REF_NAME#v}"
177 else
178 release_version="${{ github.event.inputs.tag }}"
179 release_version="${release_version#v}"
180 fi
181 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
182
183 - name: Install Node
184 uses: actions/setup-node@v6
185 with:
186 node-version-file: .nvmrc
187 registry-url: "https://registry.npmjs.org"
188
189 - name: Publish base package to NPM
190 env:
191 NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
192 shell: bash
193 run: |
194 cd npm/sigit
195
196 # Rewrite package.json with the correct release version and
197 # matching optionalDependency versions
198 node ../scripts/render-main-package.cjs \
199 "./package.json" \
200 "${{ env.RELEASE_VERSION }}"
201
202 npm_package_name="@smbcloud/sigit"
203 npm_package_version="${{ env.RELEASE_VERSION }}"
204
205 if npm view "${npm_package_name}@${npm_package_version}" version >/dev/null 2>&1; then
206 echo "${npm_package_name}@${npm_package_version} already exists on npm, skipping publish"
207 exit 0
208 fi
209
210 npm install
211 npm run build
212 npm publish --access public --provenance