Skip to content

Release

Release #371

Workflow file for this run

name: Release
on:
# Releases are cut by hand, as in e2b-dev/E2B: merging a changeset to main no
# longer publishes on its own, so changesets accumulate until someone
# dispatches this. A release that publishes nothing leaves them intact, which
# makes a re-dispatch the recovery path too.
workflow_dispatch: {}
concurrency: Release-${{ github.ref }}-foxtrot
permissions:
id-token: write
contents: write
jobs:
preflight:
name: Release preflight
runs-on: ubuntu-latest
outputs:
release: ${{ steps.version.outputs.release }}
js: ${{ steps.js.outputs.release }}
python: ${{ steps.python.outputs.release }}
charts: ${{ steps.charts.outputs.release }}
template: ${{ steps.template.outputs.release }}
itinerary: ${{ steps.itinerary.outputs.itinerary }}
steps:
- name: Check the ref
# `workflow_dispatch` offers every branch in the picker, and a feature
# branch carrying changesets would otherwise publish real packages and
# push the version bump to that branch.
if: github.ref != 'refs/heads/main'
env:
REF: ${{ github.ref }}
run: |
echo "::error::Releases must run on main; this run is on ${REF}."
exit 1
- name: Checkout Repo
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Parse .tool-versions
uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1
with:
filename: '.tool-versions'
uppercase: 'true'
prefix: 'tool_version_'
- name: Install pnpm
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
id: pnpm-install
with:
version: ${{ env.TOOL_VERSION_PNPM }}
- name: Setup Node
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
with:
node-version: '${{ env.TOOL_VERSION_NODE }}'
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 if new version
id: version
run: |
IS_RELEASE=$(./.github/scripts/is_release.sh)
echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT"
- name: Check JavaScript SDK Release
id: js
if: steps.version.outputs.release == 'true'
run: |
IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "@e2b/code-interpreter")
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/code-interpreter-python")
echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT"
- name: Check Charts SDK Release
id: charts
if: steps.version.outputs.release == 'true'
run: |
IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "@e2b/data-extractor")
echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT"
- name: Check Template SDK Release
id: template
if: steps.version.outputs.release == 'true'
run: |
IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "@e2b/code-interpreter-template")
echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT"
- name: Build release itinerary
id: itinerary
if: steps.version.outputs.release == 'true'
# This only feeds the Slack notifications, so it must never be the thing
# that blocks a release; the messages fall back to a placeholder.
continue-on-error: true
run: |
pnpm changeset status --output=.cs-status.json
ITINERARY=$(node ./.github/scripts/build_release_itinerary.cjs .cs-status.json)
rm -f .cs-status.json
{
echo "itinerary<<EOF"
echo "$ITINERARY"
echo "EOF"
} >> "$GITHUB_OUTPUT"
charts-release:
name: Charts release
needs: [preflight]
if: needs.preflight.outputs.charts == 'true'
runs-on: ubuntu-latest
outputs:
version: ${{ steps.output_version.outputs.version }}
steps:
- name: Checkout Repo
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Parse .tool-versions
uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1
with:
filename: '.tool-versions'
uppercase: 'true'
prefix: 'tool_version_'
- name: Install pnpm
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
id: pnpm-install
with:
version: ${{ env.TOOL_VERSION_PNPM }}
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '${{ env.TOOL_VERSION_PYTHON }}'
- name: Install and configure Poetry
uses: snok/install-poetry@a783c322200f0519c7926aa6faa857c4e23e9263 # v1.4.2
with:
version: '${{ env.TOOL_VERSION_POETRY }}'
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
- 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: Create new versions
run: pnpm run version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release new versions
run: |
poetry build
poetry config pypi-token.pypi ${PYPI_TOKEN}
poetry publish --skip-existing
working-directory: ./chart_data_extractor
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PYPI_TOKEN: ${{ secrets.CHARTS_PYPI_TOKEN }}
- name: Output new version
id: output_version
working-directory: ./chart_data_extractor
run: |
echo "version=$(pnpm pkg get version --workspaces=false | tr -d \\\")" >> "$GITHUB_OUTPUT"
build-docker-image:
name: Build Docker Image
runs-on: ubuntu-latest
needs: [preflight, charts-release]
if: (!cancelled()) &&
!contains(needs.*.result, 'failure') &&
(needs.preflight.outputs.template == 'true' || needs.preflight.outputs.charts == 'true')
steps:
- name: Checkout repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Parse .tool-versions
uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1
with:
filename: '.tool-versions'
uppercase: 'true'
prefix: 'tool_version_'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Log in to DockerHub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set package version
working-directory: ./template
run: |
if [ -z "${{ needs.charts-release.outputs.version }}" ]; then
VERSION=$(cat ../chart_data_extractor/pyproject.toml | grep version | cut -d '"' -f 2)
else
VERSION=${{ needs.charts-release.outputs.version }}
fi
echo "Version: $VERSION"
sed -i "s/e2b_charts/e2b_charts==${VERSION}/g" requirements.txt
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '${{ env.TOOL_VERSION_PYTHON }}'
- name: Install development dependencies
working-directory: ./template
run: pip install -r requirements-dev.txt
- name: Build and push to DockerHub
working-directory: ./template
run: |
python build_docker.py | docker buildx build \
--platform linux/amd64 \
--push \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/code-interpreter:latest -f - .
build-template:
name: Build E2B template
runs-on: ubuntu-latest
needs: [preflight, build-docker-image]
if: (!cancelled()) &&
!contains(needs.*.result, 'failure') &&
(needs.preflight.outputs.template == 'true' || needs.preflight.outputs.charts == 'true')
steps:
- name: Checkout repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Parse .tool-versions
uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1
with:
filename: '.tool-versions'
uppercase: 'true'
prefix: 'tool_version_'
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '${{ env.TOOL_VERSION_PYTHON }}'
- name: Install development dependencies
working-directory: ./template
run: pip install -r requirements-dev.txt
- name: Build E2B template
id: build-template
working-directory: ./template
run: |
python build_prod.py
env:
E2B_API_KEY: ${{ secrets.E2B_PROD_API_KEY }}
E2B_DOMAIN: ${{ vars.E2B_DOMAIN }}
python-tests:
name: Python Tests
needs: [preflight, build-template]
if: (!cancelled()) &&
!contains(needs.*.result, 'failure') &&
needs.preflight.outputs.template == 'true'
uses: ./.github/workflows/python_tests.yml
secrets: inherit
js-tests:
name: JS Tests
needs: [preflight, build-template]
if: (!cancelled()) &&
!contains(needs.*.result, 'failure') &&
needs.preflight.outputs.template == 'true'
uses: ./.github/workflows/js_tests.yml
secrets: inherit
release:
# Every upstream job is listed, not just the tests: a job that fails makes its
# dependents *skip*, and a skipped test job is not a failure — so gating on
# `needs.*.result` only works for the jobs this one depends on directly.
needs: [preflight, charts-release, build-docker-image, build-template, python-tests, js-tests]
if: (!cancelled()) &&
!contains(needs.*.result, 'failure') &&
needs.preflight.outputs.release == 'true'
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0
id: app-token
with:
app-id: ${{ vars.VERSION_BUMPER_APPID }}
private-key: ${{ secrets.VERSION_BUMPER_SECRET }}
- name: Checkout Repo
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
token: ${{ steps.app-token.outputs.token }}
- name: Parse .tool-versions
uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1
with:
filename: '.tool-versions'
uppercase: 'true'
prefix: 'tool_version_'
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '${{ env.TOOL_VERSION_PYTHON }}'
- name: Install and configure Poetry
uses: snok/install-poetry@a783c322200f0519c7926aa6faa857c4e23e9263 # v1.4.2
with:
version: '${{ env.TOOL_VERSION_POETRY }}'
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
- uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
with:
version: ${{ env.TOOL_VERSION_PNPM }}
- name: Setup Node.js 24
# Deliberately ahead of the `node` baseline in .tool-versions: npm 11 is
# what OIDC trusted publishing needs (see #259).
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
with:
node-version: "24.x"
registry-url: 'https://registry.npmjs.org'
cache: pnpm
- 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: Create new versions
run: pnpm run version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit new versions
# Commit before publishing, because `changeset publish` tags whatever HEAD
# it publishes from — tagging afterwards is what left every tag on the
# commit before its own version bump (SDK-298). Nothing in the tree
# references the artifacts about to be uploaded — `changeset version`
# leaves `pnpm-lock.yaml` untouched here, since no workspace package
# depends on another — so the commit is already complete. It stays local
# until something is actually published, so a publish that uploads
# nothing leaves the branch untouched and the changesets intact for a
# re-run.
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# `add -A`, not `commit -a`: `changeset version` writes each package's
# CHANGELOG.md as a new file the first time, which `-a` would drop.
git add -A
if git diff --cached --quiet; then
echo "::error::'changeset version' produced no changes, so there is no version bump to publish or tag."
exit 1
fi
git commit -m "[skip ci] Release new versions"
- name: Release new versions
uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0
with:
publish: pnpm run publish
createGithubReleases: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: "" # See https://github.com/changesets/changesets/issues/1152#issuecomment-3190884868
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
- name: Push new versions
# Gate on the tags rather than on whether the publish step succeeded: they
# are what has to end up reachable. `changeset publish` tags at HEAD and the
# step above pushes them to origin, so if any exist — even from a publish
# that then failed partway — the commit they point at has to land, or they
# hang off no branch, which is the SDK-298 breakage this change prevents.
if: always()
run: |
if [ -z "$(git tag --points-at HEAD)" ]; then
echo "Nothing was published; the version bump stays local and the changesets are intact for a re-run."
exit 0
fi
if ! git push; then
# A PR merged mid-release. Merge rather than rebase: the tags already
# point at this commit and rewriting it would strand them off the branch.
git fetch origin "${GITHUB_REF_NAME}"
git merge --no-edit FETCH_HEAD
git push
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
report-start:
needs: [preflight]
if: needs.preflight.outputs.release == 'true'
name: Code Interpreter Release Started - Slack Notification
runs-on: ubuntu-latest
steps:
- name: Release Started - Slack Notification
uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # v2.4.0
env:
SLACK_COLOR: "#3aa3e3"
SLACK_MESSAGE: |
:rocket: A new release has been triggered :hourglass_flowing_sand:
*Releasing:*
${{ needs.preflight.outputs.itinerary || '• (itinerary unavailable)' }}
SLACK_TITLE: Code Interpreter Release Started
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: "monitoring-releases"
report-failure:
# `preflight` included so a failure there is reported too, whether or not
# `failure()` looks past this job's direct dependencies.
needs: [preflight, charts-release, build-docker-image, build-template, python-tests, js-tests, release]
if: failure()
name: Code Interpreter Release Failed - Slack Notification
runs-on: ubuntu-latest
steps:
- name: Release Failed - Slack Notification
uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # v2.4.0
env:
SLACK_COLOR: "#ff0000"
SLACK_MESSAGE: ":here-we-go-again: :bob-the-destroyer: We need :fix-parrot: ASAP :pray:"
SLACK_TITLE: Code Interpreter Release Failed
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: "monitoring-releases"
report-success:
needs: [preflight, release]
if: (!cancelled()) && needs.release.result == 'success'
name: Code Interpreter Release Succeeded - Slack Notification
runs-on: ubuntu-latest
steps:
- name: Release Succeeded - Slack Notification
uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # v2.4.0
env:
SLACK_COLOR: "#36a64f"
SLACK_MESSAGE: |
:tada: A new version has been released successfully! :ship-it-parrot:
*Released:*
${{ needs.preflight.outputs.itinerary || '• (itinerary unavailable)' }}
SLACK_TITLE: Code Interpreter Release Succeeded
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: "monitoring-releases"