Skip to content

Commit

Permalink
ci: Check that the fast-forward check and /fast-forward work.
Browse files Browse the repository at this point in the history
  - Check that the actions work by opening a pull request in a test
    repository, and then fast forwarding it.
  • Loading branch information
nwalfield committed Aug 25, 2023
1 parent 83c6796 commit 619dea0
Show file tree
Hide file tree
Showing 3 changed files with 345 additions and 0 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# This action is run from sequoia-pgp/fast-forward. It needs to
# access the sequoia-pgp/fast-forward-unit-test repository. We can't
# use a GitHub Token: its permissions are limited to the repository in
# which the action is run. Instead, we can use a deploy key:
#
# https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys#deploy-keys
#
# Deploy keys with write access can perform the same actions as an
# organization member with admin access, or a collaborator on a
# personal repository. For more information, see "Repository roles
# for an organization" and "Permission levels for a personal account
# repository."
#
# To add a deply key to fast-forward-unit-tests, go to:
#
# https://github.com/sequoia-pgp/fast-forward-unit-tests
#
# Then go to settings, deploy keys, add deploy key.
#
# Generate a new ssh key pair in fast-forward/secrets (don't add it to
# the repository).
#
# $ ssh-keygen -t ed25519
#
# In the fast-forward repository, navigate to Settings, Secrets and
# variables, Actions, New repository secret. Name the environment
# variable `FAST_FORWARD_UNIT_TESTS_SSH_KEY`. This is automatically
# used by the fast-forward script.

name: ci
on:
push:

permissions:
contents: write
pull-requests: write
issues: write

jobs:
compile:
name: Fast forward
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Check that /fast-forward fast forwards.
run: GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} tests/fast-forward.sh
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
*~
tests/run.sh
secrets
295 changes: 295 additions & 0 deletions tests/fast-forward.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
#! /bin/bash

# Go to:
# - Top-Right Menu
# - Settings
# - Developer Settings
# - Personal access tokens
# - Tokens (classic)
# - Generate a personal access token
#
# Create a token with "repo" permission.
if test x$GITHUB_TOKEN = x
then
echo You need to set GITHUB_TOKEN
exit 1
fi

if test x$GITHUB_ACTOR = x
then
echo You need to set GITHUB_ACTOR
exit 1
fi

if test x$FAST_FORWARD_UNIT_TESTS_SSH_KEY != x
then
echo "Adding deploy key for fast-forward-unit-tests repository."
SSH_ID=$(mktemp)
echo "$FAST_FORWARD_UNIT_TESTS_SSH_KEY" > "$SSH_ID"
else
echo "No deploy key for target repository. Hoping for the best."
fi
echo SSH_ID: $SSH_ID

# Where to run the test.
OWNER=${OWNER:-sequoia-pgp}
REPO=${REPO:-fast-forward-unit-tests}

TEMPFILES=$(mktemp)
echo -n "$TEMPFILES" >> "$TEMPFILES"
function maketemp {
F=$(mktemp $*)
echo -n " $F" >> $TEMPFILES
echo "$F"
}
function maketemp_exit {
TEMPFILES=$(cat $TEMPFILES)
if test x"$TEMPFILES" != x
then
echo -e "Cleanup by running:\n $ rm -rf $TEMPFILES"
fi
}
trap maketemp_exit EXIT

set -ex

# Files from the fast-forward repository that we copy over.
FILES=".github/workflows/fast-forward.yml
.github/workflows/pull_request.yml"

FAST_FORWARD_REPO=$(git rev-parse --show-toplevel)
for f in $FILES
do
if ! test -e "$FAST_FORWARD_REPO/$f"
then
echo "Missing \"$f\". Are you really in the fast-forward repo?"
exit 1
fi
done

echo "::group::Initializing scratch repository"

D=$(maketemp -d)
echo "Scratch directory: $D"
cd $D

git init --initial-branch main .
git config user.name "Fast Forward Unit Test"
git config user.email "[email protected]"
if test "x$SSH_ID" != x
then
git config core.sshCommand "ssh -i $SSH_ID"
fi

CLONE_URL="github.com/$OWNER/$REPO.git"
git remote add origin "https://$GITHUB_ACTOR@$CLONE_URL"

# When running on a GitHub runner, we need to use the github token to
# interaction with the git repository.
git config credential.helper store
{
echo "url=https://$GITHUB_ACTOR@$CLONE_URL"
echo "username=$GITHUB_ACTOR"
echo "password=$GITHUB_TOKEN"
} | git credential approve

echo "::endgroup::"

echo "::group::Add commit #1"

