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