Skip to content

Commit 5bba8b0

Browse files
authored
ci: Apply multi-commit patch branches via octopus merge (backport #841) (#903)
Signed-off-by: Prasanth Baskar <prasanth@8gears.com>
1 parent 5bcfece commit 5bba8b0

1 file changed

Lines changed: 51 additions & 34 deletions

File tree

taskfile/release-ready.yml

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ tasks:
4141
- task: _fetch-patches
4242
- task: _validate-patches
4343
- task: _import-patches
44-
- task: _duplicate-patches
44+
- task: _octopus-patches
4545
- task: _verify-patches
4646

4747
check:
@@ -73,9 +73,13 @@ tasks:
7373
internal: true
7474
requires:
7575
vars: [PATCH_BRANCHES]
76+
env:
77+
DECLARED_PATCH_BRANCHES: '{{.PATCH_BRANCHES}}'
7678
cmds:
77-
- for: { var: PATCH_BRANCHES }
78-
cmd: git check-ref-format --branch '{{.ITEM}}' >/dev/null
79+
- |
80+
while IFS= read -r branch; do
81+
git check-ref-format --branch "${branch}" >/dev/null
82+
done <<< "${DECLARED_PATCH_BRANCHES}"
7983
8084
_clean-auth:
8185
internal: true
@@ -101,27 +105,32 @@ tasks:
101105
env:
102106
GIT_ASKPASS: '{{.PATCH_AUTH_DIR}}/git-askpass'
103107
GIT_TERMINAL_PROMPT: '0'
108+
PATCHES_FETCH_URL: '{{.PATCHES_REMOTE_URL}}'
109+
DECLARED_PATCH_BRANCHES: '{{.PATCH_BRANCHES}}'
104110
cmds:
105-
- for: { var: PATCH_BRANCHES }
106-
cmd: >-
107-
git fetch --no-tags '{{.PATCHES_REMOTE_URL}}'
108-
'+refs/heads/{{.ITEM}}:refs/remotes/patches/{{.ITEM}}'
111+
- |
112+
refspecs=()
113+
while IFS= read -r branch; do
114+
refspecs+=("+refs/heads/${branch}:refs/remotes/patches/${branch}")
115+
done <<< "${DECLARED_PATCH_BRANCHES}"
116+
git fetch --no-tags "${PATCHES_FETCH_URL}" "${refspecs[@]}"
109117
110118
_validate-patches:
111119
internal: true
120+
env:
121+
DECLARED_PATCH_BRANCHES: '{{.PATCH_BRANCHES}}'
112122
cmds:
113-
- for: { var: PATCH_BRANCHES }
114-
task: _validate-patch
115-
vars:
116-
PATCH_BRANCH: '{{.ITEM}}'
117-
118-
_validate-patch:
119-
internal: true
120-
requires:
121-
vars: [PATCH_BRANCH]
122-
preconditions:
123-
- sh: test "$(git show -s --format='%P' 'refs/remotes/patches/{{.PATCH_BRANCH}}' | wc -w)" -eq 1
124-
msg: "commercial patch branch must point to one non-merge commit: {{.PATCH_BRANCH}}"
123+
- |
124+
# Patch branches carry real multi-commit history plus sync-merge
125+
# commits, so no commit-shape rule applies; each branch only has to
126+
# share history with the target so the octopus has a merge base.
127+
base=$(git rev-parse HEAD)
128+
while IFS= read -r branch; do
129+
if ! git merge-base "refs/remotes/patches/${branch}" "${base}" >/dev/null; then
130+
echo "commercial patch branch shares no history with the target: ${branch}" >&2
131+
exit 1
132+
fi
133+
done <<< "${DECLARED_PATCH_BRANCHES}"
125134
126135
_import-patches:
127136
internal: true
@@ -135,34 +144,42 @@ tasks:
135144
- test -d .jj
136145
cmd: jj git init --colocate >/dev/null
137146

138-
_duplicate-patches:
147+
_octopus-patches:
139148
internal: true
140-
vars:
141-
PATCH_REVSET:
142-
sh: |
143-
printf '%s\n' '{{.PATCH_BRANCHES}}' | while IFS= read -r branch; do
144-
git rev-parse "refs/remotes/patches/${branch}^{commit}"
145-
done | paste -sd '|' -
146-
PATCHSET_ID:
147-
sh: printf '%s' '{{.PATCH_REVSET}}' | git hash-object --stdin
148-
PATCHSET_DESCRIPTION: 'release patches {{.PATCHSET_ID}}'
149+
env:
150+
DECLARED_PATCH_BRANCHES: '{{.PATCH_BRANCHES}}'
149151
status:
150-
- test "$(jj log -r @ --no-graph -T 'description.first_line()')" = '{{.PATCHSET_DESCRIPTION}}'
152+
- |
153+
patch_revset=$(printf '%s\n' "${DECLARED_PATCH_BRANCHES}" | while IFS= read -r branch; do
154+
git rev-parse "refs/remotes/patches/${branch}^{commit}"
155+
done | paste -sd '|' -)
156+
patchset_id=$(printf '%s' "${patch_revset}" | git hash-object --stdin)
157+
test "$(jj log -r @ --no-graph -T 'description.first_line()')" = "release patches ${patchset_id}"
151158
cmds:
152159
- |
160+
patch_revset=$(printf '%s\n' "${DECLARED_PATCH_BRANCHES}" | while IFS= read -r branch; do
161+
git rev-parse "refs/remotes/patches/${branch}^{commit}"
162+
done | paste -sd '|' -)
163+
patchset_id=$(printf '%s' "${patch_revset}" | git hash-object --stdin)
153164
base=$(jj log -r @ --no-graph -T commit_id)
154-
jj duplicate '({{.PATCH_REVSET}})' --onto @
155-
jj new "heads(${base}::) ~ ${base}" -m '{{.PATCHSET_DESCRIPTION}}'
165+
# Octopus of the fetched tips onto the target. heads() drops
166+
# redundant parents (a stacked branch already contains its parent's
167+
# tip, and a tip may already contain the base).
168+
jj new "heads(${base}|${patch_revset})" -m "release patches ${patchset_id}"
156169
157170
_verify-patches:
158171
internal: true
172+
env:
173+
DECLARED_PATCH_BRANCHES: '{{.PATCH_BRANCHES}}'
159174
preconditions:
160175
- sh: test -z "$(jj log -r '::@ & conflicts()' --no-graph -T commit_id)"
161176
msg: "commercial patches did not apply cleanly; run 'jj resolve --list'"
162177
cmds:
163178
- echo "Applied commercial patches from {{.PATCHES_SERIES}}:"
164-
- for: { var: PATCH_BRANCHES }
165-
cmd: echo ' {{.ITEM}}'
179+
- |
180+
while IFS= read -r branch; do
181+
echo " ${branch}"
182+
done <<< "${DECLARED_PATCH_BRANCHES}"
166183
167184
_clean-checkout:
168185
internal: true

0 commit comments

Comments
 (0)