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