-
Notifications
You must be signed in to change notification settings - Fork 71
chore(ci): add verify-commits make target #138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
#!/bin/bash | ||
|
||
set -o errexit | ||
set -o pipefail | ||
set -o nounset | ||
|
||
function err() { | ||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2 | ||
} | ||
|
||
function info() { | ||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" | ||
} | ||
|
||
function verify_staging_sync() { | ||
local remote="${1}" | ||
local downstream_commit="${2}" | ||
local staging_dir="staging/${remote}" | ||
|
||
local outside_staging | ||
outside_staging="$(git show --name-only "${downstream_commit}" -- ":!${staging_dir}" ':!vendor :!manifests')" | ||
if [[ -n "${outside_staging}" ]]; then | ||
err "downstream staging commit ${downstream_commit} changes files outside of ${staging_dir}, vendor, and manifests directories" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One quick thought: would we necessary group an upstream-specific commit and the requisite manifest changes in the same commit? Grouping the staging tree changes + any vendor changes makes sense to me, especially in the reversion case, but still trying to wrap my head around whether we'd like to enforce that manifest changes need to also live in that same commit. Any ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The current code ensures that no staging commit touches a staging directory and a directory other than ./vendor or ./manifests. It doesn't enforce that changes to manifests occur in a staging commit, if that's the concern. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, my mistake likely glossed over too quickly - this implementation is fine with me. |
||
err "${outside_staging}" | ||
err "hint: factor out changes to these directories into a standalone commit" | ||
return 1 | ||
fi | ||
} | ||
|
||
function verify_downstream_only() { | ||
local downstream_commit="${1}" | ||
|
||
local inside_staging | ||
inside_staging="$(git show --name-only "${downstream_commit}" -- staging)" | ||
if [[ -n "${inside_staging}" ]]; then | ||
err "downstream non-staging commit ${downstream_commit} changes staging" | ||
err "${inside_staging}" | ||
err "only staging commits (i.e. from an upstream cherry-pick) may change staging" | ||
|
||
return 1 | ||
fi | ||
} | ||
|
||
function upstream_ref() { | ||
local downstream_commit="${1}" | ||
|
||
local log | ||
log="$(git log -n 1 "${downstream_commit}")" | ||
|
||
local -a upstream_repos | ||
mapfile -t upstream_repos < <(echo "${log}" | grep 'Upstream-repository:' | awk '{print $2}') | ||
|
||
local -a upstream_commits | ||
mapfile -t upstream_commits < <(echo "${log}" | grep 'Upstream-commit:' | awk '{print $2}') | ||
njhale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (( ${#upstream_repos[@]} < 1 && ${#upstream_commits[@]} < 1 )); then | ||
# no upstream commit referenced | ||
return 0 | ||
njhale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fi | ||
|
||
|
||
local invalid | ||
if (( ${#upstream_repos[@]} != 1 )); then | ||
err "downstream staging commit ${downstream_commit} references an invalid number of repos:" | ||
err "${upstream_repos[@]}" | ||
err "staging commits must reference a single upstream repo" | ||
invalid=true | ||
fi | ||
|
||
if (( ${#upstream_commits[@]} != 1 )); then | ||
err "downstream staging commit ${downstream_commit} references an invalid number of upstream commits:" | ||
err "${upstream_commits[@]}" | ||
err "staging commits must reference a single upstream commit" | ||
invalid=true | ||
fi | ||
|
||
if [[ "${invalid}" == true ]]; then | ||
return 1 | ||
fi | ||
|
||
if git branch -r --contains "${upstream_commits[0]}" | grep -vq "${upstream_repos[0]}/.*"; then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this cause problems if we need to revert commits upstream? I suppose in that case we need to explicitly revert the commit in order, but it could be a problem if we're on a release branch where that is not trivially possible There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
reverting a commit is additive -- it creates a new commit that undoes the changes of the target -- so in theory, the original commit should still exist (if I didn't misunderstand the concern). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, we just need to enforce that we're not tossing history and it's not a problem. I think this is fine I just wanted to call it out as a potential problem if upstream ever got borked. |
||
err "downstream staging commit ${downstream_commit} references upstream commit ${upstream_commits[0]} that doesn't exist in ${upstream_repos[0]}" | ||
err "staging commits must reference a repository containing the given upstream commit" | ||
return 1 | ||
fi | ||
|
||
echo "${upstream_repos[0]}" | ||
echo "${upstream_commits[0]}" | ||
} | ||
|
||
function fetch_remotes() { | ||
local -a remotes | ||
remotes=( | ||
'api' | ||
'operator-registry' | ||
'operator-lifecycle-manager' | ||
) | ||
for r in "${remotes[@]}"; do | ||
local url | ||
url="https://github.com/operator-framework/${r}.git" | ||
|
||
git remote add "${r}" "${url}" 2>/dev/null || git remote set-url "${r}" "${url}" | ||
git fetch -q "${r}" master | ||
done | ||
} | ||
|
||
function main() { | ||
fetch_remotes || { err "failed to fetch remotes" && exit 1; } | ||
|
||
local target_branch="${1:-master}" | ||
|
||
# get all commits we're introducing into the target branch | ||
local -a new_commits | ||
mapfile -t new_commits < <(git rev-list --no-merges HEAD "^${target_branch}") | ||
info "detected ${#new_commits[@]} commit(s) to verify" | ||
|
||
local -a sr | ||
local short | ||
for commit in "${new_commits[@]}"; do | ||
short="${commit:0:7}" | ||
info "verifying ${short}..." | ||
info "$(git log -n 1 "${commit}")" | ||
|
||
mapfile -t sr < <(upstream_ref "${commit}" || exit 1) | ||
if (( ${#sr[@]} < 2 )); then # the ref contains a tuple if the values were properly parsed from the commit message | ||
# couldn't find upstream cherry-pick reference in the commit message | ||
# assume it's downstream-only commit | ||
info "${short} does not reference upstream commit, verifying as downstream-only" | ||
verify_downstream_only "${commit}" || exit 1 | ||
else | ||
# found upstream cherry-pick reference in commit message | ||
# verify as an upstream sync | ||
info "${short} references upstream commit (${sr[*]}), verifying as upstream staging sync" | ||
verify_staging_sync "${sr[0]}" "${commit}" || exit 1 | ||
fi | ||
|
||
done | ||
} | ||
|
||
main "$@" |
Uh oh!
There was an error while loading. Please reload this page.