Skip to content

Commit

Permalink
Re-adding optional project parameter to artifacts universal commands …
Browse files Browse the repository at this point in the history
…+ unit tests (#862)

* Adding project parameter to UPack commands

* Fix styling issue

* Adding scope parameter

* Pylint corrections

* Fixing previously missed Pylint issues

* Reverting unintentional change to vscode settings file and small fix in error message

* add TestUniversalPackages.*_with_project tests

* TestUniversalPackages two more unit tests
  • Loading branch information
Peter Spillman authored and atbagga committed Nov 4, 2019
1 parent a98f526 commit fc1d5cd
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 25 deletions.
7 changes: 7 additions & 0 deletions azure-devops/azext_devops/dev/artifacts/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@
# --------------------------------------------------------------------------------------------


from knack.arguments import enum_choice_list


_SCOPE_VALUES = ['project', 'organization']


def load_package_arguments(self, _):
with self.argument_context('artifacts universal') as context:
context.argument('name', options_list=('--name', '-n'))
context.argument('version', options_list=('--version', '-v'))
context.argument('scope', **enum_choice_list(_SCOPE_VALUES))
with self.argument_context('artifacts universal publish') as context:
context.argument('description', options_list=('--description', '-d'))
61 changes: 54 additions & 7 deletions azure-devops/azext_devops/dev/artifacts/universal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,27 @@

import colorama
from knack.log import get_logger
from azext_devops.dev.common.services import resolve_instance
from knack.util import CLIError
from azext_devops.dev.common.services import resolve_instance, resolve_instance_and_project
from azext_devops.dev.common.artifacttool import ArtifactToolInvoker
from azext_devops.dev.common.artifacttool_updater import ArtifactToolUpdater
from azext_devops.dev.common.external_tool import ProgressReportingExternalToolInvoker

logger = get_logger(__name__)


def publish_package(feed, name, version, path, description=None, organization=None, detect=None):
def publish_package(feed,
name,
version,
path,
description=None,
scope='organization',
organization=None,
project=None,
detect=None):
"""Publish a package to a feed.
:param scope: Scope of the feed: 'project' if the feed was created in a project, and 'organization' otherwise.
:type scope: str
:param feed: Name or ID of the feed.
:type feed: str
:param name: Name of the package, e.g. 'foo-package'.
Expand All @@ -27,13 +38,36 @@ def publish_package(feed, name, version, path, description=None, organization=No
:type path: str
"""
colorama.init() # Needed for humanfriendly spinner to display correctly
organization = resolve_instance(detect=detect, organization=organization)

if scope == 'project':
organization, project = resolve_instance_and_project(
detect=detect,
organization=organization,
project=project)
else:
if project is not None:
raise CLIError('--scope \'project\' is required when specifying a value in --project')

organization = resolve_instance(
detect=detect,
organization=organization)

artifact_tool = ArtifactToolInvoker(ProgressReportingExternalToolInvoker(), ArtifactToolUpdater())
return artifact_tool.publish_universal(organization, feed, name, version, description, path)
return artifact_tool.publish_universal(organization, project, feed, name, version, description, path)


def download_package(feed, name, version, path, file_filter=None, organization=None, detect=None):
def download_package(feed,
name,
version,
path,
file_filter=None,
scope='organization',
organization=None,
project=None,
detect=None):
"""Download a package.
:param scope: Scope of the feed: 'project' if the feed was created in a project, and 'organization' otherwise.
:type scope: str
:param feed: Name or ID of the feed.
:type feed: str
:param name: Name of the package, e.g. 'foo-package'.
Expand All @@ -46,6 +80,19 @@ def download_package(feed, name, version, path, file_filter=None, organization=N
:type file_filter: str
"""
colorama.init() # Needed for humanfriendly spinner to display correctly
organization = resolve_instance(detect=detect, organization=organization)

if scope == 'project':
organization, project = resolve_instance_and_project(
detect=detect,
organization=organization,
project=project)
else:
if project is not None:
raise CLIError('--scope \'project\' is required when specifying a value in --project')

organization = resolve_instance(
detect=detect,
organization=organization)

artifact_tool = ArtifactToolInvoker(ProgressReportingExternalToolInvoker(), ArtifactToolUpdater())
return artifact_tool.download_universal(organization, feed, name, version, path, file_filter)
return artifact_tool.download_universal(organization, project, feed, name, version, path, file_filter)
11 changes: 9 additions & 2 deletions azure-devops/azext_devops/dev/common/artifacttool.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,25 @@ def upload_pipeline_artifact(self, organization, project, run_id, artifact_name,
"--project", project, "--pipeline-id", run_id, "--artifact-name", artifact_name, "--path", path]
return self.run_artifacttool(organization, args, "Uploading")

def download_universal(self, organization, feed, package_name, package_version, path, file_filter):
def download_universal(self, organization, project, feed, package_name, package_version, path, file_filter):
args = ["universal", "download", "--service", organization, "--patvar", ARTIFACTTOOL_PAT_ENVKEY,
"--feed", feed, "--package-name", package_name, "--package-version", package_version,
"--path", path]

if project:
args.extend(["--project", project])

if file_filter:
args.extend(["--filter", file_filter])
return self.run_artifacttool(organization, args, "Downloading")

def publish_universal(self, organization, feed, package_name, package_version, description, path):
def publish_universal(self, organization, project, feed, package_name, package_version, description, path):
args = ["universal", "publish", "--service", organization, "--patvar", ARTIFACTTOOL_PAT_ENVKEY,
"--feed", feed, "--package-name", package_name, "--package-version", package_version, "--path", path]

if project:
args.extend(["--project", project])

if description:
args.extend(["--description", description])
return self.run_artifacttool(organization, args, "Publishing")
Expand Down
108 changes: 92 additions & 16 deletions azure-devops/azext_devops/test/artifacts/test_univeral.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
from azext_devops.dev.common.artifacttool import ArtifactToolInvoker
from azext_devops.dev.common.const import ARTIFACTTOOL_PAT_ENVKEY
from azext_devops.dev.common.services import clear_connection_cache
from knack.util import CLIError



class TestUniversalPackages(unittest.TestCase):

_CONST_ORGANIZATION_SCOPE = 'organization'
_CONST_PROJECT_SCOPE = 'project'
_TEST_DEVOPS_ORGANIZATION = 'https://someorg.visualstudio.com'
_TEST_DEVOPS_PROJECT = 'my-test-project'
_TEST_PAT_TOKEN = 'somepattoken'
_TEST_FEED_NAME = 'my-test-feed'
_TEST_PACKAGE_NAME = 'my-test-package'
Expand Down Expand Up @@ -57,16 +61,52 @@ def test_publish_package(self):
# assert
self.mock_run_artifacttool.assert_called_with(self._TEST_DEVOPS_ORGANIZATION,
[
'universal', 'publish',
'--service', self._TEST_DEVOPS_ORGANIZATION,
'--patvar', ARTIFACTTOOL_PAT_ENVKEY,
'--feed', self._TEST_FEED_NAME,
'--package-name', self._TEST_PACKAGE_NAME,
'--package-version', self._TEST_PACKAGE_VERSION,
'--path', self._TEST_PATH,
'universal', 'publish',
'--service', self._TEST_DEVOPS_ORGANIZATION,
'--patvar', ARTIFACTTOOL_PAT_ENVKEY,
'--feed', self._TEST_FEED_NAME,
'--package-name', self._TEST_PACKAGE_NAME,
'--package-version', self._TEST_PACKAGE_VERSION,
'--path', self._TEST_PATH,
'--description', self._TEST_PACKAGE_DESCRIPTION
],
],
'Publishing')

