name: Main

on:
  push:
    branches:
      - "**"
    tags:
      - "v*"
  pull_request:
    branches:
      - "**"
  workflow_dispatch:
    inputs:
      pipeline:
        type: string
        description: "Directives e.g. '[ci only it]'"
      checkout:
        type: string
        description: "Checkout commit instead of HEAD"
      cargo_profiles:
        type: string
        default: '["test", "bench", "release", "release-debuginfo", "release-native"]'
        description: "Matrix Selector: Cargo profiles"
      feat_sets:
        type: string
        default: '["none", "default", "logging", "all"]'
        description: "Matrix Selector: Cargo feature sets"
      rust_toolchains:
        type: string
        default: '["nightly", "stable"]'
        description: "Matrix Selector: Rust toolchains"
      rust_targets:
        type: string
        default: '["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu"]'
        description: "Matrix Selector: Rust targets"
      sys_names:
        type: string
        default: '["debian"]'
        description: "Matrix Selector: System names"
      sys_targets:
        type: string
        default: '["x86_64-v1-linux-gnu", "x86_64-v2-linux-gnu", "x86_64-v3-linux-gnu", "aarch64-v8-linux-gnu"]'
        description: "Matrix Selector: System targets"
      sys_versions:
        type: string
        default: '["testing-slim"]'
        description: "Matrix Selector: System versions"
      machines:
        type: string
        default: '["X64", "ARM64"]'
        description: "Matrix Selector: Machine architectures"
      runners:
        type: string
        default: '["het", "aws"]'
        description: "Matrix Selector: Runner labels"
      package_containers:
        type: string
        default: '["docker", "oci"]'
        description: "Bake Selector: Container packages"
      package_distros:
        type: string
        default: '["deb", "rpm", "nix"]'
        description: "Bake Selector: Distro packages"
      enable_lint:
        type: boolean
        default: true
        description: Enable linting stage
      enable_test:
        type: boolean
        default: true
        description: Enable testing stage
      enable_package:
        type: boolean
        default: false
        description: Enable packaging stage
      enable_publish:
        type: boolean
        default: false
        description: Enable publication stage

concurrency:
  group: ${{github.workflow}}-${{github.ref}}
  cancel-in-progress: false

jobs:
  init:
    name: Init
    runs-on: ${{matrix.runner}}
    env:
      default_cargo_profiles: '["test", "bench", "release"]'
      default_feat_sets: '["none", "default", "all"]'
      default_rust_toolchains: '["nightly", "stable"]'
      default_sys_names: '["debian"]'
      default_sys_versions: '["testing-slim"]'
      default_rust_targets: '["x86_64-unknown-linux-gnu"]'
      default_sys_targets: '["x86_64-v1-linux-gnu", "x86_64-v3-linux-gnu"]'
      default_machines: '["X64"]'
      default_package_containers: '["docker", "oci"]'
      default_package_distros: '["deb", "rpm", "nix"]'
      is_release: ${{contains(github.ref, 'tags/v')}}
      is_branch: ${{contains(github.ref, 'refs/heads')}}
      is_pull: ${{contains(github.ref, 'refs/pull')}}
      is_main: ${{github.ref == 'refs/heads/main'}}
      is_test: ${{github.ref == 'refs/heads/test'}}
      is_dev: ${{contains(github.ref, 'refs/heads') && github.ref != 'refs/heads/main' && github.ref != 'refs/heads/test'}}
      is_fat: ${{contains(github.ref, 'tags/v') || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/test'}}

    outputs:
      cargo_profiles: ${{inputs.cargo_profiles || vars.CARGO_PROFILES || env.default_cargo_profiles}}
      feat_sets: ${{inputs.feat_sets || vars.FEAT_SETS || env.default_feat_sets}}
      rust_toolchains: ${{inputs.rust_toolchains || vars.RUST_TOOLCHAINS || env.default_rust_toolchains}}
      rust_targets: ${{inputs.rust_targets || vars.RUST_TARGETS || env.default_rust_targets}}
      sys_names: ${{inputs.sys_names || vars.SYS_NAMES || env.default_sys_names}}
      sys_targets: ${{inputs.sys_targets || vars.SYS_TARGETS || env.default_sys_targets}}
      sys_versions: ${{inputs.sys_versions || vars.SYS_VERSIONS || env.default_sys_versions}}
      machines: ${{inputs.machines || (fromJSON(env.is_fat) && vars.MACHINES) || env.default_machines}}
      pipeline: ${{inputs.pipeline || github.event.head_commit.message || github.event.workflow_run.head_commit.message}}
      checkout: ${{inputs.checkout || github.sha}}
      enable_lint: ${{fromJSON(inputs.enable_lint || 'true')}}
      enable_test: ${{fromJSON(inputs.enable_test || 'true')}}
      enable_test_unit: ${{fromJSON(inputs.enable_test_unit || 'true')}}
      enable_test_docs: ${{fromJSON(inputs.enable_test_docs || 'true')}}
      enable_test_bench: ${{fromJSON(inputs.enable_test_bench || 'true')}}
      enable_test_memcheck: ${{fromJSON(inputs.enable_test_memcheck || 'true')}}
      enable_test_smoke: ${{fromJSON(inputs.enable_test_smoke || 'true')}}
      enable_test_nix: ${{fromJSON(inputs.enable_test_nix || 'true')}}
      enable_test_rustsdk: ${{fromJSON(inputs.enable_test_rustsdk || 'true')}}
      enable_test_complement: ${{fromJSON(inputs.enable_test_complement || 'true')}}
      complement_logs: ${{fromJSON(inputs.complement_logs || 'true')}}
      complement_verbose: ${{fromJSON(inputs.complement_verbose || 'false')}}
      complement_runner: 'het'
      enable_package: ${{fromJSON(inputs.enable_package || 'true')}}
      enable_package_book: ${{fromJSON(inputs.enable_package_book || 'true')}}
      enable_package_binary: ${{fromJSON(inputs.enable_package_binary || 'true')}}
      enable_package_container: ${{fromJSON(inputs.enable_package_container || env.is_fat || 'true')}}
      package_containers: ${{inputs.package_containers || env.default_package_containers}}
      enable_package_distro: ${{fromJSON(inputs.enable_package_distro || env.is_fat || 'false')}}
      package_distros: ${{inputs.package_distros || env.default_package_distros}}
      enable_package_checks: ${{fromJSON(inputs.enable_package_checks || env.is_test || 'false')}}
      enable_publish: ${{fromJSON(inputs.enable_publish || 'true')}}
      is_release: ${{fromJSON(env.is_release || 'false')}}
      is_main: ${{fromJSON(env.is_main || 'false')}}
      is_test: ${{fromJSON(env.is_test || 'false')}}
      is_pull: ${{fromJSON(env.is_pull || 'false')}}
      is_fat: ${{fromJSON(env.is_fat || 'false')}}
      is_dev: ${{fromJSON(env.is_dev || 'true')}}
      pages_url: 'https://matrix-construct.github.io/tuwunel/'
      release_url: ${{steps.release.outputs.upload_url}}
      docker_repo: ${{vars.DOCKER_REPO}}
      docker_acct: ${{vars.DOCKER_ACCT}}

    strategy:
      fail-fast: true
      matrix:
        runner: ${{fromJSON(inputs.runners || vars.RUNNERS || '["het"]')}}
        machine: ${{fromJSON(inputs.machines || vars.MACHINES || '["X64"]')}}
        exclude: ${{fromJSON(vars.RUNNERS_EXCLUDES || '[]')}}

    steps:
    - name: Initialize Builder
      env:
        runner: ${{matrix.runner}}
        reserved_space: '{"het": "192GB", "aws": "48GB", "gcp": "160GB"}'
        max_used_space: '{"het": "384GB", "aws": "64GB", "gcp": "192GB"}'
        min_free_space: '{"het": "512GB", "aws": "16GB", "gcp": "16GB"}'
      run: |
        set +e
        docker buildx inspect "${GITHUB_ACTOR}"
        if test x"$?" = x"0"; then
          exit 0
        fi

        set -eux
        reserved_space=$(echo -n "$reserved_space" | jq -r ".$runner")
        max_used_space=$(echo -n "$max_used_space" | jq -r ".$runner")
        min_free_space=$(echo -n "$min_free_space" | jq -r ".$runner")
        cat <<EOF > ./buildkitd.toml
        [system]
          platformsCacheMaxAge = "504h"
        [worker.oci]
          enabled = true
          rootless = false
          gc = true
          reservedSpace = "${reserved_space}"
          maxUsedSpace = "${max_used_space}"
          minFreeSpace = "${min_free_space}"
        [[worker.oci.gcpolicy]]
          reservedSpace = "${reserved_space}"
          maxUsedSpace = "${max_used_space}"
          minFreeSpace = "${min_free_space}"
          filters = ["label!=cache==pin"]
          all = true
        [[worker.oci.gcpolicy]]
          minFreeSpace = "${min_free_space}"
          all = true
        EOF

        docker buildx create \
          --bootstrap \
          --driver docker-container \
          --buildkitd-config ./buildkitd.toml \
          --name "${GITHUB_ACTOR}" \
          --buildkitd-flags "--allow-insecure-entitlement network.host"

    - if: >
        !failure() && !cancelled()
        && contains(github.ref, 'refs/tags/v')
        && matrix.runner == 'het'

      id: release
      name: Create Release
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
      with:
        release_name: Release ${{github.ref_name}}
        tag_name: ${{github.ref}}
        body_path: RELEASE.md
        draft: ${{ contains(github.ref, '-draft') }}
        prerelease: ${{ contains(github.ref, '-rc') }}

  lint:
    if: >
      !failure() && !cancelled()
      && fromJSON(needs.init.outputs.enable_lint)
      && !fromJSON(needs.init.outputs.is_release)
      && !contains(needs.init.outputs.pipeline, '[ci no lint]')
      && !contains(needs.init.outputs.pipeline, '[ci only it]')

    name: Lint
    needs: [init] #needs: [init, deps]
    uses: ./.github/workflows/lint.yml
    with:
      checkout: ${{needs.init.outputs.checkout}}
      cargo_profiles: ${{needs.init.outputs.cargo_profiles}}
      feat_sets: ${{needs.init.outputs.feat_sets}}
      rust_toolchains: ${{needs.init.outputs.rust_toolchains}}
      rust_targets: ${{needs.init.outputs.rust_targets}}
      sys_names: ${{needs.init.outputs.sys_names}}
      sys_targets: ${{needs.init.outputs.sys_targets}}
      sys_versions: ${{needs.init.outputs.sys_versions}}
      machines: ${{needs.init.outputs.machines}}
      excludes: >
        [
          {"cargo_profile": "test", "feat_set": "logging"},
          {"cargo_profile": "test", "rust_toolchain": "stable", "feat_set": "none"},
          {"cargo_profile": "test", "rust_target": "aarch64-unknown-linux-gnu"},
          {"cargo_profile": "bench"},
          {"cargo_profile": "release", "rust_toolchain": "nightly", "feat_set": "none"},
          {"cargo_profile": "release", "rust_toolchain": "nightly", "feat_set": "default"},
          {"cargo_profile": "release", "rust_toolchain": "nightly", "feat_set": "logging"},
          {"cargo_profile": "release-debuginfo"},
          {"cargo_profile": "release-native", "feat_set": "none"},
          {"cargo_profile": "release-native", "feat_set": "default"},
          {"cargo_profile": "release-native", "feat_set": "logging"},
          {"cargo_profile": "release-native", "rust_toolchain": "stable"},
          {"cargo_profile": "release-native", "rust_target": "aarch64-unknown-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "feat_set": "none"},
          {"rust_target": "aarch64-unknown-linux-gnu", "feat_set": "default"},
          {"rust_target": "aarch64-unknown-linux-gnu", "feat_set": "logging"},
          {"rust_target": "aarch64-unknown-linux-gnu", "rust_toolchain": "nightly"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v1-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v2-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v3-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v4-linux-gnu"},
          {"rust_target": "x86_64-unknown-linux-gnu", "sys_target": "aarch64-v8-linux-gnu"},
          {"sys_target": "aarch64-v8-linux-gnu", "machine": "X64"},
          {"sys_target": "x86_64-v1-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v2-linux-gnu"},
          {"sys_target": "x86_64-v3-linux-gnu"},
          {"sys_target": "x86_64-v4-linux-gnu"},
        ]

  test:
    if: >
      !failure() && !cancelled()
      && fromJSON(needs.init.outputs.enable_test)
      && !fromJSON(needs.init.outputs.is_release)
      && !contains(needs.init.outputs.pipeline, '[ci no test]')

    name: Test
    needs: [init, lint]
    uses: ./.github/workflows/test.yml
    with:
      pipeline: ${{needs.init.outputs.pipeline}}
      checkout: ${{needs.init.outputs.checkout}}
      enable_docs: ${{needs.init.outputs.enable_test_docs}}
      enable_unit: ${{needs.init.outputs.enable_test_unit}}
      enable_bench: ${{needs.init.outputs.enable_test_bench}}
      enable_memcheck: ${{needs.init.outputs.enable_test_memcheck}}
      enable_smoke: ${{needs.init.outputs.enable_test_smoke}}
      enable_nix: ${{needs.init.outputs.enable_test_nix}}
      enable_rustsdk: ${{needs.init.outputs.enable_test_rustsdk}}
      enable_complement: ${{needs.init.outputs.enable_test_complement}}
      complement_runner: ${{needs.init.outputs.complement_runner}}
      complement_logs: ${{needs.init.outputs.complement_logs}}
      complement_verbose: ${{needs.init.outputs.complement_verbose}}
      cargo_profiles: ${{needs.init.outputs.cargo_profiles}}
      feat_sets: ${{needs.init.outputs.feat_sets}}
      rust_toolchains: ${{needs.init.outputs.rust_toolchains}}
      rust_targets: ${{needs.init.outputs.rust_targets}}
      sys_names: ${{needs.init.outputs.sys_names}}
      sys_targets: ${{needs.init.outputs.sys_targets}}
      sys_versions: ${{needs.init.outputs.sys_versions}}
      machines: ${{needs.init.outputs.machines}}
      excludes: >
        [
          {"cargo_profile": "test", "rust_toolchain": "stable", "feat_set": "none"},
          {"cargo_profile": "test", "rust_target": "aarch64-unknown-linux-gnu"},
          {"cargo_profile": "release-debuginfo"},
          {"cargo_profile": "release-native", "feat_set": "none"},
          {"cargo_profile": "release-native", "feat_set": "default"},
          {"cargo_profile": "release-native", "rust_toolchain": "stable"},
          {"cargo_profile": "release-native", "rust_target": "aarch64-unknown-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "feat_set": "none"},
          {"rust_target": "aarch64-unknown-linux-gnu", "feat_set": "default"},
          {"rust_target": "aarch64-unknown-linux-gnu", "feat_set": "logging"},
          {"rust_target": "aarch64-unknown-linux-gnu", "rust_toolchain": "nightly"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v1-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v2-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v3-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v4-linux-gnu"},
          {"rust_target": "x86_64-unknown-linux-gnu", "sys_target": "aarch64-v8-linux-gnu"},
          {"sys_target": "aarch64-v8-linux-gnu", "machine": "X64"},
          {"sys_target": "x86_64-v1-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v2-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v2-linux-gnu", "feat_set": "none"},
          {"sys_target": "x86_64-v2-linux-gnu", "feat_set": "default"},
          {"sys_target": "x86_64-v3-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v3-linux-gnu", "feat_set": "none"},
          {"sys_target": "x86_64-v3-linux-gnu", "feat_set": "default"},
          {"sys_target": "x86_64-v4-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v4-linux-gnu", "feat_set": "none"},
          {"sys_target": "x86_64-v4-linux-gnu", "feat_set": "default"},
        ]

  package:
    if: >
      !failure() && !cancelled()
      && fromJSON(needs.init.outputs.enable_package)
      && !contains(needs.init.outputs.pipeline, '[ci only it]')
      && !contains(needs.init.outputs.pipeline, '[ci no build]')
      && !contains(needs.init.outputs.pipeline, '[ci no package]')

    name: Package
    needs: [init, test]
    uses: ./.github/workflows/package.yml
    with:
      enable_book: ${{needs.init.outputs.enable_package_book}}
      enable_binary: ${{needs.init.outputs.enable_package_binary}}
      enable_container: ${{needs.init.outputs.enable_package_container}}
      enable_distro: ${{needs.init.outputs.enable_package_distro}}
      enable_checks: ${{needs.init.outputs.enable_package_checks}}
      distros: ${{needs.init.outputs.package_distros}}
      containers: ${{needs.init.outputs.package_containers}}
      checkout: ${{needs.init.outputs.checkout}}
      release_url: ${{needs.init.outputs.release_url}}
      cargo_profiles: ${{needs.init.outputs.cargo_profiles}}
      feat_sets: ${{needs.init.outputs.feat_sets}}
      rust_toolchains: ${{needs.init.outputs.rust_toolchains}}
      rust_targets: ${{needs.init.outputs.rust_targets}}
      sys_names: ${{needs.init.outputs.sys_names}}
      sys_targets: ${{needs.init.outputs.sys_targets}}
      sys_versions: ${{needs.init.outputs.sys_versions}}
      machines: ${{needs.init.outputs.machines}}
      excludes: >
        [
          {"feat_set": "none"},
          {"cargo_profile": "test"},
          {"cargo_profile": "bench"},
          {"cargo_profile": "release-native"},
          {"cargo_profile": "release-debuginfo", "feat_set": "default"},
          {"cargo_profile": "release-debuginfo", "feat_set": "logging"},
          {"cargo_profile": "release-debuginfo", "rust_toolchain": "nightly"},
          {"cargo_profile": "release-debuginfo", "bake_target": "oci"},
          {"cargo_profile": "release-debuginfo", "rust_target": "aarch64-unknown-linux-gnu"},
          {"cargo_profile": "release-debuginfo", "sys_target": "x86_64-v2-linux-gnu"},
          {"cargo_profile": "release-debuginfo", "sys_target": "x86_64-v3-linux-gnu"},
          {"cargo_profile": "release-debuginfo", "sys_target": "x86_64-v4-linux-gnu"},
          {"cargo_profile": "release", "rust_toolchain": "nightly"},
          {"rust_target": "aarch64-unknown-linux-gnu", "feat_set": "default"},
          {"rust_target": "aarch64-unknown-linux-gnu", "bake_target": "nix"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v1-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v2-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v3-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v4-linux-gnu"},
          {"rust_target": "x86_64-unknown-linux-gnu", "sys_target": "aarch64-v8-linux-gnu"},
          {"sys_target": "aarch64-v8-linux-gnu", "machine": "X64"},
          {"sys_target": "x86_64-v1-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v2-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v2-linux-gnu", "feat_set": "default"},
          {"sys_target": "x86_64-v2-linux-gnu", "feat_set": "logging"},
          {"sys_target": "x86_64-v2-linux-gnu", "bake_target": "nix"},
          {"sys_target": "x86_64-v3-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v3-linux-gnu", "feat_set": "default"},
          {"sys_target": "x86_64-v3-linux-gnu", "feat_set": "logging"},
          {"sys_target": "x86_64-v3-linux-gnu", "bake_target": "nix"},
          {"sys_target": "x86_64-v4-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v4-linux-gnu", "feat_set": "default"},
          {"sys_target": "x86_64-v4-linux-gnu", "feat_set": "logging"},
          {"sys_target": "x86_64-v4-linux-gnu", "bake_target": "nix"},
        ]

  publish:
    if: >
      !failure() && !cancelled()
      && fromJSON(needs.init.outputs.enable_publish)
      && !contains(needs.init.outputs.pipeline, '[ci only it]')
      && !contains(needs.init.outputs.pipeline, '[ci no build]')
      && !contains(needs.init.outputs.pipeline, '[ci no package]')
      && !contains(needs.init.outputs.pipeline, '[ci no publish]')

    name: Publish
    needs: [init, test, package]
    uses: ./.github/workflows/publish.yml
    with:
      checkout: ${{needs.init.outputs.checkout}}
      docker_repo: ${{needs.init.outputs.docker_repo}}
      docker_acct: ${{needs.init.outputs.docker_acct}}
      release_url: ${{needs.init.outputs.release_url}}
      pages_url: ${{needs.init.outputs.pages_url}}
      cargo_profiles: ${{needs.init.outputs.cargo_profiles}}
      feat_sets: ${{needs.init.outputs.feat_sets}}
      rust_toolchains: ${{needs.init.outputs.rust_toolchains}}
      rust_targets: ${{needs.init.outputs.rust_targets}}
      sys_names: ${{needs.init.outputs.sys_names}}
      sys_targets: ${{needs.init.outputs.sys_targets}}
      sys_versions: ${{needs.init.outputs.sys_versions}}
      machines: ${{needs.init.outputs.machines}}
      excludes: >
        [
          {"feat_set": "none"},
          {"feat_set": "default"},
          {"cargo_profile": "test"},
          {"cargo_profile": "bench"},
          {"cargo_profile": "release-debuginfo"},
          {"cargo_profile": "release-native"},
          {"rust_toolchain": "nightly"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v1-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v2-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v3-linux-gnu"},
          {"rust_target": "aarch64-unknown-linux-gnu", "sys_target": "x86_64-v4-linux-gnu"},
          {"rust_target": "x86_64-unknown-linux-gnu", "sys_target": "aarch64-v8-linux-gnu"},
          {"sys_target": "aarch64-v8-linux-gnu", "machine": "X64"},
          {"sys_target": "x86_64-v1-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v2-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v2-linux-gnu", "feat_set": "logging"},
          {"sys_target": "x86_64-v3-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v3-linux-gnu", "feat_set": "logging"},
          {"sys_target": "x86_64-v4-linux-gnu", "machine": "ARM64"},
          {"sys_target": "x86_64-v4-linux-gnu", "feat_set": "logging"},
        ]

    secrets:
      ghcr_token: ${{ secrets.GHCR_TOKEN }}
      dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
