Skip to content

Commit

Permalink
Publish Image - Omit Tags (#221)
Browse files Browse the repository at this point in the history
* pull wheel are install as file

* unit tests

* update docs

* something is wrong with pipenv and CircleCI...

* simplify the dep string

* woops

* in order to support deployment process

* bump minor

* unit tests and WARN message

* docs update

* Update docs/publishing.md

Co-authored-by: Joao Moreira <[email protected]>

Co-authored-by: Joao Moreira <[email protected]>
  • Loading branch information
sshookman and jagmoreira authored May 4, 2022
1 parent de003a9 commit 3f0594c
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 21 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ Documenting All Changes to the Skelebot Project

---

## v1.30.0
#### Changed
- **Docker Publish** | Docker Publish allows for omitting version and LATEST tags

---

## v1.29.0
#### Merged: 2022-05-02
#### Released: 2022-05-02
#### Changed
- **CodeArtifact Dependencies** | Adds an option to pull CodeArtifact Python packages into a libs folder for install during docker build

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.29.0
1.30.0
14 changes: 10 additions & 4 deletions docs/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,23 @@ The values that are provided will be structured in the name of the docker image
When published the current version of the project will be used as a tag as well as 'latest'.

```
skelebot publish
usage: skelebot publish [-h] [-t [TAGS [TAGS ...]]] [-v] [-l]
optional arguments:
-h, --help show this help message and exit
-t [TAGS [TAGS ...]], --tags [TAGS [TAGS ...]]
Additional image tags
-v, --omit-version Do not publish the version as a tag
-l, --omit-latest Do not publish the 'LATEST' tag
```

If not logged-in to the provided host in the registry, you will be prompted to enter your username and password.

If you would like to make use of any custom tags when publishing the image, the tags parameter
(`-t --tags`) can be used to specify a list of tag values.

```
skelebot publish --tags LOCAL DEV STAGE
```
By default, the `LATEST` tag and a version tag will be published along with any additional tags that are specified.
Each of these may be omitted by providing the corresponding flags: `--omit-version (-v)` and `--omit-latest (-l)`

### AWS ECR
Skelebot supports publishing to AWS ECR as long as you have the proper credentials setup in `~/.aws/` as well as the [aws cli](https://aws.amazon.com/cli/) installed.
Expand Down
5 changes: 4 additions & 1 deletion skelebot/components/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def addParsers(self, subparsers):
helpMessage = "Publish your versioned Docker Image to the registry"
registryParser = subparsers.add_parser("publish", help=helpMessage)
registryParser.add_argument("-t", "--tags", nargs='*', help="Additional image tags")
registryParser.add_argument("-v", "--omit-version", action="store_true", help="Do not publish the version as a tag")
registryParser.add_argument("-l", "--omit-latest", action="store_true", help="Do not publish the 'latest' tag")

return subparsers

Expand All @@ -102,5 +104,6 @@ def execute(self, config, args, host=None):

docker.push(
config, self.host, self.port, self.user, tags=args.tags,
docker_host=host, verbose=args.verbose_global
docker_host=host, verbose=args.verbose_global, omit_latest=args.omit_latest,
omit_version=args.omit_version
)
13 changes: 10 additions & 3 deletions skelebot/systems/execution/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .dockerCommand import DockerCommandBuilder
from ...systems.generators import dockerfile
from ...systems.generators import dockerignore
from ...common import INFO
from ...common import INFO, WARN_HEADER

AWS_LOGIN_CMD = "$(aws ecr get-login --no-include-email --region {region} --profile {profile})"
AWS_LOGIN_CMD_V2 = "aws ecr get-login-password --region {region} --profile {profile} | docker{docker_host} login --username AWS --password-stdin {host}"
Expand Down Expand Up @@ -119,7 +119,7 @@ def save(config, filename="image.img", host=None, verbose=False):
cmd = DockerCommandBuilder(host=host).save(config.getImageName()).set_output(filename).build()
return execute(cmd, verbose=verbose)

def push(config, host=None, port=None, user=None, tags=None, docker_host=None, verbose=False):
def push(config, host=None, port=None, user=None, tags=None, docker_host=None, verbose=False, omit_latest=False, omit_version=False):
"""Tag with version and latest and push the project Image to the provided Docker Image Host"""

imageName = config.getImageName()
Expand All @@ -129,9 +129,16 @@ def push(config, host=None, port=None, user=None, tags=None, docker_host=None, v
image = "{host}{user}{name}".format(host=host, user=user, name=imageName)

tags = [] if tags is None else tags
tags = tags + [config.version, "latest"]
if (omit_version == False):
tags = tags + [config.version]
if (omit_latest == False):
tags = tags + ["latest"]

status = 0

if (len(tags) == 0):
print(WARN_HEADER + "No Tags to Publish")

for tag in tags:
status = execute(
DockerCommandBuilder(host=docker_host).tag(imageName, image, tag),
Expand Down
72 changes: 60 additions & 12 deletions test/test_components_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,54 +33,97 @@ def test_execute(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False)
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False,
omit_version=False, omit_latest=False)

registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot")
registry.execute(config, args)

mock_docker.login.assert_called_with(host="docker.io", docker_host=None, verbose=False)
mock_docker.build.assert_called_with(config, host=None, verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False,
omit_latest=False, omit_version=False
)

@mock.patch('skelebot.components.registry.docker')
def test_execute_omit_latest(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False,
omit_version=False, omit_latest=True)

registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot")
registry.execute(config, args)

mock_docker.login.assert_called_with(host="docker.io", docker_host=None, verbose=False)
mock_docker.build.assert_called_with(config, host=None, verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False,
omit_latest=True, omit_version=False
)

@mock.patch('skelebot.components.registry.docker')
def test_execute_omit_version(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False,
omit_version=True, omit_latest=False)

registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot")
registry.execute(config, args)

mock_docker.login.assert_called_with(host="docker.io", docker_host=None, verbose=False)
mock_docker.build.assert_called_with(config, host=None, verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False,
omit_latest=False, omit_version=True
)

@mock.patch('skelebot.components.registry.docker')
def test_execute_skip_build(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=None, skip_build_global=True, verbose_global=False)
args = argparse.Namespace(tags=None, skip_build_global=True, verbose_global=False,
omit_version=False, omit_latest=False)

registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot")
registry.execute(config, args)

mock_docker.login.assert_called_with(host="docker.io", docker_host=None, verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False,
omit_latest=False, omit_version=False
)

@mock.patch('skelebot.components.registry.docker')
def test_execute_host(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False)
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False,
omit_version=False, omit_latest=False)

registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot")
registry.execute(config, args, host="host1")

mock_docker.login.assert_called_with(host="docker.io", docker_host="host1", verbose=False)
mock_docker.build.assert_called_with(config, host="host1", verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=None, docker_host="host1", verbose=False
config, "docker.io", 88, "skelebot", tags=None, docker_host="host1", verbose=False,
omit_latest=False, omit_version=False
)

@mock.patch('skelebot.components.registry.docker')
def test_execute_aws(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False)
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False,
omit_version=False, omit_latest=False)

aws = sb.components.registry.Aws(region="us-east-1", profile="dev")
registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot", aws=aws)
Expand All @@ -91,15 +134,17 @@ def test_execute_aws(self, mock_docker):
)
mock_docker.build.assert_called_with(config, host=None, verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False
config, "docker.io", 88, "skelebot", tags=None, docker_host=None, verbose=False,
omit_latest=False, omit_version=False
)

