How to Write to Workflow Job Summary from a GitHub Action
Tags: github, python, devops, tutorial
Published: 2022-12-21 18:37:13

This post continues my series on tips for developing GitHub Actions. In this post, I explain how an Action can write to the workflow job summary, so that the users of your Action can find details of the Action formatted with markdown via the Actions tab. I start with a simple example of writing to the workflow job summary from a step of a workflow. I then explain my approach in writing to the workflow job summary from a GitHub Action implemented in Python.

__Table of Contents:__
* [How to Write to Job Summary from a Workflow Step](#how-to-write-to-job-summary-from-a-workflow-step)
* [How to Write to Job Summary from a GitHub Action Implemented in Python](#how-to-write-to-job-summary-from-a-github-action-implemented-in-python)
* [Where You Can Find Me](#where-you-can-find-me)


## How to Write to Job Summary from a Workflow Step

The GitHub Actions framework provides a straightforward way to write to the job summary of a workflow run, which includes support for formatting with Markdown. Specifically, within the GitHub Actions framework there is an environment variable `$GITHUB_STEP_SUMMARY`, which is a file that corresponds to the job summary. Simply append to that file whatever it is that you want to include in the summary for the workflow run.

Here is a minimal workflow file that does this. It is set up to run on `workflow_dispatch` events, which means that you can manually run it from the `Actions` tab of your repository. Simply insert the following into a file with the extension `.yml` within your `.github/workflows` directory. It has a single step that just writes some sample Markdown with a level 1 heading, a level 2 heading, and a "Hello GitHub" message.

```YAML
name: summary

on:
  workflow_dispatch:

jobs:
  summarize:

    runs-on: ubuntu-latest

    steps:
    - name: Write to workflow job summary
      run: |
        SUMMARY=$'# Testing Job Summary\n## Second Level Heading\nHello GitHub'
        echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY
```

Insert this into a file with the extension `.yml` within your `.github/workflows` directory. Then go to the `Actions` tab, find your workflow, and click the `Run workflow button`. After it runs, click on the run, and you'll find something that looks like the following:

![Example Workflow Summary](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2jvxsyous7hxjellnns.PNG)

The above is a screenshot of an actual run of this very workflow.


## How to Write to Job Summary from a GitHub Action Implemented in Python

I maintain several GitHub Actions implemented in Python as [container actions](https://docs.github.com/en/actions/creating-actions/creating-a-docker-container-action). One of these, [jacoco-badge-generator](https://github.com/cicirello/jacoco-badge-generator), produces coverage badges from JaCoCo test coverage reports. Additionally, it outputs the test coverage percentages to the workflow job summary. This example is based upon the approach I use in [jacoco-badge-generator](https://github.com/cicirello/jacoco-badge-generator).

First, I have a template string that I later use to format the job summary with Markdown:

```Python
markdownSummaryTemplate = """## JaCoCo Test Coverage Summary
* __Coverage:__ {0:.3%}
* __Branches:__ {1:.3%}
* __Generated by:__ jacoco-badge-generator
"""
```

Then, I have a function that formats and outputs the job summary. Make sure that you *append* to the environment file `GITHUB_STEP_SUMMARY`. The reason that I check that it exists is that this particular GitHub Action is also designed to be used as a CLI tool outside of GitHub Actions. When someone is using it in CLI mode, such as on their local system, that environment variable won't exist, and there also isn't anywhere to actually output this markdown anyway. You also need to import `os` first with `import os`.

```Python
def add_workflow_job_summary(cov, branches) :
    """Adds a job summary.
    
    Keyword arguments:
    cov - Coverage percentage
    branches - Branches coverage percentage
    """
    if "GITHUB_STEP_SUMMARY" in os.environ :
        with open(os.environ["GITHUB_STEP_SUMMARY"], "a") as f :
            print(markdownSummaryTemplate.format(cov, branches), file=f)
```

Here is a screenshot from an actual run of this Action from one of my other projects that uses it:

![Real Example Workflow Summary](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b88z4ebqlysxqvahipv4.PNG)

## Where You Can Find Me

Follow me here on DEV:

{% user cicirello %}

Follow me on GitHub:

{% github cicirello/cicirello %}

Or visit my website:

{% embed https://www.cicirello.org/ %}