Skip to content

[FAST_BUILD] Add MarkdownPiece class to make manifest pieces better structured #2238

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

Merged
merged 1 commit into from
Feb 23, 2025
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
8 changes: 2 additions & 6 deletions docs/maintaining/tagging.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,14 @@ So, the `tag_value(container)` method gets a docker container as an input and re

### Manifest

`ManifestHeader` is a build manifest header.
It contains the following sections: `Build timestamp`, `Docker image size`, and `Git commit` info.

All the other manifest classes are inherited from `ManifestInterface`:
All manifest classes except `BuildInfo` are inherited from `ManifestInterface`
and `markdown_piece(container)` method returns a piece of the build manifest.

```{literalinclude} ../../tagging/manifests/manifest_interface.py
:language: py
:start-at: class ManifestInterface
```

- The `markdown_piece(container)` method returns a piece of markdown file to be used as a part of the build manifest.

`AptPackagesManifest` example:

```{literalinclude} ../../tagging/manifests/apt_packages.py
Expand Down
11 changes: 7 additions & 4 deletions tagging/apps/write_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from tagging.hierarchy.get_taggers_and_manifests import (
get_taggers_and_manifests,
)
from tagging.manifests.header import ManifestHeader
from tagging.manifests.build_info import BuildInfo
from tagging.manifests.manifest_interface import ManifestInterface
from tagging.utils.config import Config
from tagging.utils.docker_runner import DockerRunner
Expand Down Expand Up @@ -51,14 +51,17 @@ def write_build_history_line(
def write_manifest_file(
config: Config,
filename: str,
commit_hash_tag: str,
manifests: list[ManifestInterface],
container: Container,
) -> None:
manifest_names = [manifest.__class__.__name__ for manifest in manifests]
LOGGER.info(f"Using manifests: {manifest_names}")

markdown_pieces = [ManifestHeader.create_header(config, BUILD_TIMESTAMP)] + [
manifest.markdown_piece(container) for manifest in manifests
markdown_pieces = [
f"# Build manifest for image: {config.image}:{commit_hash_tag}",
BuildInfo.markdown_piece(config, BUILD_TIMESTAMP).get_str(),
*(manifest.markdown_piece(container).get_str() for manifest in manifests),
]
markdown_content = "\n\n".join(markdown_pieces) + "\n"

Expand All @@ -82,7 +85,7 @@ def write_manifest(config: Config) -> None:
tags_prefix + "-" + tagger.tag_value(container) for tagger in taggers
]
write_build_history_line(config, filename, all_tags)
write_manifest_file(config, filename, manifests, container)
write_manifest_file(config, filename, commit_hash_tag, manifests, container)


if __name__ == "__main__":
Expand Down
12 changes: 6 additions & 6 deletions tagging/manifests/apt_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container

from tagging.manifests.manifest_interface import ManifestInterface
from tagging.manifests.manifest_interface import ManifestInterface, MarkdownPiece
from tagging.utils.quoted_output import quoted_output


class AptPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Apt Packages

{quoted_output(container, "apt list --installed")}"""
def markdown_piece(container: Container) -> MarkdownPiece:
return MarkdownPiece(
title="## Apt Packages",
sections=[quoted_output(container, "apt list --installed")],
)
18 changes: 10 additions & 8 deletions tagging/manifests/header.py → tagging/manifests/build_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
# Distributed under the terms of the Modified BSD License.
import plumbum

from tagging.manifests.manifest_interface import MarkdownPiece
from tagging.utils.config import Config
from tagging.utils.git_helper import GitHelper

docker = plumbum.local["docker"]


class ManifestHeader:
"""ManifestHeader doesn't fall under common interface, and we run it separately"""
class BuildInfo:
"""BuildInfo doesn't fall under common interface, and we run it separately"""

@staticmethod
def create_header(config: Config, build_timestamp: str) -> str:
def markdown_piece(config: Config, build_timestamp: str) -> MarkdownPiece:
commit_hash = GitHelper.commit_hash()
commit_hash_tag = GitHelper.commit_hash_tag()
commit_message = GitHelper.commit_message()
Expand All @@ -27,11 +28,10 @@ def create_header(config: Config, build_timestamp: str) -> str:
"{{.Size}}",
]().rstrip()

return f"""\
# Build manifest for image: {config.image}:{commit_hash_tag}

## Build Info

return MarkdownPiece(
title="## Build Info",
sections=[
f"""\
- Build timestamp: {build_timestamp}
- Docker image: `{config.full_image()}:{commit_hash_tag}`
- Docker image size: {image_size}
Expand All @@ -41,3 +41,5 @@ def create_header(config: Config, build_timestamp: str) -> str:
```text
{commit_message}
```"""
],
)
23 changes: 11 additions & 12 deletions tagging/manifests/conda_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container

from tagging.manifests.manifest_interface import ManifestInterface
from tagging.manifests.manifest_interface import ManifestInterface, MarkdownPiece
from tagging.utils.docker_runner import DockerRunner
from tagging.utils.quoted_output import quoted_output


class CondaEnvironmentManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Python Packages

{DockerRunner.run_simple_command(container, "python --version")}

{quoted_output(container, "conda info")}

{quoted_output(container, "mamba info")}

{quoted_output(container, "mamba list")}"""
def markdown_piece(container: Container) -> MarkdownPiece:
return MarkdownPiece(
title="## Python Packages",
sections=[
DockerRunner.run_simple_command(container, "python --version"),
quoted_output(container, "conda info"),
quoted_output(container, "mamba info"),
quoted_output(container, "mamba list"),
],
)
19 changes: 11 additions & 8 deletions tagging/manifests/julia_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container

from tagging.manifests.manifest_interface import ManifestInterface
from tagging.manifests.manifest_interface import ManifestInterface, MarkdownPiece
from tagging.utils.quoted_output import quoted_output


class JuliaPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Julia Packages

{quoted_output(container, "julia -E 'using InteractiveUtils; versioninfo()'")}

{quoted_output(container, "julia -E 'import Pkg; Pkg.status()'")}"""
def markdown_piece(container: Container) -> MarkdownPiece:
return MarkdownPiece(
title="## Julia Packages",
sections=[
quoted_output(
container, "julia -E 'using InteractiveUtils; versioninfo()'"
),
quoted_output(container, "julia -E 'import Pkg; Pkg.status()'"),
],
)
17 changes: 16 additions & 1 deletion tagging/manifests/manifest_interface.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from dataclasses import dataclass

from docker.models.containers import Container


@dataclass(frozen=True)
class MarkdownPiece:
title: str
sections: list[str]

def __post_init__(self) -> None:
# All pieces are H2
assert self.title.startswith("## ")

def get_str(self) -> str:
return "\n\n".join([self.title, *self.sections])


class ManifestInterface:
"""Common interface for all manifests"""

@staticmethod
def markdown_piece(container: Container) -> str:
def markdown_piece(container: Container) -> MarkdownPiece:
raise NotImplementedError
19 changes: 11 additions & 8 deletions tagging/manifests/r_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container

from tagging.manifests.manifest_interface import ManifestInterface
from tagging.manifests.manifest_interface import ManifestInterface, MarkdownPiece
from tagging.utils.quoted_output import quoted_output


class RPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## R Packages

{quoted_output(container, "R --version")}

{quoted_output(container, "R --silent -e 'installed.packages(.Library)[, c(1,3)]'")}"""
def markdown_piece(container: Container) -> MarkdownPiece:
return MarkdownPiece(
title="## R Packages",
sections=[
quoted_output(container, "R --version"),
quoted_output(
container, "R --silent -e 'installed.packages(.Library)[, c(1,3)]'"
),
],
)
14 changes: 8 additions & 6 deletions tagging/manifests/spark_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container

from tagging.manifests.manifest_interface import ManifestInterface
from tagging.manifests.manifest_interface import ManifestInterface, MarkdownPiece
from tagging.utils.quoted_output import quoted_output


class SparkInfoManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Apache Spark

{quoted_output(container, "/usr/local/spark/bin/spark-submit --version")}"""
def markdown_piece(container: Container) -> MarkdownPiece:
return MarkdownPiece(
title="## Apache Spark",
sections=[
quoted_output(container, "/usr/local/spark/bin/spark-submit --version")
],
)
Loading