forked from coreos/fedora-coreos-releng-automation
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
scripts: add versionary.py to drive FCOS versioning
This script implements the versioning scheme as described in: coreos/fedora-coreos-tracker#211 The tricky bit is the Y component: the "snapshot" date of the Fedora content. The algorithm I went with here is to use the git timestamp of the commit that last changed the base manifest lockfile (e.g. `manifest-lock.x86_64.json`). The reasoning is that this lockfile defines the base content from which we build. These lockfiles are updated by bots daily and are promoted as is through e.g. `testing-devel` -> `testing`, so we correctly maintain the X.Y components of the version during releases. OTOH, the overrides lockfile is maintained by humans, and will be what we use to override content if we need to backport/revert packages and respin a release (and thus, the base lockfile remains the same). The next step is to use this in the FCOS pipeline to drive versioning.
- Loading branch information
Showing
1 changed file
with
138 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
#!/usr/bin/python3 -u | ||
|
||
''' | ||
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 | ||
|
||
|
||
def main(): | ||
args = parse_args() | ||
if args.workdir is not None: | ||
os.chdir(args.workdir) | ||
assert os.path.isfile('builds/builds.json'), 'Missing builds/builds.json!' | ||
|
||
x, y, z = (get_x(), get_y(), get_z()) | ||
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") | ||
return parser.parse_args() | ||
|
||
|
||
def get_x(): | ||
""" | ||
X is the Fedora release version on which we're based. | ||
""" | ||
manifest = get_flattened_manifest() | ||
releasever = manifest['releasever'] | ||
eprint(f"Got releasever {releasever} from manifest") | ||
return int(releasever) | ||
|
||
|
||
def get_y(): | ||
""" | ||
Y is the base snapshot date in YYYYMMDD format of Fedora. We derive | ||
this using the timestamp of the base lockfile. | ||
""" | ||
strftime_format = '%Y%m%d' | ||
# XXX: should sanity check that the lockfiles for all the basearches have | ||
# matching timestamps | ||
date = subprocess.check_output(['git', 'log', '-1', '--format=format:%ad', | ||
f'--date=format:{strftime_format}', | ||
'manifest-lock.x86_64.json'], | ||
cwd='src/config', encoding='utf-8').strip() | ||
eprint(f"Got lockfile timestamp {date}") | ||
# sanity check we can parse it back as a valid date | ||
time.strptime(date, strftime_format) | ||
return int(date) | ||
|
||
|
||
def get_z(): | ||
""" | ||
Z is the stream indicator. | ||
""" | ||
# https://github.com/coreos/fedora-coreos-tracker/issues/211#issuecomment-543547587 | ||
stream_to_int = { | ||
'next': 1, | ||
'testing': 2, | ||
'stable': 3, | ||
'next-devel': 10, | ||
'testing-devel': 20, | ||
'rawhide': 91, | ||
'branched': 92, | ||
'bodhi-updates-testing': 93, | ||
'bodhi-updates': 94, | ||
} | ||
manifest = get_flattened_manifest() | ||
stream = manifest['add-commit-metadata']['fedora-coreos.stream'] | ||
eprint(f"Got stream {stream} from manifest") | ||
assert stream in stream_to_int, f"Unknown stream: {stream}" | ||
mapped = stream_to_int[stream] | ||
eprint(f"Mapped stream {stream} to {mapped}") | ||
return mapped | ||
|
||
|
||
def get_next_iteration(x, y, z): | ||
with open('builds/builds.json') as f: | ||
builds = json.load(f) | ||
|
||
if len(builds['builds']) == 0: | ||
eprint(f"No previous builds") | ||
return 0 | ||
|
||
last_buildid = builds['builds'][0]['id'] | ||
last_version = parse_version(last_buildid) | ||
if not last_version: | ||
eprint(f"Previous version {last_buildid} does not match scheme") | ||
return 0 | ||
|
||
if (x, y, z) != last_version[:3]: | ||
eprint(f"Previous version {last_buildid} x.y.z does not match") | ||
return 0 | ||
|
||
return last_version[3] + 1 | ||
|
||
|
||
def get_flattened_manifest(): | ||
return yaml.safe_load( | ||
subprocess.check_output(['rpm-ostree', 'compose', 'tree', '--repo', | ||
'tmp/repo', '--print-only', | ||
'src/config/manifest.yaml'])) | ||
|
||
|
||
def parse_version(version): | ||
m = re.match(r'^([0-9]{2})\.([0-9]{8})\.([0-9]+)\.([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(int, m.groups())) | ||
|
||
|
||
def eprint(*args): | ||
print(*args, file=sys.stderr) | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |