kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
255 wiersze
7.5 KiB
Python
Executable File
255 wiersze
7.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""
|
|
Build metadata is a script that will extract build information from the environment,
|
|
either from CI variables or from git commands.
|
|
|
|
The build information are then mapped to the output format you need. The default output
|
|
format will print the build information as json.
|
|
|
|
- Release tags are stable version tags (e.g. 1.2.9),
|
|
- Prerelease tags are unstable version tags (e.g. 1.3.0-rc3),
|
|
- Development branches are both the 'stable' and 'develop' branches,
|
|
- Feature branches are any branch that will be merged in the development branches.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
import os
|
|
import shlex
|
|
from argparse import ArgumentParser
|
|
from subprocess import check_output
|
|
from typing import List, Optional, TypedDict
|
|
|
|
from packaging.version import Version
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
PROJECT_NAME = "Funkwhale"
|
|
PROJECT_DESCRIPTION = "Funkwhale platform"
|
|
AUTHORS = "Funkwhale Collective"
|
|
WEBSITE_URL = "https://funkwhale.audio/"
|
|
SOURCE_URL = "https://dev.funkwhale.audio/funkwhale/funkwhale"
|
|
DOCUMENTATION_URL = "https://docs.funkwhale.audio"
|
|
LICENSE = "AGPL-3.0"
|
|
|
|
|
|
class Metadata(TypedDict):
|
|
commit_tag: str
|
|
commit_branch: str
|
|
commit_sha: str
|
|
commit_timestamp: str
|
|
commit_ref_name: str
|
|
|
|
version: str
|
|
"""
|
|
Version is:
|
|
- on release tags, the current tag name,
|
|
- on prerelease tags, the current tag name,
|
|
- on development branches, the latest tag name in the branch and the commit sha suffix,
|
|
- on feature branches, an empty string.
|
|
"""
|
|
tags: List[str]
|
|
"""
|
|
Tags are:
|
|
- on release tags, the current tag name and aliases in the form 'X.Y.Z', 'X.Y', 'X' and 'latest',
|
|
- on prerelease tags, the current tag name,
|
|
- on development branches, the current commit branch name,
|
|
- on feature branches, an empty list.
|
|
"""
|
|
latest: bool
|
|
"""
|
|
Latest is true when the current tag name is not a prerelease:
|
|
- on release tags: true,
|
|
- on prerelease tags: false,
|
|
- on development branches: false,
|
|
- on feature branches: false.
|
|
"""
|
|
|
|
|
|
def sh(cmd: str, **kwargs):
|
|
logger.debug("running command: %s", cmd)
|
|
return check_output(shlex.split(cmd), text=True, **kwargs).strip()
|
|
|
|
|
|
def latest_tag_on_branch() -> str:
|
|
"""
|
|
Return the latest tag on the current branch.
|
|
"""
|
|
return sh("git describe --tags --abbrev=0")
|
|
|
|
|
|
def env_or_cmd(key: str, cmd: str) -> str:
|
|
if "CI" in os.environ:
|
|
return os.environ.get(key, "")
|
|
|
|
return sh(cmd)
|
|
|
|
|
|
def extract_metadata() -> Metadata:
|
|
commit_tag = env_or_cmd(
|
|
"CI_COMMIT_TAG",
|
|
"git tag --points-at HEAD",
|
|
)
|
|
commit_branch = env_or_cmd(
|
|
"CI_COMMIT_BRANCH",
|
|
"git rev-parse --abbrev-ref HEAD",
|
|
)
|
|
commit_sha = env_or_cmd(
|
|
"CI_COMMIT_SHA",
|
|
"git rev-parse HEAD",
|
|
)
|
|
commit_timestamp = env_or_cmd(
|
|
"CI_COMMIT_TIMESTAMP",
|
|
"git show -s --format=%cI HEAD",
|
|
)
|
|
commit_ref_name = os.environ.get(
|
|
"CI_COMMIT_REF_NAME",
|
|
default=commit_tag or commit_branch,
|
|
)
|
|
|
|
logger.info("found commit_tag: %s", commit_tag)
|
|
logger.info("found commit_branch: %s", commit_branch)
|
|
logger.info("found commit_sha: %s", commit_sha)
|
|
logger.info("found commit_timestamp: %s", commit_timestamp)
|
|
logger.info("found commit_ref_name: %s", commit_ref_name)
|
|
|
|
version = ""
|
|
tags = []
|
|
latest = False
|
|
if commit_tag: # Tagged version
|
|
version = Version(commit_tag)
|
|
if version.is_prerelease:
|
|
logger.info("build is for a prerelease tag")
|
|
tags.append(commit_tag)
|
|
|
|
else:
|
|
logger.info("build is for a release tag")
|
|
tags.append(f"{version.major}.{version.minor}.{version.micro}")
|
|
tags.append(f"{version.major}.{version.minor}")
|
|
tags.append(f"{version.major}")
|
|
tags.append("latest")
|
|
latest = True
|
|
|
|
version = tags[0]
|
|
|
|
else: # Branch version
|
|
if commit_branch in ("stable", "develop"):
|
|
logger.info("build is for a development branch")
|
|
tags.append(commit_branch)
|
|
|
|
previous_tag = latest_tag_on_branch()
|
|
previous_version = Version(previous_tag)
|
|
version = f"{previous_version.base_version}-dev+{commit_sha[:7]}"
|
|
|
|
else:
|
|
logger.info("build is for a feature branch")
|
|
|
|
return {
|
|
"commit_tag": commit_tag,
|
|
"commit_branch": commit_branch,
|
|
"commit_sha": commit_sha,
|
|
"commit_timestamp": commit_timestamp,
|
|
"commit_ref_name": commit_ref_name,
|
|
"version": version,
|
|
"tags": tags,
|
|
"latest": latest,
|
|
}
|
|
|
|
|
|
def bake_output(
|
|
metadata: Metadata,
|
|
target: Optional[str],
|
|
images: Optional[List[str]],
|
|
) -> dict:
|
|
if target is None:
|
|
logger.error("no bake target provided, exiting...")
|
|
raise SystemExit(1)
|
|
if images is None:
|
|
logger.error("no bake images provided, exiting...")
|
|
raise SystemExit(1)
|
|
|
|
docker_tags = [f"{img}:{tag}" for img in images for tag in metadata["tags"]]
|
|
|
|
docker_labels = {
|
|
"org.opencontainers.image.title": PROJECT_NAME,
|
|
"org.opencontainers.image.description": PROJECT_DESCRIPTION,
|
|
"org.opencontainers.image.url": WEBSITE_URL,
|
|
"org.opencontainers.image.source": SOURCE_URL,
|
|
"org.opencontainers.image.documentation": DOCUMENTATION_URL,
|
|
"org.opencontainers.image.licenses": LICENSE,
|
|
"org.opencontainers.image.vendor": AUTHORS,
|
|
"org.opencontainers.image.version": metadata["commit_ref_name"],
|
|
"org.opencontainers.image.created": metadata["commit_timestamp"],
|
|
"org.opencontainers.image.revision": metadata["commit_sha"],
|
|
}
|
|
|
|
return {
|
|
"target": {
|
|
target: {
|
|
"tags": docker_tags,
|
|
"labels": docker_labels,
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
def env_output(metadata: Metadata) -> list[str]:
|
|
env_dict = {
|
|
"BUILD_COMMIT_TAG": str(metadata["commit_tag"]),
|
|
"BUILD_COMMIT_BRANCH": str(metadata["commit_branch"]),
|
|
"BUILD_COMMIT_SHA": str(metadata["commit_sha"]),
|
|
"BUILD_COMMIT_TIMESTAMP": str(metadata["commit_timestamp"]),
|
|
"BUILD_COMMIT_REF_NAME": str(metadata["commit_ref_name"]),
|
|
"BUILD_VERSION": str(metadata["version"]),
|
|
"BUILD_TAGS": ",".join(metadata["tags"]),
|
|
"BUILD_LATEST": str(metadata["latest"]).lower(),
|
|
}
|
|
return [f"{key}={value}" for key, value in env_dict.items()]
|
|
|
|
|
|
def main(
|
|
format_: str,
|
|
bake_target: Optional[str],
|
|
bake_images: Optional[List[str]],
|
|
) -> int:
|
|
metadata = extract_metadata()
|
|
|
|
if format_ == "bake":
|
|
result = json.dumps(
|
|
bake_output(metadata=metadata, target=bake_target, images=bake_images),
|
|
indent=2,
|
|
)
|
|
elif format_ == "env":
|
|
result = "\n".join(env_output(metadata=metadata))
|
|
else:
|
|
result = json.dumps(metadata, indent=2)
|
|
|
|
print(result)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = ArgumentParser()
|
|
parser.add_argument(
|
|
"-f",
|
|
"--format",
|
|
choices=["bake", "env"],
|
|
default=None,
|
|
help="Print format for the metadata",
|
|
)
|
|
parser.add_argument(
|
|
"--bake-target",
|
|
help="Target for the bake metadata",
|
|
)
|
|
parser.add_argument(
|
|
"--bake-image",
|
|
action="append",
|
|
dest="bake_images",
|
|
help="Image names for the bake metadata",
|
|
)
|
|
args = parser.parse_args()
|
|
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s: %(message)s")
|
|
|
|
raise SystemExit(main(args.format, args.bake_target, args.bake_images))
|