Skip to content

Commit e815fde

Browse files
authored
Better tagging directory structure (#2228)
1 parent 355813e commit e815fde

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+374
-330
lines changed

.github/workflows/docker-build-test-upload.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ jobs:
7878

7979
- name: Write tags file 🏷
8080
run: >
81-
python3 -m tagging.write_tags_file
81+
python3 -m tagging.apps.write_tags_file
8282
--registry ${{ env.REGISTRY }}
8383
--owner ${{ env.OWNER }}
8484
--short-image-name ${{ inputs.image }}
@@ -94,7 +94,7 @@ jobs:
9494

9595
- name: Write manifest and build history file 🏷
9696
run: >
97-
python3 -m tagging.write_manifest
97+
python3 -m tagging.apps.write_manifest
9898
--registry ${{ env.REGISTRY }}
9999
--owner ${{ env.OWNER }}
100100
--short-image-name ${{ inputs.image }}

.github/workflows/docker-merge-tags.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868
- name: Merge tags for the images 🔀
6969
if: env.PUSH_TO_REGISTRY == 'true'
7070
run: >
71-
python3 -m tagging.merge_tags
71+
python3 -m tagging.apps.merge_tags
7272
--short-image-name ${{ inputs.image }}
7373
--variant ${{ inputs.variant }}
7474
--tags-dir /tmp/jupyter/tags/

.github/workflows/docker-tag-push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
path: /tmp/jupyter/tags/
6363
- name: Apply tags to the loaded image 🏷
6464
run: >
65-
python3 -m tagging.apply_tags
65+
python3 -m tagging.apps.apply_tags
6666
--registry ${{ env.REGISTRY }}
6767
--owner ${{ env.OWNER }}
6868
--short-image-name ${{ inputs.image }}

.github/workflows/docker-wiki-update.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ jobs:
3737
uses: actions/checkout@v4
3838
with:
3939
repository: ${{ github.repository }}.wiki
40-
path: wiki/
40+
path: wiki_src/
4141

4242
- name: Update wiki 🏷
4343
run: >
44-
python3 -m tagging.update_wiki
45-
--wiki-dir wiki/
44+
python3 -m wiki.update_wiki
45+
--wiki-dir wiki_src/
4646
--hist-lines-dir /tmp/jupyter/hist_lines/
4747
--manifests-dir /tmp/jupyter/manifests/
4848
--repository ${{ github.repository }}

.github/workflows/docker.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ on:
3030
- "!tagging/README.md"
3131
- "tests/**"
3232
- "!tests/README.md"
33+
- "wiki/**"
3334
- "requirements-dev.txt"
3435
push:
3536
branches:
@@ -50,6 +51,7 @@ on:
5051
- "!tagging/README.md"
5152
- "tests/**"
5253
- "!tests/README.md"
54+
- "wiki/**"
5355
- "requirements-dev.txt"
5456
workflow_dispatch:
5557

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
This changelog only contains breaking and/or significant changes manually introduced to this repository (using Pull Requests).
44
All image manifests can be found in [the wiki](https://github.com/jupyter/docker-stacks/wiki).
55

6+
## 2025-02-21
7+
8+
Affected: all images.
9+
10+
- **Non-breaking:**: Better tagging directory structure ([#2228](https://github.com/jupyter/docker-stacks/pull/2228)).
11+
612
## 2025-02-18
713

814
Affected: all images.

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,20 @@ linkcheck-docs: ## check broken links
7878

7979
hook/%: VARIANT?=default
8080
hook/%: ## run post-build hooks for an image
81-
python3 -m tagging.write_tags_file \
81+
python3 -m tagging.apps.write_tags_file \
8282
--registry "$(REGISTRY)" \
8383
--owner "$(OWNER)" \
8484
--short-image-name "$(notdir $@)" \
8585
--variant "$(VARIANT)" \
8686
--tags-dir /tmp/jupyter/tags/
87-
python3 -m tagging.write_manifest \
87+
python3 -m tagging.apps.write_manifest \
8888
--registry "$(REGISTRY)" \
8989
--owner "$(OWNER)" \
9090
--short-image-name "$(notdir $@)" \
9191
--variant "$(VARIANT)" \
9292
--hist-lines-dir /tmp/jupyter/hist_lines/ \
9393
--manifests-dir /tmp/jupyter/manifests/
94-
python3 -m tagging.apply_tags \
94+
python3 -m tagging.apps.apply_tags \
9595
--registry "$(REGISTRY)" \
9696
--owner "$(OWNER)" \
9797
--short-image-name "$(notdir $@)" \

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Table of Contents
3535
:caption: Maintainer Guide
3636

3737
maintaining/new-images-and-packages-policy
38+
maintaining/tagging
3839
maintaining/tasks
3940

4041
.. toctree::

docs/maintaining/tagging.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Tagging and manifest creation
2+
3+
The main purpose of the source code in [the `tagging` folder](https://github.com/jupyter/docker-stacks/tree/main/tagging) is to properly write tag files and manifests for single-platform images,
4+
apply these tags, and merge single-platform images into one multi-arch image.
5+
6+
## What is a tag and a manifest
7+
8+
A tag is a label attached to a Docker image identifying specific attributes or versions.
9+
For example, an image `jupyter/base-notebook` with Python 3.10.5 will have a full image name `quay.io/jupyter/base-notebook:python-3.10.5`.
10+
These tags are pushed to our [Quay.io registry](https://quay.io/organization/jupyter).
11+
12+
A manifest is a description of important image attributes written in Markdown format.
13+
For example, we dump all `conda` packages with their versions into the manifest.
14+
15+
## Main principles
16+
17+
- All images are organized in a hierarchical tree.
18+
More info on [image relationships](../using/selecting.md#image-relationships).
19+
- Classes inherit from `TaggerInterface` and `ManifestInterface` to generate tags and manifest pieces by running commands in Docker containers.
20+
- Tags and manifests are reevaluated for each image in the hierarchy since values may change between parent and child images.
21+
- To tag an image and create its manifest, run `make hook/<somestack>` (e.g., `make hook/base-notebook`).
22+
23+
## Utils
24+
25+
### DockerRunner
26+
27+
`DockerRunner` is a helper class to easily run a docker container and execute commands inside this container:
28+
29+
```{literalinclude} tagging_examples/docker_runner.py
30+
:language: py
31+
```
32+
33+
### GitHelper
34+
35+
`GitHelper` methods are run in the current `git` repo and give the information about the last commit hash and commit message:
36+
37+
```{literalinclude} tagging_examples/git_helper.py
38+
:language: py
39+
```
40+
41+
The prefix of commit hash (namely, 12 letters) is used as an image tag to make it easy to inherit from a fixed version of a docker image.
42+
43+
## Taggers and Manifests
44+
45+
### Tagger
46+
47+
`Tagger` is a class that can be run inside a docker container to calculate some tag for an image.
48+
49+
All the taggers are inherited from `TaggerInterface`:
50+
51+
```{literalinclude} ../../tagging/taggers/tagger_interface.py
52+
:language: py
53+
```
54+
55+
So, the `tag_value(container)` method gets a docker container as an input and returns a tag.
56+
57+
`SHATagger` example:
58+
59+
```{literalinclude} ../../tagging/taggers/sha.py
60+
:language: py
61+
```
62+
63+
- `taggers/` subdirectory contains all the taggers.
64+
- `apps/write_tags_file.py`, `apps/apply_tags.py`, and `apps/merge_tags.py` are Python executable used to write tags for an image, apply tags from a file, and create multi-arch images.
65+
66+
### Manifest
67+
68+
`ManifestHeader` is a build manifest header.
69+
It contains the following sections: `Build timestamp`, `Docker image size`, and `Git commit` info.
70+
71+
All the other manifest classes are inherited from `ManifestInterface`:
72+
73+
```{literalinclude} ../../tagging/manifests/manifest_interface.py
74+
:language: py
75+
```
76+
77+
- The `markdown_piece(container)` method returns a piece of markdown file to be used as a part of the build manifest.
78+
79+
`AptPackagesManifest` example:
80+
81+
```{literalinclude} ../../tagging/manifests/apt_packages.py
82+
:language: py
83+
```
84+
85+
- `quoted_output(container, cmd)` simply runs the command inside a container using `DockerRunner.run_simple_command` and wraps it to triple quotes to create a valid markdown piece.
86+
It also adds the command which was run to the markdown piece.
87+
- `manifests/` subdirectory contains all the manifests.
88+
- `apps/write_manifest.py` is a Python executable to create the build manifest and history line for an image.
89+
90+
### Images Hierarchy
91+
92+
All images' dependencies on each other and what taggers and manifest are applicable to them are defined in `hierarchy/images_hierarchy.py`.
93+
94+
`hierarchy/get_taggers_and_manifests.py` defines a function to get the taggers and manifests for a specific image.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from tagging.utils.docker_runner import DockerRunner
2+
3+
with DockerRunner("ubuntu") as container:
4+
DockerRunner.run_simple_command(container, cmd="env", print_result=True)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from tagging.utils.git_helper import GitHelper
2+
3+
print("Git hash:", GitHelper.commit_hash())
4+
print("Git message:", GitHelper.commit_message())

tagging/README.md

Lines changed: 1 addition & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,3 @@
11
# Docker stacks tagging and manifest creation
22

3-
The main purpose of the source code in this folder is to properly tag all the images and to update [build manifests](https://github.com/jupyter/docker-stacks/wiki).
4-
These two processes are closely related, so the source code is widely reused.
5-
6-
A basic example of a tag is a `Python` version tag.
7-
For example, an image `jupyter/base-notebook` with `python 3.10.5` will have a full image name `quay.io/jupyter/base-notebook:python-3.10.5`.
8-
This tag (and all the other tags) are pushed to Quay.io.
9-
10-
Manifest is a description of some important part of the image in a `markdown`.
11-
For example, we dump all the `conda` packages, including their versions.
12-
13-
## Main principles
14-
15-
- All the images are located in a hierarchical tree.
16-
More info on [image relationships](../docs/using/selecting.md#image-relationships).
17-
- We have `tagger` and `manifest` classes, which can be run inside docker containers to obtain tags and build manifest pieces.
18-
- These classes are inherited from the parent image to all the child images.
19-
- Because manifests and tags might change from parent to child, `taggers` and `manifests` are reevaluated on each image.
20-
So, the values are not inherited.
21-
- To tag an image and create a manifest, run `make hook/base-notebook` (or another image of your choice).
22-
23-
## Source code description
24-
25-
In this section, we will briefly describe the source code in this folder and give examples of how to use it.
26-
27-
### DockerRunner
28-
29-
`DockerRunner` is a helper class to easily run a docker container and execute commands inside this container:
30-
31-
```python
32-
from tagging.docker_runner import DockerRunner
33-
34-
with DockerRunner("ubuntu:22.04") as container:
35-
DockerRunner.run_simple_command(container, cmd="env", print_result=True)
36-
```
37-
38-
### GitHelper
39-
40-
`GitHelper` methods are run in the current `git` repo and give the information about the last commit hash and commit message:
41-
42-
```python
43-
from tagging.git_helper import GitHelper
44-
45-
print("Git hash:", GitHelper.commit_hash())
46-
print("Git message:", GitHelper.commit_message())
47-
```
48-
49-
The prefix of commit hash (namely, 12 letters) is used as an image tag to make it easy to inherit from a fixed version of a docker image.
50-
51-
### Tagger
52-
53-
`Tagger` is a class that can be run inside a docker container to calculate some tag for an image.
54-
55-
All the taggers are inherited from `TaggerInterface`:
56-
57-
```python
58-
class TaggerInterface:
59-
"""Common interface for all taggers"""
60-
61-
@staticmethod
62-
def tag_value(container) -> str:
63-
raise NotImplementedError
64-
```
65-
66-
So, the `tag_value(container)` method gets a docker container as an input and returns a tag.
67-
68-
`SHATagger` example:
69-
70-
```python
71-
from tagging.git_helper import GitHelper
72-
from tagging.taggers import TaggerInterface
73-
74-
75-
class SHATagger(TaggerInterface):
76-
@staticmethod
77-
def tag_value(container):
78-
return GitHelper.commit_hash_tag()
79-
```
80-
81-
- `taggers.py` contains all the taggers.
82-
- `tag_image.py` is a Python executable that is used to tag the image.
83-
84-
### Manifest
85-
86-
`ManifestHeader` is a build manifest header.
87-
It contains the following sections: `Build timestamp`, `Docker image size`, and `Git commit` info.
88-
89-
All the other manifest classes are inherited from `ManifestInterface`:
90-
91-
```python
92-
class ManifestInterface:
93-
"""Common interface for all manifests"""
94-
95-
@staticmethod
96-
def markdown_piece(container) -> str:
97-
raise NotImplementedError
98-
```
99-
100-
- The `markdown_piece(container)` method returns a piece of markdown file to be used as a part of the build manifest.
101-
102-
`AptPackagesManifest` example:
103-
104-
```python
105-
from tagging.manifests import ManifestInterface, quoted_output
106-
107-
108-
class AptPackagesManifest(ManifestInterface):
109-
@staticmethod
110-
def markdown_piece(container) -> str:
111-
return f"""\
112-
## Apt Packages
113-
114-
{quoted_output(container, "apt list --installed")}"""
115-
```
116-
117-
- `quoted_output` simply runs the command inside a container using `DockerRunner.run_simple_command` and wraps it to triple quotes to create a valid markdown piece.
118-
It also adds the command which was run to the markdown piece.
119-
- `manifests.py` contains all the manifests.
120-
- `write_manifest.py` is a Python executable that is used to create the build manifest and history line for an image.
121-
122-
### Images Hierarchy
123-
124-
All images' dependencies on each other and what taggers and manifest they make use of are defined in `images_hierarchy.py`.
125-
126-
`get_taggers_and_manifests.py` defines a helper function to get the taggers and manifests for a specific image.
3+
Please, refer to the [tagging section of documentation](https://jupyter-docker-stacks.readthedocs.io/en/latest/maintaing/tagging.html) to see how tags and manifests are created.

tagging/apps/__init__.py

Whitespace-only changes.

tagging/apply_tags.py renamed to tagging/apps/apply_tags.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
import plumbum
88

9-
from tagging.common_arguments import common_arguments_parser
10-
from tagging.get_platform import unify_aarch64
11-
from tagging.get_prefix import get_file_prefix_for_platform
9+
from tagging.apps.common_cli_arguments import common_arguments_parser
10+
from tagging.utils.get_platform import unify_aarch64
11+
from tagging.utils.get_prefix import get_file_prefix_for_platform
1212

1313
docker = plumbum.local["docker"]
1414

File renamed without changes.

tagging/merge_tags.py renamed to tagging/apps/merge_tags.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
import plumbum
88

9-
from tagging.common_arguments import common_arguments_parser
10-
from tagging.get_platform import ALL_PLATFORMS
11-
from tagging.get_prefix import get_file_prefix_for_platform
9+
from tagging.apps.common_cli_arguments import common_arguments_parser
10+
from tagging.utils.get_platform import ALL_PLATFORMS
11+
from tagging.utils.get_prefix import get_file_prefix_for_platform
1212

1313
docker = plumbum.local["docker"]
1414

tagging/write_manifest.py renamed to tagging/apps/write_manifest.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77

88
from docker.models.containers import Container
99

10-
from tagging.common_arguments import common_arguments_parser
11-
from tagging.docker_runner import DockerRunner
12-
from tagging.get_prefix import get_file_prefix, get_tag_prefix
13-
from tagging.get_taggers_and_manifests import get_taggers_and_manifests
14-
from tagging.git_helper import GitHelper
15-
from tagging.manifests import ManifestHeader, ManifestInterface
10+
from tagging.apps.common_cli_arguments import common_arguments_parser
11+
from tagging.hierarchy.get_taggers_and_manifests import (
12+
get_taggers_and_manifests,
13+
)
14+
from tagging.manifests.header import ManifestHeader
15+
from tagging.manifests.manifest_interface import ManifestInterface
16+
from tagging.utils.docker_runner import DockerRunner
17+
from tagging.utils.get_prefix import get_file_prefix, get_tag_prefix
18+
from tagging.utils.git_helper import GitHelper
1619

1720
LOGGER = logging.getLogger(__name__)
1821

0 commit comments

Comments
 (0)