@mock.patch('skelebot.components.registry.docker')
def test_execute_aws_host(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False)
args = argparse.Namespace(tags=None, skip_build_global=False, verbose_global=False,
omit_version=False, omit_latest=False)

aws = sb.components.registry.Aws(region="us-east-1", profile="dev")
registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot", aws=aws)
Expand All @@ -110,15 +155,17 @@ def test_execute_aws_host(self, mock_docker):
)
mock_docker.build.assert_called_with(config, host="host1", verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=None, docker_host="host1", verbose=False
config, "docker.io", 88, "skelebot", tags=None, docker_host="host1", verbose=False,
omit_latest=False, omit_version=False
)

@mock.patch('skelebot.components.registry.docker')
def test_execute_tags(self, mock_docker):
mock_docker.build.return_value = 0

config = sb.objects.config.Config(language="R")
args = argparse.Namespace(tags=["test", "dev", "stage"], skip_build_global=False, verbose_global=False)
args = argparse.Namespace(tags=["test", "dev", "stage"], skip_build_global=False, verbose_global=False,
omit_version=False, omit_latest=False)

registry = sb.components.registry.Registry(host="docker.io", port=88, user="skelebot")
registry.execute(config, args)
Expand All @@ -127,7 +174,8 @@ def test_execute_tags(self, mock_docker):
mock_docker.build.assert_called_with(config, host=None, verbose=False)
mock_docker.push.assert_called_with(
config, "docker.io", 88, "skelebot", tags=['test', 'dev', 'stage'],
docker_host=None, verbose=False
docker_host=None, verbose=False,
omit_latest=False, omit_version=False
)

