DEV Community

Jayson DeLancey
Jayson DeLancey

Posted on • Edited on

Automating GitHub Profile Updates with GitHub Actions

Introduced in 2020, the GitHub user profile README allow individuals to give a long-form introduction. This multi-part tutorial explains how I setup my own profile to create dynamic content to aid discovery of my projects:

You can visit github.com/j12y to see the final result of what I came up with for my own profile page.

My GitHub Profile

Dynamic Updates in Response to Changes

The problem to solve is how to dynamically update my GitHub Profile if there is a content change in a template, an update to the metadata of a repos, or a new blog post. Conveniently GitHub Actions provides a solution for continuous integration (CI) / continuous delivery (CD).

A GitHub Action can be triggered:

  • manually
  • when a commit or branch is merged
  • at a scheduled interval

One big advantage is that by running directly on the GitHub platform it becomes convenient for storing secrets and enabling changes in repositories by utilizing an existing authorization.

Getting Started with GitHub Actions

The Learn GitHub Actions documentation provides a good introduction to terminology and for understanding how it works. I don't want to repeat those details and focus on how I applied it, so reference the docs if anything is unclear.

The configuration file for my project is .github/workflows/build-readme.yml. The folder naming convention is critical, but the YAML file can be named to suit the purpose and there may be multiple workflows kept in separate configuration files.

I found the easiest way to get started was with a manual trigger to make sure the job behaves in the way I expect before fully automating it. This is done by specifying a workflow_dispatch configuration.

name: Update README.md

on:
  workflow_dispatch:
Enter fullscreen mode Exit fullscreen mode

From the Actions menu in the repo, you can select the Update README.md workflow and click the Run workflow button to trigger the job to run at will.

Run workflow

GitHub Actions Jobs and Build Steps

What happens when the button is clicked depends on how the job is configured. Here's the first few steps of my build job.

jobs:
  build:
    runs-on: ubuntu-latest
    environment: buildenv
    steps:
      - name: Trigger event
        run: echo "Triggered by ${{ github.event_name }}"
      - name: Checkout repo
        uses: actions/checkout@v3
      - name: Install dependencies
        run: |
          npm install
Enter fullscreen mode Exit fullscreen mode

The runs-on configures the type of machine to run the job. There are a number of different types of runners but a github hosted ubuntu-latest is versatile enough for my needs.

We'll come back to the environment in the next section.

These first few steps demonstrate how you can run commands like npm install or import other workflows such as how it uses the actions/checkout to copy the contents of the repository into a working directory on the runner host. Read Reusable workflows for more about the syntax for referencing them.

Using Environment Variables with Actions

The previous section referenced the buildenv environment. This enables variables or secrets that you want to be able to reference but not expose in code to be stored.

Environment settings

The environment distinguishes between secrets (which will be redacted from logs) and vars which may be captured in output for debugging and can be modified without changing any code. There are also some universally available github values that can be used.

      - name: Build source
        env:
          TOKEN: ${{ secrets.TOKEN }}
          REPO: ${{ github.repository_owner }}
          USERNAME: ${{ github.repository_owner }}
          MEDIUM_ID: ${{ vars.MEDIUM_ID }}
          DEVTO_ID: ${{ vars.DEVTO_ID }}
          DOLBYIO_ID: ${{ vars.DOLBYIO_ID }}
        run: |
          npm start
Enter fullscreen mode Exit fullscreen mode

There is a bit of redundancy to this configuration that is not ideal. The variable names need to be mapped between the GitHub environment and the runner environment. I asked the community for tricks on Passing All GitHub Environment Variables and Secrets in a GitHub Actions Workflow but it seems this may be a common feature request.

One workaround would be to take all the secrets and variables, encode as JSON, pass that as a variable, and then unpack it again. Alternatively, could just store the JSON structure as the environment variable itself. In my case, since there were only a few variables I didn't add the extra complexity.

run: |
  echo "$ALL_VARS"
env:
  ALL_VARS: ${{ toJSON(vars) }}
Enter fullscreen mode Exit fullscreen mode

The npm start in my project generates the README.md output and is the primary build output from this workflow.

Next, I need to do something with the artifact.

Conditional in a GitHub Action Workflow

If there are no template changes, no new blog posts, and no repo updates it would be unnecessary to commit changes to the README.md. Worse, that can cause the job to fail since the commit would fail with no differences.

To solve for this, you can run a step to run a git diff and store the result as an environment variable.

      - name: Check for changes
        run: |-
          if git diff --exit-code; then
            echo "README_CHANGED=0" >> "$GITHUB_ENV"
          else
            echo "README_CHANGED=1" >> "$GITHUB_ENV"
            git diff
          fi
Enter fullscreen mode Exit fullscreen mode

The variable can then be checked with the if syntax which means this step will be optional depending on the value of the environment variable.

      - name: Commit change
        if: env.README_CHANGED != 0
        run: |-
          git config user.name "GitHub Action: ${{ github.workflow }} #${{ github.run_number }}"
          git config user.email "<>"
          git add README.md
          git commit -m 'GitHub Action: ${{ github.workflow }} #${{ github.run_number }}'
          git push
Enter fullscreen mode Exit fullscreen mode

If there are meaningful changes, these steps will set the git configuration for checkin to the repository with a meaningful commit message that references the GitHub Action's job number.

Actions to Manage Scheduled Jobs Like Cron

There are many ways to trigger an action to execute. One clever thing I observed others do was to have something like a webhook from a third-party service create an issue and then use the creation of an issue to trigger the action to run.

Given my use case is primarily about metadata updates and new blog content, a daily update is sufficient. With GitHub Actions you can also configure scheduled jobs that run like a cron job would at regular intervals.

on:
  schedule:
    - cron: '55 7 * * 1-5'        # Weekdays at 7:55
Enter fullscreen mode Exit fullscreen mode

Every weekday morning since that's when I'm more likely to have updates the workflow will run and update the README with any new changes.

Actions to Manage Merges

This last trigger is pretty straightforward, any time I change the content of the templates used to generate the README, I want that push and merge to trigger an update right away.

The action can run on that trigger as well:

on:
  push:
Enter fullscreen mode Exit fullscreen mode

Take Action on Your Profile

I hope this overview helps you get acquainted with GitHub Actions, perhaps using your own GitHub Profile as a way to get familiar with a low-stakes project while building your portfolio.

If you missed an earlier part of the series, check them out for specific dives into the various tools used.

Let me know if you have any questions or were able to use this on your own profile or similar project.

Top comments (0)