def test_publish_package_with_project(self):
response = publish_package(feed = self._TEST_FEED_NAME,
name = self._TEST_PACKAGE_NAME,
version = self._TEST_PACKAGE_VERSION,
description = self._TEST_PACKAGE_DESCRIPTION,
path = self._TEST_PATH,
organization = self._TEST_DEVOPS_ORGANIZATION,
project = self._TEST_DEVOPS_PROJECT,
scope = self._CONST_PROJECT_SCOPE)

# assert
self.mock_run_artifacttool.assert_called_with(self._TEST_DEVOPS_ORGANIZATION,
[
'universal', 'publish',
'--service', self._TEST_DEVOPS_ORGANIZATION,
'--patvar', ARTIFACTTOOL_PAT_ENVKEY,
'--feed', self._TEST_FEED_NAME,
'--package-name', self._TEST_PACKAGE_NAME,
'--package-version', self._TEST_PACKAGE_VERSION,
'--path', self._TEST_PATH,
'--project', self._TEST_DEVOPS_PROJECT,
'--description', self._TEST_PACKAGE_DESCRIPTION,
],
'Publishing')

def test_publish_package_when_project_without_scope_then_exception(self):
with self.assertRaises(CLIError) as exc:
response = publish_package(feed = self._TEST_FEED_NAME,
name = self._TEST_PACKAGE_NAME,
version = self._TEST_PACKAGE_VERSION,
description = self._TEST_PACKAGE_DESCRIPTION,
path = self._TEST_PATH,
organization = self._TEST_DEVOPS_ORGANIZATION,
project = self._TEST_DEVOPS_PROJECT)
self.assertIn('--scope \'project\' is required when specifying a value in --project', str(exc.exception))

