Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 1 | #!/bin/bash |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 2 | |
Karsten Tausche | f245a10 | 2021-03-19 10:14:39 +0100 | [diff] [blame] | 3 | # Copyright 2018-2021 Fairphone B.V. |
Borjan Tchakaloff | b32bf93 | 2018-10-31 21:20:20 +0100 | [diff] [blame] | 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | # |
| 17 | |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 18 | set -o nounset |
Karsten Tausche | 85c5f77 | 2021-08-24 18:36:11 +0200 | [diff] [blame] | 19 | set -o errexit |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 20 | |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 21 | # Merge partner security branches or release tags on AOSP projects |
Karsten Tausche | 0438468 | 2019-04-15 09:46:16 +0200 | [diff] [blame] | 22 | # |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 23 | # Use this script together with the repo tool in the root of the Android tree to |
| 24 | # merge partner branches or AOSP tags in supported projects. |
Karsten Tausche | 0438468 | 2019-04-15 09:46:16 +0200 | [diff] [blame] | 25 | # |
| 26 | # Following prerequisites need to be met: |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 27 | # * Run `fetch-and-push-partner` first to have up-to-date copies of related |
| 28 | # tags or branches in the (internal) projects that are referenced in your |
| 29 | # Android manifest. |
| 30 | # * Make sure to `repo init` and `repo sync` with a manifest that points to |
| 31 | # project states you want to merge on. The manifest must point to branches, |
| 32 | # not tags or fixed commits; otherwise merges cannot be pushed (as there |
| 33 | # would be no branch to push to). |
Karsten Tausche | 0438468 | 2019-04-15 09:46:16 +0200 | [diff] [blame] | 34 | # |
Maarten Derks | aa9ba26 | 2021-09-28 08:44:22 +0200 | [diff] [blame] | 35 | # Finally, use the following command line as reference to use the tool. For |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 36 | # merging release tags, set REF_IS_RELEASE_TAG=1 and AOSP_PARTNER_REF to the |
| 37 | # release tag. Then set REVIEW_TOPIC as needed and run first without |
Maarten Derks | aa9ba26 | 2021-09-28 08:44:22 +0200 | [diff] [blame] | 38 | # PUSH_TO_REMOTE, to check the merge locally before pushing. |
Karsten Tausche | 0438468 | 2019-04-15 09:46:16 +0200 | [diff] [blame] | 39 | # |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 40 | # Merging security branches: |
| 41 | # repo --no-pager forall -g aosp -vpc \ |
Maarten Derks | aa9ba26 | 2021-09-28 08:44:22 +0200 | [diff] [blame] | 42 | # 'PUSH_TO_REMOTE=1 REVIEW_TOPIC=... \ |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 43 | # "$(pwd)/vendor/fairphone/tools/bin/merge-partner-on-aosp" 2>&1' | \ |
| 44 | # tee merge-partner-on-aosp-$(date +"%Y-%m-%d_%H-%M-%S").log |
| 45 | # |
| 46 | # Merging release tags: |
| 47 | # repo --no-pager forall -g aosp -vpc \ |
| 48 | # 'PUSH_TO_REMOTE=1 REVIEW_TOPIC=... \ |
| 49 | # REF_IS_RELEASE_TAG=1 AOSP_PARTNER_REF=... |
| 50 | # "$(pwd)/vendor/fairphone/tools/bin/merge-partner-on-aosp" 2>&1' | \ |
Karsten Tausche | 0438468 | 2019-04-15 09:46:16 +0200 | [diff] [blame] | 51 | # tee merge-partner-on-aosp-$(date +"%Y-%m-%d_%H-%M-%S").log |
| 52 | # |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 53 | # |
| 54 | # Make sure to run this tool on projects with histories related to the ones |
| 55 | # you're merging (e.g., run it only on "aosp" repo groups, if the manifest is |
| 56 | # set up accordingly). |
Karsten Tausche | 0438468 | 2019-04-15 09:46:16 +0200 | [diff] [blame] | 57 | |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 58 | # The latest AOSP-Partner reference we want to merge |
Karsten Tausche | dd4c951 | 2020-04-20 12:58:17 +0200 | [diff] [blame] | 59 | AOSP_PARTNER_REF=${AOSP_PARTNER_REF:-security-aosp-pi-release} |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 60 | REF_IS_RELEASE_TAG=${REF_IS_RELEASE_TAG:-0} |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 61 | |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 62 | PUSH_TO_REMOTE=${PUSH_TO_REMOTE:-0} |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 63 | REVIEW_TOPIC=${REVIEW_TOPIC:-} |
Karsten Tausche | 4eece65 | 2021-03-19 10:28:25 +0100 | [diff] [blame] | 64 | WIP_CHANGES=${WIP_CHANGES:-1} |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 65 | |
| 66 | ALLOW_FAST_FORWARD=${ALLOW_FAST_FORWARD:-0} |
Karsten Tausche | 2a7c49b | 2020-04-21 17:01:20 +0200 | [diff] [blame] | 67 | # Allow having commits in the local history that are not merged yet on the |
| 68 | # remote. |
| 69 | ALLOW_LOCAL_COMMITS=${ALLOW_LOCAL_COMMITS:-0} |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 70 | |
| 71 | |
Karsten Tausche | f5e8c63 | 2021-10-04 16:05:01 +0200 | [diff] [blame] | 72 | # Check bash version requirements |
| 73 | # |
| 74 | # Required from version 4.4: |
| 75 | # * Initialize empty array correctly with `set -u` enabled. When resolving the |
| 76 | # variable as parameter (`some_command "${some_array[@]}"`), don't add an |
| 77 | # empty parameter if the array is empty. This breaks in bash < 4.4. |
| 78 | check_min_bash_version() { |
| 79 | local required_version="4.4" |
| 80 | local res |
| 81 | res=$(echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]} >= ${required_version}" | bc -l) |
| 82 | if [ "${res}" -eq 1 ]; then |
| 83 | return 0 |
| 84 | else |
| 85 | return 1 |
| 86 | fi |
| 87 | } |
| 88 | |
| 89 | if ! check_min_bash_version; then |
| 90 | echo "ERROR: Bash version 4.4 or higher is required." >&2 |
| 91 | fi |
| 92 | |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 93 | fast_forward_to_aosp_partner() { |
| 94 | local head_commit |
| 95 | head_commit="$1" |
| 96 | local on_branch |
| 97 | on_branch="$2" |
| 98 | echo "INFO: Fast-forwarding to the AOSP-Partner ref.…" |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 99 | if ! git merge --quiet --ff HEAD "${AOSP_PARTNER_REF}"; then |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 100 | echo "ERROR: Could not fast-forward to the AOSP-Partner ref. (${AOSP_PARTNER_REF})." >&2 |
| 101 | exit 1 |
| 102 | fi |
| 103 | # Check for last part: Is there a branch to push to? |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 104 | if [ "${on_branch}" = false ]; then |
| 105 | echo "ERROR: Fast-forward was successful but we are not on a branch. Investigate this \ |
| 106 | manually!" >&2 |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 107 | exit 1 |
| 108 | fi |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 109 | if [ 1 -eq "${PUSH_TO_REMOTE}" ]; then |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 110 | echo "INFO: Updating the remote…" |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 111 | if ! git push --quiet origin HEAD:"${target_branch}"; then |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 112 | echo "ERROR: Could not push the merged HEAD to the remote (${target_branch})." >&2 |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 113 | exit 1 |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 114 | fi |
| 115 | else |
Karsten Tausche | 3621d6b | 2020-04-20 13:04:37 +0200 | [diff] [blame] | 116 | echo "INFO: NOT pushing to the remote, PUSH_TO_REMOTE is not enabled." >&2 |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 117 | fi |
| 118 | # If the fast-forward succeeds, there is nothing more to do. |
| 119 | return 0 |
| 120 | } |
| 121 | |
Karsten Tausche | e5ae62b | 2021-08-24 16:10:38 +0200 | [diff] [blame] | 122 | # Check for "Text file busy" failure during `git commit` |
| 123 | # |
| 124 | # Sometimes `git merge` (or `git commit`) in repo fails apparently with a timing |
| 125 | # issue: |
| 126 | # > fatal: cannot exec '.git/hooks/commit-msg': Text file busy |
| 127 | # > Not committing merge; use 'git commit' to complete the merge. |
| 128 | # |
| 129 | # Detect such cases based on the merge/commit command output, because the exit |
| 130 | # codes don't reveal anything about it. |
| 131 | _check_parallel_commit_failed_and_retry() { |
| 132 | local output="$1" |
| 133 | local failure_msg="fatal: cannot exec '.git/hooks/commit-msg': Text file busy" |
| 134 | local num_tries=5 |
| 135 | for _ in $(seq "${num_tries}"); do |
| 136 | if ! echo "${output}" | grep -qFe "${failure_msg}"; then |
| 137 | # If getting here but but failure message doesn't match, something |
| 138 | # else went wrong during the merge. A merge conflict for example. |
| 139 | return 1 |
| 140 | fi |
| 141 | echo "WARNING: Commit failed due to 'Text file busy'. Retrying..." |
| 142 | local ret_val=0 |
Karsten Tausche | f1a01cd | 2021-08-26 18:09:32 +0200 | [diff] [blame] | 143 | # core.editor=true: see comment in _merge_commit_safe |
| 144 | output=$(git -c core.editor=true commit --quiet 2>&1) || ret_val=$? |
Karsten Tausche | e5ae62b | 2021-08-24 16:10:38 +0200 | [diff] [blame] | 145 | # Propagate error output, in case there is any. |
Karsten Tausche | 8485f29 | 2021-08-25 21:40:58 +0200 | [diff] [blame] | 146 | if [ -n "${output}" ]; then |
| 147 | echo "${output}" >&2 |
| 148 | fi |
Karsten Tausche | e5ae62b | 2021-08-24 16:10:38 +0200 | [diff] [blame] | 149 | if [ "${ret_val}" -eq 0 ]; then |
| 150 | # All good then, commit succeeded. |
| 151 | echo "INFO: Resolved 'Text file busy' issue with additional 'git commit' attempt." |
| 152 | return 0 |
| 153 | fi |
| 154 | sleep 0.5s |
| 155 | done |
| 156 | echo "ERROR: 'Text file busy' error persists after ${num_tries} commit attempts." >&2 |
| 157 | return 1 |
| 158 | } |
| 159 | |
Karsten Tausche | f1a01cd | 2021-08-26 18:09:32 +0200 | [diff] [blame] | 160 | # Perform a `git merge` and make sure it works |
| 161 | # |
| 162 | # We ran into various issues with scripting `git merge`; therefore it's moved to |
| 163 | # its very own function now. |
| 164 | _merge_commit_safe() { |
| 165 | # Note: Commit message, and pre/post processing |
| 166 | # We're NOT using `-m ...` or `--no-edit` at the moment, because it breaks |
| 167 | # in various ways: Not dropping comments within the message body (e.g., |
| 168 | # from GPG verification), not adding an empty line after the subject when |
| 169 | # merging annotated tags, not adding an empty line before the Change-Id. |
| 170 | # Solution: |
| 171 | # Rely on git and its hooks to set the commit message. Also, set config |
| 172 | # `core.editor=true`: This has the same effect as `--no-edit`, only that |
| 173 | # it doesn't break in the ways listed above. |
| 174 | |
| 175 | # Checkout a local branch, to make the subject line more expressive than |
| 176 | # "merge into HEAD". Cleanup the local branch first in case it's already |
| 177 | # there. |
| 178 | git branch --quiet -D "${target_branch}" 2>/dev/null || true |
| 179 | git checkout -b "${target_branch}" |
| 180 | local merge_output |
| 181 | local merge_result=0 |
| 182 | merge_output=$(git -c core.editor=true merge \ |
| 183 | --quiet --edit --log --no-ff "${AOSP_PARTNER_REF}" 2>&1) \ |
| 184 | || merge_result=$? |
| 185 | if [ -n "${merge_output}" ]; then |
| 186 | echo "${merge_output}" >&2 |
| 187 | fi |
| 188 | if [ 0 -ne ${merge_result} ]; then |
| 189 | merge_result=0 |
| 190 | _check_parallel_commit_failed_and_retry "${merge_output}" || merge_result=$? |
| 191 | fi |
| 192 | # Cleanup again. But can't do is in case we're in a middle of a merge |
| 193 | # conflict. The user needs to clean up manually then. |
| 194 | if [ 0 -eq ${merge_result} ]; then |
| 195 | git checkout --detach |
| 196 | git branch --quiet -D "${target_branch}" |
| 197 | fi |
| 198 | return ${merge_result} |
| 199 | } |
| 200 | |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 201 | # Merge or fast-forward the AOSP-Partner reference on HEAD. |
| 202 | # Fast-forward is only done if allowed. It would be pushed directly to the |
| 203 | # origin. Merges are pushed for review. If we are not actually on a branch, the |
| 204 | # merge/fast-forward is done anyways and the repo is left as it is afterwards. |
| 205 | merge_aosp_partner_on_head() { |
| 206 | local head_commit |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 207 | head_commit="${1:-}" |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 208 | local target_branch |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 209 | target_branch="${2:-}" |
| 210 | if [ -z "${head_commit}" ] || [ -z "${target_branch}" ]; then |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 211 | echo "USAGE ERROR: merge_aosp_partner_on_head <head_commit> <target_branch>" >&2 |
| 212 | exit 1 |
| 213 | fi |
| 214 | can_fast_forward=true |
| 215 | on_branch=true |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 216 | git merge-base --is-ancestor HEAD "${AOSP_PARTNER_REF}" || can_fast_forward=false |
| 217 | git show-ref --verify "refs/remotes/origin/${target_branch}" 1>/dev/null || on_branch=false |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 218 | |
| 219 | # If enabled, check if we can fast-forward. |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 220 | if [ 1 -eq "${ALLOW_FAST_FORWARD}" ] && [ "${can_fast_forward}" = true ]; then |
| 221 | fast_forward_to_aosp_partner "${head_commit}" "${on_branch}" |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 222 | return 0 |
| 223 | fi |
| 224 | |
| 225 | # Fast-forward is not enabled or is not possible. So try to merge! |
| 226 | echo "INFO: Merging the latest AOSP-Partner ref. (${AOSP_PARTNER_REF})…" |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 227 | if [ ${can_fast_forward} = true ]; then |
| 228 | echo "INFO: Could fast-forward to the AOSP-Partner ref., but will still create a merge \ |
| 229 | commit." |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 230 | fi |
| 231 | old_head=$(git rev-parse HEAD) |
Karsten Tausche | f1a01cd | 2021-08-26 18:09:32 +0200 | [diff] [blame] | 232 | # Perform the actual `git merge` -- including various workarounds. |
| 233 | if ! _merge_commit_safe; then |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 234 | echo "ERROR: Could not merge the AOSP-Partner ref. (${AOSP_PARTNER_REF})." >&2 |
| 235 | exit 1 |
| 236 | fi |
Karsten Tausche | e5ae62b | 2021-08-24 16:10:38 +0200 | [diff] [blame] | 237 | new_head=$(git rev-parse HEAD) |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 238 | if [ "_${old_head}" = "_${new_head}" ]; then |
Karsten Tausche | bc18597 | 2019-08-23 11:50:48 +0200 | [diff] [blame] | 239 | echo "INFO: AOSP-Partner ref. is already merged. Nothing to do." |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 240 | echo "DEBUG: This case should have been caught earlier (?)" |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 241 | return 0 |
| 242 | fi |
Karsten Tausche | 7a0380e | 2020-04-20 16:34:02 +0200 | [diff] [blame] | 243 | echo "INFO: Successfully merged the AOSP-Partner ref." >&2 |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 244 | if [ "${on_branch}" = false ]; then |
Karsten Tausche | f96f11b | 2019-04-12 23:39:29 +0200 | [diff] [blame] | 245 | if git diff HEAD^1..HEAD --exit-code >/dev/null; then |
| 246 | echo "WARNING: Merge was successful but we are not on a branch! \ |
| 247 | However, the merge is empty so can be ignored." >&2 |
| 248 | else |
| 249 | echo "ERROR: Merge was successful but we are not on a branch. This \ |
| 250 | merge needs to be pushed!" >&2 |
| 251 | fi |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 252 | exit 1 |
| 253 | fi |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 254 | if [ 1 -eq "${PUSH_TO_REMOTE}" ]; then |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 255 | echo "INFO: Pushing for review…" |
Karsten Tausche | f5e8c63 | 2021-10-04 16:05:01 +0200 | [diff] [blame] | 256 | local topic_params=() |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 257 | if [ "${REVIEW_TOPIC}" ]; then |
Karsten Tausche | f5e8c63 | 2021-10-04 16:05:01 +0200 | [diff] [blame] | 258 | topic_params=(-o "topic=${REVIEW_TOPIC}") |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 259 | fi |
Karsten Tausche | 4eece65 | 2021-03-19 10:28:25 +0100 | [diff] [blame] | 260 | local wip_option="" |
| 261 | if [ "${WIP_CHANGES}" -eq 1 ]; then |
| 262 | wip_option="%wip" |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 263 | fi |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 264 | local ret_val=0 |
Karsten Tausche | f5e8c63 | 2021-10-04 16:05:01 +0200 | [diff] [blame] | 265 | git push --quiet origin "HEAD:refs/for/${target_branch}${wip_option}" "${topic_params[@]}" \ |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 266 | || ret_val=$? |
| 267 | if [ "${ret_val}" -ne 0 ]; then |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 268 | echo "ERROR: Could not push the merged HEAD to the remote (${target_branch})." >&2 |
| 269 | exit 1 |
| 270 | fi |
| 271 | else |
Karsten Tausche | 3621d6b | 2020-04-20 13:04:37 +0200 | [diff] [blame] | 272 | echo "INFO: NOT pushing to the remote, PUSH_TO_REMOTE is not enabled." >&2 |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 273 | fi |
| 274 | } |
| 275 | |
Karsten Tausche | e8645ff | 2021-09-28 16:53:26 +0200 | [diff] [blame] | 276 | # Check if a commit sha1 exists locally |
| 277 | # |
| 278 | # Return 0 if the supplied commit exists, 1 otherwise. |
| 279 | _git_commit_exists() { |
| 280 | local commit=$1 |
| 281 | # Suppress error output of cat-file in case the commit does not exist. |
| 282 | if git cat-file -e "${commit}" 2>/dev/null; then |
| 283 | return 0; |
| 284 | fi |
| 285 | return 1 |
| 286 | } |
| 287 | |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 288 | # Git doesn't allow to check if a specific revision is shallow, but "partially |
| 289 | # shallow" repositories are very common in a repo tree and "re-unshallowing" is |
| 290 | # expensive. |
| 291 | _is_shallow_revision() { |
| 292 | local revision_to_check="$1" |
| 293 | |
| 294 | if [ "$(git rev-parse --is-shallow-repository)" = "false" ]; then |
| 295 | return 1 |
| 296 | fi |
| 297 | |
Karsten Tausche | e8645ff | 2021-09-28 16:53:26 +0200 | [diff] [blame] | 298 | if ! _git_commit_exists "${revision_to_check}"; then |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 299 | # We don't have the commit at all in the local repository, so it's also |
| 300 | # not shallow... |
| 301 | return 0 |
| 302 | fi |
| 303 | |
| 304 | if [ ! -f .git/shallow ]; then |
| 305 | echo "WARNING: .git/shallow missing on a shallow repo?!" |
| 306 | # Unexpected case -- assume shallow, as reported by git rev-parse above. |
| 307 | return 0 |
| 308 | fi |
| 309 | |
| 310 | for shallow_rev in $(cat .git/shallow); do |
| 311 | if git merge-base --is-ancestor "${shallow_rev}" "${revision_to_check}"; then |
| 312 | # We have a shallow revision in our history -- we're shallow. |
| 313 | return 0 |
| 314 | fi |
| 315 | done |
| 316 | # Clearly not shallow |
| 317 | return 1 |
| 318 | } |
| 319 | |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 320 | |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 321 | # Gather some information about remote and local refs and revisions |
| 322 | if [ "${REF_IS_RELEASE_TAG}" -eq 1 ]; then |
| 323 | # Get the actual commit object, not the annotated tag |
| 324 | dereferenced_partner_ref="refs/tags/${AOSP_PARTNER_REF}^{}" |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 325 | else |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 326 | # Nothing to dereference on branches |
| 327 | dereferenced_partner_ref="${AOSP_PARTNER_REF}" |
Karsten Tausche | 2a7c49b | 2020-04-21 17:01:20 +0200 | [diff] [blame] | 328 | fi |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 329 | aosp_partner_ref_list=$(git ls-remote --exit-code origin "${dereferenced_partner_ref}" 2>/dev/null) |
Karsten Tausche | 1596bc4 | 2018-08-15 13:27:45 +0200 | [diff] [blame] | 330 | case $? in |
| 331 | 0) |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 332 | # Success |
Karsten Tausche | 1596bc4 | 2018-08-15 13:27:45 +0200 | [diff] [blame] | 333 | ;; |
| 334 | 2) |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 335 | echo "ERROR: The AOSP-Partner ref does not exist on remote (${AOSP_PARTNER_REF})." >&2 |
| 336 | exit 1 |
Karsten Tausche | 1596bc4 | 2018-08-15 13:27:45 +0200 | [diff] [blame] | 337 | ;; |
| 338 | *) |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 339 | echo "ERROR: ls-remote on origin failed." >&2 |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 340 | exit 1 |
Karsten Tausche | 1596bc4 | 2018-08-15 13:27:45 +0200 | [diff] [blame] | 341 | ;; |
| 342 | esac |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 343 | aosp_partner_ref_commit=$(echo "${aosp_partner_ref_list}" | awk '{ print $1 }') |
| 344 | head_commit=$(git rev-parse HEAD) |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 345 | |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 346 | |
| 347 | # Check if the current HEAD and the target reference already point to the same |
| 348 | # commit. In that case, we can skip all further fetch and merge steps. |
| 349 | if [ "_${head_commit}" = "_${aosp_partner_ref_commit}" ]; then |
| 350 | echo "INFO: HEAD and AOSP-Partner reference point to the same commit. Nothing to do." |
Karsten Tausche | 356b7a2 | 2018-08-14 13:08:26 +0200 | [diff] [blame] | 351 | exit 0 |
Borjan Tchakaloff | 7fc801c | 2018-08-13 15:21:29 +0200 | [diff] [blame] | 352 | fi |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 353 | |
| 354 | target_branch="${REPO_RREV}" |
| 355 | # Drop the refs/heads/ prefix if it exists. |
| 356 | target_branch="${REPO_RREV#refs/heads/}" |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 357 | ls_remote_ret_val=0 |
| 358 | target_branch_commit=$(git ls-remote origin "refs/heads/${target_branch}" 2>/dev/null) \ |
| 359 | || ls_remote_ret_val=$? |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 360 | target_branch_commit=$(echo "${target_branch_commit}" | awk '{ print $1 }') |
| 361 | if [ "${ls_remote_ret_val}" -ne 0 ]; then |
| 362 | echo "ERROR: ls-remote on origin failed." >&2 |
| 363 | exit 1 |
| 364 | fi |
| 365 | if [ -z "${target_branch_commit}" ]; then |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 366 | echo "ERROR: Could not determine the remote revision of the target branch. Is this project " \ |
| 367 | "pointing to a branch?" >&2 |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 368 | exit 1 |
| 369 | fi |
| 370 | if [ "${target_branch_commit}" != "${head_commit}" ]; then |
| 371 | if [ "${ALLOW_LOCAL_COMMITS}" -eq 1 ]; then |
| 372 | echo "INFO: Continuing on top of local commits." |
| 373 | else |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 374 | echo "ERROR: Aborting as we are not on the target branch and ALLOW_LOCAL_COMMITS is not " \ |
| 375 | "enabled." >&2 |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 376 | exit 1 |
| 377 | fi |
| 378 | fi |
| 379 | |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 380 | # Make sure we have the target branch history locally |
| 381 | # We need it, because merging and conflict resolution without the (shared) |
| 382 | # histories would not work well. |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 383 | if _is_shallow_revision "${target_branch_commit}"; then |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 384 | if ! git fetch --no-tags --quiet --unshallow origin "${target_branch}"; then |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 385 | echo "ERROR: Could not unshallow the target branch." >&2 |
| 386 | exit 1 |
| 387 | fi |
| 388 | fi |
| 389 | |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 390 | # Now that we're unshallow on the current branch, check if the new revision is |
| 391 | # already part of our history. With checking that early on we can skip all |
| 392 | # further logic. |
Karsten Tausche | e8645ff | 2021-09-28 16:53:26 +0200 | [diff] [blame] | 393 | if _git_commit_exists "${aosp_partner_ref_commit}" \ |
| 394 | && git merge-base --is-ancestor "${aosp_partner_ref_commit}" HEAD; then |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 395 | echo "INFO: AOSP-Partner ref. is already merged. Nothing to do." |
| 396 | exit 0 |
| 397 | fi |
| 398 | |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 399 | # Make sure we have the AOSP-Partner reference locally. |
| 400 | if [ "${REF_IS_RELEASE_TAG}" -eq 1 ]; then |
| 401 | echo "INFO: Fetching AOSP-Partner tag from origin (${AOSP_PARTNER_REF})…" |
| 402 | _fetch_ref_spec="refs/tags/${AOSP_PARTNER_REF}" |
| 403 | else |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 404 | echo "INFO: Creating local branch for AOSP-Partner ref. fetched from origin " \ |
| 405 | "(${AOSP_PARTNER_REF})…" |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 406 | _fetch_ref_spec="${AOSP_PARTNER_REF}" |
| 407 | fi |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 408 | # Need to check if again if it's shallow. According to the checks above, the |
| 409 | # AOSP Partner ref is for sure not part of the current history, so it might |
| 410 | # still be shallow. |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 411 | unshallow_param=() |
Karsten Tausche | 96fffbd | 2021-08-25 21:56:11 +0200 | [diff] [blame] | 412 | if _is_shallow_revision "${aosp_partner_ref_commit}"; then |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 413 | unshallow_param=("--unshallow") |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 414 | fi |
Karsten Tausche | 3cd8901 | 2021-08-24 15:09:21 +0200 | [diff] [blame] | 415 | ret_val=0 |
| 416 | git fetch --no-tags --quiet "${unshallow_param[@]}" origin "${_fetch_ref_spec}:${_fetch_ref_spec}" \ |
| 417 | || ret_val=$? |
| 418 | if [ "${ret_val}" -ne 0 ]; then |
Karsten Tausche | badb7f1 | 2021-04-21 16:10:59 +0200 | [diff] [blame] | 419 | echo "ERROR: Could not fetch the AOSP-Partner ref." >&2 |
| 420 | exit 1 |
| 421 | fi |
| 422 | |
| 423 | merge_aosp_partner_on_head "${head_commit}" "${target_branch}" |