Repository navigation
138 lines (124 loc) · 4.85 KB
/
Copy pathcherry_pick_release.yml
File metadata and controls
138 lines (124 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# This workflow cherry-picks commits from master onto a release branch.
#
# Run it on release/<yyyymmdd> (see cut_release.yml) with the commits to pick,
# oldest first. It pushes the result to a cherry-pick/* branch and opens a pull
# request against the release branch; the pull request still needs a review.
# If a commit does not apply cleanly, the workflow stops and the cherry-pick
# must be done by hand.
#
# The pull request is opened as gvisor-bot (the GVISOR_BOT_TOKEN secret).
#
# Do not use this workflow for an embargoed fix: the branch and the pull
# request are public.
name: "Cherry-pick to Release Branch"
"on":
workflow_dispatch:
inputs:
commits:
description: 'Commits on master to cherry-pick, oldest first, separated by spaces'
required: true
type: string
concurrency:
group: cherry-pick-${{ github.ref_name }}
cancel-in-progress: false
jobs:
cherry-pick:
name: Cherry-pick to release branch
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
# Fail before anything is pushed.
- name: Check the gvisor-bot token
env:
GVISOR_BOT_TOKEN: ${{ secrets.GVISOR_BOT_TOKEN }}
run: |
set +x
if [[ -z "${GVISOR_BOT_TOKEN}" ]]; then
echo "::error::The GVISOR_BOT_TOKEN secret is not set; it is needed to open the pull request as gvisor-bot."
exit 1
fi
- name: Checkout
# Do not set ref: github.sha is the release branch head when the run
# was created, and the pull request is computed against it.
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Full history is required to check and cherry-pick the commits.
fetch-depth: 0
- name: Cherry-pick the commits
id: pick
env:
COMMITS: ${{ inputs.commits }}
BASE: ${{ github.ref_name }}
RUN_ID: ${{ github.run_id }}
run: |
set -euo pipefail
if ! [[ "${BASE}" =~ ^release/(20[0-9]{6})$ ]]; then
echo "::error::Run this workflow from a release/<yyyymmdd> branch, not ${BASE}."
exit 1
fi
head="cherry-pick/${BASH_REMATCH[1]}-${RUN_ID}"
git config user.name "gVisor bot"
git config user.email "gvisor-bot@google.com"
git checkout -b "${head}"
read -r -a requested <<<"${COMMITS}"
if (( ${#requested[@]} == 0 )); then
echo "::error::No commits given."
exit 1
fi
picked=()
for c in "${requested[@]}"; do
if ! sha="$(git rev-parse --verify --quiet "${c}^{commit}")"; then
echo "::error::Unknown commit: '${c}'"
exit 1
fi
if ! git merge-base --is-ancestor "${sha}" origin/master; then
echo "::error::${sha} is not on master. Merge the fix to master first."
exit 1
fi
if git merge-base --is-ancestor "${sha}" HEAD ||
[[ -n "$(git log -1 --format=%H -F --grep="(cherry picked from commit ${sha})" HEAD "origin/${BASE}")" ]]; then
echo "::error::${sha} is already on ${BASE}."
exit 1
fi
# A merge commit is picked relative to its first parent (master).
args=(-x)
if (( $(git rev-list --parents -n 1 "${sha}" | wc -w) > 2 )); then
args+=(-m 1)
fi
if ! git cherry-pick "${args[@]}" "${sha}"; then
conflicts="$(git diff --name-only --diff-filter=U)"
if [[ -z "${conflicts}" ]]; then
echo "::error::${sha} changes nothing on ${BASE}; it may already be applied."
else
echo "::error::${sha} does not apply cleanly to ${BASE}. Cherry-pick it by hand. Conflicts:"
echo "${conflicts}"
fi
exit 1
fi
picked+=("${sha}")
done
git push origin "HEAD:refs/heads/${head}"
{
echo "Cherry-picks onto \`${BASE}\` from master:"
echo
for sha in "${picked[@]}"; do
echo "- ${sha} $(git log -1 --format=%s "${sha}")"
done
} >"${RUNNER_TEMP}/body"
echo "head=${head}" >>"${GITHUB_OUTPUT}"
- name: Open the pull request
env:
GH_TOKEN: ${{ secrets.GVISOR_BOT_TOKEN }}
GH_REPO: ${{ github.repository }}
BASE: ${{ github.ref_name }}
HEAD_BRANCH: ${{ steps.pick.outputs.head }}
run: |
set -euo pipefail
url="$(gh pr create \
--base "${BASE}" \
--head "${HEAD_BRANCH}" \
--title "[${BASE}] Cherry-pick from master" \
--body-file "${RUNNER_TEMP}/body")"
echo "Opened ${url}" >>"${GITHUB_STEP_SUMMARY}"