Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise build deps and add --version arg to bake #17

Merged
merged 10 commits into from
May 8, 2024
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11"]
python-version: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11"]
python-version: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- New command line arg to `bake`: `--version`. Also switch to relative imports. ([#17])
- Raise lint dependency versions ([#17])
- Drop support for python 3.10 and add explicit support for 3.12 ([#17])

[#17]: https://github.com/stackabletech/image-tools/pull/17


## 0.0.7

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pip install git+https://github.com/stackabletech/image-tools.git@main

Update the version in:

* `pyproject.toml`
* `src/image_tools/version.py`
* `README.md` : version and pip install command.

Update the CHANGELOG.
Expand Down
13 changes: 10 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "image-tools-stackabletech"
version = "0.0.7"
dynamic = ["version"]
authors = [{ name = "Razvan Mihai", email = "razvan.mihai@stackable.tech" }]
description = "Image tools for the Stackable Data Platform."
readme = "README.md"
Expand All @@ -12,8 +16,8 @@ classifiers = [
]
dependencies = ["Jinja2>=3.1.2", "PyYAML>=6.0"]
[project.optional-dependencies]
lint = ['ruff==0.0.275', 'mypy==1.4.0']
publish = ['twine==5.0.0', 'build==1.2.1']
lint = ['ruff>=0.4', 'mypy>=1.10']
publish = ['twine>=5.0', 'build>=1.2']

[project.scripts]
bake = "image_tools.bake:main"
Expand All @@ -29,3 +33,6 @@ line-length = 120

[tool.mypy]
ignore_missing_imports = true

[tool.setuptools.dynamic]
version = { attr = "image_tools.version.__version__" }
95 changes: 56 additions & 39 deletions src/image_tools/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import importlib.util
import sys

from .version import version


DEFAULT_IMAGE_VERSION_FORMATS = [
re.compile(r"[2-9][0-9]\.[1-9][0-2]?\.\d+(-.+)?"),
re.compile(r"0\.0\.0-dev(-.+)?"),
Expand All @@ -12,30 +15,40 @@

def bake_args() -> Namespace:
parser = ArgumentParser(
description="Build and publish product images. Requires docker and buildx (https://github.com/docker/buildx)."
description=f"bake {version()} Build and publish product images. Requires docker and buildx (https://github.com/docker/buildx)."
)
parser.add_argument("-v", "--version", help="Display version", action="store_true")

(
parser.add_argument(
"-c",
"--configuration",
help="Configuration file.",
default="./conf.py",
),
)
parser.add_argument(
"-c",
"--configuration",
help="Configuration file.",
default="./conf.py",
),
parser.add_argument(
"-i",
"--image-version",
help="Image version",
default='0.0.0-dev',
default="0.0.0-dev",
type=check_image_version_format,
)
parser.add_argument("-p", "--product",
help="Product to build images for", action='append')
parser.add_argument("--shard-count", type=positive_int, default=1,
help="Split the build into N shards, which can be built separately. \
All shards must be built separately, by specifying the --shard-index argument.",)
parser.add_argument("--shard-index", type=positive_int, default=0,
help="Build shard number M out of --shard-count. Shards are zero-indexed.")
parser.add_argument("-u", "--push", help="Push images",
action="store_true")
parser.add_argument("-p", "--product", help="Product to build images for", action="append")
parser.add_argument(
"--shard-count",
type=positive_int,
default=1,
help="Split the build into N shards, which can be built separately. \
All shards must be built separately, by specifying the --shard-index argument.",
)
parser.add_argument(
"--shard-index",
type=positive_int,
default=0,
help="Build shard number M out of --shard-count. Shards are zero-indexed.",
)
parser.add_argument("-u", "--push", help="Push images", action="store_true")
parser.add_argument("-d", "--dry", help="Dry run.", action="store_true")
parser.add_argument(
"-a",
Expand All @@ -56,16 +69,21 @@ def bake_args() -> Namespace:
help="Image registry to publish to. Default: docker.stackable.tech",
default="docker.stackable.tech",
)
parser.add_argument(
"--export-tags-file",
help="Write target image tags to a text file. Useful for signing or other follow-up CI steps."
),
(
parser.add_argument(
"--export-tags-file",
help="Write target image tags to a text file. Useful for signing or other follow-up CI steps.",
),
)

result = parser.parse_args()

if result.shard_index >= result.shard_count:
raise ValueError("shard index [{}] cannot be greater or equal than shard count [{}]".format(
result.shard_index, result.shard_count))
raise ValueError(
"shard index [{}] cannot be greater or equal than shard count [{}]".format(
result.shard_index, result.shard_count
)
)
return result


Expand All @@ -76,8 +94,7 @@ def positive_int(value) -> int:
raise ValueError
return ivalue
except ValueError:
raise ValueError(
f"Invalid value [{value}]. Must be an integer greater than or equal to zero.")
raise ValueError(f"Invalid value [{value}]. Must be an integer greater than or equal to zero.")


def check_image_version_format(image_version) -> str:
Expand Down Expand Up @@ -113,18 +130,18 @@ def preflight_args() -> Namespace:
parser = ArgumentParser(
description="Run OpenShift certification checks and submit results to RedHat Partner Connect portal"
)

parser.add_argument("-v", "--version", help="Display version", action="store_true")

parser.add_argument(
"-i",
"--image-version",
help="Image version",
required=True,
type=check_image_version_format,
)
parser.add_argument(
"-p", "--product", help="Product to build images for", required=True
)
parser.add_argument(
"-s", "--submit", help="Submit results", action="store_true")
parser.add_argument("-p", "--product", help="Product to build images for", required=True)
parser.add_argument("-s", "--submit", help="Submit results", action="store_true")
parser.add_argument("-d", "--dry", help="Dry run.", action="store_true")
parser.add_argument(
"-a",
Expand Down Expand Up @@ -156,12 +173,14 @@ def preflight_args() -> Namespace:
help="Name of the preflight program. Default: preflight",
default="preflight",
)
parser.add_argument(
"-c",
"--configuration",
help="Configuration file.",
default="./conf.py",
),
(
parser.add_argument(
"-c",
"--configuration",
help="Configuration file.",
default="./conf.py",
),
)

result = parser.parse_args()

Expand All @@ -175,9 +194,7 @@ def check_architecture_input(architecture: str) -> str:
supported_arch = ["linux/amd64", "linux/arm64"]

if architecture not in supported_arch:
raise ValueError(
f"Architecture {architecture} not supported. Supported: {supported_arch}"
)
raise ValueError(f"Architecture {architecture} not supported. Supported: {supported_arch}")

return architecture

Expand Down
50 changes: 22 additions & 28 deletions src/image_tools/bake.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@

python -m image_tools.bake -p opa -i 22.12.0
"""

import sys
from typing import List, Dict, Any
from argparse import Namespace
from subprocess import run
import json

from image_tools.lib import Command
from image_tools.args import bake_args, load_configuration
from .lib import Command
from .args import bake_args, load_configuration
from .version import version


def build_image_args(version: Dict[str, str], release_version: str):
Expand All @@ -34,9 +36,7 @@ def build_image_args(version: Dict[str, str], release_version: str):
return result


def build_image_tags(
image_name: str, image_version: str, product_version: str
) -> List[str]:
def build_image_tags(image_name: str, image_version: str, product_version: str) -> List[str]:
"""
Returns a list of --tag command line arguments that are used by the
docker build command.
Expand All @@ -59,11 +59,7 @@ def generate_bakefile(args: Namespace, conf) -> Dict[str, Any]:
product_name: str = product["name"]
product_targets = {}
for version_dict in product.get("versions", []):
product_targets.update(
bakefile_product_version_targets(
args, product_name, version_dict, product_names
)
)
product_targets.update(bakefile_product_version_targets(args, product_name, version_dict, product_names))
groups[product_name] = {
"targets": list(product_targets.keys()),
}
Expand All @@ -85,19 +81,18 @@ def bakefile_target_name_for_product_version(product_name: str, version: str) ->


def bakefile_product_version_targets(
args: Namespace,
product_name: str,
versions: Dict[str, str],
product_names: List[str],
args: Namespace,
product_name: str,
versions: Dict[str, str],
product_names: List[str],
):
"""
Creates Bakefile targets defining how to build a given product version.

A product is assumed to depend on another if it defines a `versions` field with the same name as the other product.
"""
image_name = f"{args.registry}/{args.organization}/{product_name}"
tags = build_image_tags(
image_name, args.image_version, versions["product"])
tags = build_image_tags(image_name, args.image_version, versions["product"])
build_args = build_image_args(versions, args.image_version)

return {
Expand All @@ -118,15 +113,13 @@ def bakefile_product_version_targets(

def targets_for_selector(conf, selected_products: List[str]) -> List[str]:
targets = []
for selected_product in selected_products or (product['name'] for product in conf.products):
for selected_product in selected_products or (product["name"] for product in conf.products):
product_name, *versions = selected_product.split("=")
product = next(
(product for product in conf.products if product['name'] == product_name), None)
product = next((product for product in conf.products if product["name"] == product_name), None)
if product is None:
raise ValueError(f"Requested unknown product [{product_name}]")
for version in versions or (version['product'] for version in product['versions']):
targets.append(bakefile_target_name_for_product_version(
product_name, version))
for ver in versions or (ver["product"] for ver in product["versions"]):
targets.append(bakefile_target_name_for_product_version(product_name, ver))
return targets


Expand All @@ -150,7 +143,6 @@ def bake_command(args: Namespace, targets: List[str], bakefile) -> Command:
else:
target_mode = ["--load"]


return Command(
args=[
"docker",
Expand All @@ -169,12 +161,15 @@ def main() -> int:
"""Generate a Docker bake file from conf.py and build the given args.product images."""
args = bake_args()

if args.version:
print(version())
return 0

conf = load_configuration(args.configuration)

bakefile = generate_bakefile(args, conf)

targets = filter_targets_for_shard(targets_for_selector(
conf, args.product), args.shard_count, args.shard_index)
targets = filter_targets_for_shard(targets_for_selector(conf, args.product), args.shard_count, args.shard_index)

if not targets:
print("No targets match this filter")
Expand All @@ -188,10 +183,9 @@ def main() -> int:
result = run(cmd.args, input=cmd.input, check=True)

if args.export_tags_file:
with open(args.export_tags_file, 'w') as tf:
with open(args.export_tags_file, "w") as tf:
for t in targets:
tf.writelines(
(f"{t}\n" for t in bakefile["target"][t]["tags"]))
tf.writelines((f"{t}\n" for t in bakefile["target"][t]["tags"]))

return result.returncode

Expand Down
Loading
Loading