name: Generic Release on: workflow_dispatch: inputs: target: description: "Release target key" required: true type: choice options: - js/sandbox - js/code-interpreter - python/sandbox - python/code-interpreter - python/mcp/sandbox - java/sandbox - java/code-interpreter - csharp/sandbox - csharp/code-interpreter - sdks/sandbox/go - cli - server - docker/execd - docker/code-interpreter - docker/ingress - docker/egress - k8s/controller - k8s/task-executor - helm/opensandbox - helm version: description: "Version to release (e.g. 1.0.5 or v0.3.0)" required: true type: string from_tag: description: "Optional previous tag override" required: false type: string no_path_filter: description: "Disable default target path filtering" required: true default: false type: boolean extra_paths: description: "Optional extra paths (comma-separated)" required: false type: string initial_release: description: "Allow release without previous tag" required: true default: false type: boolean dry_run: description: "Preview only, no side effects" required: true default: true type: boolean permissions: contents: write id-token: write attestations: write artifact-metadata: write jobs: release-preflight: uses: ./.github/workflows/release-preflight.yml with: require_approval: ${{ inputs.dry_run == false }} release: needs: release-preflight runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v6 with: fetch-depth: 0 - name: Ensure script executable run: chmod +x scripts/release/create-release.sh - name: Run generic release script id: release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -euo pipefail ARGS=( --target "${{ inputs.target }}" --version "${{ inputs.version }}" ) if [[ -n "${{ inputs.from_tag }}" ]]; then ARGS+=(--from-tag "${{ inputs.from_tag }}") fi if [[ "${{ inputs.no_path_filter }}" == "true" ]]; then ARGS+=(--no-path-filter) fi if [[ -n "${{ inputs.extra_paths }}" ]]; then IFS=',' read -r -a EXTRA_PATHS <<< "${{ inputs.extra_paths }}" for path in "${EXTRA_PATHS[@]}"; do trimmed="$(echo "$path" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" if [[ -n "$trimmed" ]]; then ARGS+=(--path "$trimmed") fi done fi if [[ "${{ inputs.initial_release }}" == "true" ]]; then ARGS+=(--initial-release) fi if [[ "${{ inputs.dry_run }}" == "true" ]]; then ARGS+=(--dry-run) fi scripts/release/create-release.sh "${ARGS[@]}" - name: Verify release tag on origin if: ${{ inputs.dry_run == false }} env: RELEASE_TAG: ${{ steps.release.outputs.tag }} run: | set -euo pipefail local_commit="$(git rev-parse "${RELEASE_TAG}^{commit}")" remote_commit="$(git ls-remote origin "refs/tags/${RELEASE_TAG}^{}" | awk 'NR == 1 { print $1 }')" if [[ -z "$remote_commit" ]]; then remote_commit="$(git ls-remote origin "refs/tags/${RELEASE_TAG}" | awk 'NR == 1 { print $1 }')" fi if [[ -z "$remote_commit" ]]; then echo "::error::Release tag '${RELEASE_TAG}' does not exist on origin. Have an authorized release manager push the tag before publishing source artifacts." exit 1 fi if [[ "$local_commit" != "$remote_commit" ]]; then echo "::error::Local release tag '${RELEASE_TAG}' resolves to ${local_commit}, but origin resolves to ${remote_commit}. Refusing to publish source artifacts." exit 1 fi - name: Create release source archive if: ${{ inputs.dry_run == false }} id: source_archive env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ steps.release.outputs.tag }} run: | set -euo pipefail SAFE_TAG="$(printf '%s' "$RELEASE_TAG" | tr '/:' '--')" ARCHIVE_NAME="opensandbox-${SAFE_TAG}.tar.gz" ARCHIVE_DIR="dist/release-source" mkdir -p "$ARCHIVE_DIR" git archive \ --format=tar.gz \ --prefix="opensandbox-${SAFE_TAG}/" \ -o "${ARCHIVE_DIR}/${ARCHIVE_NAME}" \ "$RELEASE_TAG" ( cd "$ARCHIVE_DIR" sha256sum "$ARCHIVE_NAME" > SHA256SUMS ) echo "archive_path=${ARCHIVE_DIR}/${ARCHIVE_NAME}" >> "$GITHUB_OUTPUT" echo "checksums_path=${ARCHIVE_DIR}/SHA256SUMS" >> "$GITHUB_OUTPUT" - name: Attest source release artifacts if: ${{ inputs.dry_run == false }} uses: actions/attest@v4 with: subject-path: | ${{ steps.source_archive.outputs.archive_path }} ${{ steps.source_archive.outputs.checksums_path }} - name: Upload source release artifacts if: ${{ inputs.dry_run == false }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ steps.release.outputs.tag }} run: | set -euo pipefail gh release upload "$RELEASE_TAG" \ "${{ steps.source_archive.outputs.archive_path }}" \ "${{ steps.source_archive.outputs.checksums_path }}" \ --clobber