feat: add centos to the OS matrix #80
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Run Suites | |
| on: | |
| push: | |
| branches: ["main", "compat/**"] | |
| paths: | |
| - "examples/**" | |
| - "templates/**" | |
| - "os/**" | |
| pull_request: | |
| paths: | |
| - "examples/**" | |
| - "templates/**" | |
| - "os/**" | |
| workflow_dispatch: | |
| inputs: | |
| suite: | |
| description: "Single suite to test, with parent folder (e.g. examples/cryptolibrary)" | |
| required: false | |
| default: "" | |
| jobs: | |
| # ── Stage 1: detect which suites changed ────────────────────────────────── | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 2 | |
| - name: Detect changed suites | |
| id: set-matrix | |
| run: | | |
| # Manual trigger with explicit suite override | |
| if [[ -n "${{ github.event.inputs.suite }}" ]]; then | |
| echo "matrix=[\"${{ github.event.inputs.suite }}\"]" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # Detect changed folders under examples/ and templates/ | |
| CHANGED=$(git diff --name-only HEAD~1 HEAD \ | |
| | grep -E '^(examples|templates)/' \ | |
| | cut -d/ -f1-2 \ | |
| | sort -u \ | |
| | jq -R . | jq -sc .) | |
| # Fall back to all examples + templates if nothing detected (e.g. first commit) | |
| if [[ "${CHANGED}" == "[]" || -z "${CHANGED}" ]]; then | |
| CHANGED=$(ls -d examples/*/ templates/*/ 2>/dev/null | sed 's|/$||' | jq -R . | jq -sc .) | |
| fi | |
| echo "Before blacklist filtering: ${CHANGED}" | |
| # Apply blacklist (.github/test-blacklist.txt) | |
| BLACKLIST=$(grep -v '^\s*#' .github/test-blacklist.txt | grep -v '^\s*$' || true) | |
| echo "Blacklist: ${BLACKLIST}" | |
| if [[ -n "${BLACKLIST}" ]]; then | |
| CHANGED=$(echo "${CHANGED}" | jq -c --arg bl "${BLACKLIST}" ' | |
| ($bl | split("\n") | map(select(length > 0))) as $blacklist | | |
| map(select(. as $s | $blacklist | index($s) | not)) | |
| ') | |
| echo "After blacklist filtering: ${CHANGED}" | |
| fi | |
| echo "matrix=${CHANGED}" >> "$GITHUB_OUTPUT" | |
| echo "Suites to test: ${CHANGED}" | |
| # ── Stage 2: test matrix (os × suite) ───────────────────────────────────── | |
| test: | |
| needs: detect-changes | |
| if: ${{ needs.detect-changes.outputs.matrix != '[]' }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| # We have 2 OS and want to run max 1 job per OS (make use of pre-build RCC environments!) | |
| max-parallel: 2 | |
| matrix: | |
| suite: ${{ fromJson(needs.detect-changes.outputs.matrix) }} | |
| os: [ubuntu-latest, windows-latest] | |
| # os: [ubuntu-latest] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Read RMKS environment from .env | |
| id: suite-env | |
| shell: bash | |
| run: | | |
| ENV_FILE="${{ matrix.suite }}/.env" | |
| SPACE=$(grep '^RMKS_ENVIRONMENT=' "${ENV_FILE}" | cut -d= -f2 | tr -d '[:space:]') | |
| if [[ -z "${SPACE}" ]]; then | |
| echo "ERROR: RMKS_ENVIRONMENT is missing in ${ENV_FILE}" >&2 | |
| exit 1 | |
| fi | |
| echo "space=${SPACE}" >> "$GITHUB_OUTPUT" | |
| # Sanitize matrix.suite (e.g. examples/cryptolibrary → examples-cryptolibrary) | |
| echo "safe_name=$(echo '${{ matrix.suite }}' | tr '/' '-')" >> "$GITHUB_OUTPUT" | |
| - name: Download RCC | |
| shell: bash | |
| run: | | |
| BASE="https://github.com/elabit/robotmk/releases/download/v4.0.0" | |
| if [[ "${{ runner.os }}" == "Windows" ]]; then | |
| curl -fsSL -o rcc.exe "${BASE}/rcc_windows64.exe" | |
| echo "RCC_BIN=./rcc.exe" >> "$GITHUB_ENV" | |
| else | |
| curl -fsSL -o rcc "${BASE}/rcc_linux64" | |
| chmod +x rcc | |
| echo "RCC_BIN=./rcc" >> "$GITHUB_ENV" | |
| fi | |
| ${RCC_BIN:-./rcc} --version | |
| - name: Cache RCC holotree environment | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.robocorp/holotree | |
| key: rcc-holotree-${{ steps.suite-env.outputs.space }}-${{ runner.os }} | |
| - name: Build RCC holotree environment | |
| shell: bash | |
| run: | | |
| $RCC_BIN holotree vars \ | |
| --space ${{ steps.suite-env.outputs.space }} \ | |
| --robot ${{ matrix.suite }}/robot.yaml | |
| - name: Load .env if present | |
| shell: bash | |
| run: | | |
| ENV_FILE="${{ matrix.suite }}/.env" | |
| if [[ -f "${ENV_FILE}" ]]; then | |
| echo "Loading variables from ${ENV_FILE}" | |
| grep -v '^\s*#' "${ENV_FILE}" | grep -v '^\s*$' >> "$GITHUB_ENV" | |
| fi | |
| echo "Environment variables set for this suite:" | |
| grep -v '^\s*#' "${ENV_FILE}" | grep -v '^\s*$' || echo "No .env file or no variables found." | |
| # - name: Setup tmate session | |
| # uses: mxschmitt/action-tmate@v3 | |
| - name: Run Robot Framework suite | |
| shell: bash | |
| run: | | |
| $RCC_BIN task script \ | |
| --space ${{ steps.suite-env.outputs.space }} \ | |
| --robot ${{ matrix.suite }}/robot.yaml \ | |
| -- robot . | |
| - name: Upload RF output artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: rf-output-${{ steps.suite-env.outputs.safe_name }}-${{ matrix.os }} | |
| path: ${{ matrix.suite }}/log.html | |
| if-no-files-found: ignore | |
| # ── Stage 3: os content type (provision + verify + report) ──────────────── | |
| # Independent of the detect-changes/test pair above: exactly one job per OS | |
| # family, added deliberately one epic at a time (Story 1.5 adds debian; | |
| # Stories 2.2/3.2/4.2 each add one more matrix entry; centos is a later | |
| # addition sharing the redhat family with rhel), never auto-detected from a | |
| # directory listing the way the examples/templates matrix is. | |
| os: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| slug: [debian, ubuntu, rhel, sles, centos] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Read pinned image from the generated devcontainer.json | |
| id: os-env | |
| run: | | |
| # devcontainer.json is JSONC (allows // comments, per the Dev | |
| # Container spec) -- jq can't parse that directly, so strip | |
| # line-comments before feeding it to a JSON parser. | |
| IMAGE=$(python3 -c " | |
| import json, re | |
| text = open('os/${{ matrix.slug }}/.devcontainer/devcontainer.json').read() | |
| text = re.sub(r'//.*', '', text) | |
| print(json.loads(text)['image']) | |
| ") | |
| echo "image=${IMAGE}" >> "$GITHUB_OUTPUT" | |
| - name: Provision, verify, and report | |
| run: | | |
| # Mount ONLY os/<slug> (not the full repo root) -- this instance is | |
| # self-contained (its own copy of the shared Ansible role + RF | |
| # suite via populate.yaml, AD-3/AD-4), so this deliberately mirrors | |
| # exactly what a standalone extracted repo would see, proving the | |
| # self-containment property in CI rather than assuming it. | |
| # No devcontainer CLI in CI (AD-9), so its onCreateCommand/ | |
| # postCreateCommand split isn't applied automatically here -- chain | |
| # the same two scripts explicitly instead. `&&` gives the identical | |
| # halt-then-propagate semantics the Dev Container lifecycle gives | |
| # the interactive path: postcreate.sh only runs if oncreate.sh | |
| # succeeded, and the final exit code reflects whichever of the two | |
| # actually failed. | |
| docker run --rm \ | |
| -v "${{ github.workspace }}/os/${{ matrix.slug }}:/workspace" \ | |
| -w "/workspace" \ | |
| "${{ steps.os-env.outputs.image }}" \ | |
| bash -c "bash .devcontainer/oncreate.sh && bash .devcontainer/postcreate.sh" | |
| - name: Upload install report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: os-report-${{ matrix.slug }} | |
| path: os/${{ matrix.slug }}/report.md | |
| if-no-files-found: ignore |