name: "Containers: Test-and-Build"

on:
  workflow_dispatch:
  push:
    branches:
    - master
    paths:
    - '.containers/apps/**'
    - '.containers/base/**'
    - ".github/workflows/containers.build.yaml"
  pull_request:
    paths:
    - '.containers/apps/**'
    - '.containers/base/**'
    - ".github/workflows/containers.build.yaml"

env:
  # How long to sleep before running the tests (gives the application time to start)
  GOSS_SLEEP: 30

# Detect which folders in project-root (which contain the containers) contain changes
jobs:
  changes:
    name: Get changes
    runs-on: ubuntu-20.04
    outputs:
      matrix: "{\"container\": ${{ steps.reduce.outputs.containers }} }"
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - uses: dorny/paths-filter@v2
      id: filter
      with:
        list-files: json
        filters: |
          changed:
          - '.containers/apps/**'
          - '.containers/base/**'
    - run: echo '${{ toJson(steps.filter.outputs) }}' > changes.json
    - id: reduce
      run: |
        CONTAINERS=$(jq --raw-output '.changed_files | fromjson | .[] |= sub("(?<filepath>(?<first_directory>(?<root1>[\/]?)[^\/]+\/)(?<second_directory>(?<root2>[\/]?)[^\/]+\/(?<third_directory>(?<root3>[\/]?)[^\/]+)(?<extra_paths>.+)))"; "\(.third_directory)") | unique' changes.json)
        echo ::set-output name=containers::${CONTAINERS}

  hadolint:
    name: Run hadolint
    runs-on: ubuntu-20.04
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: hadolint
      uses: reviewdog/action-hadolint@v1.19.1
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        reporter: github-pr-review
        filter_mode: diff_context
        fail_on_error: true

  build:
    name: Build
    runs-on: ubuntu-20.04
    needs:
    - hadolint
    - changes
    strategy:
      matrix: ${{ fromJson(needs.changes.outputs.matrix) }}
      fail-fast: false
    if: "!contains(github.event.head_commit.message, '[ci-skip]')"
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    # Define if tests and push should be run against which versions/platforms
    - name: Prepare
      id: prep
      run: |
        if test -f "./.containers/apps/${{ matrix.container }}/Dockerfile"; then
          CATEGORY="apps"
        else
          CATEGORY="base"
        fi
        echo ::set-output name=category::${CATEGORY}
        VERSION=$(cat ./.containers/${CATEGORY}/${{ matrix.container }}/VERSION)
        echo ::set-output name=version::${VERSION}
        PLATFORM="linux/amd64"
        echo ::set-output name=platform::${PLATFORM}
        if test -f "./.containers/${CATEGORY}/${{ matrix.container }}/goss.yaml"; then
          echo ::set-output name=goss::true
        else
          echo ::set-output name=goss::false
        fi
        if [ "${{github.event_name}}" == "pull_request" ]; then
          echo ::set-output name=push::false
          echo ::set-output name=cache_from::"type=registry,ref=ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:buildcache" || echo ::set-output name=cache_from::""
          echo ::set-output name=cache_to::""
        else
          echo ::set-output name=push::true
          echo ::set-output name=cache_from::"type=registry,ref=ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:buildcache"
          echo ::set-output name=cache_to::"type=registry,ref=ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:buildcache,mode=max"
        fi

    - name: Set up QEMU
      uses: docker/setup-qemu-action@v1
      with:
        platforms: amd64

    - name: Login to GHCR
      uses: docker/login-action@v1
      if: github.event_name != 'pull_request'
      with:
        registry: ghcr.io
        username: ${{ secrets.GHCR_USERNAME }}
        password: ${{ secrets.GHCR_TOKEN }}

    # Install and configure Buildx
    - name: Set up Docker Buildx
      id: buildx
      uses: docker/setup-buildx-action@v1
      with:
        install: true
        version: latest
        driver-opts: image=moby/buildkit:master

    # Install the GOSS testing framework
    - name: Set up goss/dgoss
      uses: e1himself/goss-installation-action@v1.0.3
      if: ${{ steps.prep.outputs.goss == 'true' }}
      with:
        version: 'v0.3.16'

    # Creates a local build to run tests on
    - name: Build and Load local test-container
      if: ${{ steps.prep.outputs.goss == 'true' }}
      uses: docker/build-push-action@v2
      with:
        build-args: VERSION=${{ steps.prep.outputs.version }}
        context: .
        file: ./.containers/${{ steps.prep.outputs.category }}/${{ matrix.container }}/Dockerfile
        load: true
        tags: |
          ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:test
        cache-from: ${{ steps.prep.outputs.cache_from }}
        cache-to: ${{ steps.prep.outputs.cache_to }}

    # Run GOSS tests if included with the container
    - name: Run GOSS tests
      if: ${{ steps.prep.outputs.goss == 'true' }}
      env:
        GOSS_FILE: ./.containers/${{ steps.prep.outputs.category }}/${{ matrix.container }}/goss.yaml
      run: |
        dgoss run ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:test

    # Push if not a PR, otherwise just test the build process for all requested platforms
    - name: Build and Push
      uses: docker/build-push-action@v2
      with:
        build-args: VERSION=${{ steps.prep.outputs.version }}
        context: .
        platforms: ${{ steps.prep.outputs.platform }}
        file: ./.containers/${{ steps.prep.outputs.category }}/${{ matrix.container }}/Dockerfile
        push: ${{ steps.prep.outputs.push }}
        tags: |
          ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:latest
          ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:v${{ steps.prep.outputs.version }}
        cache-from: ${{ steps.prep.outputs.cache_from }}
        cache-to: ${{ steps.prep.outputs.cache_to }}

  container-build-complete:
    needs: [build]
    name: Container Build Completed
    runs-on: ubuntu-latest
    steps:
      - name: complete message
        run: echo "Container Build and Tests Completed Successfully"
