Refactor Deploy Nexus Zip command to Python 86/13286/7
authorBengt Thuree <bthuree@linuxfoundation.org>
Thu, 1 Nov 2018 23:20:12 +0000 (19:20 -0400)
committerThanh Ha <thanh.ha@linuxfoundation.org>
Mon, 12 Nov 2018 07:20:58 +0000 (15:20 +0800)
Refactor the deploy nexus zip command for better portability with
Windows systems.

Issue: RELENG-1372
Change-Id: I58ea1d7703b626f791dcd74e63251c4f3261ca7d
Co-Authored-By: Thanh Ha <thanh.ha@linuxfoundation.org>
Signed-off-by: Thanh Ha <thanh.ha@linuxfoundation.org>
Signed-off-by: Bengt Thuree <bthuree@linuxfoundation.org>
lftools/cli/deploy.py
lftools/deploy.py
releasenotes/notes/refactor-deploy-nexus-zip-018f7e5ced9f558d.yaml [new file with mode: 0644]
tests/fixtures/deploy/zip-test-files/test.zip [new file with mode: 0755]
tests/test_deploy.py

index 520ac3f..224a77b 100644 (file)
@@ -312,8 +312,16 @@ def nexus_zip(ctx, nexus_url, nexus_repo, nexus_path, deploy_zip):
 
     Requires the Nexus Unpack plugin and permission assigned to the upload user.
     """
-    status = subprocess.call(['deploy', 'nexus-zip', nexus_url, nexus_repo, nexus_path, deploy_zip])
-    sys.exit(status)
+    try:
+        deploy_sys.deploy_nexus_zip(nexus_url, nexus_repo, nexus_path, deploy_zip)
+    except IOError as e:
+        log.error(str(e))
+        sys.exit(1)
+    except HTTPError as e:
+        log.error(str(e))
+        sys.exit(1)
+
+    log.info('Zip file upload complete.')
 
 
 deploy.add_command(archives)
index 098d48f..108652f 100644 (file)
@@ -17,6 +17,7 @@ import shutil
 import subprocess
 import sys
 import tempfile
+import zipfile
 
 import glob2  # Switch to glob when Python < 3.5 support is dropped
 import requests
@@ -166,18 +167,7 @@ def deploy_archives(nexus_url, nexus_path, workspace, pattern=None):
     archives_zip = shutil.make_archive(
         '{}/archives'.format(workspace), 'zip')
     log.debug('archives zip: {}'.format(archives_zip))
-
-    # TODO: Update to use I58ea1d7703b626f791dcd74e63251c4f3261ca7d once it's available.
-    upload_files = {'upload_file': open(archives_zip, 'rb')}
-    url = '{}/service/local/repositories/logs/content-compressed/{}'.format(
-        nexus_url, nexus_path)
-    r = requests.post(url, files=upload_files)
-    log.debug('{}: {}'.format(r.status_code, r.text))
-    if r.status_code != 201:
-        raise requests.exceptions.HTTPError(
-            'Failed to upload to Nexus with status code {}.\n{}'.format(
-                r.status_code, r.content))
-
+    deploy_nexus_zip(nexus_url, 'logs', nexus_path, archives_zip)
     shutil.rmtree(work_dir)
 
 
@@ -253,18 +243,48 @@ def deploy_logs(nexus_url, nexus_path, build_url):
     console_zip = tempfile.NamedTemporaryFile(prefix='lftools-dl', delete=True)
     log.debug('console-zip: {}'.format(console_zip.name))
     shutil.make_archive(console_zip.name, 'zip', work_dir)
-    log.debug('listdir: {}'.format(os.listdir(work_dir)))
-
-    # TODO: Update to use I58ea1d7703b626f791dcd74e63251c4f3261ca7d once it's available.
-    upload_files = {'upload_file': open('{}.zip'.format(console_zip.name), 'rb')}
-    url = '{}/service/local/repositories/logs/content-compressed/{}'.format(
-        nexus_url, nexus_path)
-    r = requests.post(url, files=upload_files)
-    log.debug('{}: {}'.format(r.status_code, r.text))
-    if r.status_code != 201:
-        raise requests.exceptions.HTTPError(
-            'Failed to upload to Nexus with status code {}.\n{}'.format(
-                r.status_code, r.content))
-
+    deploy_nexus_zip(nexus_url, 'logs', nexus_path, '{}.zip'.format(console_zip.name))
     console_zip.close()
     shutil.rmtree(work_dir)
+
+
+def deploy_nexus_zip(nexus_url, nexus_repo, nexus_path, zip_file):
+    """"Deploy zip file containing artifacts to Nexus using requests.
+
+    This function simply takes a zip file preformatted in the correct
+    directory for Nexus and uploads to a specified Nexus repo using the
+    content-compressed URL.
+
+    Requires the Nexus Unpack plugin and permission assigned to the upload user.
+
+    Parameters:
+
+        nexus_url:    URL to Nexus server. (Ex: https://nexus.opendaylight.org)
+        nexus_repo:   The repository to push to. (Ex: site)
+        nexus_path:   The path to upload the artifacts to. Typically the
+                      project group_id depending on if a Maven or Site repo
+                      is being pushed.
+                      Maven Ex: org/opendaylight/odlparent
+                      Site Ex: org.opendaylight.odlparent
+        zip_file:     The zip to deploy. (Ex: /tmp/artifacts.zip)
+    """
+    url = '{}/service/local/repositories/{}/content-compressed/{}'.format(
+        _format_url(nexus_url),
+        nexus_repo,
+        nexus_path)
+    log.debug('Uploading {} to {}'.format(zip_file, url))
+
+    upload_file = open(zip_file, 'rb')
+
+    files = {'file': upload_file}
+    resp = requests.post(url, files=files)
+    log.debug('{}: {}'.format(resp.status_code, resp.text))
+
+    if resp.status_code == 400:
+        raise requests.HTTPError("Repository is read only: {}".format(nexus_repo))
+    elif resp.status_code == 404:
+        raise requests.HTTPError("Did not find repository with ID: {}".format(nexus_repo))
+
+    if not str(resp.status_code).startswith('20'):
+        raise requests.HTTPError("Failed to upload to Nexus with status code: {}.\n{}\n{}".format(
+            resp.status_code, resp.text, zipfile.ZipFile(zip_file).infolist()))
diff --git a/releasenotes/notes/refactor-deploy-nexus-zip-018f7e5ced9f558d.yaml b/releasenotes/notes/refactor-deploy-nexus-zip-018f7e5ced9f558d.yaml
new file mode 100644 (file)
index 0000000..51fe45f
--- /dev/null
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    Refactored deploy_nexus_zip() function from shell/deploy to pure Python to
+    be more portable with Windows systems.
+deprecations:
+  - |
+    shell/deploy script's deploy_nexus_zip() function is now deprecated and will
+    be removed in a future release.
diff --git a/tests/fixtures/deploy/zip-test-files/test.zip b/tests/fixtures/deploy/zip-test-files/test.zip
new file mode 100755 (executable)
index 0000000..b10a11d
Binary files /dev/null and b/tests/fixtures/deploy/zip-test-files/test.zip differ
index 5458502..be790b9 100644 (file)
@@ -138,6 +138,62 @@ def test_deploy_logs(cli_runner, datafiles, responses):
         obj={})
     assert result.exit_code == 0
 
+@pytest.mark.datafiles(
+    os.path.join(FIXTURE_DIR, 'deploy'),
+    )
+def test_deploy_nexus_zip(cli_runner, datafiles, responses):
+    os.chdir(str(datafiles))
+    nexus_url = 'https://nexus.example.org'
+    nexus_repo = 'test-repo'
+    nexus_path = 'test/path'
+
+    # Test success
+    success_upload_url = '{}/service/local/repositories/{}/content-compressed/{}'.format(
+        nexus_url,
+        nexus_repo,
+        nexus_path,
+    )
+    responses.add(responses.POST, success_upload_url,
+                  status=201)
+    result = cli_runner.invoke(
+        cli.cli,
+        ['--debug', 'deploy', 'nexus-zip', 'https://nexus.example.org', 'test-repo', 'test/path', 'zip-test-files/test.zip'],
+        obj={})
+    assert result.exit_code == 0
+
+    # Test repository 404
+    upload_404 = """<html>
+  <head>
+    <title>404 - Not Found</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+
+    <link rel="icon" type="image/png" href="https://nexus.opendaylight.org/favicon.png">
+    <!--[if IE]>
+    <link rel="SHORTCUT ICON" href="https://nexus.opendaylight.org/favicon.ico"/>
+    <![endif]-->
+
+    <link rel="stylesheet" href="https://nexus.opendaylight.org/static/css/Sonatype-content.css?2.14.7-01" type="text/css" media="screen" title="no title" charset="utf-8">
+  </head>
+  <body>
+    <h1>404 - Not Found</h1>
+    <p>Repository with ID=&quot;logs2&quot; not found</p>
+  </body>
+</html>
+"""
+    upload_404_url = '{}/service/local/repositories/{}/content-compressed/{}'.format(
+        nexus_url,
+        'logs2',
+        nexus_path,
+    )
+    responses.add(responses.POST, upload_404_url,
+                  body=upload_404, status=404)
+    result = cli_runner.invoke(
+        cli.cli,
+        ['--debug', 'deploy', 'nexus-zip', 'https://nexus.example.org', 'logs2', 'test/path', 'zip-test-files/test.zip'],
+        obj={})
+    assert result.exit_code == 1
+
 def mocked_log_error(msg1=None, msg2=None):
     """Mock local_log_error_and_exit function.
     This function is modified to simply raise an Exception.