Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/generate-baseline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Generate Ubuntu Baseline

on:
workflow_dispatch:

jobs:
generate:
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install Python deps
run: pip install PyYAML

- name: Generate baseline
run: |
python3 scripts/generate_ubuntu_baseline.py \
--lts 22.04 24.04

- name: Commit if changed
run: |
git config user.name github-actions
git config user.email [email protected]
git add _data/ubuntu-baseline.yml

if git diff --cached --quiet; then
echo "No changes"
else
git commit -m "Update Ubuntu baseline"
git push
fi
26 changes: 26 additions & 0 deletions _data/ubuntu-baseline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
generated_at: '2026-02-28T11:28:15.149816+00:00'
ubuntu:
'22.04':
optional:
libopenmpi-dev: 4.1.2
petsc-dev: 3.15.5+dfsg1
python3-dev: 3.10.6
python3-numpy: 1.21.5
required:
build-essential: 12.9ubuntu3
cmake: 3.22.1
libboost-all-dev: 1.74.0.3ubuntu7
libeigen3-dev: 3.4.0
libxml2-dev: 2.9.13+dfsg
'24.04':
optional:
libopenmpi-dev: 4.1.6
petsc-dev: 3.19.6+dfsg1
python3-dev: 3.12.3
python3-numpy: 1.26.4+ds
required:
build-essential: 12.10ubuntu1
cmake: 3.28.3
libboost-all-dev: 1.83.0.1ubuntu2
libeigen3-dev: 3.4.0
libxml2-dev: 2.9.14+dfsg
13 changes: 13 additions & 0 deletions scripts/dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
packages:
required:
- build-essential
- cmake
- libeigen3-dev
- libxml2-dev
- libboost-all-dev

optional:
- libopenmpi-dev
- petsc-dev
- python3-dev
- python3-numpy
124 changes: 124 additions & 0 deletions scripts/generate_ubuntu_baseline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env python3

import subprocess
import yaml
import argparse
from pathlib import Path
from datetime import datetime, UTC

ROOT = Path(__file__).resolve().parent.parent
DEPENDENCIES_FILE = ROOT / "scripts" / "dependencies.yml"
OUTPUT_FILE = ROOT / "_data" / "ubuntu-baseline.yml"


def load_dependencies():
with open(DEPENDENCIES_FILE, "r") as f:
data = yaml.safe_load(f)

packages = data.get("packages", {})

return {
"required": sorted(packages.get("required", [])),
"optional": sorted(packages.get("optional", [])),
}


def run_command(cmd):
result = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
if result.returncode != 0:
print(result.stderr)
return None
return result.stdout.strip()


def get_version_docker(ubuntu_version, package):
cmd = [
"docker",
"run",
"--rm",
f"ubuntu:{ubuntu_version}",
"bash",
"-c",
f"apt-get update -qq && apt-cache policy {package} | grep Candidate | awk '{{print $2}}'",
]
raw = run_command(cmd)

if not raw or raw == "(none)":
return None

# Remove epoch (e.g. "1:")
if ":" in raw:
raw = raw.split(":", 1)[1]

# Remove Debian revision (e.g. "-1ubuntu1")
raw = raw.split("-", 1)[0]

return raw


def get_version_mock(package):
return "0.0.0-mock"


def generate_data(lts_versions, mock=False):
package_groups = load_dependencies()

result = {
"generated_at": datetime.now(UTC).isoformat(),
"ubuntu": {},
}

for version in lts_versions:
result["ubuntu"][version] = {
"required": {},
"optional": {},
}

for group in ["required", "optional"]:
for pkg in package_groups[group]:
if mock:
ver = get_version_mock(pkg)
else:
ver = get_version_docker(version, pkg)

result["ubuntu"][version][group][pkg] = ver or "not-found"

return result


def write_yaml(data):
OUTPUT_FILE.parent.mkdir(parents=True, exist_ok=True)
with open(OUTPUT_FILE, "w") as f:
yaml.dump(data, f, sort_keys=True)


def main():
parser = argparse.ArgumentParser(
description="Generate Ubuntu baseline package versions using Docker."
)
parser.add_argument(
"--mock",
action="store_true",
help="Use mock versions instead of querying Docker (useful for testing the pipeline).",
)
parser.add_argument(
"--lts",
nargs="+",
required=True,
help="Ubuntu LTS versions to query (e.g. 22.04 24.04)",
)
args = parser.parse_args()

data = generate_data(args.lts, mock=args.mock)
write_yaml(data)

print(f"Generated {OUTPUT_FILE}")


if __name__ == "__main__":
main()