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 shell: bash
105 run: |
106 # We want to name our npm package @smbcloud/xcrs, and the command is xcrs.
107 # All optional platform dependencies follow the @smbcloud/xcrs-${os}-${arch}
108 # naming convention.
109
110 # Move to the npm directory
111 cd npm
112 # set the binary name, this is from the rust Cargo.toml file
113 cargo_bin="xcrs"
114 node_pkg_prefix="xcrs"
115 # derive the OS and architecture from the build matrix name
116 # note: when split by a hyphen, first part is the OS and the second is the architecture
117 node_os=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f1)
118 export node_os
119 node_arch=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f2)
120 export node_arch
121 # set the version
122 export node_version="${{ env.RELEASE_VERSION }}"
123 # set the package name
124 # note: use 'windows' as OS name instead of 'win32'
125 if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
126 export node_pkg="${node_pkg_prefix}-windows-${node_arch}"
127 else
128 export node_pkg="${node_pkg_prefix}-${node_os}-${node_arch}"
129 fi
130 # create the package directory
131 mkdir -p "${node_pkg}/bin"
132 # generate package metadata
133 node ./scripts/render-platform-package.cjs "${node_pkg}" "${node_version}" "${node_os}" "${node_arch}" "Platform binary for the xcrs CLI."
134 # copy the binary into the package
135 # note: windows binaries has '.exe' extension
136 if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
137 cargo_bin="${cargo_bin}.exe"
138 fi
139 cp "../target/${{ matrix.build.TARGET }}/release/${cargo_bin}" "${node_pkg}/bin"
140 # publish the package
141 cd "${node_pkg}"
142 npm_package_name="@smbcloud/${node_pkg}"
143 if npm view "${npm_package_name}@${node_version}" version >/dev/null 2>&1; then
144 echo "${npm_package_name}@${node_version} already exists on npm, skipping publish"
145 exit 0
146 fi
147 npm publish --access public
148
149 publish-npm-base:
150 name: Publish the base NPM package
151 needs: publish-npm-binaries
152 runs-on: ubuntu-latest
153 steps:
154 - name: Checkout
155 uses: actions/checkout@v6
156 with:
157 ref: ${{ github.event.inputs.tag || github.ref }}
158
159 - name: Set the release version
160 shell: bash
161 run: |
162 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
163 release_version="${GITHUB_REF_NAME#v}"
164 else
165 release_version="${{ github.event.inputs.tag }}"
166 release_version="${release_version#v}"
167 fi
168
169 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
170
171 - name: Install node
172 uses: actions/setup-node@v6
173 with:
174 node-version-file: .nvmrc
175 registry-url: "https://registry.npmjs.org"
176
177 - name: Publish the package
178 shell: bash
179 run: |
180 cd npm/xcrs
181
182 node ../scripts/render-main-package.cjs "./package.json" "${{ env.RELEASE_VERSION }}" xcrs
183
184 npm_package_name="@smbcloud/xcrs"
185 npm_package_version="${{ env.RELEASE_VERSION }}"
186 if npm view "${npm_package_name}@${npm_package_version}" version >/dev/null 2>&1; then
187 echo "${npm_package_name}@${npm_package_version} already exists on npm, skipping publish"
188 exit 0
189 fi
190
191 npm install
192 npm run build
193 npm publish --access public