def test_download_package(self):
response = download_package(feed = self._TEST_FEED_NAME,
Expand All @@ -79,14 +119,50 @@ def test_download_package(self):
# assert
self.mock_run_artifacttool.assert_called_with(self._TEST_DEVOPS_ORGANIZATION,
[
'universal', 'download',
'--service', self._TEST_DEVOPS_ORGANIZATION,
'--patvar', ARTIFACTTOOL_PAT_ENVKEY,
'--feed', self._TEST_FEED_NAME,
'--package-name', self._TEST_PACKAGE_NAME,
'--package-version', self._TEST_PACKAGE_VERSION,
'--path', self._TEST_PATH,
'universal', 'download',
'--service', self._TEST_DEVOPS_ORGANIZATION,
'--patvar', ARTIFACTTOOL_PAT_ENVKEY,
'--feed', self._TEST_FEED_NAME,
'--package-name', self._TEST_PACKAGE_NAME,
'--package-version', self._TEST_PACKAGE_VERSION,
'--path', self._TEST_PATH,
'--filter', self._TEST_FILTER,
],
],
'Downloading')

def test_download_package_with_project(self):
response = download_package(feed = self._TEST_FEED_NAME,
name = self._TEST_PACKAGE_NAME,
version = self._TEST_PACKAGE_VERSION,
path = self._TEST_PATH,
file_filter= self._TEST_FILTER,
organization = self._TEST_DEVOPS_ORGANIZATION,
project = self._TEST_DEVOPS_PROJECT,
scope = self._CONST_PROJECT_SCOPE)

# assert
self.mock_run_artifacttool.assert_called_with(self._TEST_DEVOPS_ORGANIZATION,
[
'universal', 'download',
'--service', self._TEST_DEVOPS_ORGANIZATION,
'--patvar', ARTIFACTTOOL_PAT_ENVKEY,
'--feed', self._TEST_FEED_NAME,
'--package-name', self._TEST_PACKAGE_NAME,
'--package-version', self._TEST_PACKAGE_VERSION,
'--path', self._TEST_PATH,
'--project', self._TEST_DEVOPS_PROJECT,
'--filter', self._TEST_FILTER,
],
'Downloading')

def test_download_package_when_project_without_scope_then_exception(self):
with self.assertRaises(CLIError) as exc:
response = download_package(feed = self._TEST_FEED_NAME,
name = self._TEST_PACKAGE_NAME,
version = self._TEST_PACKAGE_VERSION,
path = self._TEST_PATH,
file_filter= self._TEST_FILTER,
organization = self._TEST_DEVOPS_ORGANIZATION,
project = self._TEST_DEVOPS_PROJECT)
self.assertIn('--scope \'project\' is required when specifying a value in --project', str(exc.exception))

0 comments on commit fc1d5cd

Please sign in to comment.