Skip to content

Commit

Permalink
Merge d9460b9 into 83c9dfc
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronFriel committed Nov 8, 2022
2 parents 83c9dfc + d9460b9 commit efb7be0
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/ci-lint.yml
Expand Up @@ -125,3 +125,15 @@ jobs:
go-version: ${{ fromJson(inputs.version-set).go }}
- run: |
make lint_actions
linear-history:
name: linear-history
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
# This should be the merge commit of the PR or candidate merge commit in the staging branch for `bors`.
ref: ${{ inputs.ref }}
fetch-depth: 0
- name: Check for non-linear history
run: ./scripts/git-linear-history-check.sh
3 changes: 3 additions & 0 deletions bors.toml
Expand Up @@ -6,3 +6,6 @@ timeout-sec = 7200 # two hours, in seconds
status = [
'bors-ok',
]
pr_status = [
'linear-history'
]
115 changes: 115 additions & 0 deletions scripts/git-linear-history-check.sh
@@ -0,0 +1,115 @@
#!/usr/bin/env bash

# This script is designed to run against a merge commit, either produced during PR checks or a
# `bors` octopus merge commit. A non-zero exit status is returned if either of the following is true
# of the COMMITISH (see below)
# * If COMMITISH is not a merge commit (i.e.: has 0 or 1 parents.)
# * If COMMITISH is a merge commit and any of the parents have a non-linear history with the common ancestor
# of the target commit (first parent).

# usage: ./scripts/git-linear-history-check.sh [COMMITISH]
#
# COMMITISH: a commit to use, if not provided, HEAD is used.
#

# ## Non-linear merge example
#
# Merge commit hash: fc7c341c38c006f96ac288ebfcf5ce18b8e31a48
#
# PR commits: https://github.com/pulumi/pulumi/pull/11095/commits
#
# This commit is a single merge commit produced by `bors`. The 2nd parent of the commit is the PR
# commit HEAD, and the commit history shos . This script should log errors and exit with a 1 on this
# commit.

# ## Linear merge example
#
# Merge commit hash: 2a98a6e4dc36524fde5d33f2b5bdca0521441c72
#
# PR commits: https://github.com/pulumi/pulumi/pull/11261/commits
#
# This is a regular PR merge, containing a single commit. This script should not log any errors on
# this commit.


# ## Non-linear octopus merge example
#
# Merge commit hash: 0f3e53688fe04ec18180ba87f6915c454023ddf9
#
# PR commits:
# 1. https://github.com/pulumi/pulumi/pull/10687/commits
# 2. https://github.com/pulumi/pulumi/pull/10729/commits
# 3. https://github.com/pulumi/pulumi/pull/10740/commits
#
# This octopus merge has 3 PRs as parents. The first of which (#10687) has non-linear commit
# history. This script should log two errors and exit with a 1.


# ## Linear octopus merge example
#
# Merge commit hash: f033d9de02a633ad386b09d6dfff810ffe7ddea5
#
# PR commits:
# 1. https://github.com/pulumi/pulumi/pull/10815/commits
# 2. https://github.com/pulumi/pulumi/pull/10821/commits
# 3. https://github.com/pulumi/pulumi/pull/10822/commits
# 4. https://github.com/pulumi/pulumi/pull/10823/commits
#
# This octopus merge has 4 PRs as parents, all of which have linear commit history. This script
# should not log any errors on this commit.


# ## Initial commit example
#
# Commit hash: 86f6117640ebaaffb8689e241a668218b24f4690
#
# This commit has no parents, and should exit with a 1.


# ## Single parent (non-merge commit) example
#
# Commit hash: 1f861c5132a738216c69398ae600e1998c4e436b
#
# This commit has only a single parent, and should exit with a 1.

COMMITISH="${1:-"HEAD"}"
MERGED_BRANCH_COMMIT="$(git rev-parse "${COMMITISH}")"

>&2 echo "Checking merge commit ${MERGED_BRANCH_COMMIT} for non-linear history"

# git rev-list - list the merged branch commit followed by all of its parents, separated by spaces
# cut - remove the first line
# tr - replace spaces with newlines to turn this into an array
PARENTS_RAW=$(git rev-list --no-commit-header --parents -n 1 "${MERGED_BRANCH_COMMIT}" | cut -d' ' -f2- | tr ' ' '\n')

readarray -t PARENTS <<<"${PARENTS_RAW}" # split into array on newlines, -t strips newlines
if [ "${#PARENTS[@]}" -le "1" ]; then
>&2 echo "::error::Input commit ${COMMITISH} is not a merge commit, this script must run against a merge commit."
exit 1
fi

# First parent in bors & github PR merge commits is always the target branch's HEAD commit:
TARGET_BRANCH_HEAD="${PARENTS[0]}"
>&2 echo "Main branch parent is: $(git log --oneline -n 1 "${TARGET_BRANCH_HEAD}")"
# Subsequent parents are from PR branches:
PR_BRANCH_HEADS=( "${PARENTS[@]:1}" )
>&2 echo "PR branch parents are ${PR_BRANCH_HEADS[*]}"

HAS_MERGE_COMMIT=false
for PR_COMMIT in "${PR_BRANCH_HEADS[@]}"; do
>&2 echo "Checking: $(git log --oneline -n 1 "${PR_COMMIT}")"
# MERGE_BASE=$(git merge-base )
# Find the common parent of the target branch and PR branch
MERGE_COMMITS_IN_PR=$(git rev-list "${TARGET_BRANCH_HEAD}..${PR_COMMIT}" --merges | cut -d' ' -f2-)
for MERGE_COMMIT in ${MERGE_COMMITS_IN_PR}; do
>&2 echo "::error::Non-linear history, PR contains a merge ${MERGE_COMMIT}. Remove this by rebasing on the target."
HAS_MERGE_COMMIT=true
done
done

if ${HAS_MERGE_COMMIT}; then
>&2 echo "::error::Detected non-linear history."
exit 1
fi

>&2 echo "✅ Commit history is linear."

0 comments on commit efb7be0

Please sign in to comment.