Cover Image for 5 High Impact Enhancements You Can Make to Your GitHub CI/CD Pipeline

5 High Impact Enhancements You Can Make to Your GitHub CI/CD Pipeline

By Charlie Dalldorf on

GitHub is a powerful versioning and source control system as it is. But did you know there are some quick and easy ways to get more performance out of it? And a lot of these down below are great additions to your pipelines that your upper-level management and auditors will love to hear.

Let's get into it.

If you want to see the final code, workflows, and configurations for this article, they can be found here in this repository.

Automated Unit Testing Comments on Pull Requests

This enhancement uses two GitHub Action packages to achieve its goal. Code Coverage Summary takes an existing Cobertura formatted code coverage file and exports a markdown summary version of it. This then allows us to chain Sticky Pull Request Comment and add a comment to an existing Pull Request.

As an added bonus, we will add that markdown code coverage report and paste it as part of the Job Summary at the end of the workflow.

Author Note: Code Coverage Summary requires a Linux runner to be used for the package to work properly.

Inside of your project, let's add a .github folder at the root level.

image 2

Now let's go inside of our .github folder and add a workflows folder. Inside of the workflows folder, we want to add a new .yml file that will run whenever a Pull Request is created going to the main branch. Just as an example, I will name it pr.status-checks.yml.

image 3

Now we will write out our Status Check workflow. For this particular example, I am using .NET for the solution and basis for this post. But any programming language that can generate a Cobertura Unit Testing file should be good.

In this particular workflow, we need to make sure we add the permissions: write all property as part of the job. This allows the workflow the ability to modify pull requests and the GitHub Actions Job Summary itself.

Here's the workflow we should write to achieve this:

name: Pull Request - Status Checks

on:
  pull_request:
    branches: [ main ]

jobs:
  build:
    permissions: write-all
    runs-on: ubuntu-latest
    name: PR - Status Check
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 7.0.x

    - name: Restore Dependencies
      run: dotnet restore Impact/Impact.sln

    - name: Build
      run: dotnet build Impact/Impact.sln --configuration Release --no-restore

    - name: Test
      run: dotnet test Impact/Impact.sln --configuration Release --no-build --verbosity normal --collect:"XPlat Code Coverage" --logger trx --results-directory ./coverage

    - name: Code Coverage Report
      uses: irongut/CodeCoverageSummary@v1.3.0
      with:
        filename: coverage/**/coverage.cobertura.xml
        badge: true
        indicators: true
        format: markdown
        output: both

    - name: Add Coverage PR Comment
      uses: marocchino/sticky-pull-request-comment@v2
      if: github.event_name == 'pull_request'
      with:
        recreate: true
        path: code-coverage-results.md

    - name: Write to Job Summary
      run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY

Once you open up a Pull Request, this Status Check workflow should run. If your Cobertura file exports properly from the testing step of your workflow, the rest of the GitHub Actions packages should run and complete as well.

At the bottom of your GitHub Actions workflow that runs, you should see a Code Coverage Summary report that shows overall statistics for testing on your project.

image 4

And you should see that same report as a comment in your Pull Request comments section:

image 5

Code Coverage Report Generator

On the subject of Code Coverage reports, if you want something more substantial, Daniel Palme's Report Generator might be what you are looking for. His code coverage generator supports various formats for consumption and exportation.

Here is the Report Generator GitHub Actions Package.

The only thing we need to modify in our existing pr.status-checks.yml workflow file is adding the Report Generator package and Upload Artifact to attach the zip file that gets generated.

Now our workflow file looks like this:

name: Pull Request - Status Checks

on:
  pull_request:
    branches: [ main ]

jobs:
  build:
    permissions: write-all
    runs-on: ubuntu-latest
    name: PR - Status Check
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 7.0.x

    - name: Restore Dependencies
      run: dotnet restore Impact/Impact.sln

    - name: Build
      run: dotnet build Impact/Impact.sln --configuration Release --no-restore

    - name: Test
      run: dotnet test Impact/Impact.sln --configuration Release --no-build --verbosity normal --collect:"XPlat Code Coverage" --logger trx --results-directory ./coverage

    - name: Code Coverage Report
      uses: irongut/CodeCoverageSummary@v1.3.0
      with:
        filename: coverage/**/coverage.cobertura.xml
        badge: true
        indicators: true
        format: markdown
        output: both

    - name: Add Coverage PR Comment
      uses: marocchino/sticky-pull-request-comment@v2
      if: github.event_name == 'pull_request'
      with:
        recreate: true
        path: code-coverage-results.md

    - name: Write to Job Summary
      run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY

    - name: ReportGenerator
      uses: danielpalme/ReportGenerator-GitHub-Action@5.2.0
      with:
        reports: coverage/**/coverage.cobertura.xml
        targetdir: coveragereport

    - name: Upload coverage report artifact
      uses: actions/upload-artifact@v2.2.3
      with:
        name: CoverageReport  
        path: coveragereport

Near the bottom of your Workflow Job Summary page should be an artifact produced by Report Generator:

image 6

After you download that artifact and unzip it, index.html contains a good summary of unit testing statistics across your project:

image 7

And if you open up one of your classes that was tested, you also get an in-depth look at what was tested using color-coded gutters:

image 8

image 9

The Usage Page on Daniel Palme's Report Generator website has tons of information on how his package exports out these summary reports. Just about every use case I can think of is supported.

Pull Request / Issue Templates

