generated from MITLibraries/python-cli-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from MITLibraries/TIMX-340-build-ab-images
TIMX-340-build-ab-images
- Loading branch information
Showing
6 changed files
with
520 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,97 @@ | ||
"""abdiff.core.build_ab_images""" | ||
import logging | ||
import tempfile | ||
|
||
import docker | ||
import docker.models | ||
import docker.models.images | ||
from pygit2 import clone_repository | ||
from pygit2.enums import ResetMode | ||
|
||
from abdiff.core.utils import update_or_create_job_json | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def build_ab_images( | ||
job_directory: str, | ||
commit_sha_a: str, | ||
commit_sha_b: str, | ||
docker_client: docker.client.DockerClient | None = None, | ||
) -> tuple[str, str]: | ||
"""Build Docker images based on 2 commit SHAs. | ||
Args: | ||
job_directory: The directory containing all files related to a job. | ||
commit_sha_a: The SHA of the first commit for comparison. | ||
commit_sha_b: The SHA of the second commit for comparison. | ||
docker_client: A configured Docker client. | ||
""" | ||
if not docker_client: | ||
docker_client = docker.from_env() | ||
|
||
image_tags = [] | ||
for commit_sha in [commit_sha_a, commit_sha_b]: | ||
logger.debug(f"Processing commit: {commit_sha}") | ||
image_tag = f"transmogrifier-{job_directory.split("/")[-1]}-{commit_sha}:latest" | ||
if docker_image_exists(docker_client, image_tag): | ||
logger.debug(f"Docker image already exists with tag: {image_tag}") | ||
image_tags.append(image_tag) | ||
else: | ||
image = build_image(job_directory, commit_sha, docker_client) | ||
image_tags.append(image.tags[0]) | ||
logger.debug(f"Finished processing commit: {commit_sha}") | ||
|
||
images_data = {"image_tag_a": image_tags[0], "image_tag_b": image_tags[1]} | ||
update_or_create_job_json(job_directory, images_data) | ||
return (image_tags[0], image_tags[1]) | ||
|
||
|
||
def docker_image_exists( | ||
docker_client: docker.client.DockerClient, image_tag: str | ||
) -> bool: | ||
"""Check if Docker image already exists with a certain name. | ||
Args: | ||
docker_client: A configured Docker client. | ||
image_tag: The tag of the Docker image to be created. | ||
""" | ||
return image_tag in [ | ||
image_tag for image in docker_client.images.list() for image_tag in image.tags | ||
] | ||
|
||
|
||
def build_image( | ||
job_directory: str, | ||
commit_sha: str, | ||
docker_client: docker.client.DockerClient, | ||
) -> docker.models.images.Image: | ||
"""Clone repo and build Docker image. | ||
Args: | ||
job_directory: The directory containing all files related to a job. | ||
commit_sha: The SHA of the commit. | ||
docker_client: A configured Docker client. | ||
""" | ||
with tempfile.TemporaryDirectory() as clone_directory: | ||
image_tag = f"transmogrifier-{job_directory.split("/")[-1]}-{commit_sha}" | ||
clone_repo_and_reset_to_commit(clone_directory, commit_sha) | ||
image, _ = docker_client.images.build(path=clone_directory, tag=image_tag) | ||
logger.debug(f"Docker image created with tag: {image}") | ||
return image | ||
|
||
|
||
def clone_repo_and_reset_to_commit(clone_directory: str, commit_sha: str) -> None: | ||
"""Clone GitHub repo and reset to a specified commit. | ||
Args: | ||
clone_directory: The directory for the cloned repo. | ||
commit_sha: The SHA of a repo commit. | ||
""" | ||
logger.debug(f"Cloning repo to: {clone_directory}") | ||
repository = clone_repository( | ||
"https://github.com/MITLibraries/transmogrifier.git", | ||
clone_directory, | ||
) | ||
logger.debug(f"Cloned repo to: {clone_directory}") | ||
repository.reset(commit_sha, ResetMode.HARD) | ||
logger.debug(f"Cloned repo reset to commit: {commit_sha}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import os | ||
from unittest.mock import patch | ||
|
||
from abdiff.core.build_ab_images import ( | ||
build_ab_images, | ||
build_image, | ||
clone_repo_and_reset_to_commit, | ||
docker_image_exists, | ||
) | ||
from abdiff.core.utils import read_job_json | ||
|
||
|
||
@patch("abdiff.core.build_ab_images.clone_repository") | ||
def test_build_ab_images_success(mocked_clone, job_directory, mocked_docker_client): | ||
side_effect = os.makedirs(job_directory + "/clone") | ||
mocked_clone.side_effect = side_effect | ||
|
||
images = build_ab_images( | ||
job_directory, | ||
"abc123", | ||
"def456", | ||
mocked_docker_client, | ||
) | ||
assert images[0] == "transmogrifier-example-job-1-abc123:latest" | ||
assert images[1] == "transmogrifier-example-job-1-def456:latest" | ||
assert read_job_json(job_directory) == { | ||
"image_tag_a": "transmogrifier-example-job-1-abc123:latest", | ||
"image_tag_b": "transmogrifier-example-job-1-def456:latest", | ||
} | ||
|
||
|
||
def test_docker_image_exists_returns_true(mocked_docker_client): | ||
assert ( | ||
docker_image_exists( | ||
mocked_docker_client, "transmogrifier-example-job-1-def456:latest" | ||
) | ||
is True | ||
) | ||
|
||
|
||
def test_docker_image_exists_returns_false(mocked_docker_client): | ||
assert ( | ||
docker_image_exists( | ||
mocked_docker_client, "transmogrifier-example-job-1-abc123:latest" | ||
) | ||
is False | ||
) | ||
|
||
|
||
@patch("abdiff.core.build_ab_images.clone_repository") | ||
def test_build_image_success(mocked_clone, job_directory, mocked_docker_client): | ||
image = build_image( | ||
job_directory, | ||
"abc123", | ||
mocked_docker_client, | ||
) | ||
assert image.tags[0] == "transmogrifier-example-job-1-abc123:latest" | ||
|
||
|
||
@patch("abdiff.core.build_ab_images.clone_repository") | ||
def test_clone_repo_and_reset_to_commit_success(mocked_clone, job_directory): | ||
clone_directory = job_directory + "/clone" | ||
assert not os.path.exists(clone_directory) | ||
side_effect = os.makedirs(clone_directory) | ||
mocked_clone.side_effect = side_effect | ||
|
||
clone_repo_and_reset_to_commit(clone_directory, "abc123") | ||
assert os.path.exists(clone_directory) |