Skip to content

Commit 84e208a

Browse files
Merge pull request #351 from timflannagan/scripts/add-sync-script
Add a more robust script for automating the upstream/downstream sync process
2 parents eb1026a + 8a80bf9 commit 84e208a

File tree

5 files changed

+122
-17
lines changed

5 files changed

+122
-17
lines changed

Diff for: Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,10 @@ crc: crc-start crc-build crc-deploy
186186
clean:
187187
rm -rf bin
188188

189+
.PHONY: sync
190+
sync:
191+
./scripts/sync.sh
192+
189193
.PHONY: help
190194
help: ## Display this help.
191195
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
192-

Diff for: scripts/common.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#! /bin/bash
2+
3+
export KNOWN_GENERATED_PATHS=(':!vendor' ':!pkg/manifests' ':!manifests' ':!go.sum' ':!go.mod')
4+
# TODO(tflannag): This is hacky but works in the current setup.
5+
export ROOT_GENERATED_PATHS=( "vendor" "pkg/manifests" "manifests" "go.mod" "go.sum" )
6+
export UPSTREAM_REMOTES=("api" "operator-registry" "operator-lifecycle-manager")

Diff for: scripts/sync.sh

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#! /bin/bash
2+
3+
set -o nounset
4+
set -o errexit
5+
set -o pipefail
6+
7+
ROOT_DIR=$(dirname "${BASH_SOURCE[0]}")/..
8+
# shellcheck disable=SC1091
9+
source "${ROOT_DIR}/scripts/common.sh"
10+
11+
SYNC_BRANCH_NAME="sync-$(printf '%(%Y-%m-%d)T\n' -1)"
12+
13+
add_remote() {
14+
echo "Adding upstream remotes if they don't already exist"
15+
git config remote.api.url >&- || git remote add api https://github.com/operator-framework/api
16+
git config remote.operator-registry.url >&- || git remote add api https://github.com/operator-framework/operator-registry
17+
git config remote.operator-lifecycle-manager.url >&- || git remote add api https://github.com/operator-framework/operator-lifecycle-manager
18+
git config remote.upstream.url >&- || git remote add upstream https://github.com/openshift/operator-framework-olm
19+
}
20+
21+
fetch_remote() {
22+
git fetch upstream
23+
24+
echo "Fetching upstream remotes"
25+
for remote in "${UPSTREAM_REMOTES[@]}"; do
26+
git fetch "$remote"
27+
done
28+
}
29+
30+
new_candidate_branch() {
31+
echo "Creating a sync branch if it doesn't already exist"
32+
git checkout -b "$SYNC_BRANCH_NAME" upstream/master 2>/dev/null || git checkout "$SYNC_BRANCH_NAME"
33+
}
34+
35+
candidates() {
36+
# TODO: add support for only collecting a single remote.
37+
echo "Collecting all upstream commits since last sync"
38+
for remote in "${UPSTREAM_REMOTES[@]}"; do
39+
"${ROOT_DIR}"/scripts/sync_get_candidates.sh "$remote"
40+
done
41+
}
42+
43+
pop() {
44+
echo "Applying all upstream commit candidates"
45+
for remote in "${UPSTREAM_REMOTES[@]}"; do
46+
"${ROOT_DIR}"/scripts/sync_pop_candidate.sh "$remote" -a
47+
done
48+
}
49+
50+
check_local_branch_commit_diff() {
51+
commits_ahead=$(git rev-list upstream/master..HEAD | wc -l)
52+
53+
if [[ "$commits_ahead" -gt 1 ]]; then
54+
# TODO: automatically open a new pull request here.
55+
echo "The local sync branch is $commits_ahead commits ahead of the upstream/master branch"
56+
else
57+
echo "No sync PR is needed as the upstream/master branch is up-to-date"
58+
fi
59+
}
60+
61+
main() {
62+
add_remote
63+
fetch_remote
64+
new_candidate_branch
65+
candidates
66+
pop
67+
check_local_branch_commit_diff
68+
}
69+
70+
main

Diff for: scripts/sync_pop_candidate.sh

+36-15
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#!/usr/bin/env bash
22

3-
cph=$(git rev-list -n 1 CHERRY_PICK_HEAD 2> /dev/null)
4-
53
set -o errexit
64
set -o pipefail
75

6+
ROOT_DIR=$(dirname "${BASH_SOURCE[@]}")/..
7+
# shellcheck disable=SC1091
8+
source "${ROOT_DIR}/scripts/common.sh"
9+
810
pop_all=true
911