# Add the workflow files.
for f in $FILES
do
mkdir -p $(dirname $f)
cp "$FAST_FORWARD_REPO/$f" "$f"
git add "$f"
done

git commit -m 'Initial commit' --no-gpg-sign

BASE=fast-forward-test-0$RANDOM
git push origin main:$BASE

echo "::endgroup::"

# Create a new commit, push it to a different branch.
echo "::group::Add commit #2"

echo $RANDOM > hello
git add hello
git commit -m 'Hello' --no-gpg-sign

PR=$BASE-pr
git push origin main:$PR

echo "::endgroup::"

echo "::group::Open pull request"

# Create a pull request.
OPEN_PR_RESULT=$(maketemp)
curl --silent --show-error --output $OPEN_PR_RESULT -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$OWNER/$REPO/pulls \
-d '{
"title":"Test",
"body":"This is a test, only a test!",
"head":"'"$PR"'",
"base":"'"$BASE"'"
}'

PR_URL=$(jq -r ".url" < $OPEN_PR_RESULT)
if test "x$PR_URL" = xnull
then
echo "Couldn't get PR's URL"
exit 1
fi
PR_NUMBER=$(jq -r ".number" < $OPEN_PR_RESULT)
if test "x$PR_NUMBER" = xnull
then
echo "Couldn't get PR's URL"
exit 1
fi

echo "::endgroup::"

# Wait for the check-fast-forward job to finish and check the results.
echo "::group::Check that the check-fast-forward action ran, and said yes"

COMMENTS_RESULT=$(maketemp)
for i in $(seq 1 10)
do
if test $i -eq 10
then
echo "Timeout waiting for check-fast-forward job"
cat "$COMMENTS_RESULT"
exit 1
fi
sleep 3

curl --silent --show-error --output "$COMMENTS_RESULT" -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments

COMMENT=$(jq -r .[0].body <"$COMMENTS_RESULT")
if test "x$COMMENT" = xnull
then
# The job hasn't completed yet.
continue
else
if echo $COMMENT | grep -q 'you can add a comment with `/fast-forward` to fast forward'
then
echo check-fast-forward worked.
else
echo "Unexpected comment in response to push, did check-fast-forward change?"
cat $COMMENTS_RESULT
exit 1
fi
fi

break
done

echo "::endgroup::"

echo "::group::Post a /fast-forward comment to fast forward the pull request"

curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments \
-d '{ "body":"We should /fast-forward this..." }'

# Wait for the fast-forward job to finish and then check the results.
for i in $(seq 1 10)
do
if test $i -eq 10
then
echo "Timeout waiting for fast-forward job"
cat "$COMMENTS_RESULT"
exit 1
fi
sleep 3

curl --silent --show-error --output "$COMMENTS_RESULT" -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments

# Comment 0 is from check-fast-forward, 1 is our /fast-forward,
# and 2 will be from fast-forward.
COMMENT=$(jq -r .[2].body <"$COMMENTS_RESULT")
if test "x$COMMENT" = xnull
then
# The job hasn't completed yet.
continue
else
if echo $COMMENT | grep -q 'Fast forwarding `'"$BASE"'`'
then
echo fast-forward worked.
else
echo "Unexpected comment in response to /fast-forward, did fast-forward change?"
cat "$COMMENTS_RESULT"
exit 1
fi
fi

break
done

echo "::endgroup::"

# Make sure the base was fast forwarded by checking that it's sha is
# now identical to HEAD.
echo "::group::Check that the remote branch was fast forwarded"

git fetch -a origin $BASE

BASE_SHA=$(git rev-parse origin/$BASE)
if test x$BASE_SHA = x
then
echo "Base branch disappeared?!?"
exit 1
fi
HEAD_SHA=$(git rev-parse HEAD)
if test "x$BASE_SHA" != "x$HEAD_SHA"
then
echo "Base was not fast forwarded to HEAD: $BASE_SHA != $HEAD_SHA!"
exit 1
fi

echo "Pull request was fast forwarded!"

echo "::endgroup::"

# Make sure the base was fast forwarded by checking that it's sha is
# now identical to HEAD.
echo "::group::Check that the PR is closed"

MERGED_PR_RESULT=$(maketemp)
curl --silent --show-error --output $MERGED_PR_RESULT -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER
cat $MERGED_PR_RESULT

STATE=$(jq -r .state <"$MERGED_PR_RESULT")
if test "x$STATE" != xclosed
then
echo "PR was not closed (state: '$STATE')"
exit 1
fi

echo "::endgroup::"

# Clean up on success.
rm -rf $D

0 comments on commit 619dea0

Please sign in to comment.