SuperAPI AI Directory

ov-github-actions-ci

Agents & models

View repository

Updated 10-16 03:11

About this skill

Work on OpenVINO GitHub Actions CI

Guides changes to the regular GitHub Actions CI in this repository: validation and reusable workflows, custom actions, CI scripts, Dockerfiles, and the Smart CI configuration that drives them.

Read the CI developer docs under docs/dev/ci/github_actions first — they are the authoritative, repo-specific reference and this skill is a checklist on top of them. Keep them in sync when behavior changes (see Skill self-improvement). The key pages:

Topic Doc
Big picture, workflow structure, triggers, results/artifacts/logs overview.md
Reusable job_*.yml workflows reusable_workflows.md
Custom composite actions custom_actions.md
Smart CI (skip unaffected jobs) smart_ci.md
Runners (runs-on) runners.md
Docker images / handle_docker docker_images.md
Caches (GHA / shared drive / sccache) caches.md
Adding tests (step / job / workflow) adding_tests.md
OpenVINO Provider (prebuilt artifacts) openvino_provider.md
Workflow security security.md

For framework syntax, use the official GitHub Actions documentation. If user requires an out-of-scope feature, consult the official documentation.

Out of scope: gh-aw agentic workflows (.github/workflows/*.md + *.lock.yml, e.g. ci-doctor) — use the ov-agentic-workflows skill instead.

Repository layout

  • Workflows — .github/workflows/
    • Validation workflows: named after the OS/config, e.g. ubuntu_22.yml, windows_vs2022_release.yml, mac_arm64.yml, linux_arm64.yml, android.yml. Entry points with on: triggers; they wire together Build + test jobs.
    • Reusable workflows: job_*.yml (e.g. job_python_unit_tests.yml, job_cxx_unit_tests.yml). Called via uses: ./.github/workflows/job_*.yml with on: workflow_call: inputs. Not triggered directly.
  • Custom actions — .github/actions/ (composite action.yml): setup_python, system_info, smart-ci, handle_docker, openvino_provider, store_artifacts/restore_artifacts, cache, etc.
  • CI scripts — .github/scripts/ (Python helpers: workflow_rerun/, external_pr_labeller.py, check_copyright.py, ...).
  • Dockerfiles — .github/dockerfiles/ov_build/** and ov_test/**, plus the docker_tag file.
  • Smart CI config — .github/labeler.yml (path globs → component/label) and .github/components.yml (component dependency graph).
  • Scans/meta — workflows_scans.yml (CodeQL actions + semgrep on workflow changes), dependency_review.yml.

Golden rules

  1. Pin third-party actions to a full commit SHA, with the version in a trailing comment. First-party ./.github/actions/* are referenced by path, not pinned.
    uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
    
  2. Least-privilege permissions:. Start from permissions: read-all (workflow level) and grant the minimum extra scope at the job level only where needed. Never widen without a reason.
  3. Follow security.md — it is the source of truth. Key rules: never use pull_request_target, never hard-code secrets, and treat all github.* / github.event.* user-controlled values as untrusted (route them through env: or action inputs, never interpolate directly into run: shell). Ping the CI task force for anything involving secrets or elevated triggers.
  4. Put shared job logic in a reusable job_*.yml, not copy-paste. If the same job appears in more than one validation workflow, it should be a workflow_call reusable workflow parameterized by runner, image/container, and affected-components.
  5. Respect Smart CI. Test jobs/steps that validate a specific component must gate on fromJSON(needs.smart_ci.outputs.affected_components).<COMPONENT>.{build,test} and list Smart_CI in needs. Do not make an expensive job run unconditionally.
  6. Custom Docker images come from handle_docker, not hard-coded tags. Reference build/test images as ${{ fromJSON(needs.docker.outputs.images).ov_build.<name> }} and add Docker to needs. Plain passthrough images must use the ACR mirror openvinogithubactions.azurecr.io/..., never docker.io.
  7. Keep changes scoped and validate before finishing (see Validation). .github/** is owned by @openvinotoolkit/openvino-ci-maintainers and changes there are label category: CI (workflows also get github_actions).

Key conventions

  • Runner selection (runs-on) — self-hosted Azure pools aks-{os}-{cores}-cores-{ram}gb[-arm] for heavy build/test; GitHub-hosted (ubuntu-22.04, ...) for light jobs (labelers, style). GPU jobs use [ self-hosted, gpu|igpu|dgpu ] and must run in Docker. Azure aks-* runners are required to pull from the ACR / use custom images. Match cores to parallelism (see runners.md).
  • Containers — most self-hosted jobs run in a container:. Mount the shared drive with volumes: [ /mount:/mount ] and add ${{ github.workspace }}:${{ github.workspace }} where the workspace must be identical inside/outside the container.
  • Caches — GHA cache (actions/cache, ≤10 GB) for small deps; shared drive (/mount/..., e.g. PIP_CACHE_PATH: /mount/caches/pip/linux) for large assets on Linux self-hosted; sccache → Azure Blob for C/C++ build cache (needs SCCACHE_AZURE_* env + CMAKE_*_COMPILER_LAUNCHER: sccache + SCCACHE_AZURE_KEY_PREFIX).
  • Artifacts — Build job packs and uploads; test jobs needs: Build and download. Follow the existing store_artifacts/restore_artifacts actions and artifact-name conventions in the workflow.
  • timeout-minutes — always set a sensible per-job timeout.

Common tasks

Add a test (choose the smallest unit)

Follow adding_tests.md:

  • New tests inside an existing suite → no workflow change needed.
  • New step in an existing job → add a name + run step, gate with if: fromJSON(inputs.affected-components).<COMPONENT>.test when component-specific.
  • New job → add to the right validation workflow (or a job_*.yml); set needs: [Build, Smart_CI], runs-on, container, timeout-minutes, and a Smart CI if:.

Add / edit a reusable workflow (job_*.yml)

  1. Give it on: workflow_call: with typed inputs (runner, image, affected-components, python-version, ...) and permissions: read-all.
  2. Reference it from validation workflows via uses: ./.github/workflows/job_<name>.yml with with: and needs: [ Build, Smart_CI ].
  3. Keep the input contract minimal and documented via description:.

Wire up Smart CI for a component

  1. Map source paths → label in .github/labeler.yml ('category: X': [globs]).
  2. Declare dependents in .github/components.yml under revalidate: (build+test) / build: (build only); use [] for none, or 'all' to force full validation. Dependencies are not transitive.
  3. Add Smart_CI to the validating job's needs and gate with if: fromJSON(needs.smart_ci.outputs.affected_components).<COMPONENT>.{build,test}. Keep the same condition on every step/job in the dependency chain — a skipped step feeding an ungated dependent leaves it running against missing outputs.
  4. Aggregate results into the Overall_Status job (it needs: the real jobs and reports one required check). A workflow that must be required cannot use a paths: filter — a filtered-out run reports no status and blocks the merge queue; rely on Smart CI + Overall_Status instead.

Add / change a custom action

  • Composite action.yml under .github/actions/<name>/. Declare inputs (with description, required, default) and runs: using: composite. Every run step needs an explicit shell:.
  • Reference untrusted input via env: inside the step, not inline interpolation.
  • Update custom_actions.md if the action is user-facing.

Choosing the implementation environment

  • Python is the default and preferred implementation language for a custom action's logic. Use it for any action that does not need extensive access to the GitHub (Actions) API — file/artifact handling, environment setup, packaging, running tools, parsing, etc.
    • If the action needs a requirements.txt, it must pin the full dependency tree, not just top-level packages. Generate it from a clean environment with pip freeze:
      python3 -m venv /tmp/act-env && . /tmp/act-env/bin/activate
      pip install <top-level-deps>            # only the packages you directly import
      pip freeze > .github/actions/<name>/requirements.txt
      
      This makes installs reproducible and pinned. Regenerate the same way whenever deps change.
  • Use JavaScript/TypeScript only when the action uses the GitHub (Actions) API extensively — the Octokit/@actions/* toolkit gives first-class typed access to it. The bundled .github/actions/cache action is the reference example of a JS-based action.
  • When in doubt, prefer Python and keep API interaction minimal.

Add / use a custom Docker image

Follow docker_images.md: add a Dockerfile under .github/dockerfiles/{ov_build,ov_test}/<platform>/, ensure a Docker job runs handle_docker with the image path in images:, add Docker to consumers' needs, and set image: ${{ fromJSON(needs.docker.outputs.images).<group>.<name> }}. When adding a new env-setup script, add it under category: docker_env in labeler.yml, exclude it from .dockerignore, and bump .github/dockerfiles/docker_tag (handle_docker prompts you).

Change a runner or container

Pick the pool from runners.md; keep container volumes/options (shared drive, sccache) consistent with sibling jobs. GPU → Docker + self-hosted label.

Validation before finishing

  • YAML/lint: run actionlint if available (actionlint .github/workflows/<file>.yml); otherwise sanity-check YAML parses. Mirror what workflows_scans.yml (CodeQL actions + semgrep) and dependency_review.yml enforce — those run on any .github/workflows/** change.
  • Pinning: every third-party uses: is a full SHA + version comment.
  • Permissions: workflow defaults to least privilege; extra scopes are job-scoped and justified.
  • Smart CI: new component-specific jobs/steps are gated and Smart_CI is in needs.
  • Scope: only intended files changed; no stray docker_tag/labeler/components edits unless required.
  • Do not hand-edit any *.lock.yml — those belong to agentic workflows.

Pitfalls to check

  • Unpinned or tag-pinned third-party action — supply-chain risk; CodeQL/semgrep will flag it.
  • Untrusted input in run: — ${{ github.event.* }} interpolated into shell is an injection vector; route through env:.
  • Over-broad permissions: — especially write scopes at workflow level.
  • Job that ignores Smart CI — burns limited self-hosted/GPU capacity on unaffected PRs.
  • Smart CI condition mismatch across a dependency chain — a step skipped by a Smart CI if: whose dependent step/job lacks the same condition runs against missing outputs/artifacts. Gate the whole chain consistently.
  • paths: filter on a required workflow — filtered-out runs report no status and hang the merge queue; use Smart CI + Overall_Status instead of paths:.
  • Hard-coded docker.io / non-ACR image on aks-* — pulls fail or hit rate limits; use the ACR mirror or handle_docker output.
  • Missing Docker/Smart_CI/Build in needs — races or missing artifacts/inputs.
  • Editing a job_*.yml input contract without updating every caller's with: block.
  • Docker env change without docker_tag bump — the image won't rebuild; handle_docker fails the check.
  • Missing timeout-minutes — a hung job can occupy a runner indefinitely.
  • GPU job without Docker — required on persistent GPU runners.

Skill self-improvement

Keep this skill and the CI docs in sync with reality. When a change reveals a new rule, pattern, or footgun:

  • New reusable workflow / custom action / Dockerfile convention — note it under Common tasks and, if user-facing, in the matching page under docs/dev/ci/github_actions/.
  • New footgun (a pinning/permission/Smart CI/Docker/cache mistake that bit you) — add it to Pitfalls.
  • A rule becomes obsolete (a workflow removed, a runner pool renamed, a path moved) — update or remove the stale entry instead of leaving it.
  • Keep it concise — prefer linking to the (updated) doc over duplicating detail; this file is a short actionable checklist, not a second copy of the documentation.
  • This directory is reachable via both .agents/skills/ and .claude/skills/ (the former is a symlink to the latter), so a single edit updates both — do not create a duplicate copy.