chore(ci): centralize tool version management into a single source of truth
This commit is contained in:
+58
-19
@@ -6,12 +6,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [master, develop*]
|
branches: [master, develop*]
|
||||||
|
|
||||||
env:
|
|
||||||
UV_VERSION: "0.8.0"
|
|
||||||
PYTHON_VERSION: "3.13"
|
|
||||||
NOX_DEFAULT_VENV_BACKEND: "uv"
|
|
||||||
HELM_VERSION: "v3.16.4"
|
|
||||||
|
|
||||||
# Logging policy (server-load reduction):
|
# Logging policy (server-load reduction):
|
||||||
# The Forgejo server stores every line a step streams to its console as the
|
# The Forgejo server stores every line a step streams to its console as the
|
||||||
# live job log, and that aggregate volume across all controller-driven CI
|
# live job log, and that aggregate volume across all controller-driven CI
|
||||||
@@ -27,7 +21,40 @@ env:
|
|||||||
# always streamed — the pipeline greps for them.
|
# always streamed — the pipeline greps for them.
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
load-versions:
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: python:3.13-slim
|
||||||
|
outputs:
|
||||||
|
uv-version: ${{ steps.versions.outputs.uv-version }}
|
||||||
|
python-version: ${{ steps.versions.outputs.python-version }}
|
||||||
|
helm-version: ${{ steps.versions.outputs.helm-version }}
|
||||||
|
kubeconform-version: ${{ steps.versions.outputs.kubeconform-version }}
|
||||||
|
steps:
|
||||||
|
- name: Install Node.js (required by actions/checkout)
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y -qq nodejs && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Load tool versions from .tool-versions
|
||||||
|
id: versions
|
||||||
|
run: |
|
||||||
|
# Source the tool versions file and export as GitHub Actions outputs
|
||||||
|
while IFS='=' read -r key value; do
|
||||||
|
# Skip empty lines and comments
|
||||||
|
[[ -z "$key" || "$key" =~ ^# ]] && continue
|
||||||
|
# Trim whitespace
|
||||||
|
key=$(echo "$key" | xargs)
|
||||||
|
value=$(echo "$value" | xargs)
|
||||||
|
# Convert to lowercase with hyphens for output names
|
||||||
|
output_key=$(echo "$key" | tr '[:upper:]_' '[:lower:]-')
|
||||||
|
echo "${output_key}=${value}" >> $GITHUB_OUTPUT
|
||||||
|
echo "Loaded: ${output_key}=${value}"
|
||||||
|
done < .tool-versions
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -40,7 +67,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -74,6 +101,7 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
typecheck:
|
typecheck:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -86,7 +114,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -119,6 +147,7 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
security:
|
security:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -131,7 +160,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -165,6 +194,7 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
quality:
|
quality:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -177,7 +207,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -211,6 +241,7 @@ jobs:
|
|||||||
|
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
unit_tests:
|
unit_tests:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -231,6 +262,7 @@ jobs:
|
|||||||
- name: Install Helm CLI
|
- name: Install Helm CLI
|
||||||
if: steps.helm-cache.outputs.cache-hit != 'true'
|
if: steps.helm-cache.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
|
HELM_VERSION="${{ needs.load-versions.outputs.helm-version }}"
|
||||||
ARCH="amd64"
|
ARCH="amd64"
|
||||||
HELM_TARBALL="helm-${HELM_VERSION}-linux-${ARCH}.tar.gz"
|
HELM_TARBALL="helm-${HELM_VERSION}-linux-${ARCH}.tar.gz"
|
||||||
curl -fsSL "https://get.helm.sh/${HELM_TARBALL}" -o "/tmp/${HELM_TARBALL}"
|
curl -fsSL "https://get.helm.sh/${HELM_TARBALL}" -o "/tmp/${HELM_TARBALL}"
|
||||||
@@ -246,7 +278,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -285,6 +317,7 @@ jobs:
|
|||||||
|
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
integration_tests:
|
integration_tests:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -305,6 +338,7 @@ jobs:
|
|||||||
- name: Install Helm CLI
|
- name: Install Helm CLI
|
||||||
if: steps.helm-cache.outputs.cache-hit != 'true'
|
if: steps.helm-cache.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
|
HELM_VERSION="${{ needs.load-versions.outputs.helm-version }}"
|
||||||
ARCH="amd64"
|
ARCH="amd64"
|
||||||
HELM_TARBALL="helm-${HELM_VERSION}-linux-${ARCH}.tar.gz"
|
HELM_TARBALL="helm-${HELM_VERSION}-linux-${ARCH}.tar.gz"
|
||||||
curl -fsSL "https://get.helm.sh/${HELM_TARBALL}" -o "/tmp/${HELM_TARBALL}"
|
curl -fsSL "https://get.helm.sh/${HELM_TARBALL}" -o "/tmp/${HELM_TARBALL}"
|
||||||
@@ -320,7 +354,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -364,10 +398,10 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
|
needs: [load-versions, lint, typecheck, security, quality, unit_tests]
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
needs: [lint, typecheck, security, quality, unit_tests]
|
|
||||||
# Bound the job so a hung run fails cleanly with diagnostics instead of
|
# Bound the job so a hung run fails cleanly with diagnostics instead of
|
||||||
# being externally reaped to "no data". The parallel engine runs in
|
# being externally reaped to "no data". The parallel engine runs in
|
||||||
# ~4min; this leaves generous headroom for install + chunk tail.
|
# ~4min; this leaves generous headroom for install + chunk tail.
|
||||||
@@ -401,7 +435,7 @@ jobs:
|
|||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
if: steps.gate.outputs.run == 'true'
|
if: steps.gate.outputs.run == 'true'
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
if: steps.gate.outputs.run == 'true'
|
if: steps.gate.outputs.run == 'true'
|
||||||
@@ -460,6 +494,7 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -472,7 +507,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install uv and nox
|
- name: Install uv and nox
|
||||||
run: |
|
run: |
|
||||||
pip install -q uv==${{ env.UV_VERSION }} nox
|
pip install -q uv==${{ needs.load-versions.outputs.uv-version }} nox
|
||||||
|
|
||||||
- name: Cache uv packages
|
- name: Cache uv packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -508,7 +543,7 @@ jobs:
|
|||||||
# continue-on-error: true allows the status-check gate to pass even
|
# continue-on-error: true allows the status-check gate to pass even
|
||||||
# when the docker:dind runner is unavailable (infrastructure issue).
|
# when the docker:dind runner is unavailable (infrastructure issue).
|
||||||
# The docker job still runs; only infrastructure failures are tolerated.
|
# The docker job still runs; only infrastructure failures are tolerated.
|
||||||
needs: [lint, typecheck, security, quality, unit_tests]
|
needs: [load-versions, lint, typecheck, security, quality, unit_tests]
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
@@ -580,6 +615,7 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
helm:
|
helm:
|
||||||
|
needs: load-versions
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
@@ -602,6 +638,7 @@ jobs:
|
|||||||
- name: Install Helm CLI
|
- name: Install Helm CLI
|
||||||
if: steps.helm-cache.outputs.cache-hit != 'true'
|
if: steps.helm-cache.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
|
HELM_VERSION="${{ needs.load-versions.outputs.helm-version }}"
|
||||||
ARCH="amd64"
|
ARCH="amd64"
|
||||||
HELM_TARBALL="helm-${HELM_VERSION}-linux-${ARCH}.tar.gz"
|
HELM_TARBALL="helm-${HELM_VERSION}-linux-${ARCH}.tar.gz"
|
||||||
curl -fsSL "https://get.helm.sh/${HELM_TARBALL}" -o "/tmp/${HELM_TARBALL}"
|
curl -fsSL "https://get.helm.sh/${HELM_TARBALL}" -o "/tmp/${HELM_TARBALL}"
|
||||||
@@ -615,7 +652,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install kubeconform
|
- name: Install kubeconform
|
||||||
run: |
|
run: |
|
||||||
KUBECONFORM_VERSION="v0.7.0"
|
KUBECONFORM_VERSION="${{ needs.load-versions.outputs.kubeconform-version }}"
|
||||||
ARCH="amd64"
|
ARCH="amd64"
|
||||||
KUBECONFORM_TARBALL="kubeconform-linux-${ARCH}.tar.gz"
|
KUBECONFORM_TARBALL="kubeconform-linux-${ARCH}.tar.gz"
|
||||||
curl -fsSL "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/${KUBECONFORM_TARBALL}" \
|
curl -fsSL "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/${KUBECONFORM_TARBALL}" \
|
||||||
@@ -792,13 +829,14 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
status-check:
|
status-check:
|
||||||
if: always()
|
if: always()
|
||||||
needs: [lint, typecheck, security, quality, unit_tests, integration_tests, coverage, build, docker, helm, push-validation]
|
needs: [load-versions, lint, typecheck, security, quality, unit_tests, integration_tests, coverage, build, docker, helm, push-validation]
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: python:3.13-slim
|
image: python:3.13-slim
|
||||||
steps:
|
steps:
|
||||||
- name: Check required job results
|
- name: Check required job results
|
||||||
run: |
|
run: |
|
||||||
|
echo "load-versions: ${{ needs.load-versions.result }}"
|
||||||
echo "lint: ${{ needs.lint.result }}"
|
echo "lint: ${{ needs.lint.result }}"
|
||||||
echo "typecheck: ${{ needs.typecheck.result }}"
|
echo "typecheck: ${{ needs.typecheck.result }}"
|
||||||
echo "security: ${{ needs.security.result }}"
|
echo "security: ${{ needs.security.result }}"
|
||||||
@@ -811,7 +849,8 @@ jobs:
|
|||||||
echo "helm: ${{ needs.helm.result }}"
|
echo "helm: ${{ needs.helm.result }}"
|
||||||
echo "push-validation: ${{ needs.push-validation.result }}"
|
echo "push-validation: ${{ needs.push-validation.result }}"
|
||||||
|
|
||||||
if [ "${{ needs.lint.result }}" != "success" ] || \
|
if [ "${{ needs.load-versions.result }}" != "success" ] || \
|
||||||
|
[ "${{ needs.lint.result }}" != "success" ] || \
|
||||||
[ "${{ needs.typecheck.result }}" != "success" ] || \
|
[ "${{ needs.typecheck.result }}" != "success" ] || \
|
||||||
[ "${{ needs.security.result }}" != "success" ] || \
|
[ "${{ needs.security.result }}" != "success" ] || \
|
||||||
[ "${{ needs.quality.result }}" != "success" ] || \
|
[ "${{ needs.quality.result }}" != "success" ] || \
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Tool versions for CI pipeline
|
||||||
|
# This file is the single source of truth for tool versions used in the CI pipeline.
|
||||||
|
# Format: TOOL_NAME=version
|
||||||
|
|
||||||
|
UV_VERSION=0.8.0
|
||||||
|
PYTHON_VERSION=3.13
|
||||||
|
HELM_VERSION=v3.16.4
|
||||||
|
KUBECONFORM_VERSION=v0.7.0
|
||||||
@@ -186,3 +186,73 @@ Feature: CI workflow validation
|
|||||||
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
When I parse the CI workflow YAML
|
When I parse the CI workflow YAML
|
||||||
Then the job "status-check" should depend on "helm"
|
Then the job "status-check" should depend on "helm"
|
||||||
|
|
||||||
|
# --- Tool version centralization ---
|
||||||
|
|
||||||
|
Scenario: Tool versions file exists
|
||||||
|
Given the tool versions file at ".tool-versions"
|
||||||
|
Then the tool versions file should exist
|
||||||
|
|
||||||
|
Scenario: Tool versions file contains UV_VERSION
|
||||||
|
Given the tool versions file at ".tool-versions"
|
||||||
|
When I parse the tool versions file
|
||||||
|
Then the tool versions should contain "UV_VERSION"
|
||||||
|
|
||||||
|
Scenario: Tool versions file contains PYTHON_VERSION
|
||||||
|
Given the tool versions file at ".tool-versions"
|
||||||
|
When I parse the tool versions file
|
||||||
|
Then the tool versions should contain "PYTHON_VERSION"
|
||||||
|
|
||||||
|
Scenario: Tool versions file contains HELM_VERSION
|
||||||
|
Given the tool versions file at ".tool-versions"
|
||||||
|
When I parse the tool versions file
|
||||||
|
Then the tool versions should contain "HELM_VERSION"
|
||||||
|
|
||||||
|
Scenario: Tool versions file contains KUBECONFORM_VERSION
|
||||||
|
Given the tool versions file at ".tool-versions"
|
||||||
|
When I parse the tool versions file
|
||||||
|
Then the tool versions should contain "KUBECONFORM_VERSION"
|
||||||
|
|
||||||
|
Scenario: CI workflow reads UV_VERSION from tool versions file
|
||||||
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
|
When I parse the CI workflow YAML
|
||||||
|
Then the workflow should have a job named "load-versions"
|
||||||
|
And the job "load-versions" should run "load tool versions from .tool-versions"
|
||||||
|
|
||||||
|
Scenario: CI workflow load-versions job outputs uv-version
|
||||||
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
|
When I parse the CI workflow YAML
|
||||||
|
Then the job "load-versions" should have output "uv-version"
|
||||||
|
|
||||||
|
Scenario: CI workflow load-versions job outputs python-version
|
||||||
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
|
When I parse the CI workflow YAML
|
||||||
|
Then the job "load-versions" should have output "python-version"
|
||||||
|
|
||||||
|
Scenario: CI workflow load-versions job outputs helm-version
|
||||||
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
|
When I parse the CI workflow YAML
|
||||||
|
Then the job "load-versions" should have output "helm-version"
|
||||||
|
|
||||||
|
Scenario: CI workflow load-versions job outputs kubeconform-version
|
||||||
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
|
When I parse the CI workflow YAML
|
||||||
|
Then the job "load-versions" should have output "kubeconform-version"
|
||||||
|
|
||||||
|
Scenario: CI workflow jobs depend on load-versions
|
||||||
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
|
When I parse the CI workflow YAML
|
||||||
|
Then the job "lint" should depend on "load-versions"
|
||||||
|
And the job "typecheck" should depend on "load-versions"
|
||||||
|
And the job "unit_tests" should depend on "load-versions"
|
||||||
|
And the job "integration_tests" should depend on "load-versions"
|
||||||
|
And the job "e2e_tests" should depend on "load-versions"
|
||||||
|
And the job "helm" should depend on "load-versions"
|
||||||
|
And the job "build" should depend on "load-versions"
|
||||||
|
|
||||||
|
Scenario: CI workflow uses load-versions outputs for uv installation
|
||||||
|
Given the CI workflow file at ".forgejo/workflows/ci.yml"
|
||||||
|
When I parse the CI workflow YAML
|
||||||
|
Then the job "lint" should reference "needs.load-versions.outputs.uv-version"
|
||||||
|
And the job "typecheck" should reference "needs.load-versions.outputs.uv-version"
|
||||||
|
And the job "unit_tests" should reference "needs.load-versions.outputs.uv-version"
|
||||||
|
|||||||
@@ -189,3 +189,79 @@ def step_then_at_least_one_job_uses_cache(context):
|
|||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
"No job in the CI workflow uses actions/cache for dependency caching"
|
"No job in the CI workflow uses actions/cache for dependency caching"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@given('the tool versions file at "{path}"')
|
||||||
|
def step_given_tool_versions_file(context, path):
|
||||||
|
"""Store the tool versions file path."""
|
||||||
|
context.tool_versions_path = Path(path)
|
||||||
|
|
||||||
|
|
||||||
|
@then("the tool versions file should exist")
|
||||||
|
def step_then_tool_versions_exists(context):
|
||||||
|
"""Verify the tool versions file exists."""
|
||||||
|
if not context.tool_versions_path.exists():
|
||||||
|
raise AssertionError(
|
||||||
|
f"Tool versions file not found at {context.tool_versions_path}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@when("I parse the tool versions file")
|
||||||
|
def step_when_parse_tool_versions(context):
|
||||||
|
"""Parse the tool versions file."""
|
||||||
|
tool_versions_path = context.tool_versions_path
|
||||||
|
if not tool_versions_path.exists():
|
||||||
|
raise FileNotFoundError(f"Tool versions file not found at {tool_versions_path}")
|
||||||
|
|
||||||
|
context.tool_versions = {}
|
||||||
|
with tool_versions_path.open("r") as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
# Skip empty lines and comments
|
||||||
|
if not line or line.startswith("#"):
|
||||||
|
continue
|
||||||
|
if "=" in line:
|
||||||
|
key, value = line.split("=", 1)
|
||||||
|
context.tool_versions[key.strip()] = value.strip()
|
||||||
|
|
||||||
|
|
||||||
|
@then('the tool versions should contain "{key}"')
|
||||||
|
def step_then_tool_versions_contain(context, key):
|
||||||
|
"""Verify the tool versions file contains a specific key."""
|
||||||
|
if key not in context.tool_versions:
|
||||||
|
raise AssertionError(
|
||||||
|
f"Tool version '{key}' not found in tool versions file. "
|
||||||
|
f"Available keys: {list(context.tool_versions.keys())}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@then('the job "{job_name}" should have output "{output_name}"')
|
||||||
|
def step_then_job_has_output(context, job_name, output_name):
|
||||||
|
"""Verify a job has a specific output."""
|
||||||
|
jobs = context.ci_workflow.get("jobs", {})
|
||||||
|
job = jobs.get(job_name)
|
||||||
|
if job is None:
|
||||||
|
raise AssertionError(f"Job '{job_name}' not found in workflow")
|
||||||
|
|
||||||
|
outputs = job.get("outputs", {})
|
||||||
|
if output_name not in outputs:
|
||||||
|
raise AssertionError(
|
||||||
|
f"Output '{output_name}' not found in job '{job_name}'. "
|
||||||
|
f"Available outputs: {list(outputs.keys())}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@then('the job "{job_name}" should reference "{reference}"')
|
||||||
|
def step_then_job_references(context, job_name, reference):
|
||||||
|
"""Verify a job references a specific value (e.g., needs.load-versions.outputs.uv-version)."""
|
||||||
|
jobs = context.ci_workflow.get("jobs", {})
|
||||||
|
job = jobs.get(job_name)
|
||||||
|
if job is None:
|
||||||
|
raise AssertionError(f"Job '{job_name}' not found in workflow")
|
||||||
|
|
||||||
|
# Convert the job to a string and search for the reference
|
||||||
|
job_str = str(job)
|
||||||
|
if reference not in job_str:
|
||||||
|
raise AssertionError(
|
||||||
|
f"Reference '{reference}' not found in job '{job_name}'"
|
||||||
|
)
|
||||||
|
|||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Load tool versions from .tool-versions file
|
||||||
|
# This script sources the .tool-versions file and exports the variables
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TOOL_VERSIONS_FILE=".tool-versions"
|
||||||
|
|
||||||
|
if [ ! -f "$TOOL_VERSIONS_FILE" ]; then
|
||||||
|
echo "ERROR: $TOOL_VERSIONS_FILE not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Source the tool versions file
|
||||||
|
# This exports all TOOL_NAME=version pairs as environment variables
|
||||||
|
while IFS='=' read -r key value; do
|
||||||
|
# Skip empty lines and comments
|
||||||
|
[[ -z "$key" || "$key" =~ ^# ]] && continue
|
||||||
|
# Trim whitespace
|
||||||
|
key=$(echo "$key" | xargs)
|
||||||
|
value=$(echo "$value" | xargs)
|
||||||
|
export "$key=$value"
|
||||||
|
done < "$TOOL_VERSIONS_FILE"
|
||||||
|
|
||||||
|
# Output the loaded versions for verification
|
||||||
|
echo "Loaded tool versions from $TOOL_VERSIONS_FILE:"
|
||||||
|
grep -v '^#' "$TOOL_VERSIONS_FILE" | grep -v '^$' | sed 's/^/ /'
|
||||||
Reference in New Issue
Block a user