Skip to content

Commit 0427cba

Browse files
[CNSL-1934] Add automated pending deploy branch management
Introduces two workflows to manage the release process: 1. pending-deploy-pr.yml (workflow_dispatch trigger): - Finds the latest automation/pending-deploy-YYYYMMDD-hhmmss branch - Creates a PR to merge it into main - Triggers a pending deploy check 2. pending-deploy-check.yml (pull_request and workflow_dispatch trigger): - Validates pending deploy PRs before merge - Checks that Managed-service-commit-SHA trailers reference deployed commits - Blocks merge until all changes are confirmed deployed in managed-service - Posts PR comments detailing any undeployed commits This ensures SDK releases only reference deployed CC API changes. Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
1 parent 7777b8d commit 0427cba

14 files changed

Lines changed: 1293 additions & 0 deletions
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: Pending Deploy Check
2+
3+
# This workflow validates that pending deploy PRs are safe to merge.
4+
#
5+
# Trigger: Pull requests to main from automation/pending-deploy-* branches
6+
# Purpose: Verify all commits in the PR have been deployed in managed-service
7+
#
8+
# Why: SDK changes are generated from managed-service OpenAPI specs. We must ensure
9+
# the corresponding managed-service changes have been deployed before merging the SDK changes,
10+
# otherwise the SDK could reference unreleased API features.
11+
#
12+
# Flow:
13+
# 1. For each commit in the PR, extract the Managed-service-commit-SHA trailer
14+
# 2. Check if that SHA is in the latest managed-service release tag
15+
# 3. If any commits are not yet deployed, post a detailed comment and fail the PR
16+
17+
on:
18+
pull_request:
19+
branches: [main]
20+
workflow_dispatch:
21+
inputs:
22+
branch:
23+
description: 'Pending deploy branch to check'
24+
required: true
25+
type: string
26+
pr_url:
27+
description: 'PR URL to comment on if check fails'
28+
required: true
29+
type: string
30+
31+
permissions:
32+
contents: read # Checkout repository and read commit history
33+
pull-requests: write # Post failure comments on PRs
34+
35+
jobs:
36+
pending-deploy-check:
37+
runs-on: ubuntu-latest
38+
if: |
39+
(github.event_name == 'pull_request' && startsWith(github.head_ref, 'automation/pending-deploy-')) ||
40+
(github.event_name == 'workflow_dispatch' && startsWith(inputs.branch, 'automation/pending-deploy-'))
41+
steps:
42+
- name: Checkout repository
43+
uses: actions/checkout@v6
44+
with:
45+
fetch-depth: 0
46+
47+
- name: Validate workflow input
48+
if: github.event_name == 'workflow_dispatch'
49+
id: validate-input
50+
env:
51+
GITHUB_TOKEN: ${{ github.token }}
52+
run: |
53+
source scripts/lib/actions-helpers.sh
54+
55+
# Extract PR number from URL
56+
PR_NUMBER=$(echo "${{ inputs.pr_url }}" | grep -oE '[0-9]+$')
57+
set_output pr_number "$PR_NUMBER"
58+
59+
# Validate the PR's head branch matches the input branch
60+
PR_HEAD_BRANCH=$(gh pr view "$PR_NUMBER" --json headRefName --jq '.headRefName')
61+
if [ "$PR_HEAD_BRANCH" != "${{ inputs.branch }}" ]; then
62+
log_error "PR #$PR_NUMBER head branch ($PR_HEAD_BRANCH) does not match input branch (${{ inputs.branch }})"
63+
exit 1
64+
fi
65+
66+
- name: Run deployment check
67+
id: check-deployment
68+
env:
69+
PENDING_DEPLOY_BRANCH: ${{ inputs.branch || github.head_ref }}
70+
MANAGED_SERVICE_TOKEN: ${{ secrets.MANAGED_SERVICE_TOKEN }}
71+
run: scripts/pending-deploy-check.sh
72+
73+
- name: Post failure comment and fail
74+
if: steps.check-deployment.outputs.has_issues == 'true'
75+
env:
76+
PR_NUMBER: ${{ steps.validate-input.outputs.pr_number || github.event.pull_request.number }}
77+
GITHUB_TOKEN: ${{ github.token }}
78+
run: |
79+
scripts/post-failure-comment.sh
80+
source scripts/lib/actions-helpers.sh
81+
log_error "Deployment check failed - see PR comment for details"
82+
exit 1
83+
84+
- name: Summary
85+
if: always()
86+
run: |
87+
source scripts/lib/actions-helpers.sh
88+
if [ "${{ steps.check-deployment.outputs.has_issues }}" != "true" ]; then
89+
log_info "All commits in pending deploy branch are deployed in managed-service"
90+
else
91+
log_info "Some commits are not deployed or potentially not deployed"
92+
fi
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: Pending Deploy PR
2+
3+
# This workflow creates PRs to apply pending deploy changes to main.
4+
#
5+
# Trigger: workflow_dispatch - called by TeamCity when managed-service is deployed
6+
# Purpose: Automatically create a PR to merge the latest automation/pending-deploy-* branch into main
7+
#
8+
# Flow:
9+
# 1. Find the latest automation/pending-deploy-YYYYMMDD-HHMMSS branch
10+
# 2. Check if it has commits not in main
11+
# 3. Create a PR if one doesn't already exist
12+
13+
on:
14+
workflow_dispatch:
15+
inputs:
16+
timestamp:
17+
description: 'Deployment timestamp'
18+
required: true
19+
type: string
20+
commit_sha:
21+
description: 'Deployed commit SHA'
22+
required: true
23+
type: string
24+
25+
permissions:
26+
contents: read # Checkout repository and read branches/tags
27+
pull-requests: write # Create and update PRs
28+
actions: write # Trigger pending deploy check workflow
29+
30+
jobs:
31+
pending-deploy-pr:
32+
runs-on: ubuntu-latest
33+
outputs:
34+
branch: ${{ steps.create-pr.outputs.branch }}
35+
pr_url: ${{ steps.create-pr.outputs.pr_url }}
36+
steps:
37+
- name: Checkout repository
38+
uses: actions/checkout@v6
39+
with:
40+
fetch-depth: 0 # Need full history to compare branches and commits
41+
42+
- name: Run pending deploy PR workflow
43+
id: create-pr
44+
env:
45+
GITHUB_TOKEN: ${{ github.token }}
46+
GITHUB_REPOSITORY: ${{ github.repository }}
47+
run: scripts/pending-deploy-pr.sh
48+
49+
# GitHub Actions doesn't automatically trigger workflows when a PR is created using GITHUB_TOKEN
50+
# (to prevent recursive workflow triggers). Since we need deployment validation to run,
51+
# we explicitly dispatch the check workflow here.
52+
- name: Trigger pending deploy check
53+
if: steps.create-pr.outputs.pr_url != '' && steps.create-pr.outputs.branch != ''
54+
id: trigger-check
55+
env:
56+
GH_TOKEN: ${{ github.token }}
57+
run: |
58+
source scripts/lib/actions-helpers.sh
59+
if ! gh workflow run pending-deploy-check.yml \
60+
--repo ${{ github.repository }} \
61+
--field branch="${{ steps.create-pr.outputs.branch }}" \
62+
--field pr_url="${{ steps.create-pr.outputs.pr_url }}"; then
63+
log_error "Failed to trigger pending-deploy-check workflow. You may need to manually trigger the check for ${{ steps.create-pr.outputs.pr_url }}"
64+
else
65+
log_info "Successfully triggered pending-deploy-check workflow"
66+
fi
67+
68+
- name: Summary
69+
if: always()
70+
run: |
71+
source scripts/lib/actions-helpers.sh
72+
if [ -z "${{ steps.create-pr.outputs.branch }}" ]; then
73+
log_info "No pending deploy branches found"
74+
elif [ "${{ steps.create-pr.outputs.has_new_commits }}" != "true" ]; then
75+
log_info "Pending deploy branch has no new commits"
76+
elif [ -n "${{ steps.create-pr.outputs.pr_url }}" ]; then
77+
log_info "PR created or updated for pending deploy branch"
78+
if [ "${{ steps.trigger-check.outcome }}" = "success" ]; then
79+
log_info "Deployment check workflow triggered successfully"
80+
elif [ "${{ steps.trigger-check.outcome }}" = "failure" ]; then
81+
log_info "Failed to trigger deployment check workflow"
82+
fi
83+
fi

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Automated pending deploy branch management with two GitHub Actions workflows:
13+
- `pending-deploy-pr.yml`: Creates PRs from pending deploy branches to main (triggered via
14+
workflow_dispatch) and triggers a pending deploy check
15+
- `pending-deploy-check.yml`: Validates that SDK commits reference deployed managed-service changes
16+
before allowing merge
17+
1018
## [7.1.0] - 2026-04-14
1119

