generated from MITLibraries/python-cli-template
-
Notifications
You must be signed in to change notification settings - Fork 0
TIMX 345 - Add CLI command init-job #13
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
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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,27 +1,120 @@ | ||
| import json | ||
| import logging | ||
| from collections.abc import Callable | ||
| from datetime import timedelta | ||
| from time import perf_counter | ||
|
|
||
| import click | ||
| from click.exceptions import ClickException | ||
|
|
||
| from abdiff.config import configure_logger | ||
| from abdiff.core import build_ab_images | ||
| from abdiff.core import init_job as core_init_job | ||
| from abdiff.core.utils import read_job_json | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @click.command() | ||
| @click.group(context_settings={"help_option_names": ["-h", "--help"]}) | ||
| @click.option( | ||
| "-v", "--verbose", is_flag=True, help="Pass to log at debug level instead of info" | ||
| "-v", | ||
| "--verbose", | ||
| is_flag=True, | ||
| help="Pass to log at debug level instead of info.", | ||
| ) | ||
| def main(*, verbose: bool) -> None: | ||
| start_time = perf_counter() | ||
| @click.pass_context | ||
| def main( | ||
| ctx: click.Context, | ||
| verbose: bool, # noqa: FBT001 | ||
| ) -> None: | ||
| ctx.ensure_object(dict) | ||
| ctx.obj["START_TIME"] = perf_counter() | ||
| root_logger = logging.getLogger() | ||
| logger.info(configure_logger(root_logger, verbose=verbose)) | ||
| logger.info("Running process") | ||
|
|
||
| # Do things here! | ||
|
|
||
| elapsed_time = perf_counter() - start_time | ||
| @main.result_callback() | ||
| @click.pass_context | ||
| def post_main_group_subcommand( | ||
| ctx: click.Context, | ||
| *_args: tuple, | ||
| **_kwargs: dict, | ||
| ) -> None: | ||
| """Callback for any work to perform after a main sub-command completes.""" | ||
| logger.info( | ||
| "Total time to complete process: %s", str(timedelta(seconds=elapsed_time)) | ||
| "Total elapsed: %s", | ||
| str( | ||
| timedelta(seconds=perf_counter() - ctx.obj["START_TIME"]), | ||
| ), | ||
| ) | ||
|
|
||
|
|
||
| @main.command() | ||
| def ping() -> None: | ||
| """Debug ping/pong command.""" | ||
| logger.debug("got ping, preparing to pong") | ||
| click.echo("pong") | ||
ghukill marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| def shared_job_options(cli_command: Callable) -> Callable: | ||
| """Decorator to provide shared CLI arguments to Job related commands.""" | ||
| cli_command = click.option( | ||
| "-d", | ||
| "--job-directory", | ||
| type=str, | ||
| required=True, | ||
| help="Job working directory to create.", | ||
| )(cli_command) | ||
|
|
||
| cli_command = click.option( | ||
| "-m", | ||
| "--message", | ||
| type=str, | ||
| required=False, | ||
| help="Message to describe Job.", | ||
| default="Not provided.", | ||
| )(cli_command) | ||
|
|
||
| return cli_command # noqa: RET504 | ||
|
|
||
|
|
||
| @main.command() | ||
| @shared_job_options | ||
| @click.option( | ||
| "-a", | ||
| "--commit-sha-a", | ||
| type=str, | ||
| required=True, | ||
| help="Transmogrifier commit SHA for version 'A'", | ||
| ) | ||
| @click.option( | ||
| "-b", | ||
| "--commit-sha-b", | ||
| type=str, | ||
| required=True, | ||
| help="Transmogrifier commit SHA for version 'B'", | ||
| ) | ||
| def init_job( | ||
| job_directory: str, | ||
| commit_sha_a: str, | ||
| commit_sha_b: str, | ||
| message: str, | ||
| ) -> None: | ||
| """Initialize a new Job.""" | ||
| try: | ||
| core_init_job(job_directory, message) | ||
| except FileExistsError as exc: | ||
| message = ( | ||
| f"Job directory already exists: '{job_directory}', cannot create new job." | ||
| ) | ||
| raise ClickException(message) from exc | ||
|
|
||
| build_ab_images( | ||
| job_directory, | ||
| commit_sha_a, | ||
| commit_sha_b, | ||
| ) | ||
|
|
||
| job_json = json.dumps(read_job_json(job_directory), indent=2) | ||
| logger.info(f"Job initialized: {job_json}") | ||
This file contains hidden or 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,17 +1,82 @@ | ||
| import os | ||
| from unittest.mock import patch | ||
|
|
||
| from abdiff.cli import main | ||
| from abdiff.core.utils import read_job_json | ||
|
|
||
|
|
||
| def test_cli_no_options(caplog, runner): | ||
| result = runner.invoke(main) | ||
| def test_cli_default_log_level_info(caplog, runner): | ||
| result = runner.invoke(main, ["ping"]) | ||
| assert result.exit_code == 0 | ||
| assert "Logger 'root' configured with level=INFO" in caplog.text | ||
| assert "Running process" in caplog.text | ||
| assert "Total time to complete process" in caplog.text | ||
| assert "pong" in result.output | ||
|
|
||
|
|
||
| def test_cli_all_options(caplog, runner): | ||
| result = runner.invoke(main, ["--verbose"]) | ||
| def test_cli_verbose_sets_debug_log_level(caplog, runner): | ||
| caplog.set_level("DEBUG") | ||
| result = runner.invoke(main, ["--verbose", "ping"]) | ||
| assert result.exit_code == 0 | ||
| assert "Logger 'root' configured with level=DEBUG" in caplog.text | ||
| assert "Running process" in caplog.text | ||
| assert "Total time to complete process" in caplog.text | ||
| assert "got ping, preparing to pong" in caplog.text | ||
|
|
||
|
|
||
| def test_cli_main_group_callback_called(caplog, runner): | ||
| result = runner.invoke(main, ["--verbose", "ping"]) | ||
| assert result.exit_code == 0 | ||
| assert "Total elapsed" in caplog.text | ||
|
|
||
|
|
||
| @patch("abdiff.core.build_ab_images.docker_image_exists") | ||
| def test_init_job_all_arguments_success( | ||
| mocked_image_exists, | ||
| caplog, | ||
| runner, | ||
| job_directory, | ||
| ): | ||
| mocked_image_exists.return_value = True | ||
| caplog.set_level("DEBUG") | ||
|
|
||
| message = "This is a Super Job." | ||
| _result = runner.invoke( | ||
| main, | ||
| [ | ||
| "--verbose", | ||
| "init-job", | ||
| f"--job-directory={job_directory}", | ||
| f"--message={message}", | ||
| "--commit-sha-a=abc123", | ||
| "--commit-sha-b=def456", | ||
| ], | ||
| ) | ||
|
|
||
| assert os.path.exists(job_directory) | ||
|
|
||
| job_data = read_job_json(job_directory) | ||
| assert job_data == { | ||
| "job_directory": job_directory, | ||
| "job_message": message, | ||
| "image_tag_a": "transmogrifier-example-job-1-abc123:latest", | ||
| "image_tag_b": "transmogrifier-example-job-1-def456:latest", | ||
| } | ||
|
|
||
|
|
||
| def test_init_job_pre_existing_job_directory_raise_error( | ||
| caplog, | ||
| runner, | ||
| job_directory, | ||
| ): | ||
| caplog.set_level("DEBUG") | ||
| os.makedirs(job_directory) | ||
| result = runner.invoke( | ||
| main, | ||
| [ | ||
| "--verbose", | ||
| "init-job", | ||
| f"--job-directory={job_directory}", | ||
| "--message=This is a Super Job.", | ||
| "--commit-sha-a=abc123", | ||
| "--commit-sha-b=def456", | ||
| ], | ||
| ) | ||
| assert result.exit_code == 1 | ||
| assert "Job directory already exists" in result.output |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.