def test_validate_valid(self):
Expand Down
57 changes: 57 additions & 0 deletions test/test_systems_execution_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,63 @@ def test_push(self, mock_getcwd, mock_call, mock_expanduser):
mock_call.assert_any_call("docker push docker.io:8888/skelebot/test:6.6.6", shell=True)
mock_call.assert_any_call("docker push docker.io:8888/skelebot/test:latest", shell=True)

@mock.patch('os.path.expanduser')
@mock.patch('skelebot.systems.execution.docker.call')
@mock.patch('os.getcwd')
def test_push_omit_version(self, mock_getcwd, mock_call, mock_expanduser):
host = "docker.io"
port = 8888
user = "skelebot"
folderPath = "{path}/test/files".format(path=self.path)

mock_expanduser.return_value = "{path}/test/plugins".format(path=self.path)
mock_getcwd.return_value = folderPath
mock_call.return_value = 0

config = sb.systems.generators.yaml.loadConfig()
sb.systems.execution.docker.push(config, host, port, user, omit_version=True)

mock_call.assert_any_call("docker tag test docker.io:8888/skelebot/test:latest", shell=True)
mock_call.assert_any_call("docker push docker.io:8888/skelebot/test:latest", shell=True)

@mock.patch('os.path.expanduser')
@mock.patch('skelebot.systems.execution.docker.call')
@mock.patch('os.getcwd')
def test_push_omit_latest(self, mock_getcwd, mock_call, mock_expanduser):
host = "docker.io"
port = 8888
user = "skelebot"
folderPath = "{path}/test/files".format(path=self.path)

mock_expanduser.return_value = "{path}/test/plugins".format(path=self.path)
mock_getcwd.return_value = folderPath
mock_call.return_value = 0

config = sb.systems.generators.yaml.loadConfig()
sb.systems.execution.docker.push(config, host, port, user, omit_latest=True)

mock_call.assert_any_call("docker tag test docker.io:8888/skelebot/test:6.6.6", shell=True)
mock_call.assert_any_call("docker push docker.io:8888/skelebot/test:6.6.6", shell=True)

@mock.patch('skelebot.systems.execution.docker.print')
@mock.patch('os.path.expanduser')
@mock.patch('skelebot.systems.execution.docker.call')
@mock.patch('os.getcwd')
def test_push_omit_both(self, mock_getcwd, mock_call, mock_expanduser, mock_print):
host = "docker.io"
port = 8888
user = "skelebot"
folderPath = "{path}/test/files".format(path=self.path)

mock_expanduser.return_value = "{path}/test/plugins".format(path=self.path)
mock_getcwd.return_value = folderPath
mock_call.return_value = 0

config = sb.systems.generators.yaml.loadConfig()
sb.systems.execution.docker.push(config, host, port, user, omit_version=True, omit_latest=True)

mock_print.assert_called_with("\x1b[33mWARN\x1b[0m | No Tags to Publish")

@mock.patch('os.path.expanduser')
@mock.patch('skelebot.systems.execution.docker.call')
@mock.patch('os.getcwd')
Expand Down

0 comments on commit 3f0594c

Please sign in to comment.