55 branches : [main]
66
77# contents:write is required for autotag-from-changelog to push tags.
8+ # pull-requests:write is required for retargeting PRs to pending deploy branches.
89permissions :
910 contents : write
11+ pull-requests : write
1012
1113jobs :
1214 release :
1315 runs-on : ubuntu-latest
16+ outputs :
17+ tag-created : ${{ steps.autotag.outputs.tag-created }}
1418 steps :
1519 - uses : actions/checkout@v6
1620 with :
@@ -28,10 +32,176 @@ jobs:
2832 env :
2933 GH_TOKEN : ${{ secrets.CCLOUD_PRIVATE_DISPATCH_PAT }}
3034 run : |
35+ source scripts/lib/logging.sh
36+
3137 if [ -z "$GH_TOKEN" ]; then
32- echo "::warning:: CCLOUD_PRIVATE_DISPATCH_PAT secret is not set. Skipping dispatch to ccloud-private for ${{ steps.autotag.outputs.tag }}."
38+ log_warning " CCLOUD_PRIVATE_DISPATCH_PAT secret is not set. Skipping dispatch to ccloud-private for ${{ steps.autotag.outputs.tag }}."
3339 exit 0
3440 fi
3541 gh api repos/cockroachdb/ccloud-private/dispatches \
3642 -f event_type=sdk-release \
3743 -f "client_payload[version]=${{ steps.autotag.outputs.tag }}"
44+
45+ # After a successful release, this job ensures there's always a fresh pending deploy
46+ # branch ready for the next release cycle. It:
47+ # 1. Finds the most recently merged pending deploy branch (from PRs to main)
48+ # 2. Finds any existing live pending deploy branches
49+ # 3. Creates a new pending deploy branch if there are no live ones or if the live
50+ # ones are stale (associated with an older date than the last merged one)
51+ # 4. Retargets all open PRs to point to the current pending deploy branch
52+ manage-pending-deploy :
53+ needs : release
54+ if : needs.release.outputs.tag-created == 'true'
55+ runs-on : ubuntu-latest
56+ steps :
57+ - uses : actions/checkout@v6
58+ with :
59+ fetch-depth : 0
60+
61+ # Step 1: Determine the previous pending deploy branch timestamp from main
62+ # Find the most recent merged PR to main where the head branch was automation/pending-deploy-YYYYMMDD-hhmmss
63+ - name : Find previous pending deploy branch from merged PRs
64+ id : previous
65+ env :
66+ GH_TOKEN : ${{ github.token }}
67+ run : |
68+ source scripts/lib/logging.sh
69+
70+ log_info "Searching for previous pending deploy branch from merged PRs..."
71+
72+ # Fetch last 50 merged PRs to find the most recent pending deploy branch.
73+ # 50 should be sufficient given typical API change and SDK release cadence.
74+ previous_branch=$(gh pr list \
75+ --state merged \
76+ --base main \
77+ --limit 50 \
78+ --json headRefName,mergedAt \
79+ --jq '[.[] | select(.headRefName | test("^automation/pending-deploy-[0-9]{8}-[0-9]{6}$"))] | sort_by(.mergedAt) | reverse | .[0].headRefName')
80+
81+ if [ -z "$previous_branch" ] || [ "$previous_branch" = "null" ]; then
82+ log_info "No previous pending deploy branch found from merged PRs"
83+ echo "previous_branch_timestamp=" >> "$GITHUB_OUTPUT"
84+ else
85+ log_info "Found previous pending deploy branch: $previous_branch"
86+
87+ # Extract timestamp from the branch name: automation/pending-deploy-YYYYMMDD-hhmmss
88+ previous_branch_timestamp=$(echo "$previous_branch" | sed -E 's/^automation\/pending-deploy-([0-9]{8}-[0-9]{6})$/\1/' | tr -d '-')
89+
90+ echo "previous_branch_timestamp=$previous_branch_timestamp" >> "$GITHUB_OUTPUT"
91+
92+ log_info " Timestamp: $previous_branch_timestamp"
93+ fi
94+
95+ # Step 2: Determine the current live pending deploy branch in the main repository
96+ # Look for live remote branches matching automation/pending-deploy-YYYYMMDD-hhmmss
97+ # If multiple exist, select the one with the latest timestamp
98+ - name : Find current live pending deploy branch
99+ id : current
100+ run : |
101+ source scripts/lib/logging.sh
102+
103+ log_info "Searching for live pending deploy branches in the main repository..."
104+
105+ # List all remote branches matching the pattern, sorted by timestamp descending
106+ current_branch=$(git ls-remote --heads origin | \
107+ grep -oE 'automation/pending-deploy-[0-9]{8}-[0-9]{6}$' | \
108+ sort -r | \
109+ head -n 1)
110+
111+ if [ -z "$current_branch" ]; then
112+ log_info "No live pending deploy branch found"
113+ echo "current_branch=" >> "$GITHUB_OUTPUT"
114+ echo "current_branch_timestamp=" >> "$GITHUB_OUTPUT"
115+ else
116+ log_info "Found current live pending deploy branch: $current_branch"
117+
118+ # Extract timestamp
119+ current_branch_timestamp=$(echo "$current_branch" | sed -E 's/^automation\/pending-deploy-([0-9]{8}-[0-9]{6})$/\1/' | tr -d '-')
120+
121+ echo "current_branch=$current_branch" >> "$GITHUB_OUTPUT"
122+ echo "current_branch_timestamp=$current_branch_timestamp" >> "$GITHUB_OUTPUT"
123+
124+ log_info " Timestamp: $current_branch_timestamp"
125+ fi
126+
127+ # Step 3: Decide which pending deploy branch should be used now
128+ # If previous timestamp >= current timestamp, create a new branch
129+ - name : Select pending deploy branch
130+ id : selected
131+ env :
132+ PREVIOUS_BRANCH_TIMESTAMP : ${{ steps.previous.outputs.previous_branch_timestamp }}
133+ CURRENT_BRANCH : ${{ steps.current.outputs.current_branch }}
134+ CURRENT_BRANCH_TIMESTAMP : ${{ steps.current.outputs.current_branch_timestamp }}
135+ run : |
136+ source scripts/lib/logging.sh
137+
138+ # Get current UTC timestamp in YYYYMMDD-hhmmss format
139+ current_timestamp=$(date -u +%Y%m%d-%H%M%S)
140+ log_info "Current UTC timestamp: $current_timestamp"
141+
142+ # Decision logic: create new branch if previous >= current, otherwise use current
143+ if [ -z "$CURRENT_BRANCH" ]; then
144+ # No current live branch exists, create new
145+ log_info "No current live branch exists, creating new branch..."
146+ selected_branch="automation/pending-deploy-${current_timestamp}"
147+ needs_creation=true
148+ elif [ -n "$PREVIOUS_BRANCH_TIMESTAMP" ] && [ "$PREVIOUS_BRANCH_TIMESTAMP" -ge "$CURRENT_BRANCH_TIMESTAMP" ]; then
149+ # Previous timestamp >= current timestamp, create new branch
150+ log_info "Previous timestamp ($PREVIOUS_BRANCH_TIMESTAMP) >= current timestamp ($CURRENT_BRANCH_TIMESTAMP), creating new branch..."
151+ selected_branch="automation/pending-deploy-${current_timestamp}"
152+ needs_creation=true
153+ else
154+ # Use current live branch
155+ log_info "Using current live branch"
156+ selected_branch="$CURRENT_BRANCH"
157+ needs_creation=false
158+ fi
159+
160+ log_info "Selected pending deploy branch: $selected_branch"
161+ log_info "Needs creation: $needs_creation"
162+
163+ echo "selected_branch=$selected_branch" >> "$GITHUB_OUTPUT"
164+ echo "needs_creation=$needs_creation" >> "$GITHUB_OUTPUT"
165+
166+ # Step 4: Ensure the selected pending deploy branch exists in the main repository
167+ # Create it from main if it doesn't already exist remotely
168+ - name : Create pending deploy branch if needed
169+ if : steps.selected.outputs.needs_creation == 'true'
170+ env :
171+ SELECTED_BRANCH : ${{ steps.selected.outputs.selected_branch }}
172+ run : |
173+ source scripts/lib/logging.sh
174+
175+ log_info "Creating pending deploy branch: $SELECTED_BRANCH"
176+
177+ # Create the branch from main and push it to the main repository
178+ git checkout -b "$SELECTED_BRANCH" origin/main
179+ git push origin "$SELECTED_BRANCH"
180+
181+ log_info "Branch $SELECTED_BRANCH created and pushed to origin"
182+
183+ # Step 5: Retarget open PRs from any pending deploy branch to the selected branch
184+ - name : Retarget open PRs
185+ env :
186+ GH_TOKEN : ${{ github.token }}
187+ SELECTED_BRANCH : ${{ steps.selected.outputs.selected_branch }}
188+ run : |
189+ source scripts/lib/logging.sh
190+
191+ log_info "Looking for open PRs targeting pending deploy branches..."
192+
193+ # Find all open PRs and filter for those targeting automation/pending-deploy-YYYYMMDD-hhmmss branches
194+ prs_to_retarget=$(gh pr list --state open --json number,baseRefName --jq '.[] | select(.baseRefName | test("^automation/pending-deploy-[0-9]{8}-[0-9]{6}$")) | select(.baseRefName != "'$SELECTED_BRANCH'") | "\(.number):\(.baseRefName)"')
195+
196+ if [ -z "$prs_to_retarget" ]; then
197+ log_info "No open PRs found targeting pending deploy branches"
198+ else
199+ log_info "Found PRs to retarget to $SELECTED_BRANCH:"
200+ echo "$prs_to_retarget" | while IFS=: read -r pr_number base_branch; do
201+ log_info " PR #$pr_number (from $base_branch)"
202+ gh pr edit "$pr_number" --base "$SELECTED_BRANCH"
203+ log_info " Retargeted PR #$pr_number to $SELECTED_BRANCH"
204+ done
205+
206+ log_info "All PRs retargeted successfully"
207+ fi
0 commit comments