From e90d19939f0cc966a5dc4029eba71468d264865c Mon Sep 17 00:00:00 2001 From: Jakub Dobry Date: Mon, 16 Feb 2026 19:34:33 -0800 Subject: [PATCH 1/7] allow skipping tests for release candidates --- .github/workflows/release_candidates.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release_candidates.yml b/.github/workflows/release_candidates.yml index 0e7cad52f1..f196ac8c14 100644 --- a/.github/workflows/release_candidates.yml +++ b/.github/workflows/release_candidates.yml @@ -33,6 +33,11 @@ on: required: false default: '' type: string + skip-tests: + description: 'Skip tests before publishing' + required: false + default: false + type: boolean permissions: contents: write @@ -47,6 +52,7 @@ jobs: IS_CLI: ${{ contains(github.event.pull_request.labels.*.name, 'cli-rc') || (github.event_name == 'workflow_dispatch' && github.event.inputs.cli == 'true') }} IS_PYTHON: ${{ contains(github.event.pull_request.labels.*.name, 'python-rc') || (github.event_name == 'workflow_dispatch' && github.event.inputs.python-sdk == 'true') }} PUBLISH_TAG: ${{ github.event.inputs.tag || 'rc' }} + SKIP_TESTS: ${{ github.event.inputs.skip-tests == 'true' }} steps: - name: Sanitize preid @@ -109,7 +115,7 @@ jobs: installer-parallel: true - name: Test Python SDK - if: ${{ env.IS_PYTHON == 'true' }} + if: ${{ env.IS_PYTHON == 'true' && env.SKIP_TESTS != 'true' }} working-directory: packages/python-sdk run: | poetry install @@ -134,7 +140,7 @@ jobs: - name: Test JS SDK working-directory: packages/js-sdk - if: ${{ env.IS_JS == 'true' }} + if: ${{ env.IS_JS == 'true' && env.SKIP_TESTS != 'true' }} run: | pnpm run test env: From 99d8dcc35275d66d56c38a1c2fa8cf98be002c96 Mon Sep 17 00:00:00 2001 From: Jakub Dobry Date: Mon, 16 Feb 2026 19:57:46 -0800 Subject: [PATCH 2/7] support new npm publishing --- .github/workflows/release_candidates.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release_candidates.yml b/.github/workflows/release_candidates.yml index f196ac8c14..ccd483a369 100644 --- a/.github/workflows/release_candidates.yml +++ b/.github/workflows/release_candidates.yml @@ -41,6 +41,7 @@ on: permissions: contents: write + id-token: write jobs: release: @@ -86,7 +87,7 @@ jobs: version: '${{ env.TOOL_VERSION_PNPM }}' - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' || env.IS_PYTHON == 'true' }} with: node-version: '${{ env.TOOL_VERSION_NODEJS }}' @@ -99,6 +100,12 @@ jobs: pnpm config set auto-install-peers true pnpm config set exclude-links-from-lockfile true + - name: Update npm + if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }} + run: | + npm install -g npm@^11.6 + npm --version + - name: Set up Python uses: actions/setup-python@v4 if: ${{ env.IS_PYTHON == 'true' }} @@ -151,9 +158,7 @@ jobs: if: ${{ env.IS_JS == 'true' }} run: | npm version prerelease --preid=${{ env.PREID }} - npm publish --tag ${{ env.PUBLISH_TAG }} - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + npm publish --tag ${{ env.PUBLISH_TAG }} --provenance - name: Install dependencies if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }} @@ -165,9 +170,7 @@ jobs: if: ${{ env.IS_CLI == 'true' }} run: | npm version prerelease --preid=${{ env.PREID }} - npm publish --tag ${{ env.PUBLISH_TAG }} - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + npm publish --tag ${{ env.PUBLISH_TAG }} --provenance - name: Commit new versions if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' || env.IS_PYTHON == 'true' }} From 9f7d56c1f808216efe130d86b04468c22645482d Mon Sep 17 00:00:00 2001 From: Jakub Dobry Date: Tue, 17 Feb 2026 00:22:19 -0800 Subject: [PATCH 3/7] Add CI workflow to build and publish package artifacts on PRs --- .github/workflows/pkg_artifacts.yml | 146 ++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 .github/workflows/pkg_artifacts.yml diff --git a/.github/workflows/pkg_artifacts.yml b/.github/workflows/pkg_artifacts.yml new file mode 100644 index 0000000000..edf2b83525 --- /dev/null +++ b/.github/workflows/pkg_artifacts.yml @@ -0,0 +1,146 @@ +name: Package Artifacts + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + pull-requests: write + +jobs: + build: + name: Build Packages + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Parse .tool-versions + uses: wistia/parse-tool-versions@v2.1.1 + with: + filename: '.tool-versions' + uppercase: 'true' + prefix: 'tool_version_' + + - uses: pnpm/action-setup@v4 + with: + version: '${{ env.TOOL_VERSION_PNPM }}' + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '${{ env.TOOL_VERSION_NODEJS }}' + cache: pnpm + + - name: Configure pnpm + run: | + pnpm config set auto-install-peers true + pnpm config set exclude-links-from-lockfile true + + - name: Sanitize branch name + run: | + BRANCH="${{ github.head_ref }}" + echo "BRANCH_ID=$(echo "$BRANCH" | sed 's/[^0-9A-Za-z-]/-/g')" >> "$GITHUB_ENV" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build JS SDK + working-directory: packages/js-sdk + run: pnpm run build + + - name: Pack JS SDK + working-directory: packages/js-sdk + run: | + npm version prerelease --preid=${{ env.BRANCH_ID }} --no-git-tag-version + npm pack + + - name: Upload JS SDK artifact + uses: actions/upload-artifact@v4 + with: + name: e2b-js-sdk + path: packages/js-sdk/*.tgz + + - name: Build CLI + working-directory: packages/cli + run: pnpm run build + + - name: Pack CLI + working-directory: packages/cli + run: | + npm version prerelease --preid=${{ env.BRANCH_ID }} --no-git-tag-version + npm pack + + - name: Upload CLI artifact + uses: actions/upload-artifact@v4 + with: + name: e2b-cli + path: packages/cli/*.tgz + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '${{ env.TOOL_VERSION_PYTHON }}' + + - name: Install and configure Poetry + uses: snok/install-poetry@v1 + with: + version: '${{ env.TOOL_VERSION_POETRY }}' + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Build Python SDK + working-directory: packages/python-sdk + run: | + BASE_VERSION=$(poetry version -s) + poetry version "${BASE_VERSION}+${BRANCH_ID}" + poetry build + + - name: Upload Python SDK artifact + uses: actions/upload-artifact@v4 + with: + name: e2b-python-sdk + path: packages/python-sdk/dist/* + + - name: Comment on PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + JS_VERSION=$(node -p "require('./packages/js-sdk/package.json').version") + CLI_VERSION=$(node -p "require('./packages/cli/package.json').version") + JS_TGZ=$(ls packages/js-sdk/*.tgz | xargs -n1 basename) + CLI_TGZ=$(ls packages/cli/*.tgz | xargs -n1 basename) + PY_VERSION=$(grep '^version' packages/python-sdk/pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/') + PY_WHL=$(ls packages/python-sdk/dist/*.whl | xargs -n1 basename) + + BODY=""$'\n' + BODY+="### Package Artifacts"$'\n\n' + BODY+="Built from ${GITHUB_SHA::7}. Download artifacts from [this workflow run](${RUN_URL})."$'\n\n' + BODY+="**JS SDK** (\`e2b@${JS_VERSION}\`):"$'\n' + BODY+='```sh'$'\n' + BODY+="npm install ./${JS_TGZ}"$'\n' + BODY+='```'$'\n\n' + BODY+="**CLI** (\`@e2b/cli@${CLI_VERSION}\`):"$'\n' + BODY+='```sh'$'\n' + BODY+="npm install ./${CLI_TGZ}"$'\n' + BODY+='```'$'\n\n' + BODY+="**Python SDK** (\`e2b==${PY_VERSION}\`):"$'\n' + BODY+='```sh'$'\n' + BODY+="pip install ./${PY_WHL}"$'\n' + BODY+='```'$'\n' + + COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ + --jq '.[] | select(.body | contains("")) | .id' \ + | tail -1) + + if [ -n "$COMMENT_ID" ]; then + gh api "repos/${{ github.repository }}/issues/comments/${COMMENT_ID}" \ + -X PATCH -f body="$BODY" + else + gh pr comment "$PR_NUMBER" --body "$BODY" + fi From 23276e011b4a150b33bcf5d9d04e7ef773f12ce0 Mon Sep 17 00:00:00 2001 From: Jakub Dobry Date: Tue, 17 Feb 2026 00:41:07 -0800 Subject: [PATCH 4/7] publish release candidates through release --- .github/workflows/publish_candidates.yml | 114 ++++++++++++++ .github/workflows/release.yml | 165 +++++++++++++------- .github/workflows/release_candidates.yml | 183 ----------------------- 3 files changed, 226 insertions(+), 236 deletions(-) create mode 100644 .github/workflows/publish_candidates.yml delete mode 100644 .github/workflows/release_candidates.yml diff --git a/.github/workflows/publish_candidates.yml b/.github/workflows/publish_candidates.yml new file mode 100644 index 0000000000..7731b1e58d --- /dev/null +++ b/.github/workflows/publish_candidates.yml @@ -0,0 +1,114 @@ +name: Publish Candidates + +on: + workflow_call: + inputs: + js-sdk: + required: false + type: boolean + default: false + python-sdk: + required: false + type: boolean + default: false + cli: + required: false + type: boolean + default: false + tag: + required: true + type: string + preid: + required: true + type: string + +permissions: + contents: read + id-token: write + +jobs: + publish: + name: Publish Release Candidates + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Parse .tool-versions + uses: wistia/parse-tool-versions@v2.1.1 + with: + filename: '.tool-versions' + uppercase: 'true' + prefix: 'tool_version_' + + - uses: pnpm/action-setup@v4 + if: ${{ inputs.js-sdk || inputs.cli }} + with: + version: '${{ env.TOOL_VERSION_PNPM }}' + + - name: Setup Node.js + uses: actions/setup-node@v6 + if: ${{ inputs.js-sdk || inputs.cli }} + with: + node-version: '${{ env.TOOL_VERSION_NODEJS }}' + registry-url: https://registry.npmjs.org + cache: pnpm + + - name: Configure pnpm + if: ${{ inputs.js-sdk || inputs.cli }} + run: | + pnpm config set auto-install-peers true + pnpm config set exclude-links-from-lockfile true + + - name: Update npm + if: ${{ inputs.js-sdk || inputs.cli }} + run: | + npm install -g npm@^11.6 + npm --version + + - name: Set up Python + uses: actions/setup-python@v4 + if: ${{ inputs.python-sdk }} + with: + python-version: '${{ env.TOOL_VERSION_PYTHON }}' + + - name: Install and configure Poetry + uses: snok/install-poetry@v1 + if: ${{ inputs.python-sdk }} + with: + version: '${{ env.TOOL_VERSION_POETRY }}' + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Publish Python RC + if: ${{ inputs.python-sdk }} + working-directory: packages/python-sdk + run: | + poetry version prerelease + poetry build + poetry config pypi-token.pypi ${PYPI_TOKEN} && poetry publish --skip-existing + env: + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + + - name: Install JS dependencies + if: ${{ inputs.js-sdk || inputs.cli }} + run: pnpm install --frozen-lockfile + + - name: Publish JS RC + if: ${{ inputs.js-sdk }} + working-directory: packages/js-sdk + run: | + npm version prerelease --preid=${{ inputs.preid }} + npm publish --tag ${{ inputs.tag }} --provenance + + - name: Reinstall dependencies + if: ${{ inputs.js-sdk || inputs.cli }} + run: pnpm install --frozen-lockfile + + - name: Publish CLI RC + if: ${{ inputs.cli }} + working-directory: packages/cli + run: | + npm version prerelease --preid=${{ inputs.preid }} + npm publish --tag ${{ inputs.tag }} --provenance diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fff4f1d761..0007470907 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,6 +2,44 @@ name: Release on: workflow_dispatch: + inputs: + mode: + description: 'Release mode' + type: choice + options: + - release + - candidate + default: release + js-sdk: + description: 'Release JS SDK (candidate only)' + required: false + default: false + type: boolean + python-sdk: + description: 'Release Python SDK (candidate only)' + required: false + default: false + type: boolean + cli: + description: 'Release CLI (candidate only)' + required: false + default: false + type: boolean + tag: + description: 'Dist-tag for candidate (e.g. rc, beta, snapshot)' + required: false + default: 'rc' + type: string + preid: + description: 'Prerelease identifier (defaults to branch name, candidate only)' + required: false + default: '' + type: string + skip-tests: + description: 'Skip tests (candidate only)' + required: false + default: false + type: boolean concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -10,11 +48,16 @@ permissions: contents: write jobs: - is_release: - name: Is release? + # ── Production release ─────────────────────────────────── + preflight: + name: Release preflight + if: github.event.inputs.mode != 'candidate' runs-on: ubuntu-latest outputs: release: ${{ steps.version.outputs.release }} + js-sdk: ${{ steps.js.outputs.release }} + python-sdk: ${{ steps.python.outputs.release }} + cli: ${{ steps.cli.outputs.release }} steps: - name: Checkout Repo uses: actions/checkout@v3 @@ -54,91 +97,52 @@ jobs: IS_RELEASE=$(./.github/scripts/is_release.sh) echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT" - changes: - name: Repository changes - needs: [is_release] - if: needs.is_release.outputs.release == 'true' - runs-on: ubuntu-latest - outputs: - js-sdk: ${{ steps.js.outputs.release }} - python-sdk: ${{ steps.python.outputs.release }} - cli: ${{ steps.cli.outputs.release }} - steps: - - name: Checkout Repo - uses: actions/checkout@v3 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install pnpm - uses: pnpm/action-setup@v4 - id: pnpm-install - with: - version: '${{ env.TOOL_VERSION_PNPM }}' - - - name: Setup Node - uses: actions/setup-node@v6 - with: - node-version: '${{ env.TOOL_VERSION_NODEJS }}' - registry-url: 'https://registry.npmjs.org' - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - - name: Configure pnpm - run: | - pnpm config set auto-install-peers true - pnpm config set exclude-links-from-lockfile true - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Check JavasScript SDK Release + - name: Check JavaScript SDK Release id: js + if: steps.version.outputs.release == 'true' run: | IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "e2b") echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT" - name: Check Python SDK Release id: python + if: steps.version.outputs.release == 'true' run: | IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "@e2b/python-sdk") echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT" - name: Check CLI Release id: cli + if: steps.version.outputs.release == 'true' run: | IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "@e2b/cli") echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT" python-tests: name: Python SDK Tests - needs: [changes] - if: needs.changes.outputs.python-sdk == 'true' + needs: [preflight] + if: needs.preflight.outputs.python-sdk == 'true' uses: ./.github/workflows/python_sdk_tests.yml secrets: inherit js-tests: name: JS SDK Tests - needs: [changes] - if: needs.changes.outputs.js-sdk == 'true' + needs: [preflight] + if: needs.preflight.outputs.js-sdk == 'true' uses: ./.github/workflows/js_sdk_tests.yml secrets: inherit cli-tests: name: CLI Tests - needs: [changes] - if: needs.changes.outputs.cli == 'true' + needs: [preflight] + if: needs.preflight.outputs.cli == 'true' uses: ./.github/workflows/cli_tests.yml secrets: inherit publish: name: Publish - needs: [is_release, python-tests, js-tests, cli-tests] - if: (!cancelled()) && !contains(needs.*.result, 'failure') && needs.is_release.outputs.release == 'true' + needs: [preflight, python-tests, js-tests, cli-tests] + if: (!cancelled()) && !contains(needs.*.result, 'failure') && needs.preflight.outputs.release == 'true' uses: ./.github/workflows/publish_packages.yml secrets: inherit @@ -156,3 +160,58 @@ jobs: SLACK_TITLE: Release Failed SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: 'monitoring-releases' + + # ── Release candidate ──────────────────────────────────── + rc-validate: + name: Validate RC inputs + if: github.event.inputs.mode == 'candidate' + runs-on: ubuntu-latest + outputs: + preid: ${{ steps.preid.outputs.preid }} + steps: + - name: Block production tags + run: | + if [ "${{ github.event.inputs.tag }}" = "latest" ]; then + echo "::error::Publishing with the 'latest' tag is not allowed for candidates. Use 'release' mode instead." + exit 1 + fi + + - name: Sanitize preid + id: preid + run: | + RAW_PREID="${{ github.event.inputs.preid || github.ref_name }}" + echo "preid=$(echo "$RAW_PREID" | sed 's/[^0-9A-Za-z-]/-/g')" >> "$GITHUB_OUTPUT" + + rc-python-tests: + name: RC Python Tests + needs: [rc-validate] + if: github.event.inputs.python-sdk == 'true' && github.event.inputs.skip-tests != 'true' + uses: ./.github/workflows/python_sdk_tests.yml + secrets: inherit + + rc-js-tests: + name: RC JS Tests + needs: [rc-validate] + if: github.event.inputs.js-sdk == 'true' && github.event.inputs.skip-tests != 'true' + uses: ./.github/workflows/js_sdk_tests.yml + secrets: inherit + + rc-cli-tests: + name: RC CLI Tests + needs: [rc-validate] + if: github.event.inputs.cli == 'true' && github.event.inputs.skip-tests != 'true' + uses: ./.github/workflows/cli_tests.yml + secrets: inherit + + rc-publish: + name: Publish RC + needs: [rc-validate, rc-python-tests, rc-js-tests, rc-cli-tests] + if: (!cancelled()) && !contains(needs.*.result, 'failure') + uses: ./.github/workflows/publish_candidates.yml + with: + js-sdk: ${{ github.event.inputs.js-sdk == 'true' }} + python-sdk: ${{ github.event.inputs.python-sdk == 'true' }} + cli: ${{ github.event.inputs.cli == 'true' }} + tag: ${{ github.event.inputs.tag }} + preid: ${{ needs.rc-validate.outputs.preid }} + secrets: inherit diff --git a/.github/workflows/release_candidates.yml b/.github/workflows/release_candidates.yml deleted file mode 100644 index ccd483a369..0000000000 --- a/.github/workflows/release_candidates.yml +++ /dev/null @@ -1,183 +0,0 @@ -name: Release Candidates - -on: - pull_request: - types: - - labeled - - opened - - reopened - - synchronize - workflow_dispatch: - inputs: - js-sdk: - description: 'Release JS SDK' - required: false - default: false - type: boolean - python-sdk: - description: 'Release Python SDK' - required: false - default: false - type: boolean - cli: - description: 'Release CLI' - required: false - default: false - type: boolean - tag: - description: 'Dist-tag (e.g. rc, beta, snapshot)' - required: true - type: string - preid: - description: 'Prerelease identifier (defaults to branch name if empty)' - required: false - default: '' - type: string - skip-tests: - description: 'Skip tests before publishing' - required: false - default: false - type: boolean - -permissions: - contents: write - id-token: write - -jobs: - release: - name: Release Candidate - runs-on: ubuntu-latest - - env: - IS_JS: ${{ contains(github.event.pull_request.labels.*.name, 'js-rc') || (github.event_name == 'workflow_dispatch' && github.event.inputs.js-sdk == 'true') }} - IS_CLI: ${{ contains(github.event.pull_request.labels.*.name, 'cli-rc') || (github.event_name == 'workflow_dispatch' && github.event.inputs.cli == 'true') }} - IS_PYTHON: ${{ contains(github.event.pull_request.labels.*.name, 'python-rc') || (github.event_name == 'workflow_dispatch' && github.event.inputs.python-sdk == 'true') }} - PUBLISH_TAG: ${{ github.event.inputs.tag || 'rc' }} - SKIP_TESTS: ${{ github.event.inputs.skip-tests == 'true' }} - - steps: - - name: Sanitize preid - run: | - RAW_PREID="${{ github.event.inputs.preid || github.head_ref || github.ref_name }}" - echo "PREID=$(echo "$RAW_PREID" | sed 's/[^0-9A-Za-z-]/-/g')" >> "$GITHUB_ENV" - - - name: Block production tags - if: ${{ github.event_name == 'workflow_dispatch' }} - run: | - if [ "${{ github.event.inputs.tag }}" = "latest" ]; then - echo "::error::Publishing with the 'latest' tag is not allowed from this workflow. Use the Release workflow instead." - exit 1 - fi - - - name: Checkout Repo - uses: actions/checkout@v4 - with: - ref: ${{ github.head_ref || github.ref }} - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - uses: pnpm/action-setup@v4 - if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }} - with: - version: '${{ env.TOOL_VERSION_PNPM }}' - - - name: Setup Node.js - uses: actions/setup-node@v6 - if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' || env.IS_PYTHON == 'true' }} - with: - node-version: '${{ env.TOOL_VERSION_NODEJS }}' - registry-url: https://registry.npmjs.org - cache: pnpm - - - name: Configure pnpm - if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }} - run: | - pnpm config set auto-install-peers true - pnpm config set exclude-links-from-lockfile true - - - name: Update npm - if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }} - run: | - npm install -g npm@^11.6 - npm --version - - - name: Set up Python - uses: actions/setup-python@v4 - if: ${{ env.IS_PYTHON == 'true' }} - with: - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - - - name: Install and configure Poetry - uses: snok/install-poetry@v1 - if: ${{ env.IS_PYTHON == 'true' }} - with: - version: '${{ env.TOOL_VERSION_POETRY }}' - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Test Python SDK - if: ${{ env.IS_PYTHON == 'true' && env.SKIP_TESTS != 'true' }} - working-directory: packages/python-sdk - run: | - poetry install - poetry run pytest --verbose -x - env: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - - - name: Release Candidate - if: ${{ env.IS_PYTHON == 'true' }} - working-directory: packages/python-sdk - run: | - poetry version prerelease - poetry build - poetry config pypi-token.pypi ${PYPI_TOKEN} && poetry publish --skip-existing - env: - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - - - name: Install JS dependencies - if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }} - run: | - pnpm install --frozen-lockfile - - - name: Test JS SDK - working-directory: packages/js-sdk - if: ${{ env.IS_JS == 'true' && env.SKIP_TESTS != 'true' }} - run: | - pnpm run test - env: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - - - name: Release JS Candidate - working-directory: packages/js-sdk - if: ${{ env.IS_JS == 'true' }} - run: | - npm version prerelease --preid=${{ env.PREID }} - npm publish --tag ${{ env.PUBLISH_TAG }} --provenance - - - name: Install dependencies - if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' }} - run: | - pnpm install --frozen-lockfile - - - name: Release CLI Candidate - working-directory: packages/cli - if: ${{ env.IS_CLI == 'true' }} - run: | - npm version prerelease --preid=${{ env.PREID }} - npm publish --tag ${{ env.PUBLISH_TAG }} --provenance - - - name: Commit new versions - if: ${{ env.IS_JS == 'true' || env.IS_CLI == 'true' || env.IS_PYTHON == 'true' }} - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git commit -am "[skip ci] Release new versions" || exit 0 - git push - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From edc01f56dbc5d83de29806f11da36d6554b7e4ab Mon Sep 17 00:00:00 2001 From: Jakub Dobry Date: Tue, 17 Feb 2026 09:41:36 -0800 Subject: [PATCH 5/7] address PR bots comments --- .github/workflows/pkg_artifacts.yml | 3 ++- .github/workflows/publish_candidates.yml | 7 ++++--- .github/workflows/release.yml | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pkg_artifacts.yml b/.github/workflows/pkg_artifacts.yml index edf2b83525..5a52e1a9ab 100644 --- a/.github/workflows/pkg_artifacts.yml +++ b/.github/workflows/pkg_artifacts.yml @@ -40,8 +40,9 @@ jobs: pnpm config set exclude-links-from-lockfile true - name: Sanitize branch name + env: + BRANCH: ${{ github.head_ref }} run: | - BRANCH="${{ github.head_ref }}" echo "BRANCH_ID=$(echo "$BRANCH" | sed 's/[^0-9A-Za-z-]/-/g')" >> "$GITHUB_ENV" - name: Install dependencies diff --git a/.github/workflows/publish_candidates.yml b/.github/workflows/publish_candidates.yml index 7731b1e58d..dc6425379d 100644 --- a/.github/workflows/publish_candidates.yml +++ b/.github/workflows/publish_candidates.yml @@ -85,7 +85,8 @@ jobs: if: ${{ inputs.python-sdk }} working-directory: packages/python-sdk run: | - poetry version prerelease + BASE_VERSION=$(poetry version -s) + poetry version "${BASE_VERSION}rc${{ github.run_number }}" poetry build poetry config pypi-token.pypi ${PYPI_TOKEN} && poetry publish --skip-existing env: @@ -99,7 +100,7 @@ jobs: if: ${{ inputs.js-sdk }} working-directory: packages/js-sdk run: | - npm version prerelease --preid=${{ inputs.preid }} + npm version prerelease --preid=${{ inputs.preid }}.${{ github.run_number }} --no-git-tag-version npm publish --tag ${{ inputs.tag }} --provenance - name: Reinstall dependencies @@ -110,5 +111,5 @@ jobs: if: ${{ inputs.cli }} working-directory: packages/cli run: | - npm version prerelease --preid=${{ inputs.preid }} + npm version prerelease --preid=${{ inputs.preid }}.${{ github.run_number }} --no-git-tag-version npm publish --tag ${{ inputs.tag }} --provenance diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0007470907..02b445f6cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -206,7 +206,7 @@ jobs: rc-publish: name: Publish RC needs: [rc-validate, rc-python-tests, rc-js-tests, rc-cli-tests] - if: (!cancelled()) && !contains(needs.*.result, 'failure') + if: (!cancelled()) && !contains(needs.*.result, 'failure') && needs.rc-validate.result == 'success' uses: ./.github/workflows/publish_candidates.yml with: js-sdk: ${{ github.event.inputs.js-sdk == 'true' }} From a5d53d06b8036869ab6ffd4b7c291cc43a59be1c Mon Sep 17 00:00:00 2001 From: Jakub Dobry Date: Tue, 17 Feb 2026 11:43:41 -0800 Subject: [PATCH 6/7] ci: add pagination when fetching PR comments --- .github/workflows/pkg_artifacts.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pkg_artifacts.yml b/.github/workflows/pkg_artifacts.yml index 5a52e1a9ab..24ddbf3725 100644 --- a/.github/workflows/pkg_artifacts.yml +++ b/.github/workflows/pkg_artifacts.yml @@ -136,6 +136,7 @@ jobs: BODY+='```'$'\n' COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ + --paginate \ --jq '.[] | select(.body | contains("")) | .id' \ | tail -1) From 2e9acc7b5471cbafbad3a2915ac9886e102ace3e Mon Sep 17 00:00:00 2001 From: Jakub Dobry Date: Tue, 17 Feb 2026 21:16:32 -0800 Subject: [PATCH 7/7] ci: sanitize RC tag input in release workflow --- .github/workflows/release.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 02b445f6cb..ad5cc31d22 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -168,10 +168,18 @@ jobs: runs-on: ubuntu-latest outputs: preid: ${{ steps.preid.outputs.preid }} + tag: ${{ steps.tag.outputs.tag }} steps: + - name: Sanitize tag + id: tag + run: | + RAW_TAG="${{ github.event.inputs.tag }}" + SAFE_TAG="$(echo "$RAW_TAG" | sed 's/[^0-9A-Za-z-]/-/g')" + echo "tag=$SAFE_TAG" >> "$GITHUB_OUTPUT" + - name: Block production tags run: | - if [ "${{ github.event.inputs.tag }}" = "latest" ]; then + if [ "${{ steps.tag.outputs.tag }}" = "latest" ]; then echo "::error::Publishing with the 'latest' tag is not allowed for candidates. Use 'release' mode instead." exit 1 fi @@ -212,6 +220,6 @@ jobs: js-sdk: ${{ github.event.inputs.js-sdk == 'true' }} python-sdk: ${{ github.event.inputs.python-sdk == 'true' }} cli: ${{ github.event.inputs.cli == 'true' }} - tag: ${{ github.event.inputs.tag }} + tag: ${{ needs.rc-validate.outputs.tag }} preid: ${{ needs.rc-validate.outputs.preid }} secrets: inherit