1
0
mirror of https://github.com/coreos/fedora-coreos-config.git synced 2026-02-05 09:45:30 +01:00
Files
fedora-coreos-config/versionary
Jonathan Lebon a5af12c127 versionary: support --dev
Add a `--dev` switch which will be used to replace the functionality
lost by `automatic-version-prefix` after moving away from directly
running rpm-ostree composes to the container native path.
2025-08-10 09:43:00 -04:00

178 lines
4.8 KiB
Python
Executable File

#!/usr/bin/python3 -u
# This file originally lived in
# https://github.com/coreos/fedora-coreos-releng-automation. See that repo for
# archeological git research.
'''
Implements the Fedora CoreOS versioning scheme as per:
https://github.com/coreos/fedora-coreos-tracker/issues/81
https://github.com/coreos/fedora-coreos-tracker/issues/211
'''
import argparse
import json
import os
import re
import subprocess
import sys
import time
import yaml
from datetime import datetime
# streams which don't use lockfiles
UNLOCKED_STREAMS = [
'rawhide',
'branched',
'bodhi-updates-testing',
'bodhi-updates',
]
# https://github.com/coreos/fedora-coreos-tracker/issues/211#issuecomment-543547587
STREAM_TO_NUM = {
'next': 1,
'testing': 2,
'stable': 3,
'next-devel': 10,
'testing-devel': 20,
'rawhide': 91,
'branched': 92,
'bodhi-updates-testing': 93,
'bodhi-updates': 94,
}
def main():
args = parse_args()
if args.workdir is not None:
os.chdir(args.workdir)
assert os.path.isdir('builds'), 'Missing builds/ dir'
manifest = get_flattened_manifest()
x, y, z = (get_x(manifest), get_y(manifest), get_z(manifest, args.dev))
n = get_next_iteration(x, y, z)
new_version = f'{x}.{y}.{z}.{n}'
# sanity check the new version by trying to re-parse it
assert parse_version(new_version) is not None
print(new_version)
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--workdir', help="path to cosa workdir")
parser.add_argument('--dev', action='store_true', help="generate a developer version")
return parser.parse_args()
def get_x(manifest):
"""
X is the Fedora release version on which we're based.
"""
releasever = manifest['releasever']
eprint(f"x: {releasever} (from manifest)")
return int(releasever)
def get_y(manifest):
"""
Y is the base snapshot date in YYYYMMDD format of Fedora. We derive
this using the timestamp in the base lockfile.
"""
stream = manifest['add-commit-metadata']['fedora-coreos.stream']
# XXX: should sanity check that the lockfiles for all the basearches have
# matching timestamps
exts = ['json', 'yaml']
for ext in exts:
try:
with open(f"src/config/manifest-lock.x86_64.{ext}") as f:
lockfile = yaml.safe_load(f)
generated = lockfile.get('metadata', {}).get('generated')
if not generated:
raise Exception("Missing 'metadata.generated' key "
f"from {lockfile}")
dt = datetime.strptime(generated, '%Y-%m-%dT%H:%M:%SZ')
assert stream not in UNLOCKED_STREAMS
msg_src = "from lockfile"
break
except FileNotFoundError:
continue
else:
# must be an unlocked stream
assert stream in UNLOCKED_STREAMS
msg_src = "unlocked stream"
dt = datetime.now()
ymd = dt.strftime('%Y%m%d')
eprint(f"y: {ymd} ({msg_src})")
return int(ymd)
def get_z(manifest, dev):
"""
Z is the stream indicator.
"""
if dev:
eprint("z: dev (overridden)")
return 'dev'
stream = manifest['add-commit-metadata']['fedora-coreos.stream']
assert stream in STREAM_TO_NUM, f"Unknown stream: {stream}"
mapped = STREAM_TO_NUM[stream]
eprint(f"z: {mapped} (mapped from stream {stream})")
return mapped
def get_next_iteration(x, y, z):
try:
with open('builds/builds.json') as f:
builds = json.load(f)
except FileNotFoundError:
builds = {'builds': []}
if len(builds['builds']) == 0:
eprint("n: 0 (no previous builds)")
return 0
last_buildid = builds['builds'][0]['id']
last_version = parse_version(last_buildid)
if not last_version:
eprint(f"n: 0 (previous version {last_buildid} does not match scheme)")
return 0
if (x, y, z) != last_version[:3]:
eprint(f"n: 0 (previous version {last_buildid} x.y.z does not match)")
return 0
n = last_version[3] + 1
eprint(f"n: {n} (incremented from previous version {last_buildid})")
return n
def get_flattened_manifest():
return yaml.safe_load(
subprocess.check_output(['rpm-ostree', 'compose', 'tree',
'--print-only', 'src/config/manifest.yaml']))
def parse_version(version):
m = re.match(r'^([0-9]{2})\.([0-9]{8})\.([0-9]+|dev)\.([0-9]+)$', version)
if m is None:
return None
# sanity-check date
try:
time.strptime(m.group(2), '%Y%m%d')
except ValueError:
return None
return tuple(map(lambda x: 'dev' if x == 'dev' else int(x), m.groups()))
def eprint(*args):
print(*args, file=sys.stderr)
if __name__ == "__main__":
sys.exit(main())