git-auto-commit-action

repository·master·Indexed 24 days ago

https://github.com/stefanzweifel/git-auto-commit-action

A GitHub Action that detects changed files during a workflow run and automatically commits and pushes them back to the repository. Designed for automation tasks like auto-formatting or dependency updates, it supports custom commit messages, file patterns, GPG signing, and git hooks for shell snippets. Requires a UNIX-like system with bash and appropriate GITHUB_TOKEN permissions.

Tokens
10.5K
Snippets
26
Records
36
Agent score
81%

What's inside git-auto-commit-action

  1. Use Git Hooks to run custom shell snippets

    master

    The action allows you to run custom shell snippets around specific git operations. These hooks run in the same bash process as the action, meaning they have access to the repository working directory and all INPUT_* environment variables.

    Important Details:

    • Hooks run under set -eu. An unset variable will abort the action. Use ${VAR:-} to provide defaults.
    • A hook only runs if its corresponding git operation is actually performed (e.g., before_add_hook won't run if the working tree is clean).
    • If a hook exits with a non-zero status, the action fails. Use || true to ignore failures.
    • Security: When using pull_request_target, do not interpolate GitHub context (like ${{ github.event.pull_request.title }}) directly into a hook, as this allows for shell injection. Instead, pass the value via an env variable.

    Available Hooks

    HookRuns around
    before_add_hook / after_add_hookgit add
    before_commit_hook / after_commit_hookgit commit
    before_tag_hook / after_tag_hookgit tag
    before_push_hook / after_push_hookgit push (skipped if skip_push: true)
    - uses: stefanzweifel/git-auto-commit-action@v7
      env:
        PR_TITLE: ${{ github.event.pull_request.title }}
      with:
        before_commit_hook: |
          # $PR_TITLE is read as data, not evaluated as code
          echo "PR: $PR_TITLE"
          ./scripts/prepare-commit.sh
  2. Trigger new Workflow runs with a Personal Access Token (PAT)

    master

    Commits made using the default GITHUB_TOKEN will not trigger new GitHub Actions workflow runs. To allow commits to trigger subsequent workflows, you must use a Personal Access Token (PAT) passed to the actions/checkout step.

    Token Requirements:

    • Classic PAT: Apply repo and workflow scopes.
    • Fine-grained PAT: Apply Contents permissions.

    For organizational use, using a robot account is recommended over a personal account.

    - uses: actions/checkout@v7
      with:
        token: ${{ secrets.PAT }}
  3. Sign commits using GPG

    master

    To sign commits with a GPG key, use an action like crazy-max/ghaction-import-gpg to set up the key. Because git-auto-commit-action does not automatically use your identity, you must explicitly override commit_author, commit_user_name, and commit_user_email using the outputs from your GPG import step.

    - name: "Import GPG key"
      id: import-gpg
      uses: crazy-max/ghaction-import-gpg@v7
      with: 
        gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
        passphrase: ${{ secrets.GPG_PASSPHRASE }}
        git_user_signingkey: true
        git_commit_gpgsign: true
    
    - name: "Commit and push changes"
      uses: stefanzweifel/git-auto-commit-action@v7
      with: 
         commit_author: "${{ steps.import-gpg.outputs.name }} <${{ steps.import-gpg.outputs.email }}>"
         commit_user_name: ${{ steps.import-gpg.outputs.name }}
         commit_user_email: ${{ steps.import-gpg.outputs.email }}
  4. Use git-auto-commit-action in forks from public repositories

    master

    By default, the action does not run on Pull Requests from forks. To enable it, you can use the pull_request_target trigger.

    Security Warning: Using pull_request_target can expose repository secrets to malicious actors. If you use this trigger, ensure you are not interpolating attacker-controlled fields (like PR title or body) directly into shell code. Use env: blocks to pass these values safely.

    Implementation Details:

    • When using pull_request_target, you must configure actions/checkout to fetch the fork's repository and branch specifically, otherwise changes will be committed to the base repository instead of the fork.
    • As of v7, actions/checkout may require allow-unsafe-pr-checkout: true to fetch fork code under pull_request_target.
    name: Format PHP
    
    on:
      push:
        branches:
          - main
      pull_request_target:
    
    jobs:
      php-cs-fixer:
        runs-on: ubuntu-latest
        permissions:
          contents: write
    
        steps:
        - uses: actions/checkout@v7
          with: 
            # Checkout the fork/head-repository and push changes to the fork.
            # If you skip this, the base repository will be checked out and changes 
            # will be committed to the base repository!
            repository: ${{ github.event.pull_request.head.repo.full_name }}
    
            # Checkout the branch made in the fork. Will automatically push changes 
            # back to this branch.
            ref: ${{ github.head_ref }}
    
        - name: Run php-cs-fixer
          uses: docker://oskarstark/php-cs-fixer-ga
    
        - uses: stefanzweifel/git-auto-commit-action@v7
  5. Fail the build instead of pushing changes (drift check)

    master

    If you want to ensure code quality without allowing a bot to automatically push fixes, you can use the action as a drift check. Instead of committing, configure the action to skip checkout, fetch, and push. You can then use the changes_detected output to determine if any files were modified by your formatting or linting steps and fail the build if they were.

    Implementation Steps

    1. Run your formatting/linting command (e.g., npx prettier --write .).
    2. Run stefanzweifel/git-auto-commit-action@v7 with skip_checkout: true, skip_fetch: true, and skip_push: true.
    3. Add a step that checks if steps.<id>.outputs.changes_detected == 'true' and exits with an error if true.
    name: Format check
    
    on: pull_request
    
    jobs:
      check:
        runs-on: ubuntu-latest
        permissions:
          contents: read
    
        steps:
          - uses: actions/checkout@v5
    
          - uses: actions/setup-node@v4
            with:
              node-version: 20
    
          - run: npx prettier --write .
    
          - uses: stefanzweifel/git-auto-commit-action@v7
            id: auto-commit
            with:
              skip_checkout: true
              skip_fetch: true
              skip_push: true
    
          - name: Fail if formatting was needed
            if: steps.auto-commit.outputs.changes_detected == 'true'
            run: |
              echo "::error::Code is not formatted. Run 'npx prettier --write .' locally."
              exit 1
  6. Push to protected branches using force push

    master

    If you have enabled force pushes for your protected branches in GitHub settings, you can configure the Action to use force pushing by setting the push_options parameter to --force.

    - uses: stefanzweifel/git-auto-commit-action@v7
      with:
        commit_message: Apply php-cs-fixer changes
        push_options: --force
  7. Sign automated commits with GPG

    master

    If your repository has branch protection rules requiring signed commits, you must configure the action to use a GPG key. This typically involves importing a GPG key via another action and then passing the identity (name and email) from that action into the commit_user_name, commit_user_email, and commit_author parameters of git-auto-commit-action.

    Configuration Requirements

    • Permissions: The job must have contents: write permissions.
    • Identity: Use the outputs from your GPG import step to populate the commit identity fields to ensure the signature matches the author.
    name: Format (signed)
    
    on: pull_request
    
    jobs:
      format:
        runs-on: ubuntu-latest
        permissions:
          contents: write
    
        steps:
          - uses: actions/checkout@v5
            with:
              ref: ${{ github.head_ref }}
    
          - name: Import GPG key
            id: import-gpg
            uses: crazy-max/ghaction-import-gpg@v6
            with:
              gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
              passphrase: ${{ secrets.GPG_PASSPHRASE }}
              git_user_signingkey: true
              git_commit_gpgsign: true
    
          - run: npx prettier --write .
    
          - uses: stefanzweifel/git-auto-commit-action@v7
            with:
              commit_message: "style: apply prettier"
              commit_user_name: ${{ steps.import-gpg.outputs.name }}
              commit_user_email: ${{ steps.import-gpg.outputs.email }}
              commit_author: "${{ steps.import-gpg.outputs.name }} <${{ steps.import-gpg.outputs.email }}>"
  8. Amend existing commits with --amend and --no-edit

    master

    To use the action to amend the previous commit rather than creating a new one, follow these requirements:

    1. Fetch Depth: Set fetch-depth: 2 in actions/checkout to ensure the previous commit is available.
    2. Extract Metadata: Use git log to extract the previous commit's message and author information.
    3. Configure Action:
      • Pass the extracted message to commit_message.
      • Pass the extracted author to commit_author.
      • Set commit_options: '--amend --no-edit'.
      • Set push_options: '--force' to overwrite the remote history.
      • Set skip_fetch: true to avoid conflicts.

    Warning: Amending published commits rewrites history and can cause issues for other contributors.

    - uses: actions/checkout@v7
      with: 
        # Fetch the last 2 commits instead of just 1. (Fetching just 1 commit would overwrite the whole history)
        fetch-depth: 2
    
    # Other steps in your workflow to trigger a changed file
    
    - name: Get last commit message
      id: last-commit
      run: |
        echo "message=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT
        echo "author=$(git log -1 --pretty="%an <%ae>")" >> $GITHUB_OUTPUT
    
    - uses: stefanzweifel/git-auto-commit-action@v7
      with: 
        commit_author: ${{ steps.last-commit.outputs.author }}
        commit_message: ${{ steps.last-commit.outputs.message }}
        commit_options: '--amend --no-edit'
        push_options: '--force'
        skip_fetch: true
  9. Create multiline commit messages

    master

    To use a commit message that spans multiple lines, you must first generate the multiline string in a separate step using GitHub Actions' multiline string syntax (EOF delimiter) and then pass the resulting output to the commit_message input of the git-auto-commit-action.

        # Building a multiline commit message
        # Adjust to your liking
        - run: echo "Commit Message 1" >> commitmessage.txt
        - run: echo "Commit Message 2" >> commitmessage.txt
        - run: echo "Commit Message 3" >> commitmessage.txt
    
        # Create a multiline string to be used by the git-auto-commit Action
        - name: Set commit message
          id: commit_message_step
          run: |
            echo 'commit_message<<EOF' >> $GITHUB_OUTPUT
            cat commitmessage.txt >> $GITHUB_OUTPUT
            echo 'EOF' >> $GITHUB_OUTPUT
    
        # Quick and dirty step to get rid of the temporary file holding the commit message
        - run: rm -rf commitmessage.txt
    
        - uses: stefanzweifel/git-auto-commit-action@v7
          id: commit
          with: 
            commit_message: ${{ steps.commit_message_step.outputs.commit_message }}