Merge remote-tracking branch 'upstream/main' into feature/self-host-runners

# Conflicts:
#	.github/workflows/test-deploy-universal.yml
#	.github/workflows/test-deploy-workstation.yml
This commit is contained in:
Alejandro Roman committed 2026-06-27 23:45:38 +02:00
commit 17d6ac904f
597 files changed
+19255 -5920

No files matched your search

+2
View File
@@ -8,7 +8,9 @@ This directory holds the shell helpers that GitHub Actions workflows under [`.gi
|---|---|
| [runner/](runner/) | Host-runner hygiene around image builds and deploys (disk, swap, Docker daemon, diagnostics). |
| [cancel/](cancel/) | Cancellation of in-progress workflow runs on PR-close and branch-delete events. |
| [cleanup/](cleanup/) | Scheduled repository maintenance that prunes stale GitHub resources. |
| [resolve/](resolve/) | Derivation of structured workflow inputs and outputs from repository state. |
| [sync/](sync/) | Ref synchronization before workflow jobs derive CI scope from git history. |
| [update/](update/) | The scheduled `Update: Versions` pipeline (version bumps and PR open/refresh). |
| [release/](release/) | Release-time gates that decide whether a tagged commit may be released. |
+11
View File
@@ -0,0 +1,11 @@
# Repository Cleanup 🧹
Shell helpers for scheduled repository-maintenance workflows that prune stale GitHub resources.
## Scope 📋
Helpers in this directory are invoked by maintenance workflows under [`.github/workflows/`](../../../.github/workflows/).
They may call the GitHub API through `gh`, but MUST keep destructive selection criteria inside scripts so workflow files remain orchestration-only.
CI image cleanup derives distro-specific package names from `INFINITO_DISTROS`, whose default comes from [default.env](../../../default.env) through the environment loader.
For the workflow catalog that drives these calls see [workflows.md](../../../docs/contributing/tools/github/actions/workflows.md).
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../../.." && pwd)"
# shellcheck source=scripts/meta/env/load.sh
# shellcheck disable=SC1091
source "${REPO_ROOT}/scripts/meta/env/load.sh"
: "${GH_TOKEN:?Missing GH_TOKEN}"
: "${ORG:?Missing ORG}"
package_prefix="${PACKAGE_PREFIX:-core}"
max_age_days="${MAX_AGE_DAYS:-30}"
tag_prefix="${TAG_PREFIX:-ci-}"
if [[ ! "${max_age_days}" =~ ^[0-9]+$ ]]; then
echo "ERROR: MAX_AGE_DAYS must be a non-negative integer." >&2
exit 1
fi
if [[ -z "${tag_prefix}" ]]; then
echo "ERROR: TAG_PREFIX must not be empty." >&2
exit 1
fi
if ! command -v gh >/dev/null 2>&1; then
echo "ERROR: gh CLI not found." >&2
exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
echo "ERROR: jq not found." >&2
exit 1
fi
encode_package_name() {
local package="${1}"
jq -rn --arg value "${package}" '$value | @uri'
}
resolve_packages() {
if [[ -n "${PACKAGES:-}" ]]; then
printf '%s\n' "${PACKAGES}"
return 0
fi
: "${INFINITO_DISTROS:?Missing INFINITO_DISTROS}"
for distro in ${INFINITO_DISTROS}; do
printf '%s/%s\n' "${package_prefix}" "${distro}"
done
}
is_deletable_ci_version() {
local version="${1}"
local tags
tags="$(jq -r '.tags[]?' <<<"${version}")"
[[ -n "${tags}" ]] || return 1
# Keep release tags even when the version also has ci-* tags.
grep -q "^${tag_prefix}" <<<"${tags}" || return 1
grep -Eq "^(latest|v.*)$" <<<"${tags}" && return 1
grep -vq "^${tag_prefix}" <<<"${tags}" && return 1
return 0
}
cutoff="$(date -u -d "${max_age_days} days ago" +%s)"
while IFS= read -r package; do
package="${package#"${package%%[![:space:]]*}"}"
package="${package%"${package##*[![:space:]]}"}"
[[ -n "${package}" ]] || continue
encoded_package="$(encode_package_name "${package}")"
gh api --paginate \
"/orgs/${ORG}/packages/container/${encoded_package}/versions" \
--jq '.[] | {id: .id, updated_at: .updated_at, tags: .metadata.container.tags}' |
jq -c '.' |
while IFS= read -r version; do
id="$(jq -r '.id' <<<"${version}")"
updated_at="$(jq -r '.updated_at' <<<"${version}")"
updated_ts="$(date -u -d "${updated_at}" +%s)"
if [[ "${updated_ts}" -ge "${cutoff}" ]]; then
continue
fi
is_deletable_ci_version "${version}" || continue
echo "Deleting ${package} version ${id} updated at ${updated_at}"
gh api \
--method DELETE \
"/orgs/${ORG}/packages/container/${encoded_package}/versions/${id}"
done
done < <(resolve_packages)
+12 -3
View File
@@ -6,9 +6,18 @@
# INFINITO_WHITELIST — optional space-separated allowlist
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
cd "${REPO_ROOT}"
# shellcheck source=scripts/meta/env/python.sh
source "${REPO_ROOT}/scripts/meta/env/python.sh"
apps="$(./scripts/meta/resolve/apps.sh)"
[[ -n "$apps" ]] || apps='[]'
echo "apps=$apps" >>"$GITHUB_OUTPUT"
echo "apps_json=$apps" >>"$GITHUB_OUTPUT"
echo "apps_json=$apps"
matrix="$(printf '%s' "$apps" | "${PYTHON}" -m utils.github.variant_bundles)"
[[ -n "$matrix" ]] || matrix='[]'
echo "apps=$matrix" >>"$GITHUB_OUTPUT"
echo "apps=$matrix"
+5 -2
View File
@@ -17,11 +17,14 @@ version_tag="$1"
owner="$(_helpers/scripts/meta/resolve/repository/owner.sh)"
repo_prefix="$(_helpers/scripts/meta/resolve/repository/name.sh)"
distros="$(_helpers/scripts/meta/resolve/distros.sh)"
# shellcheck source=scripts/meta/env/load.sh
# shellcheck disable=SC1091
source "_helpers/scripts/meta/env/load.sh"
: "${INFINITO_DISTROS:?Missing INFINITO_DISTROS}"
{
echo "version_tag=${version_tag}"
echo "distros=${distros}"
echo "distros=${INFINITO_DISTROS}"
echo "repo_prefix=${repo_prefix}"
echo "owner=${owner}"
} >>"$GITHUB_OUTPUT"
+3
View File
@@ -0,0 +1,3 @@
# GitHub Sync Helpers 🔄
This directory contains shell helpers that synchronize repository refs before later workflow jobs derive CI scope from git history.
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -euo pipefail
: "${GITHUB_REPOSITORY:?Missing GITHUB_REPOSITORY}"
default_source="${CI_SYNC_MAIN_SOURCE_REPOSITORY_DEFAULT:-infinito-nexus/core}"
configured_source="${CI_SYNC_MAIN_SOURCE_REPOSITORY:-}"
configured_source_is_set="${CI_SYNC_MAIN_SOURCE_REPOSITORY_IS_SET:-false}"
if [[ "${configured_source_is_set}" == "true" ]]; then
source_repository="${configured_source}"
else
source_repository="${default_source}"
fi
source_trimmed="${source_repository//[[:space:]]/}"
source_lower="$(printf '%s' "${source_trimmed}" | tr '[:upper:]' '[:lower:]')"
case "${source_lower}" in
"" | "false" | "0" | "no" | "off" | "none")
echo "Main sync skipped because CI_SYNC_MAIN_SOURCE_REPOSITORY is disabled."
exit 0
;;
esac
normalize_repository() {
local value="${1}"
value="${value#https://github.com/}"
value="${value#http://github.com/}"
value="${value#ssh://git@github.com/}"
value="${value#git@github.com:}"
value="${value%.git}"
printf '%s' "${value}" | tr '[:upper:]' '[:lower:]'
}
target_repository="$(normalize_repository "${GITHUB_REPOSITORY}")"
source_repository="$(normalize_repository "${source_trimmed}")"
if [[ "${source_repository}" == "${target_repository}" ]]; then
echo "Main sync skipped because source repository matches current repository: ${GITHUB_REPOSITORY}."
exit 0
fi
if [[ "${source_repository}" != */* ]]; then
echo "ERROR: CI_SYNC_MAIN_SOURCE_REPOSITORY must be '<owner>/<repo>', a GitHub URL, or a disabled value." >&2
exit 1
fi
echo "Syncing ${GITHUB_REPOSITORY}:main from ${source_repository}:main."
git fetch "https://github.com/${source_repository}.git" main:refs/remotes/main-sync-source/main --force
git push origin refs/remotes/main-sync-source/main:refs/heads/main --force