twistlock 0.0.0-development

Docker <> Rust interface
Documentation
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: Build

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

permissions:
  contents: read
  checks: write
  pull-requests: write
  issues: write
  packages: write

env:
  CARGO_TERM_COLOR: always
  # Use docker.io for Docker Hub if empty
  REGISTRY: ghcr.io
  APPLICATION_NAME: twistlock
  # github.repository as <account>/<repo>
  IMAGE_NAME: ${{ github.repository }}

concurrency:
  # each new commit to a PR runs this workflow
  # so we need to avoid a long running older one from overwriting the "pr-<number>-latest"
  group: "${{ github.workflow }} @ ${{ github.ref_name }}"
  cancel-in-progress: true

jobs:
  changes:
    name: Detect changes
    runs-on: ubuntu-latest
    outputs:
      code: ${{ steps.filter.outputs.code }}
    steps:
      - name: Checkout
        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2

      - name: Check if we actually made changes
        uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # tag=v2.11.1
        id: filter
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          filters: .github/file-filters.yml

  calculate-version:
    name: Calculate version
    runs-on: ubuntu-latest
    needs:
      - changes
    outputs:
      version: ${{ steps.version.outputs.nextversion }}
    if: |
      github.event_name == 'pull_request' &&
      fromJSON(needs.changes.outputs.code) == true
    steps:
      - name: Checkout
        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
        with:
          fetch-depth: 0

      - name: Cache dependencies
        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
        env:
          CACHE_NAME: cargo-cache-dependencies
        with:
          path: |
            ~/.cargo
            ./target
          key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-cocogitto
          restore-keys: |
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-

      - name: Set up toolchain
        shell: bash
        run: |
          rm ${HOME}/.cargo/bin/rustfmt
          rm ${HOME}/.cargo/bin/cargo-fmt
          rustup update

          cargo --version

      - name: Get binstall
        shell: bash
        run: |
          cd /tmp
          archive="cargo-binstall-x86_64-unknown-linux-musl.tgz"
          wget "https://github.com/cargo-bins/cargo-binstall/releases/latest/download/${archive}"

          tar -xvf "./${archive}"

          rm "./${archive}"

          mv ./cargo-binstall ~/.cargo/bin/

      - name: Install cocogitto to get the next version number
        shell: bash
        run: |
          cargo binstall --no-confirm cocogitto --target x86_64-unknown-linux-musl --pkg-url "{ repo }/releases/download/{ version }/{ name }-{ version }-{ target }.tar.gz" --bin-dir "{ bin }" --pkg-fmt tgz

      - name: Calculate next version
        id: version
        shell: bash
        run: |
          VERSION="$(cog bump --auto --dry-run || true)"

          if [[ -z $VERSION ]]; then
              VERSION="$(git tag --points-at "$(git rev-list --tags --max-count=1)" | sort --reverse | head --lines 1)"

              echo "No version generated, defaulting to latest git tag: ${VERSION}"
          else
              echo "New version: ${VERSION}"
          fi

          # remove v
          VERSION="${VERSION//v/}"

          # store
          echo "nextversion=${VERSION}" >> ${GITHUB_OUTPUT}

  cargo-build:
    name: Cargo build
    runs-on: ubuntu-latest
    needs:
      - changes
    if: |
      github.event_name == 'pull_request' &&
      fromJSON(needs.changes.outputs.code) == true
    steps:
      - name: Checkout
        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2

      - name: Cache dependencies
        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
        env:
          CACHE_NAME: cargo-cache-dependencies
        with:
          path: |
            ~/.cargo
            ./target
          key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-build
          restore-keys: |
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-

      - name: Set up toolchain
        shell: bash
        run: |
          rm ${HOME}/.cargo/bin/rustfmt
          rm ${HOME}/.cargo/bin/cargo-fmt
          rustup update

          cargo --version

      - name: Build
        shell: bash
        run: |
          cargo build --all-targets --workspace --verbose

  cargo-fmt:
    name: Cargo fmt
    runs-on: ubuntu-latest
    needs:
      - changes
    if: |
      github.event_name == 'pull_request' &&
      fromJSON(needs.changes.outputs.code) == true
    steps:
      - name: Checkout
        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2

      - name: Cache dependencies
        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
        env:
          CACHE_NAME: cargo-cache-dependencies
        with:
          path: |
            ~/.cargo
            ./target
          key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-fmt
          restore-keys: |
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-

      - name: Set up toolchain
        shell: bash
        run: |
          rm ${HOME}/.cargo/bin/rustfmt
          rm ${HOME}/.cargo/bin/cargo-fmt
          rustup update

          cargo --version

      - name: Check formatting
        shell: bash
        run: |
          cargo fmt --all -- --check --verbose

  cargo-test-and-report:
    name: Cargo test (and report)
    runs-on: ubuntu-latest
    needs:
      - changes
    if: fromJSON(needs.changes.outputs.code) == true
    steps:
      - name: Checkout
        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2

      - name: Cache dependencies
        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
        env:
          CACHE_NAME: cargo-cache-dependencies
        with:
          path: |
            ~/.cargo
            ./target
          key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-test
          restore-keys: |
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-

      - name: Set up toolchain
        shell: bash
        run: |
          rm ${HOME}/.cargo/bin/rustfmt
          rm ${HOME}/.cargo/bin/cargo-fmt
          rustup update

          cargo --version

      - name: Install llvm-tools-preview
        shell: bash
        run: |
          rustup component add llvm-tools-preview

      - name: Get binstall
        shell: bash
        run: |
          archive="cargo-binstall-x86_64-unknown-linux-musl.tgz"
          wget "https://github.com/ryankurte/cargo-binstall/releases/latest/download/${archive}"

          tar -xvf "./${archive}"

          rm "./${archive}"

          mv ./cargo-binstall ~/.cargo/bin/

      - name: Install nextest, custom test runner, with native support for junit
        shell: bash
        run: |
          cargo binstall --no-confirm cargo-nextest;

      - name: Install grcov
        shell: bash
        run: |
          cargo binstall --no-confirm grcov --pkg-url "{ repo }/releases/download/v{ version }/{ name }-{ target }.tar.bz2" --pkg-fmt tbz2 --bin-dir "{ bin }";

      - name: Build with instrumentation support
        shell: bash
        env:
          RUSTFLAGS: "-C instrument-coverage"
        run: |
          cargo build --all-targets --workspace --verbose

      - name: Run nextest
        shell: bash
        id: tests
        env:
          RUSTFLAGS: "-C instrument-coverage"
          LLVM_PROFILE_FILE: "profiling/profile-%p-%m.profraw"
        run: |
          cargo nextest run --profile ci --no-fail-fast --all-targets --workspace
        continue-on-error: true

      - name: Upload test results
        uses: EnricoMi/publish-unit-test-result-action@4e7013f9576bd22ffdae979dc6e68cb9ec2aeece # v2.7.0
        with:
          check_name: Test results
          github_token: ${{ secrets.GITHUB_TOKEN }}
          junit_files: reports/results.xml

      - name: Run grcov
        shell: bash
        run: |
          grcov $(find profiling -name "profile-*.profraw" -print) --source-dir . --binary-path ./target/debug/ --output-type lcov --branch --ignore-not-existing --llvm --keep-only "src/**" --keep-only "tests/**" --output-path ./reports/lcov.info

      - name: Upload to CodeCov
        uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          directory: reports
          fail_ci_if_error: true

      - name: Fail if tests failed
        shell: bash
        if: steps.tests.outcome != 'success'
        run: |
          # the test reporter we use (or any for that matter)
          # all show a report. But we cannot depend on that report because
          # we don't know which subsection it belongs in GitHub
          # so we explicitly fail this one
          # which will fail All Done
          exit 1;

  cargo-clippy-and-report:
    name: Cargo clippy (and report)
    runs-on: ubuntu-latest
    needs:
      - changes
    if: |
      github.event_name == 'pull_request' &&
      fromJSON(needs.changes.outputs.code) == true
    steps:
      - name: Checkout
        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2

      - name: Cache dependencies
        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
        env:
          CACHE_NAME: cargo-cache-dependencies
        with:
          path: |
            ~/.cargo
            ./target
          key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-clippy
          restore-keys: |
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-
            ${{ runner.os }}-build-${{ env.CACHE_NAME }}-

      - name: Set up toolchain
        shell: bash
        run: |
          rm ${HOME}/.cargo/bin/rustfmt
          rm ${HOME}/.cargo/bin/cargo-fmt
          rustup update

          cargo --version

      - name: Run Clippy for GitHub Actions report
        uses: actions-rs-plus/clippy-check@9035ac35de400d5b7d37b4ce176ebd153e424d29 # v2
        with:
          args: --workspace --all-targets --all-features -- --deny clippy::all --deny clippy::pedantic --deny clippy::cargo

  all-done:
    name: All done
    # this is the job that should be marked as required on GitHub. It's the only one that'll reliably trigger
    # when any upstream fails: success
    # when all upstream skips: pass
    # when all upstream success: success
    # combination of upstream skip and success: success
    runs-on: ubuntu-latest
    needs:
      - calculate-version
      - cargo-build
      - cargo-fmt
      - cargo-clippy-and-report
      - cargo-test-and-report
    if: always()
    steps:
      - name: Fail!
        shell: bash
        if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
        run: |
          echo "One / more upstream failed or was cancelled. Failing job..."

          exit 1

      - name: Success!
        shell: bash
        run: |
          echo "Great success!"