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 :
@@ -35,3 +39,150 @@ jobs:
3539 gh api repos/cockroachdb/ccloud-private/dispatches \
3640 -f event_type=sdk-release \
3741 -f "client_payload[version]=${{ steps.autotag.outputs.tag }}"
42+
43+ manage-pending-deploy :
44+ needs : release
45+ if : needs.release.outputs.tag-created == 'true'
46+ runs-on : ubuntu-latest
47+ steps :
48+ - uses : actions/checkout@v6
49+ with :
50+ fetch-depth : 0
51+
52+ # Step 1: Determine the previous pending deploy branch timestamp from main
53+ # Find the most recent merged PR to main where the head branch was pending-deploy-YYYYMMDD-hhmmss
54+ - name : Find previous pending deploy branch from merged PRs
55+ id : previous
56+ env :
57+ GH_TOKEN : ${{ github.token }}
58+ run : |
59+ echo "Searching for previous pending deploy branch from merged PRs..."
60+
61+ # Fetch last 50 merged PRs to find the most recent pending deploy branch.
62+ # 50 should be sufficient given typical API change and SDK release cadence.
63+ previous_branch=$(gh pr list \
64+ --state merged \
65+ --base main \
66+ --limit 50 \
67+ --json headRefName,mergedAt \
68+ --jq '[.[] | select(.headRefName | test("^pending-deploy-[0-9]{8}-[0-9]{6}$"))] | sort_by(.mergedAt) | reverse | .[0].headRefName')
69+
70+ if [ -z "$previous_branch" ] || [ "$previous_branch" = "null" ]; then
71+ echo "No previous pending deploy branch found from merged PRs"
72+ echo "previous_branch_timestamp=" >> "$GITHUB_OUTPUT"
73+ else
74+ echo "Found previous pending deploy branch: $previous_branch"
75+
76+ # Extract timestamp from the branch name: pending-deploy-YYYYMMDD-hhmmss
77+ previous_branch_timestamp=$(echo "$previous_branch" | sed -E 's/^pending-deploy-([0-9]{8}-[0-9]{6})$/\1/' | tr -d '-')
78+
79+ echo "previous_branch_timestamp=$previous_branch_timestamp" >> "$GITHUB_OUTPUT"
80+
81+ echo " Timestamp: $previous_branch_timestamp"
82+ fi
83+
84+ # Step 2: Determine the current live pending deploy branch in the main repository
85+ # Look for live remote branches matching pending-deploy-YYYYMMDD-hhmmss
86+ # If multiple exist, select the one with the latest timestamp
87+ - name : Find current live pending deploy branch
88+ id : current
89+ run : |
90+ echo "Searching for live pending deploy branches in the main repository..."
91+
92+ # List all remote branches matching the pattern, sorted by timestamp descending
93+ current_branch=$(git ls-remote --heads origin | \
94+ grep -oE 'pending-deploy-[0-9]{8}-[0-9]{6}$' | \
95+ sort -r | \
96+ head -n 1)
97+
98+ if [ -z "$current_branch" ]; then
99+ echo "No live pending deploy branch found"
100+ echo "current_branch=" >> "$GITHUB_OUTPUT"
101+ echo "current_branch_timestamp=" >> "$GITHUB_OUTPUT"
102+ else
103+ echo "Found current live pending deploy branch: $current_branch"
104+
105+ # Extract timestamp
106+ current_branch_timestamp=$(echo "$current_branch" | sed -E 's/^pending-deploy-([0-9]{8}-[0-9]{6})$/\1/' | tr -d '-')
107+
108+ echo "current_branch=$current_branch" >> "$GITHUB_OUTPUT"
109+ echo "current_branch_timestamp=$current_branch_timestamp" >> "$GITHUB_OUTPUT"
110+
111+ echo " Timestamp: $current_branch_timestamp"
112+ fi
113+
114+ # Step 3: Decide which pending deploy branch should be used now
115+ # If previous timestamp >= current timestamp, create a new branch
116+ - name : Select pending deploy branch
117+ id : selected
118+ env :
119+ PREVIOUS_BRANCH_TIMESTAMP : ${{ steps.previous.outputs.previous_branch_timestamp }}
120+ CURRENT_BRANCH : ${{ steps.current.outputs.current_branch }}
121+ CURRENT_BRANCH_TIMESTAMP : ${{ steps.current.outputs.current_branch_timestamp }}
122+ run : |
123+ # Get current UTC timestamp in YYYYMMDD-hhmmss format
124+ current_timestamp=$(date -u +%Y%m%d-%H%M%S)
125+ echo "Current UTC timestamp: $current_timestamp"
126+
127+ # Decision logic: create new branch if previous >= current, otherwise use current
128+ if [ -z "$CURRENT_BRANCH" ]; then
129+ # No current live branch exists, create new
130+ echo "No current live branch exists, creating new branch..."
131+ selected_branch="pending-deploy-${current_timestamp}"
132+ needs_creation=true
133+ elif [ -n "$PREVIOUS_BRANCH_TIMESTAMP" ] && [ "$PREVIOUS_BRANCH_TIMESTAMP" -ge "$CURRENT_BRANCH_TIMESTAMP" ]; then
134+ # Previous timestamp >= current timestamp, create new branch
135+ echo "Previous timestamp ($PREVIOUS_BRANCH_TIMESTAMP) >= current timestamp ($CURRENT_BRANCH_TIMESTAMP), creating new branch..."
136+ selected_branch="pending-deploy-${current_timestamp}"
137+ needs_creation=true
138+ else
139+ # Use current live branch
140+ echo "Using current live branch"
141+ selected_branch="$CURRENT_BRANCH"
142+ needs_creation=false
143+ fi
144+
145+ echo "Selected pending deploy branch: $selected_branch"
146+ echo "Needs creation: $needs_creation"
147+
148+ echo "selected_branch=$selected_branch" >> "$GITHUB_OUTPUT"
149+ echo "needs_creation=$needs_creation" >> "$GITHUB_OUTPUT"
150+
151+ # Step 4: Ensure the selected pending deploy branch exists in the main repository
152+ # Create it from main if it doesn't already exist remotely
153+ - name : Create pending deploy branch if needed
154+ if : steps.selected.outputs.needs_creation == 'true'
155+ env :
156+ SELECTED_BRANCH : ${{ steps.selected.outputs.selected_branch }}
157+ run : |
158+ echo "Creating pending deploy branch: $SELECTED_BRANCH"
159+
160+ # Create the branch from main and push it to the main repository
161+ git checkout -b "$SELECTED_BRANCH" origin/main
162+ git push origin "$SELECTED_BRANCH"
163+
164+ echo "Branch $SELECTED_BRANCH created and pushed to origin"
165+
166+ # Step 5: Retarget open PRs from any pending deploy branch to the selected branch
167+ - name : Retarget open PRs
168+ env :
169+ GH_TOKEN : ${{ github.token }}
170+ SELECTED_BRANCH : ${{ steps.selected.outputs.selected_branch }}
171+ run : |
172+ echo "Looking for open PRs targeting pending deploy branches..."
173+
174+ # Find all open PRs and filter for those targeting pending-deploy-YYYYMMDD-hhmmss branches
175+ prs_to_retarget=$(gh pr list --state open --json number,baseRefName --jq '.[] | select(.baseRefName | test("^pending-deploy-[0-9]{8}-[0-9]{6}$")) | select(.baseRefName != "'$SELECTED_BRANCH'") | "\(.number):\(.baseRefName)"')
176+
177+ if [ -z "$prs_to_retarget" ]; then
178+ echo "No open PRs found targeting pending deploy branches"
179+ else
180+ echo "Found PRs to retarget to $SELECTED_BRANCH:"
181+ echo "$prs_to_retarget" | while IFS=: read -r pr_number base_branch; do
182+ echo " PR #$pr_number (from $base_branch)"
183+ gh pr edit "$pr_number" --base "$SELECTED_BRANCH"
184+ echo " Retargeted PR #$pr_number to $SELECTED_BRANCH"
185+ done
186+
187+ echo "All PRs retargeted successfully"
188+ fi
0 commit comments