1220
### Added

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ add-boilerplate:
4040
validate:
4141
go run main.go
4242

43+
# Run bash helper script tests
44+
.PHONY: test-scripts
45+
test-scripts:
46+
./scripts/run-tests.sh
47+
4348
default: generate-openapi-client validate
4449

4550
# build-tool is a helper that builds $TOOL_PKG in a temp directory so that it

scripts/lib/actions-helpers.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env bash
2+
# Logging functions for GitHub Actions workflows
3+
4+
# Output an informational message to stdout
5+
log_info() {
6+
local message="$1"
7+
echo "$message"
8+
}
9+
10+
# Output an error message using GitHub Actions workflow command format
11+
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message
12+
log_error() {
13+
local message="$1"
14+
echo "::error::$message" >&2
15+
}
16+
17+
# Output a warning message using GitHub Actions workflow command format
18+
log_warning() {
19+
local message="$1"
20+
echo "::warning::$message" >&2
21+
}
22+
23+
# Output a notice message using GitHub Actions workflow command format
24+
log_notice() {
25+
local message="$1"
26+
echo "::notice::$message"
27+
}
28+
29+
# Write a single-line output: set_output key value
30+
set_output() {
31+
echo "$1=$2" >> "${GITHUB_OUTPUT:-/dev/null}"
32+
}

0 commit comments

Comments
 (0)