Artifact storage

Firmware is built in other repositories and stored as GitHub workflow artifacts, GitHub release assets, or Cloudsmith packages. These classes handle authentication, lookup, and download.

They include a fallback to allow providing the artifacts directly, without downloading from the storage buckets, allowing to use locally built artifacts. For Cloudsmith, the fallback is when CLOUDSMITH_NAMESPACE is unset (no token required for public repos), and GitHub, GITHUB_TOKEN (token required).

GitHub

Download workflow artifacts and release assets from GitHub.

Basic usage:

import logging
logging.basicConfig(level=logging.INFO)

from hw_tests.github import GitHub

# Gets defaults from context
gh = GitHub(context)

# Get artifact 'example' from run '1234' (overrides the context)
# of the repository from the context
path = gh.download(
    name='example',
    run_id='1234',
)
class hw_tests.github.GitHub(context)

GitHub API client for a test run.

The default repository and workflow run come from workflow_run_url in context if present, else from GITHUB_REPOSITORY and GITHUB_RUN_ID. GITHUB_TOKEN is used for authentication; without it, workflow artifacts cannot be downloaded.

Parameters:

context – Test context, see hw_tests.context.build_context().

static in_actions()

Return whether the process runs in GitHub Actions.

static mask(value)

Hide value from logs and, in GitHub Actions, from job output.

static get_id_token()

Return a GitHub Actions OIDC token.

The audience is https://github.com/<owner>. The job needs the id-token: write permission.

property owner_repository

Default repository, as owner/name.

list_artifacts(owner_repository=None, run_id=None, source=None)

List the artifacts of a workflow run or the assets of a release.

Results are cached per run or release. Expired artifacts are skipped.

Parameters:
  • owner_repository – Repository. Defaults to owner_repository.

  • run_id – Workflow run ID. Defaults to the run from the context.

  • source – Release, as {'repository': ..., 'tag': ...}. Takes precedence over owner_repository and run_id.

Returns:

Artifact or asset dicts from the GitHub API. Empty if the run cannot be resolved or there is no token.

download(name: str, owner_repository: str | None = None, run_id: str | None = None, path: Path | str | None = None, source: dict | None = None) → Path

Download an artifact and extract it if it is an archive.

Like actions/download-artifact. Release assets are cached in $HW_TEST_CACHE_DIR (default $XDG_CACHE_HOME/hw-test).

If a workflow artifact cannot be downloaded (no token or no run), a warning is logged and _artifacts/<test name>/<n> is returned, where n counts calls. Put the files there to run locally.

Parameters:
  • name – Artifact or asset name.

  • owner_repository – Repository. Defaults to owner_repository.

  • run_id – Workflow run ID. Defaults to the run from the context.

  • path – Output directory for workflow artifacts. A temporary directory by default.

  • source – Release, as {'repository': ..., 'tag': ...}.

Returns:

Directory containing the artifact.

Cloudsmith

Download build artifacts from Cloudsmith.

Basic usage:

import logging
logging.basicConfig(level=logging.INFO)

from hw_tests.cloudsmith import Cloudsmith

cs = Cloudsmith()

# Get the latest artifact from branch 'refs/heads/...'
path = cs.download(
    repository='linux',
    name='adi_bcm2709_defconfig-gcc-arm-devel',
    version='refs/heads/rpi-6.12.y',
)
class hw_tests.cloudsmith.Cloudsmith(context=None)

Cloudsmith API client.

Packages are looked up in $CLOUDSMITH_NAMESPACE/<repository>. Authentication is done on creation, see authenticate().

Parameters:

context – Test context. Its name sets the local fallback directory of download().

authenticate()

Get an API token and validate it.

Uses CLOUDSMITH_API_KEY if set. Otherwise, in GitHub Actions, gets a token through github_oidc(). Without a token, only public artifacts can be downloaded.

github_oidc()

Exchange a GitHub OIDC token for a Cloudsmith API token.

Requires CLOUDSMITH_SERVICE_SLUG and CLOUDSMITH_NAMESPACE. The token is exported as CLOUDSMITH_API_KEY to the environment and GITHUB_ENV, for the next steps.

static get_api_token(org_name: str, cs_service_slug: str, id_token: str, api_host: str = 'api.cloudsmith.io') → str

Return a Cloudsmith API token for an OIDC id_token.

Raises:

ValueError – Cloudsmith returned an empty token.

static validate(token: str, api_host: str = 'api.cloudsmith.io') → None

Check token against the API and log the authenticated user.

Raises:

requests.HTTPError – the token is rejected.

download(repository: str, name: str, version: str | None = None, tags: tuple | list = (), path: Path | str | None = None) → Path

Download an artifact and extract it if it is an archive.

The package is selected by version if given, else by tags:

  • version as a full 40-char SHA: exact match.

  • version as a git ref (refs/heads/*, refs/tags/*, refs/pull/*): latest package built from that ref.

  • other version values, such as a short SHA: latest pushed package matching the version.

  • tags: latest package that has all the tags, for example ('on/push', 'refs/heads/main').

If CLOUDSMITH_NAMESPACE is not set, a warning is logged and _artifacts/<test name>/<n> is returned, where n counts calls. Put the files there to run locally. Without a context, a ValueError is raised instead.

Parameters:
  • repository – Cloudsmith repository in CLOUDSMITH_NAMESPACE.

  • name – Package name.

  • version – SHA, git ref, or version.

  • tags – Tags to match when version is not given.

  • path – Output directory. A temporary directory by default.

Returns:

Directory containing the artifact.

Raises:

LookupError – no package matches.