docker-devkit 0.2.0__py3-none-any.whl → 0.2.1.dev109__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,11 +6,13 @@ import platform
6
6
  import re
7
7
  from pathlib import Path
8
8
  from subprocess import CalledProcessError
9
- from typing import Annotated, Any, Literal
9
+ from tempfile import TemporaryDirectory
10
+ from typing import Annotated, Any, Literal, TypedDict
10
11
 
11
12
  import typer
12
13
  from bashrun.bash import bash, bash_output
13
14
  from ci_devkit.builds import push_build
15
+ from ci_devkit.setup_oras import install_oras
14
16
  from .detect_gpu import GPU_TYPES, Gpu, detect_gpu
15
17
  from .documents import BakeDocument, digest_pinned, parse_bake
16
18
  from pydantic_settings import BaseSettings
@@ -32,7 +34,16 @@ METADATA_PATH = Path("metadata.json")
32
34
 
33
35
  Mode = Literal["local", "ci"]
34
36
 
35
- IMAGES_LOCK_PLATFORM = "images-lock"
37
+ DIGEST_PROJECT = "images-digests"
38
+ DIGEST_PLATFORM = "all"
39
+ DIGEST_FILE_NAME = "images-digests.json"
40
+
41
+
42
+ class DigestEntry(TypedDict):
43
+ ref: str
44
+ digest: str
45
+ tags: list[str]
46
+
36
47
 
37
48
  app = typer.Typer(add_completion=False, pretty_exceptions_show_locals=False)
38
49
 
@@ -53,17 +64,6 @@ def build(
53
64
  list[str] | None,
54
65
  typer.Option("--targets", "-t", help="Build only these services (from the image manifest)."),
55
66
  ] = None,
56
- builds_registry: Annotated[
57
- str | None,
58
- typer.Option("--builds-registry", help="OCI registry path to push the resolved lock to (CI build artifacts)."),
59
- ] = None,
60
- lock_project: Annotated[
61
- str | None,
62
- typer.Option("--lock-project", help="Project component of the lock's builds-shelf address (CI only)."),
63
- ] = None,
64
- run_number: Annotated[
65
- int, typer.Option("--run-number", help="CI run number baked into the lock's builds-shelf tag.")
66
- ] = 0,
67
67
  ) -> None:
