# Docker stacks tagging and manifest creation
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).
These two processes are closely related, so the source code is widely reused.
Basic example of a tag is a `python` version tag.
For example, an image `jupyter/base-notebook` with `python 3.8.8` will have a tag `jupyter/base-notebook:python-3.8.8`.
This tag (and all the other tags) are pushed to Docker Hub.
Manifest is a description of some important part of the image in a `markdown`.
For example, we dump all the `conda` packages including their versions.
## Main principles
- All the images are located in a hierarchical tree. More info on [image relationships](../docs/using/selecting.md#image-relationships).
- We have `tagger` and `manifest` classes, which can be run inside docker containers to obtain tags and build manifest pieces.
- These classes are inherited from the parent image to all the children images.
- Because manifests and tags might change from parent to children, `taggers` and `manifests` are reevaluated on each image. So, the values are not inherited.
- To tag an image and create a manifest, run `make hook/base-notebook` (or another image of your choice).
## Source code description
In this section we will briefly describe source code in this folder and give examples on how to use it.
### DockerRunner
`DockerRunner` is a helper class to easily run a docker container and execute commands inside this container:
```python
from .docker_runner import DockerRunner
with DockerRunner("ubuntu:bionic") as container:
DockerRunner.run_simple_command(container, cmd="env", print_result=True)
```
### GitHelper
`GitHelper` methods are run in the current `git` repo and give the information about last commit hash and commit message:
```python
from .git_helper import GitHelper
print("Git hash:", GitHelper.commit_hash())
print("Git message:", GitHelper.commit_message())
```
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.
### Tagger
`Tagger` is a class, which can be run inside docker container to calculate some tag for an image.
All the taggers are inherited from `TaggerInterface`:
```python
class TaggerInterface:
"""Common interface for all taggers"""
@staticmethod
def tag_value(container) -> str:
raise NotImplementedError
```
So, `tag_value(container)` method gets a docker container as an input and returns some tag.
`SHATagger` example:
```python
class SHATagger(TaggerInterface):
@staticmethod
def tag_value(container):
return GitHelper.commit_hash_tag()
```
- `taggers.py` contains all the taggers.
- `tag_image.py` is a python executable which is used to tag the image.
### Manifest
`ManifestHeader` is a build manifest header.
It contains information about `Build datetime`, `Docker image size` and `Git commit` info.
All the other manifest classes are inherited from `ManifestInterface`:
```python
class ManifestInterface:
"""Common interface for all manifests"""
@staticmethod
def markdown_piece(container) -> str:
raise NotImplementedError
```
- `markdown_piece(container)` method returns piece of markdown file to be used as a part of build manifest.
`AptPackagesManifest` example:
```python
class AptPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container) -> str:
return "\n".join([
"## Apt Packages",
"",
quoted_output(container, "apt list --installed")
])
```
- `quoted_output` simply runs the command inside container using `DockerRunner.run_simple_command` and wraps it to triple quotes to create a valid markdown piece of file.
- `manifests.py` contains all the manifests.
- `create_manifests.py` is a python executable which is used to create the build manifest for an image.
### Images Hierarchy
All images dependencies on each other and what taggers and manifest they make use of is defined in `images_hierarchy.py`.
`get_taggers_and_manifests.py` defines a helper function to get the taggers and manifests for a specific image.