1012
set +u
@@ -32,20 +34,37 @@ function pop() {
3234
fi
3335
printf 'popping: %s\n' "${rc}"
3436

35-
if [[ ! $cph ]]; then
36-
git cherry-pick --allow-empty --keep-redundant-commits -Xsubtree="${subtree_dir}" "${rc}"
37-
else
38-
if [[ $cph != "${rc}" ]]; then
39-
printf 'unexpected CHERRY_PICK_HEAD:\ngot %s\nexpected: %s\n' "${cph}" "${rc}"
40-
exit
41-
fi
42-
printf 'cherry-pick in progress for %s\n' "${cph}"
43-
git add .
37+
if ! git cherry-pick --allow-empty --keep-redundant-commits -Xsubtree="${subtree_dir}" "${rc}"; then
38+
# Always blast away the vendor directory given OLM/registry still commit it into source control.
39+
git rm -rf "${subtree_dir}"/vendor 2>/dev/null || true
40+
41+
num_conflicts=$(git diff --name-only --diff-filter=U --relative | wc -l)
42+
while [[ $num_conflicts != 0 ]] ; do
43+
file=$(git diff --name-only --diff-filter=U --relative)
44+
45+
if [[ $file == *"go.mod"* ]]; then
46+
git diff "${subtree_dir}"/go.mod
47+
48+
git checkout --theirs "${subtree_dir}"/go.mod
49+
pushd "${subtree_dir}"
50+
go mod tidy
51+
git add go.mod go.sum
52+
popd
53+
else
54+
git checkout --theirs "$file"
55+
git diff "$file"
56+
git add "$file"
57+
fi
58+
59+
num_conflicts=$(git diff --name-only --diff-filter=U --relative | wc -l)
60+
echo "Number of merge conflicts remaining: $num_conflicts"
61+
done
4462

4563
if [[ -z $(git status --porcelain) ]]; then
4664
git commit --allow-empty
4765
else
48-
git cherry-pick --continue
66+
echo "Current cherry pick status: $(git status --porcelain)"
67+
git -c core.editor=true cherry-pick --continue
4968
fi
5069
fi
5170

@@ -56,19 +75,21 @@ function pop() {
5675
# 4. Remove from cherrypick set
5776
make vendor
5877
make manifests
59-
git add .
78+
git add "${subtree_dir}" "${ROOT_GENERATED_PATHS[@]}"
6079
git status
6180
git commit --amend --allow-empty --no-edit --trailer "Upstream-repository: ${remote}" --trailer "Upstream-commit: ${rc}"
6281

6382
tmp_set=$(mktemp)
6483
tail -n +2 "${cherrypick_set}" > "${tmp_set}"; cat "${tmp_set}" > "${cherrypick_set}"
6584

66-
(( --remaining ))
85+
# Note: handle edge case where there's zero remaining to avoid
86+
# returning a non-zero exit code.
87+
(( --remaining )) || true
6788
printf '%d picks remaining (pop_all=%s)\n' "${remaining}" "${pop_all}"
6889

6990
if [[ $pop_all == 'true' ]] && (( remaining > 0 )); then
7091
pop
7192
fi
7293
}
7394

74-
pop
95+
pop

Diff for: scripts/verify_commits.sh

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ set -o errexit
44
set -o pipefail
55
set -o nounset
66

7+
ROOT_DIR=$(dirname "${BASH_SOURCE[@]}")/..
8+
# shellcheck disable=SC1091
9+
source "${ROOT_DIR}/scripts/common.sh"
10+
711
function err() {
812
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
913
}
@@ -18,7 +22,7 @@ function verify_staging_sync() {
1822
local staging_dir="staging/${remote}"
1923

2024
local outside_staging
21-
outside_staging="$(git show --name-only "${downstream_commit}" -- ":!${staging_dir}" ':!vendor' ':!manifests' ':!go.sum' ':!go.mod')"
25+
outside_staging="$(git show --name-only "${downstream_commit}" -- ":!${staging_dir}" "${KNOWN_GENERATED_PATHS[@]}")"
2226
if [[ -n "${outside_staging}" ]]; then
2327
err "downstream staging commit ${downstream_commit} changes files outside of ${staging_dir}, vendor, and manifests directories"
2428
err "${outside_staging}"
@@ -136,3 +140,4 @@ function main() {
136140
}
137141

138142
main "$@"
143+
test $? -gt 0 || echo "Successfully validated all commits"

0 commit comments

Comments
 (0)