68
68
  run_build(
69
69
  upgrade=upgrade,
@@ -73,9 +73,6 @@ def build(
73
73
  gpu_only=gpu_only,
74
74
  no_cache=no_cache,
75
75
  targets_opt=targets_opt,
76
- builds_registry=builds_registry,
77
- lock_project=lock_project,
78
- run_number=run_number,
79
76
  )
80
77
 
81
78
 
@@ -89,9 +86,6 @@ def run_build(
89
86
  no_cache: bool = False,
90
87
  targets_opt: list[str] | None = None,
91
88
  env_overlay: dict[str, str] | None = None,
92
- builds_registry: str | None = None,
93
- lock_project: str | None = None,
94
- run_number: int = 0,
95
89
  ) -> None:
96
90
  root = Path.cwd()
97
91
  manifest = require_manifest(root)
@@ -223,22 +217,56 @@ def run_build(
223
217
  if not set(targets) <= baked_images.keys():
224
218
  raise RuntimeError("Bake output does not cover the requested targets")
225
219
 
226
- push_images_lock(builds_registry, lock_project, run_number, lock_file)
227
-
228
-
229
- def push_images_lock(builds_registry: str | None, lock_project: str | None, run_number: int, lock_file: Path) -> None:
230
- if builds_registry is None:
231
- return
232
- if not lock_project or run_number <= 0:
233
- raise typer.BadParameter("--builds-registry requires --lock-project and a positive --run-number")
234
- push_build(
235
- builds_registry,
236
- lock_project,
237
- IMAGES_LOCK_PLATFORM,
238
- f"run-{run_number}",
239
- lock_file.parent,
240
- [lock_file.name],
241
- )
220
+ # Push the digest manifest to the repo's builds shelf (address and SHA derived, never flagged)
221
+ if mode == "ci":
222
+ github_repository = os.environ.get("GITHUB_REPOSITORY", "")
223
+ if not github_repository:
224
+ raise SystemExit("GITHUB_REPOSITORY not set — ci mode reads the GitHub runner environment")
225
+ shelf = f"ghcr.io/{github_repository}/builds"
226
+ sha = bash_output("git rev-parse HEAD").strip()
227
+ push_image_digests(shelf, sha, baked_images, targets)
228
+
229
+
230
+ def push_image_digests(
231
+ shelf: str,
232
+ sha: str,
233
+ baked_images: dict[str, Any],
234
+ targets: list[str],
235
+ ) -> None:
236
+ install_oras()
237
+ manifest = distill_digest_manifest(baked_images, targets)
238
+ with TemporaryDirectory(prefix="digest-manifest-") as staging:
239
+ manifest_path = Path(staging) / DIGEST_FILE_NAME
240
+ manifest_path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
241
+ push_build(
242
+ shelf,
243
+ DIGEST_PROJECT,
244
+ DIGEST_PLATFORM,
245
+ f"sha-{sha}",
246
+ Path(staging),
247
+ [DIGEST_FILE_NAME],
248
+ )
249
+
250
+
251
+ def distill_digest_manifest(baked_images: dict[str, Any], targets: list[str]) -> dict[str, DigestEntry]:
252
+ manifest: dict[str, DigestEntry] = {}
253
+ for target in targets:
254
+ entry = baked_images[target]
255
+ image_name = entry["image.name"]
256
+ digest = entry["containerimage.digest"]
257
+ refs = [reference.strip() for reference in image_name.split(",") if reference.strip()]
258
+ image_ref = ""
259
+ tags: list[str] = []
260
+ for reference in refs:
261
+ reference = reference.split("@", 1)[0]
262
+ repository, separator, tag = reference.rpartition(":")
263
+ if separator:
264
+ image_ref = repository
265
+ tags.append(tag)
266
+ if not tags:
267
+ raise ValueError(f"target '{target}' produced no tagged image references from '{image_name}'")
268
+ manifest[target] = {"ref": image_ref, "digest": digest, "tags": tags}
269
+ return manifest
242
270
 
243
271
 
244
272
  # Vibe code - Gemini 3
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: docker-devkit
3
- Version: 0.2.0
3
+ Version: 0.2.1.dev109
4
4
  Summary: Docker-stack lifecycle commands (up/down/build) driven by a pyproject-declared compose assembly
5
5
  License-File: LICENSE
6
6
  License-File: NOTICE
7
7
  Requires-Python: >=3.13
8
8
  Requires-Dist: bashrun>=0.1.0
9
- Requires-Dist: ci-devkit==0.1.15.dev36756330648
9
+ Requires-Dist: ci-devkit>=0.1.15
10
10
  Requires-Dist: packaging>=24.1
11
11
  Requires-Dist: pathspec>=1.0.4
12
12
  Requires-Dist: pydantic-settings>=2.9.1
@@ -1,5 +1,5 @@
1
1
  docker_devkit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- docker_devkit/build_docker.py,sha256=g6KPTOp5TDyG550Zun_XNpWH2D19arh-PaAjgBoSyhU,11685
2
+ docker_devkit/build_docker.py,sha256=i4uSR7OLflqspfbIlaYnfD6M7VlrRoKBW-8Jgc-D9MQ,12667
3
3
  docker_devkit/config.py,sha256=UMAS6yF1E9PIbsRs2TVig9XwSNCvQe5w9eTLUHOPKq0,3112
4
4
  docker_devkit/context_sha.py,sha256=lhCxUcYM98xCdDum3hsFRFw5WYrjvZUSMbOu_7ZmQjE,3041
5
5
  docker_devkit/detect_gpu.py,sha256=C4e3vixvSSJS6xQiMVWp2IdWSAgMr551KrBTuIrkTk4,456
@@ -13,9 +13,9 @@ docker_devkit/modes.py,sha256=Lwhblzu5Kn7qhfy_QMqE28XuflSIJtCRBYNX7Iq8Qfo,1510
13
13
  docker_devkit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  docker_devkit/score_generate.py,sha256=psbQm-MWf9A5YP0ov0rLPUiuVAQbUWn6yfUmB-CXurU,9434
15
15
  docker_devkit/up.py,sha256=32A2_6mxAF00XILecxYTzCQw0QvSjevBWCnayF5X1Xs,4284
16
- docker_devkit-0.2.0.dist-info/METADATA,sha256=fn2EhThFFa4ujzxUir7XHA-CWt21VkJfQKy3Iv9kyQU,530
17
- docker_devkit-0.2.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
18
- docker_devkit-0.2.0.dist-info/entry_points.txt,sha256=6cAHqlMvuXI00uTJLf73MTqWnLd1-m5sDgJrSyHWv4U,244
19
- docker_devkit-0.2.0.dist-info/licenses/LICENSE,sha256=RFhQPdSOiMTguUX7JSoIuTxA7HVzCbj_p8WU36HjUQQ,10947
20
- docker_devkit-0.2.0.dist-info/licenses/NOTICE,sha256=jvglZza3GCdN7v4_TLuXUqX9C_uABlwAKUkcIeKwk_8,26
21
- docker_devkit-0.2.0.dist-info/RECORD,,
16
+ docker_devkit-0.2.1.dev109.dist-info/METADATA,sha256=J8rxb9gnmPD8hwmr_kDMfDUxzd3UYKR7Vg-Bg1kGVMU,522
17
+ docker_devkit-0.2.1.dev109.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
18
+ docker_devkit-0.2.1.dev109.dist-info/entry_points.txt,sha256=6cAHqlMvuXI00uTJLf73MTqWnLd1-m5sDgJrSyHWv4U,244
19
+ docker_devkit-0.2.1.dev109.dist-info/licenses/LICENSE,sha256=RFhQPdSOiMTguUX7JSoIuTxA7HVzCbj_p8WU36HjUQQ,10947
20
+ docker_devkit-0.2.1.dev109.dist-info/licenses/NOTICE,sha256=jvglZza3GCdN7v4_TLuXUqX9C_uABlwAKUkcIeKwk_8,26
21
+ docker_devkit-0.2.1.dev109.dist-info/RECORD,,