Skip to content

ruben-rodriguez/github-actions

Repository files navigation

github-actions

This repository contains some sample apps and associated test suites written in different languages (Java, Go and Python), organized in folders. The purpose is quite simple: test and discover GitHub Actions workflow features, capabilities and potential limitations. Please note this is still a work in progress exercise, hence might contain some errors and other hiccups, and is subject to change. Also, keep in mind GitHub Actions is a recent feature which is still evolving and adding / changing different features.

Repository structure:

.
├── .github/workflows: GitHub actions workflow.
├── .gitsecret: git secret related config files.
├── app: Python demo web application used for robot framework testing.
│   └── html: web application resources.
├── go-apps: go simple apps to build and test.
│   ├── hello: Hello World Go application and test suite.
│   ├── hello2: Clone of previous Hello World Go application and test suite.
├── java-apps: java simple spring apps and tests; each app loads different env variables from .env file.
│   ├── HelloWorld: Hello World Java application and test suite.
│   └── test: Clone of previous Hello World Java. application and test suite.
├── robot-tests : Robot Framework sample tests for the Python Webapp Demo.
├── secrets: secrets obscured.
└── *.env: environment files

Workflows

Currently, there are 3 different workflows defined in this repository:

  • Pull Request Workflow (pull-reques.yaml): triggered on pull request events, executes all tests defined for all exisiting applications.

  • Push Go Workflow (go-app.yaml): triggered on push events, check branch name for existing Go application name and executes tests appropriately. Branch naming convention: <app-name>/<feature-name>

  • Slack PR Notification Workflow (slack-pr-notification.yaml): triggered on pull request events, notfies Slack #review channel of new opened Pull Requests.

Pull Request Workflow

Triggered on pull request events, executes all tests defined for all exisiting applications.

name: Build and test apps

on: [pull_request]

It contains the following jobs (summary):

  • slack-notify-start: sends a notification to #builds slack channel when workflow starts:

  • java: leverages matrix strategy to build and test all java apps organized in different folders. It executes mvn commands and reveals git secrets.

  • go: leverages matrix strategy to build and test all go apps organized in different folders. It executes go commands.

  • python: runs and test Python demo WebApp using Robot Framework. It uploads Robot Framework reports to /reports folder created at workflow execution time.

  • check: this job is always executed regardless other jobs' finish status. It checks that the core jobs (go, java, python) finish correctly without errors. It is then required by branch policy to merge pull requests.

  • generate_report: fetches Robot Framework results from /reports folder and appends the results to commit message:

  • slack-notify-end: this job is always executed and checks the check job to update the slack notification previously sent appropriately (success or failure):

Slack PR notification Workflow Description

This workflow is used to notify on PR open and reopen events:

on:
  pull_request:
    types: [opened, reopened]

Push Go Workflow

Triggered on push events, check branch name for existing Go application name and executes tests appropriately. Branch naming convention: <app-name>/<feature-name>

It contains the following jobs (summary):

  • check-app: checks branch name and tries to locate a folder with its name. If found, sets working dir variable taken in the next step.
- name: Check if dir exists
              id: dir_exists
              run: |
                file ./go-apps/go/"${{ env.APP_NAME }}" | grep "No such" | wc -l
                echo "::set-output name=dir_exists::$(file ./go-apps/go/"${{ env.APP_NAME }}" | grep "No such" | wc -l)"
  • go-test: if previous job outputs that there is a folder in the go apps directory matching branch naming convention, it sets the working dir to the one set in previous job; then executes slack notification and go command steps.
go-test:
      if: ${{ needs.check-app.outputs.dir_exists  == '0' }} 
      runs-on: ubuntu-latest
      needs: [check-app]
      defaults:
        run:
          working-directory: ${{ needs.check-app.outputs.dir }}

GitHub Actions features leveraged by this workflow

  • Job status verification:
if: ${{ success() }}
  • Job and steps outputs and ids:
outputs:
      msgid: ${{ steps.slack.outputs.message_id }}
steps:
      id: slack #
...
with:
      message_id: ${{ needs.slack-notify-start.outputs.msgid }}
  • Matrix strategy to execute jobs for every repository folder:
 strategy:
      matrix:
        javaApps: [java-apps/test, java-apps/HelloWorld]
   defaults:
      run:
        working-directory: ${{ matrix.javaApps }}
  • Execution of commands directly, for loading env variables, for example:
run: |
   export $(grep -v '#.*' .env | xargs)
   echo $TEST
  • Job dependency and status check:
check:
   if: ${{ always() }}
   runs-on: ubuntu-latest
   name: Check success
   needs: [go, java, python]
steps:
   - name: Check build matrix go status
     if: ${{ needs.go.result != 'success' }}
     run: exit 1

Workflow Further Improvements

  • Skip checks on docs changes, feature branches: Skip Duplicate Actions
  • Skip jobs based on branch names, example:
on:
  # Trigger the workflow on push or pull request,
  # but only for the master branch
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

GitHub Actions Limitations (might not be such)

Used Actions

References