From e86d46bad036c7972ca628c152826a884281699b Mon Sep 17 00:00:00 2001 From: Al Finkelstein Date: Fri, 24 Jul 2020 14:21:36 -0500 Subject: [PATCH] Remove internal dependencies and generalize support - Replace utilitarian reliance with auditree-framework - Generalize usage to all git remote version control systems - Update docs around new CLI generalized usage - Fix tests to work with new CLI generalized usage --- .github/ISSUE_TEMPLATE/proposed-change.md | 5 -- .github/PULL_REQUEST_TEMPLATE.md | 5 +- .github/workflows/python-publish.yml | 35 +++++++++++++ .github/workflows/python-test.yml | 26 ++++++++++ CONTRIBUTING.md | 38 ++------------ README.md | 62 +++++++++++++---------- harvest/cli.py | 29 +++++++---- harvest/collator.py | 39 ++++++++++---- harvest/reporter.py | 11 ++-- setup.cfg | 31 +++++++----- test/test_base_reporter.py | 14 +++-- test/test_cli_collate.py | 26 ++++------ test/test_cli_report.py | 27 +++++++--- test/test_collator.py | 60 +++++++--------------- 14 files changed, 228 insertions(+), 180 deletions(-) create mode 100644 .github/workflows/python-publish.yml create mode 100644 .github/workflows/python-test.yml diff --git a/.github/ISSUE_TEMPLATE/proposed-change.md b/.github/ISSUE_TEMPLATE/proposed-change.md index f91bec8..8f9fa6f 100644 --- a/.github/ISSUE_TEMPLATE/proposed-change.md +++ b/.github/ISSUE_TEMPLATE/proposed-change.md @@ -33,8 +33,3 @@ _Provide the test process that will be followed to adequately verify that the approach above satisfies the requirements provided. This level of detail may not be available at the time of issue creation and can be completed at a later time._ - -## Time-line and Components - -_If the resolution of the issue needs to be split into multiple units of work -then provide a task/component breakdown. Otherwise, N/A for not applicable._ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b6d5d8c..6cd757b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,8 +18,7 @@ _Provide a bulleted list of the changes included in the pull request._ _Provide a bulleted list of tests included in the pull request and/or tests performed to validate the work included in the pull request._ -## Issue(s) +## Context -_Provide a bulleted list of links to any GitHub issue, or any other task -management reference (FogBugz, Box Note, etc...) that reviewers can reference +_Provide a bulleted list of GitHub issues, or any other references (mailing list discussion, etc...) that reviewers can reference for additional information regarding scope of the pull request._ diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..0cc0ea7 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,35 @@ +# This workflows will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: PyPI upload + +on: + release: + types: [created] + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + make develop + - name: Test & lint + run: | + make code-lint + make test + + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml new file mode 100644 index 0000000..14319cf --- /dev/null +++ b/.github/workflows/python-test.yml @@ -0,0 +1,26 @@ +name: format | lint | test +on: [push, pull_request] +jobs: + lint_unit_tests_coverage: + name: Run code validation steps + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.7' + - name: Install dependencies + run: | + make develop + - name: Run formatter + run: | + make code-format + - name: Run linter + run: | + make code-lint + - name: Run unit tests with coverage + run: | + make test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9e3b30..cd97215 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,34 +1,10 @@ # Contributing -If you want to add to the harvest tool, please familiarize yourself with the code & our [Coding Standards][]. -Before you submit a PR, please [file an issue][new collab] to request collaborator access. +If you want to add to harvest, please familiarise yourself with the code & our [Coding Standards][]. Before you submit a PR, please [file an issue][new collab] to request collaborator access. -## Assumptions and pre-requisites +If you would like to contribute reports, either add them via PR to [Arboretum][] or push to your own repository & let us know of its existence. -The following is a list of topics that contributors **should already** be comfortable -with in order to contribute to `harvest`. Details on these topics are outside of -the scope of the `harvest` documentation. - -- [Python][python] - - Moderate to advanced experience with Python code is necessary to contribute - to the `harvest`. - -- Python [unit tests][python-unit-tests] - - An understanding of the Python unit testing framework including mocking and patching is - expected and needed to write unit tests for any `harvest` contribution. - -- [Jinja2][jinja2] - - Familiarity with [Jina2][jinja2] is useful if you're looking to write templated reports. - -- Auditree [compliance framework][auditree-framework] - - Typical use cases for `harvest` center around gather evidence from an evidence locker - and optionally formatting, filtering, and manipulating that evidence into readable reports. - To that end, a general understanding of the Auditree [compliance framework][auditree-framework] is - useful. +Follow the guidelines outlined in the [generating reports][] section of the harvest docs when contributing reports to [Arboretum][]. ## Code formatting and style @@ -52,11 +28,7 @@ suite locally by using: make test ``` +[Arboretum]: https://github.com/ComplianceAsCode/auditree-arboretum [Coding Standards]: https://github.com/ComplianceAsCode/auditree-framework/blob/master/doc/coding-standards.rst -[flake8]: https://gitlab.com/pycqa/flake8 +[generating reports]: https://github.com/ComplianceAsCode/auditree-harvest#generate-reports [new collab]: https://github.com/ComplianceAsCode/auditree-harvest/issues/new?template=new-collaborator.md -[yapf]: https://github.com/google/yapf -[python]: https://www.python.org/ -[python-unit-tests]: https://docs.python.org/3/library/unittest.html -[jinja2]: http://jinja.pocoo.org/docs/2.10/ -[auditree-framework]: https://github.com/ComplianceAsCode/auditree-framework diff --git a/README.md b/README.md index 95e258e..61e0c25 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -# auditree-harvest - [![OS Compatibility][platform-badge]](#prerequisites) [![Python Compatibility][python-badge]][python-dl] [![pre-commit][pre-commit-badge]][pre-commit] +[![Code validation](https://github.com/ComplianceAsCode/auditree-harvest/workflows/format%20%7C%20lint%20%7C%20test/badge.svg)][lint-test] +[![Upload Python Package](https://github.com/ComplianceAsCode/auditree-harvest/workflows/PyPI%20upload/badge.svg)][pypi-upload] + +# auditree-harvest The Auditree data gathering and reporting tool. @@ -26,13 +28,13 @@ site or installed using your package manager. Python version can be checked with: -``` -> python --version +```sh +python --version ``` or -``` +```sh python3 --version ``` @@ -44,13 +46,18 @@ It is best practice, but not mandatory, to run `harvest` from a dedicated Python virtual environment. Assuming that you have the Python [virtualenv][virtual-env] package already installed, you can create a virtual environment named `venv` by executing `virtualenv venv` which will create a `venv` folder at the location of -where you executed the command. +where you executed the command. Alternatively you can use the python `venv` module +to do the same. + +```sh +python3 -m venv venv +``` Assuming that you have a virtual environment and that virtual environment is in the current directory then to install a new instance of `harvest`, activate your virtual environment and use `pip` to install `harvest` like so: -``` +```sh . ./venv/bin/activate pip install auditree-harvest ``` @@ -58,7 +65,7 @@ pip install auditree-harvest As we add functionality to `harvest` users will want to upgrade their `harvest` package regularly. To upgrade `harvest` to the most recent version do: -``` +```sh . ./venv/bin/activate pip install auditree-harvest --upgrade ``` @@ -85,16 +92,15 @@ token=your-gh-token ### Collate data To collate historical versions of a file from a Git repository hosting service -like Github, provide the organization (`org` positional argument), the repository -name (`repo` positional argument), the relative path to the file within the remote -repository including the file name (`filepath` positional argument) and an optional -date range (`--start` and `--end` arguments). You can also, optionally, provide -the local Git repository path (`--repo-path` argument), if the repository -already exists locally and you wish to override the remote repository download -behavior. +like Github, provide the repository URL (`repo` positional argument), the +relative path to the file within the remote repository including the file name +(`filepath` positional argument) and an optional date range (`--start` and `--end` +arguments). You can also, optionally, provide the local Git repository path +(`--repo-path` argument), if the repository already exists locally and you wish +to override the remote repository download behavior. -``` -harvest collate org-foo repo-bar /raw/baz/baz.json --start 20191201 --end 20191212 --repo-path ./bar-repo +```sh +harvest collate https://github.com/org-foo/repo-bar /raw/baz/baz.json --start 20191201 --end 20191212 --repo-path ./bar-repo ``` - File versions are written to the current local directory where `harvest` was @@ -115,28 +121,28 @@ date is retrieved. ### Generate report(s) To run a report using content contained in a Git repository hosting service -like Github, provide the organization (`org` positional argument), the repository -name (`repo` positional argument), the report package (`package`), the report name (`name` -positional argument) and include any configuration that the report requires (`--config`) -as a JSON string. You can also, optionally, provide the local Git repository path -(`--repo-path` argument), if the repository already exists locally and you wish -to override the remote repository download behavior. +like Github, provide the repository URL (`repo` positional argument), the report +package (`package`), the report name (`name` positional argument) and include +any configuration that the report requires (`--config`) as a JSON string. You +can also, optionally, provide the local Git repository path (`--repo-path` +argument), if the repository already exists locally and you wish to override +the remote repository download behavior. -``` -harvest report org-foo repo-bar auditree_arboretum check_results_summary --config '{"start":"20191212","end":"20191221"}' +```sh +harvest report https://github.com/org-foo/repo-bar auditree_arboretum check_results_summary --config '{"start":"20191212","end":"20191221"}' ``` #### Getting report details To see a full summary of available reports within any package (like `auditree-arboretum`) do: -``` +```sh harvest reports auditree_arboretum --list ``` To see details on a specific report that include usage example do something like: -``` +```sh harvest reports auditree_arboretum --detail check_results_summary ``` @@ -228,3 +234,5 @@ it will handle the rest. [pps-rpt-tmpl]: https://github.com/ComplianceAsCode/auditree-harvest/blob/main/auditree_arboretum/provider/auditree/reports/report_templates/python_packages_summary.md.tmpl [pre-commit-badge]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white [pre-commit]: https://github.com/pre-commit/pre-commit +[lint-test]: https://github.com/ComplianceAsCode/auditree-harvest/actions?query=workflow%3A%22Test+python+code+%26+lint%22 +[pypi-upload]: https://github.com/ComplianceAsCode/auditree-harvest/actions?query=workflow%3A%22Upload+Python+Package%22 diff --git a/harvest/cli.py b/harvest/cli.py index 06cad28..905b31f 100644 --- a/harvest/cli.py +++ b/harvest/cli.py @@ -18,6 +18,9 @@ import os from argparse import SUPPRESS from datetime import datetime +from urllib.parse import urlparse + +from compliance.utils.credentials import Config from harvest import __version__ as version from harvest.collator import Collator @@ -31,17 +34,16 @@ from ilcli import Command -from utilitarian import config_spec, credentials - class _CoreHarvestCommand(Command): def _init_arguments(self): self.add_argument( - 'org', help='the organization (owner) of a repository' - ) - self.add_argument( - 'repo', help='the name of a repository within an organization' + 'repo', + help=( + 'the URL to the repository containing files to be processed ' + 'by harvest, as an example https://github.com/my-org/my-repo' + ) ) self.add_argument( '--repo-path', @@ -62,6 +64,13 @@ def _init_arguments(self): '--no-validate', action='store_false', help=SUPPRESS, default=True ) + def _validate_arguments(self, args): + parsed = urlparse(args.repo) + if not (parsed.scheme and parsed.hostname and parsed.path): + return ( + 'ERROR: repo url must be of the form https://hostname/org/repo' + ) + class Collate(_CoreHarvestCommand): """Retrieve historical versions of a file from a git repository.""" @@ -109,12 +118,12 @@ def _validate_arguments(self, args): return 'ERROR: start date cannot be after end date' if args.end > datetime.today(): return 'ERROR: end date cannot be in the future' + return super()._validate_arguments(args) def _run(self, args): collator = Collator( - args.org, args.repo, - credentials.Config(args.creds, spec=config_spec.NullConfigSpec()), + Config(args.creds), 'master', args.repo_path, args.no_validate @@ -167,12 +176,12 @@ def _validate_arguments(self, args): self.template_dir = args.template_dir or os.path.dirname( rpt_module.__file__ ) + return super()._validate_arguments(args) def _run(self, args): reporter = self.report( - args.org, args.repo, - credentials.Config(args.creds, spec=config_spec.NullConfigSpec()), + Config(args.creds), 'master', args.repo_path, self.template_dir, diff --git a/harvest/collator.py b/harvest/collator.py index 0349086..459e011 100644 --- a/harvest/collator.py +++ b/harvest/collator.py @@ -16,6 +16,7 @@ import os import tempfile from datetime import datetime, timedelta +from urllib.parse import urlparse import git @@ -25,12 +26,12 @@ class Collator(object): """Harvest collator to retrieve Git repository content.""" - def __init__( - self, org, repo, creds, branch, repo_path=None, validate=True - ): + def __init__(self, repo_url, creds, branch, repo_path=None, validate=True): """Construct the Collator object.""" - self.org = org - self.repo = repo + parsed = urlparse(repo_url) + self.scheme = parsed.scheme + self.hostname = parsed.hostname + self.org, self.repo = parsed.path.strip('/').split('/') self.creds = creds self.branch = branch self.repo_path = repo_path @@ -107,12 +108,28 @@ def checkout(self): self.git_repo.remote().fetch() self.git_repo.remote().pull() else: - auth = f'{self.creds["github_enterprise"].token}:x-oauth-basic@' - self.git_repo = git.Repo.clone_from( - f'https://{auth}github.ibm.com/{self.org}/{self.repo}.git', - local_path, - branch=self.branch - ) + token = None + if 'github.com' in self.hostname: + token = self.creds['github'].token + elif 'github' in self.hostname: + token = self.creds['github_enterprise'].token + elif 'bitbucket' in self.hostname: + token = self.creds['bitbucket'].token + elif 'gitlab' in self.hostname: + token = self.creds['gitlab'].token + url_path = f'{self.hostname}/{self.org}/{self.repo}.git' + try: + self.git_repo = git.Repo.clone_from( + f'{self.scheme}://{token}@{url_path}', + local_path, + branch=self.branch + ) + except git.exc.GitCommandError as e: + raise git.exc.GitCommandError( + [c.replace(token, f'{"":*<10}') for c in e.command], + e.status, + e.stderr.strip('\n') + ) from None def _valid_repo(self): remote_url = self.git_repo.remotes.origin.url diff --git a/harvest/reporter.py b/harvest/reporter.py index 47a7b7a..d1f198a 100644 --- a/harvest/reporter.py +++ b/harvest/reporter.py @@ -29,8 +29,7 @@ class BaseReporter(object): def __init__( self, - org, - repo, + repo_url, creds, branch, repo_path=None, @@ -39,8 +38,7 @@ def __init__( **config ): """Construct the reporter object.""" - self.org = org - self.repo = repo + self.repo_url = repo_url self.creds = creds self.branch = branch self.repo_path = repo_path @@ -56,7 +54,7 @@ def report_filename(self): def get_file_content(self, filepath, file_dt=None): """ - Retrieve file content for a given file and date from a GHE repo. + Retrieve file content for a given file and date from a git repository. :param str filepath: The relative path to the file within the repo :param datetime file_dt: The date of the file version @@ -65,8 +63,7 @@ def get_file_content(self, filepath, file_dt=None): """ if not self.collator: self.collator = Collator( - self.org, - self.repo, + self.repo_url, self.creds, self.branch, self.repo_path, diff --git a/setup.cfg b/setup.cfg index 0dbafb3..1616c3a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,33 +1,39 @@ [metadata] -name = auditree_harvest +name = auditree-harvest version = attr: harvest.__version__ -description = The Auditree evidence reporting tool +description = The Auditree data gathering and reporting tool author = Auditree Security and Compliance author_email = al.finkelstein@ibm.com -url = https://github.com/ComplianceAsCode/auditree-harvest +url = https://auditree.github.io/ license = Apache License 2.0 classifiers = - Programming Language :: Python :: 3 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 -long_description = https://github.com/ComplianceAsCode/auditree-harvest + Programming Language :: Python :: 3.9 + License :: OSI Approved :: Apache Software License + Operating System :: MacOS :: MacOS X + Operating System :: POSIX :: Linux +long_description_content_type = text/markdown +long_description = file: README.md [options] packages = find: install_requires = - ilcli>=0.2.3 - utilitarian>=0.41.7 - GitPython>=3.0.4 - jinja2>=2.10.3 + auditree-framework>=1.0.0 [options.packages.find] exclude = + test.* test [bdist_wheel] universal = 1 +[options.entry_points] +console_scripts = + harvest=harvest.cli:run + [options.extras_require] dev = pre-commit>=2.4.0 @@ -35,7 +41,6 @@ dev = pytest-cov>=2.6.1 recommonmark Sphinx>=1.7.2 - -[options.entry_points] -console_scripts = - harvest=harvest.cli:run + setuptools + wheel + twine diff --git a/test/test_base_reporter.py b/test/test_base_reporter.py index 4af262d..d94a73e 100644 --- a/test/test_base_reporter.py +++ b/test/test_base_reporter.py @@ -37,15 +37,20 @@ class TestBaseReporter(unittest.TestCase): def setUp(self): """Initialize supporting test objects before each test.""" - self.args = ['org', 'repo', 'creds', 'branch', 'repo-path', TMPLT_DIR] + self.args = [ + 'https://github.com/org/repo', + 'creds', + 'branch', + 'repo-path', + TMPLT_DIR + ] self.reporter = BaseReporter(*self.args) def test_constructor_with_config(self): """Ensures base reporter object is constructed with config.""" reporter = BaseReporter(*self.args, foo='foo', bar='bar') self.assertIsInstance(reporter, BaseReporter) - self.assertEqual(reporter.org, 'org') - self.assertEqual(reporter.repo, 'repo') + self.assertEqual(reporter.repo_url, 'https://github.com/org/repo') self.assertEqual(reporter.creds, 'creds') self.assertEqual(reporter.branch, 'branch') self.assertEqual(reporter.repo_path, 'repo-path') @@ -56,8 +61,7 @@ def test_constructor_with_config(self): def test_constructor_without_config(self): """Ensures base reporter object is constructed without config.""" self.assertIsInstance(self.reporter, BaseReporter) - self.assertEqual(self.reporter.org, 'org') - self.assertEqual(self.reporter.repo, 'repo') + self.assertEqual(self.reporter.repo_url, 'https://github.com/org/repo') self.assertEqual(self.reporter.creds, 'creds') self.assertEqual(self.reporter.branch, 'branch') self.assertEqual(self.reporter.repo_path, 'repo-path') diff --git a/test/test_cli_collate.py b/test/test_cli_collate.py index d8aa6d2..e5d6572 100644 --- a/test/test_cli_collate.py +++ b/test/test_cli_collate.py @@ -34,7 +34,7 @@ def test_collate_no_dates(self, mock_read, mock_write): """Ensures collate sub-command works when no dates provided.""" mock_read.return_value = ['commit-foo'] self.harvest.run( - ['collate', 'foo-org', 'bar-repo', 'my/path/baz.json'] + ['collate', 'https://github.com/foo/bar', 'my/path/baz.json'] ) today = datetime.today() @@ -53,8 +53,7 @@ def test_collate_using_repo_path(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--repo-path', 'os/repo/path' @@ -77,8 +76,7 @@ def test_collate_start_date_only(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--start', '20191020' @@ -102,8 +100,7 @@ def test_collate_end_date_only(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--end', '20191020' @@ -124,8 +121,7 @@ def test_collate_both_dates(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--start', '20191020', @@ -148,8 +144,7 @@ def test_collate_start_eq_end(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--start', '20191120', @@ -171,8 +166,7 @@ def test_collate_start_gt_end(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--start', '20191120', @@ -190,8 +184,7 @@ def test_collate_future_start(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--start', (datetime.today() + timedelta(days=1)).strftime('%Y%m%d') @@ -207,8 +200,7 @@ def test_collate_future_end(self, mock_read, mock_write): self.harvest.run( [ 'collate', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'my/path/baz.json', '--start', '20191120', diff --git a/test/test_cli_report.py b/test/test_cli_report.py index 5fc5016..d7683c9 100644 --- a/test/test_cli_report.py +++ b/test/test_cli_report.py @@ -47,7 +47,12 @@ def test_validate_pkg_not_found(self): """Ensures processing stops when package is not found.""" self.mock_get_report_module.side_effect = ModuleNotFoundError() self.harvest.run( - ['report', 'foo-org', 'bar-repo', 'no.such.pkg', 'a_module'] + [ + 'report', + 'https://github.com/foo/bar', + 'no.such.pkg', + 'a_module' + ] ) self.mock_get_report_module.assert_called_once_with( 'no.such.pkg', 'a_module' @@ -61,7 +66,12 @@ def test_validate_rpt_not_found(self): self.mock_get_report_module.return_value = 'a_module' self.mock_get_report_classes.return_value = None self.harvest.run( - ['report', 'foo-org', 'bar-repo', 'a.valid.pkg', 'a_module'] + [ + 'report', + 'https://github.com/foo/bar', + 'a.valid.pkg', + 'a_module' + ] ) self.mock_get_report_module.assert_called_once_with( 'a.valid.pkg', 'a_module' @@ -75,7 +85,12 @@ def test_validate_rpt_ambiguous(self): self.mock_get_report_module.return_value = 'a_module' self.mock_get_report_classes.return_value = ['rpt1', 'rpt2'] self.harvest.run( - ['report', 'foo-org', 'bar-repo', 'a.valid.pkg', 'a_module'] + [ + 'report', + 'https://github.com/foo/bar', + 'a.valid.pkg', + 'a_module' + ] ) self.mock_get_report_module.assert_called_once_with( 'a.valid.pkg', 'a_module' @@ -92,8 +107,7 @@ def test_validate_rpt_successful(self, mock_err): self.harvest.run( [ 'report', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'a.valid.pkg', 'a_module', '--template-dir', @@ -117,8 +131,7 @@ def test_validate_rpt_fails_on_gen(self, mock_err): self.harvest.run( [ 'report', - 'foo-org', - 'bar-repo', + 'https://github.com/foo/bar', 'a.valid.pkg', 'a_module', '--template-dir', diff --git a/test/test_collator.py b/test/test_collator.py index 29e9268..1f8f77f 100644 --- a/test/test_collator.py +++ b/test/test_collator.py @@ -31,9 +31,9 @@ def setUp(self): """Initialize supporting test objects before each test.""" creds_mock = MagicMock() creds_mock.token = 'foo-ghe-token' - self.creds = {'github_enterprise': creds_mock} + self.creds = {'github': creds_mock} - self.args = ['org-foo', 'repo-foo', self.creds, 'master'] + self.args = ['https://github.com/foo/bar', self.creds, 'master'] commit_foo_mock = create_autospec(Commit) commit_foo_mock.hexsha = 'foo-hexsha' @@ -49,8 +49,10 @@ def setUp(self): def test_constructor_default(self): """Ensures collate object is constructed with default branch.""" collator = Collator(*self.args) - self.assertEqual(collator.org, 'org-foo') - self.assertEqual(collator.repo, 'repo-foo') + self.assertEqual(collator.scheme, 'https') + self.assertEqual(collator.hostname, 'github.com') + self.assertEqual(collator.org, 'foo') + self.assertEqual(collator.repo, 'bar') self.assertEqual(collator.creds, self.creds) self.assertEqual(collator.branch, 'master') self.assertIsNone(collator.repo_path) @@ -59,8 +61,10 @@ def test_constructor_default(self): def test_constructor_with_repo_path(self): """Ensures collate object is constructed as expected.""" collator = Collator(*self.args, 'my/repo/path') - self.assertEqual(collator.org, 'org-foo') - self.assertEqual(collator.repo, 'repo-foo') + self.assertEqual(collator.scheme, 'https') + self.assertEqual(collator.hostname, 'github.com') + self.assertEqual(collator.org, 'foo') + self.assertEqual(collator.repo, 'bar') self.assertEqual(collator.creds, self.creds) self.assertEqual(collator.branch, 'master') self.assertEqual(collator.repo_path, 'my/repo/path') @@ -161,27 +165,11 @@ def test_checkout_clone(self, is_dir_mock, clone_from_mock): collator.checkout() is_dir_mock.assert_called_once_with( - '/'.join( - [ - tempfile.gettempdir(), - 'harvest', - 'org-foo', - 'repo-foo', - '.git' - ] - ) + '/'.join([tempfile.gettempdir(), 'harvest', 'foo', 'bar', '.git']) ) clone_from_mock.assert_called_once_with( - '/'.join( - [ - 'https://foo-ghe-token:x-oauth-basic@github.ibm.com', - 'org-foo', - 'repo-foo.git' - ] - ), - '/'.join( - [tempfile.gettempdir(), 'harvest', 'org-foo', 'repo-foo'] - ), + 'https://foo-ghe-token@github.com/foo/bar.git', + '/'.join([tempfile.gettempdir(), 'harvest', 'foo', 'bar']), branch='master' ) self.assertEqual(collator.git_repo, 'my-cloned-repo') @@ -206,20 +194,10 @@ def test_checkout_fetch(self, is_dir_mock, repo_mock): collator.checkout() is_dir_mock.assert_called_once_with( - '/'.join( - [ - tempfile.gettempdir(), - 'harvest', - 'org-foo', - 'repo-foo', - '.git' - ] - ) + '/'.join([tempfile.gettempdir(), 'harvest', 'foo', 'bar', '.git']) ) repo_mock.assert_called_once_with( - '/'.join( - [tempfile.gettempdir(), 'harvest', 'org-foo', 'repo-foo'] - ) + '/'.join([tempfile.gettempdir(), 'harvest', 'foo', 'bar']) ) self.assertEqual(collator.git_repo, mock_repo) mock_fetch.assert_called_once_with() @@ -239,7 +217,7 @@ def test_checkout_fetch_repo_path(self, repo_mock): mock_remote.clone_from = mock_clone_from mock_repo.remote.return_value = mock_remote mock_origin = MagicMock() - mock_origin.url = 'git@github.ibm.com:org-foo/repo-foo.git' + mock_origin.url = 'git@github.com:foo/bar.git' mock_remotes = MagicMock() mock_remotes.origin = mock_origin mock_repo.remotes = mock_remotes @@ -267,7 +245,7 @@ def test_checkout_fetch_repo_path_mismatch(self, repo_mock): mock_remote.clone_from = mock_clone_from mock_repo.remote.return_value = mock_remote mock_origin = MagicMock() - mock_origin.url = 'git@github.ibm.com:org-bar/repo-bar.git' + mock_origin.url = 'git@github.com:bar/foo.git' mock_remotes = MagicMock() mock_remotes.origin = mock_origin mock_repo.remotes = mock_remotes @@ -282,6 +260,4 @@ def test_checkout_fetch_repo_path_mismatch(self, repo_mock): mock_pull.assert_not_called() mock_clone_from.assert_not_called() - self.assertEqual( - str(cm.exception), 'org-foo/repo-foo repository mismatch' - ) + self.assertEqual(str(cm.exception), 'foo/bar repository mismatch')