@@ -2,6 +2,44 @@ name: Release
22
33on :
44 workflow_dispatch :
5+ inputs :
6+ mode :
7+ description : ' Release mode'
8+ type : choice
9+ options :
10+ - release
11+ - candidate
12+ default : release
13+ js-sdk :
14+ description : ' Release JS SDK (candidate only)'
15+ required : false
16+ default : false
17+ type : boolean
18+ python-sdk :
19+ description : ' Release Python SDK (candidate only)'
20+ required : false
21+ default : false
22+ type : boolean
23+ cli :
24+ description : ' Release CLI (candidate only)'
25+ required : false
26+ default : false
27+ type : boolean
28+ tag :
29+ description : ' Dist-tag for candidate (e.g. rc, beta, snapshot)'
30+ required : false
31+ default : ' rc'
32+ type : string
33+ preid :
34+ description : ' Prerelease identifier (defaults to branch name, candidate only)'
35+ required : false
36+ default : ' '
37+ type : string
38+ skip-tests :
39+ description : ' Skip tests (candidate only)'
40+ required : false
41+ default : false
42+ type : boolean
543
644concurrency : ${{ github.workflow }}-${{ github.ref }}
745
@@ -10,8 +48,10 @@ permissions:
1048 contents : write
1149
1250jobs :
51+ # ── Production release ───────────────────────────────────
1352 is_release :
1453 name : Is release?
54+ if : github.event.inputs.mode != 'candidate'
1555 runs-on : ubuntu-latest
1656 outputs :
1757 release : ${{ steps.version.outputs.release }}
@@ -156,3 +196,137 @@ jobs:
156196 SLACK_TITLE : Release Failed
157197 SLACK_WEBHOOK : ${{ secrets.SLACK_WEBHOOK }}
158198 SLACK_CHANNEL : ' monitoring-releases'
199+
200+ # ── Release candidate ────────────────────────────────────
201+ release-candidate :
202+ name : Release Candidate
203+ if : github.event.inputs.mode == 'candidate'
204+ runs-on : ubuntu-latest
205+
206+ env :
207+ IS_JS : ${{ github.event.inputs.js-sdk == 'true' }}
208+ IS_CLI : ${{ github.event.inputs.cli == 'true' }}
209+ IS_PYTHON : ${{ github.event.inputs.python-sdk == 'true' }}
210+ PUBLISH_TAG : ${{ github.event.inputs.tag }}
211+ SKIP_TESTS : ${{ github.event.inputs.skip-tests == 'true' }}
212+
213+ steps :
214+ - name : Sanitize preid
215+ run : |
216+ RAW_PREID="${{ github.event.inputs.preid || github.ref_name }}"
217+ echo "PREID=$(echo "$RAW_PREID" | sed 's/[^0-9A-Za-z-]/-/g')" >> "$GITHUB_ENV"
218+
219+ - name : Block production tags
220+ run : |
221+ if [ "${{ github.event.inputs.tag }}" = "latest" ]; then
222+ echo "::error::Publishing with the 'latest' tag is not allowed for candidates. Use 'release' mode instead."
223+ exit 1
224+ fi
225+
226+ - name : Checkout Repo
227+ uses : actions/checkout@v4
228+
229+ - name : Parse .tool-versions
230+ uses : wistia/parse-tool-versions@v2.1.1
231+ with :
232+ filename : ' .tool-versions'
233+ uppercase : ' true'
234+ prefix : ' tool_version_'
235+
236+ - uses : pnpm/action-setup@v4
237+ if : ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }}
238+ with :
239+ version : ' ${{ env.TOOL_VERSION_PNPM }}'
240+
241+ - name : Setup Node.js
242+ uses : actions/setup-node@v6
243+ if : ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }}
244+ with :
245+ node-version : ' ${{ env.TOOL_VERSION_NODEJS }}'
246+ registry-url : https://registry.npmjs.org
247+ cache : pnpm
248+
249+ - name : Configure pnpm
250+ if : ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }}
251+ run : |
252+ pnpm config set auto-install-peers true
253+ pnpm config set exclude-links-from-lockfile true
254+
255+ - name : Update npm
256+ if : ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }}
257+ run : |
258+ npm install -g npm@^11.6
259+ npm --version
260+
261+ - name : Set up Python
262+ uses : actions/setup-python@v4
263+ if : ${{ env.IS_PYTHON == 'true' }}
264+ with :
265+ python-version : ' ${{ env.TOOL_VERSION_PYTHON }}'
266+
267+ - name : Install and configure Poetry
268+ uses : snok/install-poetry@v1
269+ if : ${{ env.IS_PYTHON == 'true' }}
270+ with :
271+ version : ' ${{ env.TOOL_VERSION_POETRY }}'
272+ virtualenvs-create : true
273+ virtualenvs-in-project : true
274+ installer-parallel : true
275+
276+ - name : Test Python SDK
277+ if : ${{ env.IS_PYTHON == 'true' && env.SKIP_TESTS != 'true' }}
278+ working-directory : packages/python-sdk
279+ run : |
280+ poetry install
281+ poetry run pytest --verbose -x
282+ env :
283+ E2B_API_KEY : ${{ secrets.E2B_API_KEY }}
284+
285+ - name : Publish Python RC
286+ if : ${{ env.IS_PYTHON == 'true' }}
287+ working-directory : packages/python-sdk
288+ run : |
289+ poetry version prerelease
290+ poetry build
291+ poetry config pypi-token.pypi ${PYPI_TOKEN} && poetry publish --skip-existing
292+ env :
293+ PYPI_TOKEN : ${{ secrets.PYPI_TOKEN }}
294+
295+ - name : Install JS dependencies
296+ if : ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }}
297+ run : pnpm install --frozen-lockfile
298+
299+ - name : Test JS SDK
300+ if : ${{ env.IS_JS == 'true' && env.SKIP_TESTS != 'true' }}
301+ working-directory : packages/js-sdk
302+ run : pnpm run test
303+ env :
304+ E2B_API_KEY : ${{ secrets.E2B_API_KEY }}
305+
306+ - name : Publish JS RC
307+ if : ${{ env.IS_JS == 'true' }}
308+ working-directory : packages/js-sdk
309+ run : |
310+ npm version prerelease --preid=${{ env.PREID }}
311+ npm publish --tag ${{ env.PUBLISH_TAG }} --provenance
312+
313+ - name : Reinstall dependencies
314+ if : ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }}
315+ run : pnpm install --frozen-lockfile
316+
317+ - name : Publish CLI RC
318+ if : ${{ env.IS_CLI == 'true' }}
319+ working-directory : packages/cli
320+ run : |
321+ npm version prerelease --preid=${{ env.PREID }}
322+ npm publish --tag ${{ env.PUBLISH_TAG }} --provenance
323+
324+ - name : Commit new versions
325+ if : ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' || env.IS_PYTHON == 'true' }}
326+ run : |
327+ git config user.name "github-actions[bot]"
328+ git config user.email "github-actions[bot]@users.noreply.github.com"
329+ git commit -am "[skip ci] Release new versions" || exit 0
330+ git push
331+ env :
332+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments