# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
# ══════════════════════════════════════════════════════════════════════
# ReleaseKit: Rollback Pipeline
# ══════════════════════════════════════════════════════════════════════
#
# SAMPLE WORKFLOW — Copy to .github/workflows/releasekit-rollback.yml
#
# This workflow provides a one-click rollback for failed or problematic
# releases. It can:
#
# 1. Delete git tags (local + remote)
# 2. Delete GitHub Releases
# 3. Yank packages from registries (opt-in)
#
# ── Manual Dispatch UI ────────────────────────────────────────────────
#
# ┌─────────────────────────────────────────────────────────────┐
# │ workflow_dispatch UI │
# │ │
# │ tag: [genkit-v1.2.0] tag to roll back │
# │ workspace: [py / go / js / ...] │
# │ all_tags: [✓] delete all tags at the same commit │
# │ yank: [✓] also yank from package registry │
# │ yank_reason: [________] reason for yanking │
# │ dry_run: [✓] simulate, no side effects │
# └─────────────────────────────────────────────────────────────┘
#
# ── Job Execution Flow ──────────────────────────────────────────────
#
# ┌──────────┐
# │ rollback │ Single job — no auth job needed (same-job secret)
# └────┬─────┘
# │
# ├─► checkout (full history + tags, token = secrets.GITHUB_TOKEN)
# │
# ├─► releasekit rollback
# │ │
# │ ├─► resolve tag → find commit SHA
# │ │
# │ ├─► --all-tags? ──► find all tags on same commit
# │ │ └─► delete each tag (local + remote)
# │ │
# │ ├─► delete GitHub Release(s)
# │ │
# │ └─► --yank? ──► yank from package registry
# │ └─► with --yank-reason if provided
# │
# └─► (done)
#
# Unlike the release workflows, rollback is a single-job workflow.
# It uses secrets.GITHUB_TOKEN directly — no sentinel pattern needed
# because there are no cross-job boundaries.
#
# ── Safety ────────────────────────────────────────────────────────────
#
# The workflow defaults to dry_run=true so accidental triggers are
# harmless. Yanking is opt-in and requires explicit confirmation.
#
# ══════════════════════════════════════════════════════════════════════
name: "ReleaseKit: Rollback"
on:
workflow_call:
inputs:
tag:
description: 'Git tag to roll back'
required: true
type: string
workspace:
description: 'Workspace to target'
required: false
default: py
type: string
all_tags:
description: 'Delete ALL tags pointing to the same commit'
required: false
default: true
type: boolean
yank:
description: 'Also yank/deprecate versions from the package registry'
required: false
default: false
type: boolean
yank_reason:
description: 'Reason for yanking'
required: false
type: string
dry_run:
description: 'Dry run'
required: false
default: true
type: boolean
secrets:
GITHUB_TOKEN:
required: false
workflow_dispatch:
inputs:
tag:
description: 'Git tag to roll back (e.g. genkit-v1.2.0)'
required: true
type: string
workspace:
description: 'Workspace to target'
required: false
default: py
type: choice
options:
- py
- go
- js
- js-cli
- dart
- rust
all_tags:
description: 'Delete ALL tags pointing to the same commit (all per-package tags from the same release)'
required: false
default: true
type: boolean
yank:
description: 'Also yank/deprecate versions from the package registry'
required: false
default: false
type: boolean
yank_reason:
description: 'Reason for yanking (shown to users installing the package)'
required: false
type: string
dry_run:
description: 'Dry run — log what would happen without deleting anything'
required: true
default: true
type: boolean
# Only one rollback runs at a time.
concurrency:
group: releasekit-rollback
cancel-in-progress: false
permissions:
contents: write # Delete tags and releases
pull-requests: write # Update PR labels
env:
RELEASEKIT_DIR: py/tools/releasekit
jobs:
rollback:
name: "Rollback: ${{ inputs.tag }}"
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-releasekit
with:
token: ${{ secrets.GITHUB_TOKEN }}
releasekit-dir: ${{ env.RELEASEKIT_DIR }}
enable-ollama: "false"
- uses: ./.github/actions/run-releasekit
with:
command: rollback
workspace: ${{ inputs.workspace }}
releasekit-dir: ${{ env.RELEASEKIT_DIR }}
dry-run: ${{ inputs.dry_run && 'true' || 'false' }}
tag: ${{ inputs.tag }}
all-tags: ${{ inputs.all_tags && 'true' || 'false' }}
yank: ${{ inputs.yank && 'true' || 'false' }}
yank-reason: ${{ inputs.yank_reason }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}