please reconsider setting GITHUB_COMMIT_MESSAGE or equivalent

It is suprisingly difficult to obtain the commit message in it’s full glory due to various limitations.  I understand that setting GITHUB_COMMIT_MESSAGE may not make sense for all different types of events, but I believe that setting this value for push and pull_request events should be done for us.

https://github.community/t5/GitHub-Actions/Accessing-commit-message-in-pull-request-event/m-p/40925/highlight/true#M4418 by @yanjingzhu seems to have worked in the past, but for me this will result in a fatal: bad object <sha>.  I believe what happens for pull_request is that a bare repo is initialized with exactly one commit, which is the refs/pull/XYZ/merge commit.  So the original commit is not in the history anymore.

Here is what I was able to achieve as a linux-only solution (note: I was working on a Python project, you could omit that and just install / use jq or something to parse the json):

jobs:
  dist:
    name: Distribution
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Python
        uses: actions/setup-python@v1
        with:
          python-version: 3.x
      - name: Extract Commit Message (Pull Request)
        if: github.event_name == 'pull_request'
        run: |
          # For pull requests, github.ref will be e.g., refs/pull/XYZ/merge. We
          # want to query the /head commit, so replace /merge with /head.
          ref="$(echo '${{ github.ref }}' | sed 's@^\(refs/pull.*\)/merge$@\1/head@g')"
          curl https://api.github.com/repos/${{ github.repository }}/commits/$ref > commit.json
          msg="$(python -c 'import json; print(json.load(open("commit.json"))["commit"]["message"])')"
          # ::set-env and friends choke on multiline values, replace newlines.
          # https://github.community/t5/GitHub-Actions/set-output-Truncates-Multiline-Strings/m-p/37870
          msg="${msg//'%'/'%25'}"
          msg="${msg//$'\n'/'%0A'}"
          msg="${msg//$'\r'/'%0D'}"
          echo "::set-env name=COMMIT_MESSAGE::$msg"
      - name: Extract Commit Message (Push)
        if: github.event_name == 'push'
        run: |
          # ::set-env and friends choke on multiline values, replace newlines.
          # https://github.community/t5/GitHub-Actions/set-output-Truncates-Multiline-Strings/m-p/37870
          msg="${{ github.event.head_commit.message }}"
          msg="${msg//'%'/'%25'}"
          msg="${msg//$'\n'/'%0A'}"
          msg="${msg//$'\r'/'%0D'}"
          echo "::set-env name=COMMIT_MESSAGE::$msg"
      - name: DEBUG COMMIT MESSAGE
        run: |
          echo "Commit Message"
          echo "$COMMIT_MESSAGE"

I have opened a new issue because the ones I have found either have been marked as resolved (but have outdated answers), or the answer is incomplete (e.g., only gets you the first line of the commit message).  Please consider making an official GITHUB_COMMIT_MESSAGE environment variable and populating it for us, the above solution is overly complicated, and doesn’t work on every platform.

I’m really hoping I’ve overlooked something, and please correct me if there is a more direct solution!  But it seems that something changed relatively recently that prevents the old solutions for pull_request working.  Thank you for your consideration, many people want to perform or skip actions via phrases in their commit messages but it is currently very difficult to achieve this.

2 Likes

Thank you for your suggestion. I would like direct you to Feedback form for GitHub Actions to share your idea. 

As you said the previous workaround there https://github.community/t5/GitHub-Actions/Accessing-commit-message-in-pull-request-event/m-p/40925/highlight/true#M4418 could not work in your side. What’s the GITHUB context like? Can you share the repo url and the workflow runs url here? 

For Pull Request, I use this to get the commit message, 

- name: Checkout
        uses: actions/checkout@v2
        with:
          ref: ${{ github.event.pull_request.head.sha }}

      - name: Get Commit Message
        run: |
          MSG=$(git log --format=%B -n 1 ${{ github.event.after }})
          echo "::set-env name=COMMIT_MESSAGE::${MSG}"
2 Likes

That’s a great option! If you are doing PR, @mrchief 's v2 checkout using the with: ref will be good. Apparently what is in the GitHub Context (github.event.* variables) is populated by checkout action. I didn’t make the connection that actions/checkout was the thing that sets these up.

Probably there are options to look at to use v2 with github.event.[something] for push, refer to linked answer in OP to dump json context to console so you can variable hunt :slight_smile:

@yanjingzhu sorry for not seeing your response, I don’t think I was getting e-mails from GH community. Your original answer uses github.event.after which will exist if you checkout@v1 but not v2.

@svenevs Checkout@v2 has an input variable named fetch-depth, its default value is 1. Only the merge commit will be check out . You could set fetch-depth: 0 . Then github.event.after will exist.

      - uses: actions/checkout@v2
        with: 
          fetch-depth: 0

@yanjingzhu thanks for the explanation :slight_smile: After realizing how it works, it’s understandable why pulling down as little as possible is the desired behavior (it’s also really clever how it works!). The below will work for checkout v2 on PR and branch builds (@mrchief’s ref only works on PR) :

      steps:
      - uses: actions/checkout@v2
        with:
          ref: ${{ github.event.after }}

The env variable would be nice, but I think there is probably a better long term solution given that GH actions fires for events like comments etc that don’t have a commit message associated with them. Something to use with if conditions, like a built-in function commit_matches(regex), or commit_contains(substr)?

  • For events that do not have a commit message, it always returns false.
  • For PR, it checks the commit that caused it (user doesn’t need to know about the merge commit / checkout stuff).
  • For branch, use sha associated with event.

Does that seem like a better feature to request? As checkout evolves the above may stop working for perfectly legitimate reasons. I think many users would really appreciate a built-in way of simple pattern testing for skipping / testing alternate paths etc in CI via the commit message. Then we can [ci skip] at a higher level and not even use bandwidth to pull the commit? :slight_smile: