| #!/bin/sh |
| |
| # Copyright 2018 Fairphone B.V. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| # There are only a limited amount of valid situations: |
| # 1- The project is not pointing to AOSP, ignore it; |
| # 2- The AOSP-Partner reference did not move from the AOSP reference; |
| # 3- The AOSP-Partner reference is a direct child of the AOSP reference, the |
| # project can be fast-forwarded to it; |
| # 4- The AOSP-Partner reference is *not* a direct child of the AOSP reference, |
| # the AOSP-Partner has to be merged in and the new commit submitted for |
| # review. |
| |
| # The latest AOSP reference we want to merge on top of |
| AOSP_REF=${AOSP_REF:-android-7.1.2_r36} |
| # The latest AOSP-Partner reference we want to merge |
| AOSP_PARTNER_REF=${AOSP_PARTNER_REF:-security-aosp-nyc-mr2-release} |
| # Current Security Patch Level from the AOSP-Partner reference |
| AOSP_PARTNER_SPL=${AOSP_PARTNER_SPL:-2018-05-05} |
| |
| AOSP_BASE_URL=https://android.googlesource.com |
| |
| CAF_REF=${CAF_REF:-LA.UM.5.8.r1-02900-8x98.0} |
| INTEGRATION_BRANCH=${INTEGRATION_BRANCH:-int/n/fp2} |
| STAGING_BRANCH=${STAGING_BRANCH:-staging/n/fp2} |
| |
| PUSH_TO_REMOTE=${PUSH_TO_REMOTE:-0} |
| REVIEW_TOPIC=${REVIEW_TOPIC:-} |
| PUBLIC_REVIEW=${PUBLIC_REVIEW:-0} |
| |
| ALLOW_FAST_FORWARD=${ALLOW_FAST_FORWARD:-0} |
| |
| |
| fast_forward_to_aosp_partner() { |
| local head_commit |
| head_commit="$1" |
| local on_branch |
| on_branch="$2" |
| echo "INFO: Fast-forwarding to the AOSP-Partner ref.…" |
| git merge --quiet --ff HEAD ${AOSP_PARTNER_REF} |
| if test $? -ne 0; then |
| echo "ERROR: Could not fast-forward to the AOSP-Partner ref. (${AOSP_PARTNER_REF})." >&2 |
| exit 1 |
| fi |
| # Check for last part: Is there a branch to push to? |
| if test ${on_branch} = false; then |
| echo "ERROR: Fast-forward was successful but we are not on a branch. Investigate this manually!" >&2 |
| exit 1 |
| fi |
| if test 1 -eq ${PUSH_TO_REMOTE}; then |
| echo "INFO: Updating the remote…" |
| git push --quiet origin HEAD:${target_branch} |
| if test $? -ne 0; then |
| echo "ERROR: Could not push the merged HEAD to the remote (${target_branch})." >&2 |
| exit 1 |
| fi |
| else |
| echo "INFO: PUSH_TO_REMOTE is not set to 1. Rolling back to the previous ref.…" |
| # Abandon the change |
| git checkout --quiet ${head_commit} |
| fi |
| # If the fast-forward succeeds, there is nothing more to do. |
| return 0 |
| } |
| |
| # Merge or fast-forward the AOSP-Partner reference on HEAD. |
| # Fast-forward is only done if allowed. It would be pushed directly to the |
| # origin. Merges are pushed for review. If we are not actually on a branch, the |
| # merge/fast-forward is done anyways and the repo is left as it is afterwards. |
| merge_aosp_partner_on_head() { |
| local head_commit |
| head_commit="$1" |
| local target_branch |
| target_branch="$2" |
| if [ -z "${head_commit}" -o -z "${target_branch}" ]; then |
| echo "USAGE ERROR: merge_aosp_partner_on_head <head_commit> <target_branch>" >&2 |
| exit 1 |
| fi |
| can_fast_forward=true |
| on_branch=true |
| git merge-base --is-ancestor HEAD ${AOSP_PARTNER_REF} || can_fast_forward=false |
| git show-ref --verify refs/remotes/origin/${target_branch} 1>/dev/null || on_branch=false |
| |
| # If enabled, check if we can fast-forward. |
| if test 1 -eq ${ALLOW_FAST_FORWARD} -a ${can_fast_forward} = true; then |
| fast_forward_to_aosp_partner ${head_commit} ${on_branch} |
| return 0 |
| fi |
| |
| # Fast-forward is not enabled or is not possible. So try to merge! |
| echo "INFO: Merging the latest AOSP-Partner ref. (${AOSP_PARTNER_REF})…" |
| if test ${can_fast_forward} = true; then |
| echo "INFO: Could fast-forward to the AOSP-Partner ref., but will still create a merge commit." |
| fi |
| old_head=$(git rev-parse HEAD) |
| merge_result=0 |
| git merge --quiet -m "Merge the ${AOSP_PARTNER_SPL} SPL branch from AOSP-Partner" --log --no-ff ${AOSP_PARTNER_REF} || merge_result=$? |
| new_head=$(git rev-parse HEAD) |
| if test 0 -ne ${merge_result}; then |
| echo "ERROR: Could not merge the AOSP-Partner ref. (${AOSP_PARTNER_REF})." >&2 |
| exit 1 |
| fi |
| if test "_${old_head}" = "_${new_head}"; then |
| echo "INFO: Security branch is already merged. Nothing to do." |
| return 0 |
| fi |
| # Amend the commit message to get the Change-Id line |
| gitdir=$(git rev-parse --git-dir) |
| scp -p -P 29418 review.fairphone.software:hooks/commit-msg ${gitdir}/hooks/ |
| git commit --quiet --amend --no-edit |
| if test ${on_branch} = false; then |
| echo "ERROR: Merge was successful but we are not on a branch. Investigate this manually!" >&2 |
| exit 1 |
| fi |
| if test 1 -eq ${PUSH_TO_REMOTE}; then |
| echo "INFO: Pushing for review…" |
| local topic_postfix="" |
| if [ "${REVIEW_TOPIC}" ]; then |
| topic_postfix="/${REVIEW_TOPIC}" |
| fi |
| local reference="drafts" |
| if [ "${PUBLIC_REVIEW}" -eq 1 ]; then |
| reference="for" |
| fi |
| git push --quiet origin HEAD:refs/${reference}/${target_branch}${topic_postfix} |
| if test $? -ne 0; then |
| echo "ERROR: Could not push the merged HEAD to the remote (${target_branch})." >&2 |
| exit 1 |
| fi |
| else |
| echo "INFO: Rolling back to the previous ref. (abandoning $(git rev-parse HEAD))…" |
| # Abandon the change |
| git checkout --quiet ${head_commit} |
| fi |
| } |
| |
| |
| is_shallow=0 |
| |
| head_commit=$(git rev-parse HEAD) |
| aosp_ref_commit=$(git rev-parse --quiet --verify "${AOSP_REF}^{commit}") |
| integration_branch_commit=$(git rev-parse --quiet --verify "remotes/origin/${INTEGRATION_BRANCH}") |
| staging_branch_commit=$(git rev-parse --quiet --verify "remotes/origin/${STAGING_BRANCH}") |
| |
| |
| # Make sure we are on the integration or staging branch or on CAF |
| current_known_branch="" |
| if test "_${head_commit}" = "_${integration_branch_commit}"; then |
| echo "INFO: Currently pointing to the integration branch." |
| current_known_branch="${INTEGRATION_BRANCH}" |
| elif test "_${head_commit}" = "_${staging_branch_commit}"; then |
| echo "INFO: Currently pointing to the staging branch." |
| current_known_branch="${STAGING_BRANCH}" |
| elif test "_${head_commit}" = "_$(git rev-parse --quiet --verify "${CAF_REF}^{commit}")"; then |
| echo "INFO: Pointing to the CAF ref." |
| current_known_branch="${CAF_REF}" |
| else |
| echo "ERROR: HEAD is not pointing to the integration or staging branch, or CAF (${INTEGRATION_BRANCH}, ${STAGING_BRANCH}, ${CAF_REF})." >&2 |
| exit 1 |
| fi |
| |
| # Make sure we are aware of the latest AOSP reference |
| if test -z "${aosp_ref_commit}"; then |
| # If the project is a prebuilt one, we might have a shallow checkout. |
| # Double check the reference from the remote. |
| git fetch --no-tags --quiet origin ${AOSP_REF} |
| aosp_ref_commit=$(git rev-parse --quiet --verify 'FETCH_HEAD^{commit}') |
| if test -z "${aosp_ref_commit}"; then |
| echo "ERROR: Cannot find the latest AOSP ref. (${AOSP_REF})." >&2 |
| exit 1 |
| else |
| is_shallow=1 |
| echo "INFO: Current checkout is shallow." |
| fi |
| fi |
| |
| # Check if we have the partner ref in the repository |
| git ls-remote --exit-code origin ${AOSP_PARTNER_REF} > /dev/null 2>&1 |
| case $? in |
| 0) |
| echo "INFO: Creating local branch for AOSP-Partner ref. fetched from origin (${AOSP_PARTNER_REF})…" |
| git fetch --no-tags --quiet origin ${AOSP_PARTNER_REF}:${AOSP_PARTNER_REF} |
| if test $? -ne 0; then |
| echo "ERROR: Could not fetch the AOSP-Partner ref." >&2 |
| exit 1 |
| fi |
| aosp_partner_ref_commit=$(git rev-list -n1 ${AOSP_PARTNER_REF} 2> /dev/null) |
| ;; |
| 2) |
| echo "WARNING: The AOSP-Partner ref. ${AOSP_PARTNER_REF} does not exist on remote, ignoring project." >&2 |
| exit 0 |
| ;; |
| *) |
| echo "ERROR: Could not fetch the AOSP-Partner ref. ${AOSP_PARTNER_REF} from origin." >&2 |
| exit 1 |
| ;; |
| esac |
| |
| # Are we currently pointing to the AOSP reference? |
| if test "_${head_commit}" = "_${aosp_ref_commit}"; then |
| # Is there something to update? |
| if test "_${aosp_ref_commit}" = "_${aosp_partner_ref_commit}"; then |
| echo "INFO: Currently pointing to the AOSP-Partner ref. (which is also the AOSP ref.)." |
| else |
| # Let's merge! |
| merge_aosp_partner_on_head "${head_commit}" "${current_known_branch}" |
| fi |
| exit 0 |
| # Why are not pointing to the AOSP reference? |
| elif test "_${head_commit}" = "_${aosp_partner_ref_commit}"; then |
| # 1- Because we could fast-forward to the AOSP-Partner reference |
| echo "INFO: Currently pointing to the AOSP-Partner ref." |
| elif test 0 -eq ${is_shallow} \ |
| -a "_${head_commit}" = "_$(git rev-list --quiet --merges -1 HEAD)" \ |
| -a "_${aosp_ref_commit}" = "_$(git rev-parse --quiet --verify 'HEAD^1')" \ |
| -a "_${aosp_partner_ref_commit}" = "_$(git rev-parse --quiet --verify 'HEAD^2')"; then |
| #2- Because we already merged the AOSP-Partner reference |
| echo "INFO: Already merged the AOSP-Partner ref. on the AOSP ref." |
| elif test 1 -eq ${is_shallow}; then |
| echo "WARNING: Shallow checkout, could not check if we merged the AOSP-Partner ref." >&2 |
| else |
| echo "WARNING: We are on ${current_known_branch} which is not tracking AOSP. Still trying to merge…" >&2 |
| merge_aosp_partner_on_head "${head_commit}" "${current_known_branch}" |
| fi |