Skip to content

Commit 27b89b3

Browse files
committed
chore: add verify-commits make target
Add a Make target that verifies that commits added between the current head and master: - reference only one upstream, if any - if referencing an upstream, only make changes to the vendor directory and the respective staging directory
1 parent 088bd07 commit 27b89b3

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ verify-manifests: manifests
147147
verify-nested-vendor:
148148
./scripts/check-staging-vendor.sh
149149

150+
.PHONY: verify-commits
151+
verify-commits:
152+
echo "$$(env)"
153+
./scripts/verify_commits $(TARGET_BRANCH)
154+
150155
.PHONY: verify
151156
verify:
152157
echo "Checking for unstaged root vendor changes"
@@ -155,6 +160,8 @@ verify:
155160
$(MAKE) verify-manifests
156161
echo "Checking for unsynced nested [go.mod,go.sum] files"
157162
$(MAKE) verify-nested-vendor
163+
echo "Checking commit integrity"
164+
$(MAKE) verify-commits
158165

159166
.PHONY: help
160167
help: ## Display this help.

scripts/verify_commits

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/bin/bash
2+
3+
function err() {
4+
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
5+
}
6+
7+
function verify_staging_diff() {
8+
local remote="${1}"
9+
local upstream_commit="${2}"
10+
local downstream_commit="${3}"
11+
local staging_dir="staging/${remote}"
12+
13+
local outside_staging
14+
outside_staging="$(git show --name-only "${downstream_commit}" -- ":!${staging_dir}")"
15+
if [[ -n "${outside_staging}" ]]; then
16+
err "downstream staging commit ${downstream_commit} changes files outside of ${staging_dir}:"
17+
err "${outside_staging}"
18+
err "factor out changes to ${staging_dir} into a standalone commit"
19+
return 1
20+
fi
21+
22+
local divergence
23+
divergence="$(git diff --stat "${upstream_commit}" "${downstream_commit}:${staging_dir}" -- ':!vendor')"
24+
if [[ -n "${divergence}" ]]; then
25+
err "downstream staging commit ${downstream_commit} diverges from upstream commit ${upstream_commit}:"
26+
err "${divergence}"
27+
err "changes must match referenced upstream commit ${upstream_commit}"
28+
return 1
29+
fi
30+
}
31+
32+
function verify_root_diff() {
33+
local downstream_commit="${1}"
34+
35+
local inside_staging
36+
inside_staging="$(git show --name-only "${downstream_commit}" -- staging)"
37+
if [[ -n "${inside_staging}" ]]; then
38+
err "downstream non-staging commit ${downstream_commit} changes staging"
39+
err "${inside_staging}"
40+
err "only staging commits (i.e. from an upstream cherry-pick) may change staging"
41+
42+
return 1
43+
fi
44+
}
45+
46+
function upstream_ref() {
47+
local downstream_commit="${1}"
48+
49+
local log
50+
log="$(git log -n 1 "${downstream_commit}")"
51+
52+
local -a upstream_repos
53+
mapfile -t upstream_repos < <(echo "${log}" | grep 'Upstream-repository:' | awk '{print $2}')
54+
55+
local -a upstream_commits
56+
mapfile -t upstream_commits < <(echo "${log}" | grep 'Upstream-commit:' | awk '{print $2}')
57+
58+
if (( ${#upstream_repos[@]} < 1 && ${#upstream_commits[@]} < 1 )); then
59+
# no upstream commit referenced
60+
return 0
61+
fi
62+
63+
if (( ${#upstream_repos[@]} > 1 )); then
64+
err "downstream staging commit ${downstream_commit} references more than one upstream repo:"
65+
err "${upstream_repos[@]}"
66+
err "staging commits may only reference a single upstream repo"
67+
return 1
68+
fi
69+
70+
if (( ${#upstream_commits[@]} > 1 )); then
71+
err "downstream staging commit ${downstream_commit} references more than one upstream commit:"
72+
err "${upstream_commits[@]}"
73+
err "staging commits may only reference a single upstream commit"
74+
return 1
75+
fi
76+
77+
if git branch -r --contains "${upstream_commits[0]}" | grep -vq "${upstream_repos[0]}/.*"; then
78+
err "downstream staging commit ${downstream_commit} references upstream commit ${upstream_commits[0]} that doesn't exist in ${upstream_repos[0]}"
79+
err "staging commits must reference a repository containing the given upstream commit"
80+
return 1
81+
fi
82+
83+
echo "${upstream_repos[0]}"
84+
echo "${upstream_commits[0]}"
85+
}
86+
87+
function fetch_remotes() {
88+
local -a remotes
89+
remotes=(
90+
'api'
91+
'operator-registry'
92+
'operator-lifecycle-manager'
93+
)
94+
for r in "${remotes[@]}"; do
95+
local url
96+
url="[email protected]/operator-framework/${r}.git"
97+
if git remote show "${r}"; then
98+
git remote set-url "${r}" "${url}"
99+
else
100+
echo "remote ${r} doesn't exist"
101+
git remote add "${r}" "${url}"
102+
fi
103+
104+
git fetch "${r}" master
105+
done
106+
}
107+
108+
function main() {
109+
fetch_remotes || err "failed to fetch remotes"
110+
111+
local target_branch="${1:-master}"
112+
113+
# get all commits we're introducing into the target branch
114+
local -a new_commits
115+
mapfile -t new_commits < <(git rev-list HEAD "^${target_branch}")
116+
117+
local -a sr
118+
for commit in "${new_commits[@]}"; do
119+
mapfile -t sr < <(upstream_ref "${commit}")
120+
if (( ${#sr[@]} < 2 )); then # the ref contains a tuple if the values were properly parsed from the commit message
121+
# couldn't find staging cherry-pick reference in the commit message
122+
# verify as a downstream-only commit
123+
verify_root_diff "${commit}"
124+
else
125+
# found staging cherry-pick reference in commit message
126+
# verify as a staging update
127+
verify_staging_diff "${sr[@]}" "${commit}"
128+
fi
129+
130+
done
131+
}
132+
133+
main "$@"

0 commit comments

Comments
 (0)