Search code examples
gitdockergithubgithub-actionsbuilding-github-actions

Push to origin from GitHub action


I'm trying to push to origin remote from GitHub action. The logic of my action is:

  • handle pull_request_review events and filter by comment message
  • checkout to master, merge PR branch, run some checks and push it to origin

The script is:

if [[ "${GITHUB_EVENT_NAME}" != "pull_request_review" ]]; then
  echo "unsupported event: ${GITHUB_EVENT_NAME}"
  exit 1
fi

user=$(jq -r .review.user.login ${GITHUB_EVENT_PATH})
cmd=$(jq -r .review.body ${GITHUB_EVENT_PATH})
echo "reviewer is ${user}, command is ${cmd}"

if [[ "${cmd}" == "merge" ]]; then
  head=$(jq -r .pull_request.head.ref ${GITHUB_EVENT_PATH})
  git config user.email [email protected]
  git config user.name test
  git checkout -B _tmp origin/${head}
  git checkout -B master origin/master
  git merge --no-ff _tmp
  git push origin master
fi

I'm running this script from alpine:3.10 Docker container:

FROM alpine:3.10

LABEL "com.github.actions.name"="Hello world action"
LABEL "com.github.actions.icon"="shield"
LABEL "com.github.actions.color"="green"

WORKDIR /app
COPY action.sh action.sh
RUN apk --update add bash git jq
CMD ["bash", "/app/action.sh"]

First steps are working fine (checkout and merge), but action failed to push the merge to origin because of the error:

+ git push origin master
fatal: could not read Username for 'https://github.com': No such device or address

It looks like GitHub-action Docker container is not configured to push to GitHub. How can I configure it? Is it possible to use some of the env variables provided by GitHub or maybe some mounted files (like in /github/* path)?


Solution

  • actions/checkout@v2 onwards

    From version 2 of checkout, the detached HEAD state issue is resolved and simplifies pushing to origin.

    name: Push commit
    on: push
    permissions:
      contents: write
    jobs:
      report:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - name: Create report file
            run: date +%s > report.txt
          - name: Commit report
            run: |
              git config --global user.name 'Your Name'
              git config --global user.email '[email protected]'
              git commit -am "Automated report"
              git push
    

    If you need the push event to trigger other workflows, use a repo scoped Personal Access Token.

          - uses: actions/checkout@v3
            with:
              token: ${{ secrets.PAT }}
    

    actions/checkout@v1 (original answer)

    To add some further detail to the excellent answer by @rmunn. The problem is that the actions/checkout@v1 action leaves the git repository in a detached HEAD state. See this issue about it for more detailed information: https://github.com/actions/checkout/issues/6

    Here is a complete example to demonstrate how to get the checked out repository to a usable state and push to the remote.

    name: Push commit
    on: push
    jobs:
      report:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v1
          - name: Create report file
            run: date +%s > report.txt
          - name: Commit report
            run: |
              git config --global user.name 'Your Name'
              git config --global user.email '[email protected]'
              git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
              git checkout "${GITHUB_REF:11}"
              git commit -am "Automated report"
              git push
    

    To include untracked (new) files change the workflow to use the following.

              git add -A
              git commit -m "Automated report"
    

    The above workflow should work for the majority of events. For on: pull_request workflows the merging branch (GITHUB_HEAD_REF) should be checked out to replace the default merge commit.

    Important: If you have other pull request checks besides the following workflow then you must use a Personal Access Token instead of the default GITHUB_TOKEN. This is due to a deliberate limitation imposed by GitHub Actions that events raised by a workflow (such as push) cannot trigger further workflow runs. This is to prevent accidental "infinite loop" situations, and as an anti-abuse measure. Using a repo scoped Personal Access Token is an approved workaround. See this GitHub issue for further detail on the workaround.

    name: Push commit on pull request
    on: pull_request
    jobs:
      report:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v1
            with:
              ref: ${{ github.head_ref }}
          - name: Create report file
            run: date +%s > report.txt
          - name: Commit report
            run: |
              git config --global user.name 'Your Name'
              git config --global user.email '[email protected]'
              git remote set-url origin https://x-access-token:${{ secrets.PAT }}@github.com/${{ github.repository }}
              git commit -am "Automated report"
              git push
    

    For further examples of push to origin during an on: pull_request workflow see this blog post, GitHub Actions: How to Automate Code Formatting in Pull Requests.