How to Create Files in a GitHub Action and Commit Them to Your Repository

I recently worked with GitHub Actions, where I generated a JSON file and then needed to add it to the repository. I parsed some Markdown files and then dynamically created a manifest JSON file of them, committing it into the repo every time a push was made.

I hit a permissions roadblock I embarrassingly spent over an hour solving, and I hope you don’t make the same mistake.

name: Build Blog JSON

on:
  push:
    paths:
      - 'blog-posts/\*\*/\*.md'

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Get list of Markdown files
      run: |
        cd blog-posts
        files=($(ls \*.md))
        json\_array=()
        for file in "${files[@]}"
        do
          date\_string=$(grep -E '^date: ' "$file" | cut -d' ' -f2)
          # Use the date command to extract the year, month, and date
          year=$(date -d "$date\_string" +%Y)
          month=$(date -d "$date\_string" +%m)
          day=$(date -d "$date\_string" +%d)
          json\_array+=($(echo "{\\"file\\":\\"$file\\",\\"date\\":\\"$date\_string\\",\\"year\\":\\"$year\\",\\"month\\":\\"$month\\",\\"day\\":\\"$day\\"}"))
        done
        echo "[$(IFS=,; echo "${json\_array[\*]}" | jq -s -c 'sort\_by(.date)')]" > ../static/blog.json
        
    - name: Remove trailing comma
      run: |
        sed -i '$ s/,$//' static/blog.json
        
    - name: Commit changes
      run: |
        git config --global user.email "no-reply@github.com"
        git config --global user.name "GitHub Actions"
        git add static/blog.json
        git commit -m "Update blog.json"
        git remote set-url origin https://x-access-token:${{ secrets.GITHUB\_TOKEN }}@github.com/${{ github.repository }}
        git push
      env:
        GITHUB\_TOKEN: ${{ secrets.GITHUB\_TOKEN }}

Now, the important part of my action is the Commit changes action. You need to supply an email and name for the committer. In this instance, I just made up something generic. The first important line is setting the origin URL. We are referencing some variables GitHub creates for us automatically. Notably, GITHUB_TOKEN and repository.

Many of the blog posts and even the documentation alluded to the fact that this is all you have to do. And maybe I was referencing outdated information, but there is an additional step for permissions you need to do.

Under your repository settings, go to “Actions” and then “General”, and scroll right to the bottom until you get to “Workflow permissions”. By default, the GITHUB_TOKEN that is automatically created only has read permission. To commit, you need Read and write permissions.

Without this change, your GITHUB_TOKEN will not have permission and you will keep seeing a permission denied message. That’s all you need to do.