1 name: NPM XCRS Release
2
3 on:
4 workflow_dispatch:
5 inputs:
6 tag:
7 description: "Release tag (e.g. v0.3.39)"
8 required: true
9
10 permissions:
11 id-token: write
12 contents: read
13
14 jobs:
15 publish-npm-binaries:
16 name: Publish NPM packages
17 runs-on: ${{ matrix.build.OS }}
18 strategy:
19 fail-fast: false
20 matrix:
21 build:
22 - {
23 NAME: linux-x64-glibc,
24 OS: ubuntu-latest,
25 TARGET: x86_64-unknown-linux-gnu,
26 }
27 - {
28 NAME: linux-arm64-glibc,
29 OS: ubuntu-24.04-arm,
30 TARGET: aarch64-unknown-linux-gnu,
31 }
32 - {
33 NAME: win32-x64-msvc,
34 OS: windows-2022,
35 TARGET: x86_64-pc-windows-msvc,
36 }
37 - {
38 NAME: win32-arm64-msvc,
39 OS: windows-2022,
40 TARGET: aarch64-pc-windows-msvc,
41 }
42 - {
43 NAME: darwin-x64,
44 OS: macos-15-intel,
45 TARGET: x86_64-apple-darwin,
46 }
47 - {
48 NAME: darwin-arm64,
49 OS: macos-latest,
50 TARGET: aarch64-apple-darwin,
51 }
52 steps:
53 - name: Checkout
54 uses: actions/checkout@v6
55 with:
56 ref: ${{ github.event.inputs.tag || github.ref }}
57
58 - name: Set the release version
59 shell: bash
60 run: |
61 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
62 release_version="${GITHUB_REF_NAME#v}"
63 else
64 release_version="${{ github.event.inputs.tag }}"
65 release_version="${release_version#v}"
66 fi
67
68 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
69
70 - name: Read Rust toolchain
71 shell: bash
72 run: |
73 rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
74 if [ -z "$rust_toolchain" ]; then
75 echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
76 exit 1
77 fi
78
79 echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
80
81 - name: Install toolkit
82 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
83 with:
84 toolchain: ${{ env.RUST_TOOLCHAIN }}
85
86 - name: Install Rust target
87 shell: bash
88 run: |
89 rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }}
90 rustup target list --installed
91
92 - name: Build
93 shell: bash
94 run: |
95 cargo build --release --locked --target ${{ matrix.build.TARGET }} --package xcrs
96
97 - name: Install node
98 uses: actions/setup-node@v6
99 with:
100 node-version-file: .nvmrc
101 registry-url: "https://registry.npmjs.org"
102
103 - name: Publish to NPM
104 env:
105 NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
106 shell: bash
107 run: |
108 # We want to name our npm package @smbcloud/xcrs, and the command is xcrs.
109 # All optional platform dependencies follow the @smbcloud/xcrs-${os}-${arch}
110 # naming convention.
111
112 # Move to the npm directory
113 cd npm
114 # set the binary name, this is from the rust Cargo.toml file
115 cargo_bin="xcrs"
116 node_pkg_prefix="xcrs"
117 # derive the OS and architecture from the build matrix name
118 # note: when split by a hyphen, first part is the OS and the second is the architecture
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 # set the version
124 export node_version="${{ env.RELEASE_VERSION }}"
125 # set the package name
126 # note: use 'windows' as OS name instead of 'win32'
127 if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
128 export node_pkg="${node_pkg_prefix}-windows-${node_arch}"
129 else
130 export node_pkg="${node_pkg_prefix}-${node_os}-${node_arch}"
131 fi
132 # create the package directory
133 mkdir -p "${node_pkg}/bin"
134 # generate package metadata
135 node ./scripts/render-platform-package.cjs "${node_pkg}" "${node_version}" "${node_os}" "${node_arch}" "Platform binary for the xcrs CLI."
136 # copy the binary into the package
137 # note: windows binaries has '.exe' extension
138 if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
139 cargo_bin="${cargo_bin}.exe"
140 fi
141 cp "../target/${{ matrix.build.TARGET }}/release/${cargo_bin}" "${node_pkg}/bin"
142 # publish the package
143 cd "${node_pkg}"
144 npm_package_name="@smbcloud/${node_pkg}"
145 if npm view "${npm_package_name}@${node_version}" version >/dev/null 2>&1; then
146 echo "${npm_package_name}@${node_version} already exists on npm, skipping publish"
147 exit 0
148 fi
149 npm publish --access public
150
151 publish-npm-base:
152 name: Publish the base NPM package
153 needs: publish-npm-binaries
154 runs-on: ubuntu-latest
155 steps:
156 - name: Checkout
157 uses: actions/checkout@v6
158 with:
159 ref: ${{ github.event.inputs.tag || github.ref }}
160
161 - name: Set the release version
162 shell: bash
163 run: |
164 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
165 release_version="${GITHUB_REF_NAME#v}"
166 else
167 release_version="${{ github.event.inputs.tag }}"
168 release_version="${release_version#v}"
169 fi
170
171 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
172
173 - name: Install node
174 uses: actions/setup-node@v6
175 with:
176 node-version-file: .nvmrc
177 registry-url: "https://registry.npmjs.org"
178
179 - name: Publish the package
180 env:
181 NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
182 shell: bash
183 run: |
184 cd npm/xcrs
185
186 node ../scripts/render-main-package.cjs "./package.json" "${{ env.RELEASE_VERSION }}" xcrs
187
188 npm_package_name="@smbcloud/xcrs"
189 npm_package_version="${{ env.RELEASE_VERSION }}"
190 if npm view "${npm_package_name}@${npm_package_version}" version >/dev/null 2>&1; then
191 echo "${npm_package_name}@${npm_package_version} already exists on npm, skipping publish"
192 exit 0
193 fi
194
195 npm install
196 npm run build
197 npm publish --access public