Standardizing GitHub Issues or Pull Requests is a great way to add consistency to your repositories. The predictable format can help guide developers and reviewers on what to expect whenever a new request is made.

Let's start with the Pull Request Template. We want to create a pull_request_template.md file inside of .github.

image 10

Using Markdown, we can set up a standard format on what every Pull Request will look like when it gets created in GitHub. Here is an example you can copy and paste for this example:

# Description

Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change.

Fixes # (issue)

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

- [ ] Test A
- [ ] Test B

**Test Configuration**:
* Firmware version:
* Hardware:
* Toolchain:
* SDK:

# Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules

Once this Markdown file has been added to the Main Branch, when we create a new Pull Request, we should see that Markdown pre-populated inside the text area section of a PR:

image 11

And after the Pull Request is created:

image 12

Arthur Coudouy has a good blog post about this on his website: GitHub pull request template. And here is GitHub's Pull Request Template Documentation.

Issue templates are treated a bit differently. We need to create an ISSUE_TEMPLATE folder under .github and we can add a 1-bug-report.yml as well. Next, we can populate that new YAML file with this Markdown text (taken from GitHub's Issue Template Documentation):

name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug", "triage"]
assignees:
  - octocat
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this bug report!
  - type: input
    id: contact
    attributes:
      label: Contact Details
      description: How can we get in touch with you if we need more info?
      placeholder: ex. email@example.com
    validations:
      required: false
  - type: textarea
    id: what-happened
    attributes:
      label: What happened?
      description: Also tell us, what did you expect to happen?
      placeholder: Tell us what you see!
      value: "A bug happened!"
    validations:
      required: true
  - type: dropdown
    id: version
    attributes:
      label: Version
      description: What version of our software are you running?
      options:
        - 1.0.2 (Default)
        - 1.0.3 (Edge)
      default: 0
    validations:
      required: true
  - type: dropdown
    id: browsers
    attributes:
      label: What browsers are you seeing the problem on?
      multiple: true
      options:
        - Firefox
        - Chrome
        - Safari
        - Microsoft Edge
  - type: textarea
    id: logs
    attributes:
      label: Relevant log output
      description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
  - type: checkboxes
    id: terms
    attributes:
      label: Code of Conduct
      description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com)
      options:
        - label: I agree to follow this project's Code of Conduct
          required: true

Now when you go and create a new Issue, there will be a new template waiting for you:

image 13

Clicking on Get Started will bring you to the Issue creation screen where you can fill in values from the YAML configuration file:

image 14

And our newly created Issue:

image 15

GitHub's Issue Template Documentation goes into great detail on how to best create multiple templates for your GitHub repositories.

Automated Style and Linting Checks

This is another great one to add on top of unit testing. It is one thing to test that your code is functioning as it should. It is another to see if it is styled sensibly.

For this one, let's add linting.status-checks.yml under the workflows folder. And for this one, we will run this check as Push instead of a Pull Reqest. For this example, this is a .NET formatting check using dotnet format and checking the .editorconfig file. Depending on the language you use, you will have different requirements and commands to run this functionality.

We can use this workflow to run this Status Check:

name: Linting - Status Checks

on:
  push:
    branches-ignore: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    name: PR - Status Check
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 7.0.x

    - name: Restore Dependencies
      run: dotnet restore Impact/Impact.sln

    - name: Build
      run: dotnet build Impact/Impact.sln --configuration Release --no-restore

    - name: Format
      run: dotnet format Impact/Impact.sln --verify-no-changes

And here's the successful run:

image 16

Microsoft's Dotnet Format Documentation

Release Drafter

image 17

When I talk about adding this feature to a GitHub repository, everybody's ears perk up. Release Drafter is a GitHub Actions Package that takes PRs that have been merged to the main branch and adds them as a draft to the Releases portion of that repository.

We need to add two files for this enhancement. The first will be the Release Drafter configuration file. Let's create release-drafter.yml inside of our .github folder and add this as our test bench:

name-template: 'v$RESOLVED_VERSION 🌈'
tag-template: 'v$RESOLVED_VERSION'
categories:
  - title: '🚀 Features'
    labels:
      - 'feature'
      - 'enhancement'
  - title: '🐛 Bug Fixes'
    labels:
      - 'fix'
      - 'bugfix'
      - 'bug'
  - title: '🧰 Maintenance'
    label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
version-resolver:
  major:
    labels:
      - 'major'
  minor:
    labels:
      - 'minor'
  patch:
    labels:
      - 'patch'
  default: patch
template: |
  ## Changes

  $CHANGES

Next, we add another release-drafter.yml inside of .github/workflows and add this to the file:

name: Release Drafter

on:
  push:
    branches:
      - main

permissions:
  contents: read

jobs:
  update_release_draft:
    permissions:
      contents: write
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
      - uses: release-drafter/release-drafter@v5
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Once we get these two files into the main branch, our repository will be primed to add Pull Requests into a drafted release. A Release Drafter workflow will run after a PR gets merged into the main branch:

image 18

What we see inside our drafted release is an auto-incremented title, changes that were made, and a link back to the PR that got merged into the main branch.

image 19

This is one of the easiest enhancements you can make to your GitHub repositories. It is a great way to track changes and have that paper trail of who did what, etc.

Thanks for reading and I hope this was helpful to you. If you have not implemented some of these in your repositories, these make great enhancements to give them some extra punch.

If you want to see the final code, workflows, and configurations for this article, they can be found here in this repository.

Until next time!