Skip to content

Commit

Permalink
Initial checkout-merge action
Browse files Browse the repository at this point in the history
  • Loading branch information
jsoref committed Dec 9, 2021
0 parents commit 95ebaa6
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/checkout.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Word Counts
on:
pull_request_target:

jobs:
count:
name: Word Count
permissions:
contents: read
pull-requests: read
runs-on: ubuntu-latest
if: "contains(github.event_name, 'pull_request') || github.event_name == 'push'"
steps:
- name: checkout
uses: actions/checkout@v2
- name: checkout-merge
if: "contains(github.event_name, 'pull_request')"
uses: ./
- name: check-count
if: env.MERGE_FAILED != '1'
id: count
run: git ls-files -z | xargs -0 wc
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 Josh Soref

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Checkout Merge

This action synthesizes the merge commit GitHub would give you via `refs/pull/X/merge`.

With GitHub.com's current implementation as of Dec 8, 2021, if it was able to make a
merge commit, and then a push causes the current state to be not mergable, the
`refs/pull/X/merge` ref may stick around resulting in confusing output.

With this action, instead, you will not get a merge commit.

If you use [@actions/checkout](https://github.com/actions/checkout) to try to
check out `refs/pull/X/merge` and it doesn't exist, the action will make three
attempts (failing each time), and then leave your workflow in a failed state
and your user with a fairly confusing log.

If you instead use [@actions/checkout](https://github.com/actions/checkout) to
check out the base commit, then you can use this action to get a merge commit.
If it isn't able to, it can produce an error message that is hopefully easier
for users to understand, and allow you to decide whether your workflow should
✅ or ❌.

## Usage

```yaml
- name: checkout
uses: actions/checkout@v2
- name: checkout-merge
if: "contains(github.event_name, 'pull_request')"
uses: check-spelling/checkout-merge@main
with:
# Base for merge (it will be checked out)
# Default: ${{ github.event.pull_request.base.sha }}
base_ref: ''

# Head for merge (it will be fetched and merged)
# Default: ${{ github.event.pull_request.head.sha }}
head_ref: ''

# Relative path under $GITHUB_WORKSPACE to the repository
# Default: .
path: ''

# Suppress reporting errors (consumers would report the message themselves)
# By default, this action reports errors in the workflow overview.
# If you want to handle reporting the error in some other manner,
# you can set this flag.
# Default: false
do_not_report: ''
- if: env.MERGE_FAILED != '1'
run: ...
```
### Outputs
* `message` - Message describing what prevented the action from producing a merge commit.

* `status` - `success` or `failed`

### Environment products

* `$MERGE_FAILED` will be set to `1` if a merge can't be created.
44 changes: 44 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: 'Checkout Merge'
description: 'Generate a merge commit'
author: 'jsoref'
branding:
icon: 'git-commit'
color: 'green'
inputs:
base_ref:
description: |
This commit will be refetched (to give the merge the best chance of
succceeding) and used as the base for the merge.
default: ${{ github.event.pull_request.base.sha }}
required: false
head_ref:
description: |
This commit will be fetched and merged into the base commit.
default: ${{ github.event.pull_request.head.sha }}
required: false
path:
description: 'Relative path under $GITHUB_WORKSPACE to the repository'
default: "."
required: false
do_not_report:
description: 'Suppress reporting errors (consumers would report the message themselves)'
default: ''
required: false
outputs:
message:
description: "User facing message about attempt to merge"
value: ${{ steps.merge.outputs.message }}
status:
description: "Whether the merge succeeded"
value: ${{ steps.merge.status }}
runs:
using: composite
steps:
- id: merge
shell: bash
env:
INPUT_BASE_REF: ${{ inputs.base_ref }}
INPUT_HEAD_REF: ${{ inputs.head_ref }}
INPUT_PATH: ${{ inputs.path }}
INPUT_DO_NOT_REPORT: ${{ inputs.do_not_report }}
run: ${{ github.action_path }}/merge
39 changes: 39 additions & 0 deletions merge
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash
report_failure() {
echo "MERGE_FAILED=1" >> "$GITHUB_ENV"
echo '::set-output name=status::failed'
echo "::set-output name=message::$1"
if [ -z "$INPUT_DO_NOT_REPORT" ]; then
echo "::error ::$1"
fi
exit 0
}

cd "$INPUT_PATH" || report_failure "Could not change to input_path ($INPUT_PATH)"
SENDER=$(jq -r .sender.login "$GITHUB_EVENT_PATH")
USER_JSON=$(mktemp)
curl -s "$GITHUB_API_URL/users/$SENDER" -o "$USER_JSON"
export GIT_AUTHOR_NAME=$(jq -r .name "$USER_JSON")
export GIT_AUTHOR_EMAIL=$(jq -r '.email // empty' "$USER_JSON")
if [ -z "$GIT_AUTHOR_EMAIL" ]; then
GIT_AUTHOR_EMAIL=$(jq -r '( (.id|tostring) + "+" + .login + "@users.noreply.github.com")' "$GITHUB_EVENT_PATH")
fi
export GIT_COMMITTER_NAME=GitHub
export [email protected]
git fetch --unshallow origin "$INPUT_BASE_REF" ||
report_failure "Can't get history for base_ref ($INPUT_BASE_REF). Please contact support"
GITHUB_BASE_SHA=$(git rev-parse FETCH_HEAD)

git -c advice.detachedHead=false checkout "$GITHUB_BASE_SHA" || {
git status
report_failure "Couldn't check out base_ref ($INPUT_BASE_REF); repository is probably dirty."
}

git fetch origin "$INPUT_HEAD_REF" ||
report_failure "Can't get head_ref ($INPUT_HEAD_REF). Please contact support"

GITHUB_HEAD_SHA=$(git rev-parse FETCH_HEAD)
git merge -m "Merge $GITHUB_HEAD_SHA into $GITHUB_BASE_SHA" FETCH_HEAD ||
report_failure "Can't generate merge; there's probably a conflict. Resolve it to get workflow feedback."

echo '::set-output name=status::success'

0 comments on commit 95ebaa6

Please sign in to comment.