# 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: Go Release Pipeline
# ══════════════════════════════════════════════════════════════════════
#
# SAMPLE WORKFLOW — Copy to .github/workflows/releasekit-go.yml to use.
#
# This workflow implements a release pipeline for Go modules managed
# by a go.work workspace. It uses releasekit to automate:
#
# 1. PREPARE — compute version bumps, generate changelogs, open
# or update a Release PR.
# 2. RELEASE — tag the merge commit, create a GitHub Release.
# 3. PUBLISH — verify modules are available on the Go module proxy
# (Go modules are published by pushing tags; the proxy
# fetches them from VCS on first request).
#
# Go modules don't need an explicit "publish" step like PyPI or npm.
# After tagging, the Go module proxy (proxy.golang.org) picks up the
# new version when any user requests it. The publish job here simply
# polls the proxy to confirm availability.
#
# ── Automatic Flow ──────────────────────────────────────────────────
#
# push to main ──► releasekit prepare ──► Release PR
# (go/** or golang/**) (autorelease: pending)
# │
# merge PR
# │
# ▼
# releasekit release ──► tags + GitHub Release
# │
# ▼
# releasekit publish ──► verify on proxy.golang.org
# │
# ▼
# repository_dispatch ──► downstream repos
#
# ── Manual Dispatch Flow ────────────────────────────────────────────
#
# ┌─────────────────────────────────────────────────────────────┐
# │ workflow_dispatch UI │
# │ │
# │ action: [prepare ▼] ──► runs PREPARE job only │
# │ [release ▼] ──► runs RELEASE + PUBLISH + NOTIFY │
# │ │
# │ dry_run: [✓] simulate, no side effects │
# │ force_prepare: [✓] skip preflight, force PR creation │
# │ group: [________] target a release group │
# │ bump_type: [auto / patch / minor / major] │
# │ prerelease: [________] e.g. rc.1, beta.1 │
# │ skip_publish: [✓] tag + release but don't verify proxy │
# │ concurrency: [0] max parallel verify (0 = auto) │
# │ max_retries: [2] retry failed verifications │
# └─────────────────────────────────────────────────────────────┘
#
# ── Trigger Matrix ──────────────────────────────────────────────────
#
# Event │ Jobs that run
# ───────────────────┼──────────────────────────────────
# push to main │ prepare
# PR merged │ release → publish → notify
# dispatch: prepare │ prepare
# dispatch: release │ release → publish → notify
#
# ── Inputs Reference ────────────────────────────────────────────────
#
# Input │ Type │ Default │ Description
# ───────────────┼─────────┼─────────┼──────────────────────────────
# action │ choice │ release │ Pipeline stage: prepare or release
# dry_run │ boolean │ true │ Simulate without side effects
# force_prepare │ boolean │ false │ Force PR creation (--force)
# group │ string │ (all) │ Target a specific release group
# bump_type │ choice │ auto │ Override semver bump detection
# prerelease │ string │ (none) │ Prerelease suffix (e.g. rc.1)
# skip_publish │ boolean │ false │ Tag + release, skip proxy verify
# concurrency │ string │ 0 │ Max parallel verify jobs
# max_retries │ string │ 2 │ Retry failed verifications
# no_ai │ boolean │ false │ Disable AI features
# model │ string │ (chain) │ Override AI model
# codename_theme │ string │ (cfg) │ Override codename theme
#
# The workflow is idempotent: re-running any step is safe because
# releasekit skips already-created tags and already-verified versions.
# ══════════════════════════════════════════════════════════════════════
name: "ReleaseKit: Go"
on:
workflow_call:
inputs:
action:
description: 'Which pipeline stage to run'
required: false
default: release
type: string
dry_run:
description: 'Dry run'
required: false
default: true
type: boolean
force_prepare:
description: 'Force PR creation'
required: false
default: false
type: boolean
group:
description: 'Release group'
required: false
type: string
bump_type:
description: 'Override bump type'
required: false
default: auto
type: string
prerelease:
description: 'Prerelease suffix'
required: false
type: string
skip_publish:
description: 'Skip proxy verification'
required: false
default: false
type: boolean
concurrency:
description: 'Max parallel verify jobs'
required: false
default: '0'
type: string
max_retries:
description: 'Max retries'
required: false
default: '2'
type: string
no_ai:
description: 'Disable all AI features'
required: false
default: false
type: boolean
model:
description: 'Override AI model'
required: false
default: ''
type: string
codename_theme:
description: 'Override codename theme'
required: false
default: ''
type: string
secrets:
GITHUB_TOKEN:
required: false
GEMINI_API_KEY:
required: false
workflow_dispatch:
inputs:
action:
description: 'Which pipeline stage to run'
required: true
default: release
type: choice
options:
- prepare
- release
dry_run:
description: 'Dry run — log what would happen without creating tags or publishing'
required: true
default: true
type: boolean
force_prepare:
description: 'Force create/update the Release PR even if no new bumps are detected'
required: false
default: false
type: boolean
group:
description: 'Release group to target (leave empty for all)'
required: false
type: string
bump_type:
description: 'Override auto-detected bump type'
required: false
default: auto
type: choice
options:
- auto
- patch
- minor
- major
prerelease:
description: 'Publish as prerelease (e.g. rc.1, beta.1)'
required: false
type: string
skip_publish:
description: 'Tag and create GitHub Release but skip proxy verification'
required: false
default: false
type: boolean
concurrency:
description: 'Max parallel verify jobs (0 = auto)'
required: false
default: '0'
type: string
max_retries:
description: 'Max retries for failed verify attempts (0 = no retries)'
required: false
default: '2'
type: string
no_ai:
description: 'Disable all AI features (summarization, codenames)'
required: false
default: false
type: boolean
model:
description: 'Override AI model (e.g. ollama/gemma3:12b)'
required: false
type: string
codename_theme:
description: 'Override codename theme (e.g. galaxies, animals)'
required: false
type: string
push:
branches: [main]
paths:
- "go/**"
- "golang/**"
pull_request:
types: [closed]
branches: [main]
# Only one release pipeline runs at a time.
concurrency:
group: releasekit-go-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
env:
RELEASEKIT_DIR: py/tools/releasekit
GO_VERSION: "1.22"
DRY_RUN: ${{ github.event_name == 'pull_request' && 'false' || (inputs.dry_run == 'false' && 'false' || 'true') }}
jobs:
# ═══════════════════════════════════════════════════════════════════════
# PREPARE: Compute bumps and open/update Release PR
# ═══════════════════════════════════════════════════════════════════════
prepare:
name: Prepare Release PR
if: |
(github.event_name == 'push' &&
!startsWith(github.event.head_commit.message, 'chore(release):') &&
!contains(github.event.head_commit.message, 'releasekit--release')) ||
(github.event_name == 'workflow_dispatch' && inputs.action == 'prepare')
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
has_bumps: ${{ steps.rk.outputs.has-bumps }}
pr_url: ${{ steps.rk.outputs.pr-url }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: go/go.sum
- name: Run releasekit prepare
id: rk
uses: ./py/tools/releasekit
with:
command: prepare
workspace: go
force: ${{ inputs.force_prepare && 'true' || 'false' }}
group: ${{ inputs.group }}
bump-type: ${{ inputs.bump_type }}
prerelease: ${{ inputs.prerelease }}
no-ai: ${{ inputs.no_ai && 'true' || 'false' }}
model: ${{ inputs.model }}
codename-theme: ${{ inputs.codename_theme }}
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
# ═══════════════════════════════════════════════════════════════════════
# RELEASE: Tag merge commit and create GitHub Release
# ═══════════════════════════════════════════════════════════════════════
release:
name: Tag and Release
if: |
(github.event_name == 'pull_request' &&
github.event.pull_request.merged == true &&
contains(github.event.pull_request.labels.*.name, 'autorelease: pending')) ||
(github.event_name == 'workflow_dispatch' && inputs.action == 'release')
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
release_url: ${{ steps.rk.outputs.release-url }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run releasekit release
id: rk
uses: ./py/tools/releasekit
with:
command: release
workspace: go
dry-run: ${{ env.DRY_RUN }}
no-ai: ${{ inputs.no_ai && 'true' || 'false' }}
model: ${{ inputs.model }}
codename-theme: ${{ inputs.codename_theme }}
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
# ═══════════════════════════════════════════════════════════════════════
# PUBLISH: Verify modules on the Go module proxy
# ═══════════════════════════════════════════════════════════════════════
publish:
name: Verify on Go Proxy
needs: release
if: inputs.skip_publish != 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: go/go.sum
- name: Run releasekit publish
id: rk
uses: ./py/tools/releasekit
with:
command: publish
workspace: go
dry-run: ${{ env.DRY_RUN }}
force: "true"
group: ${{ inputs.group }}
concurrency: ${{ inputs.concurrency || '0' }}
max-retries: ${{ inputs.max_retries || '2' }}
no-ai: ${{ inputs.no_ai && 'true' || 'false' }}
model: ${{ inputs.model }}
codename-theme: ${{ inputs.codename_theme }}
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
- name: Upload manifest artifact
if: success() && env.DRY_RUN != 'true'
uses: actions/upload-artifact@v4
with:
name: release-manifest-go
path: .releasekit-state.json
retention-days: 90
# ═══════════════════════════════════════════════════════════════════════
# NOTIFY: Post-release notifications
# ═══════════════════════════════════════════════════════════════════════
notify:
name: Notify Downstream
needs: [release, publish]
if: success()
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Dispatch release event
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
event-type: genkit-go-release
client-payload: '{"release_url": "${{ needs.release.outputs.release_url }}"}'