From 723bd8aa342d8c03339ff619dd99c50c6d26d621 Mon Sep 17 00:00:00 2001 From: Matt Chung Date: Sat, 30 Jan 2016 15:22:56 +0000 Subject: [PATCH 1/3] Added ability to retrieve status of multiple imported issues Created unit and integration test for imported_issues Closes: https://github.com/sigmavirus24/github3.py/issues/497 --- github3/repos/repo.py | 26 +++++++++++++++++++ .../cassettes/Repository_imported_issues.json | 1 + tests/integration/test_repos_repo.py | 13 ++++++++++ tests/unit/test_repos_repo.py | 19 ++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 tests/cassettes/Repository_imported_issues.json diff --git a/github3/repos/repo.py b/github3/repos/repo.py index fa1020af4..673139af8 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1281,6 +1281,32 @@ def imported_issue(self, imported_issue_id): json = self._json(data, 200) return self._instance_or_null(ImportedIssue, json) + @requires_auth + def imported_issues(self, number=-1, since=None, etag=None): + """Retrieve imported issues + + :param int number: (optional), number of imported issues to return. + Default: -1 returns all branches + :param since: (optional), Only commits after this date will + be returned. This can be a `datetime` or an `ISO8601` formatted + date string. + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`ImportedIssue ` + """ + + data = { + 'since': since + } + + self._remove_none(data) + url = self._build_url('import/issues', base_url=self._api) + + return self._iter(int(number), url, ImportedIssue, etag=etag, + params=data, + headers=ImportedIssue.IMPORT_CUSTOM_HEADERS) + @requires_auth def import_issue(self, title, body, created_at, assignee=None, milestone=None, closed=None, labels=None, comments=None): diff --git a/tests/cassettes/Repository_imported_issues.json b/tests/cassettes/Repository_imported_issues.json new file mode 100644 index 000000000..3b0fd1b14 --- /dev/null +++ b/tests/cassettes/Repository_imported_issues.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0a2", "Accept-Charset": "utf-8", "Connection": "keep-alive", "Content-Type": "application/json", "Authorization": "token "}, "method": "GET", "uri": "https://api.github.com/repos/github3py/test_rename1"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+2Yz46jOBDG34XrZONOMpmdQVrNvMFc9rSXyAEHrAaMbJMojfrd5yubf0ErkrSvLbVaBFw/PpddpqraSKZRvNt93Wxevv1YRRUvRRRHVhh70IJ+baJVdGqK4tA9yqTNm+OuvrLZIHWphI7iNipUJitAhpEg0Fs2f3/fbvbfVhE/c8v1odEFRuXW1iZmzN80a2/VGKETVVlR2XWiStawzvrn+Z8deJnuIASOcGMGq2UH8tagGTbVk9uymAnwj9346ciTKgp1gf1c7+Ir2GBG7nMIWWUfQcCsZcrmAg7DNN5p8tLYJ+U4kxYTw7rKlCAGS6BF+pykzgiCaLHfW6ZFrRytOZpEy9pKVT0p7cYUKKUzXsk3/gEUTA0IJOpJEc4EpuKMHfekrbdpWa3lmSdXcocWiZBnePcjvJkxcPZaU1T+nniGfC6tOPC0pGA78cKI91XkNFgMdjdWiK6H9vk8llMxrKYPr5PSrwN0MdacJ8cImpMJdMe/SwTEFewx+VdxDcGQecvwv4uGBCHKj0pzq+5F+qK8G07Lpj9pX1jByxDZzh6cXKkgLzp7cKQxjXhoky7O2mEM6wOhasqjP6ke2f6LZA+AUm6MzCohQrw3MFrWH6VHzaskD6L2iJb5K7fOPAsRSuagHAt1DMHgM8Yco2Um5/7LYQ+B2ghKiBumFqdQoYQYmFaHrbQTSYyBiC+XxaKHqOwRrO28WfAqa3gWBB0YdKDjk5zxt7u5xmLEjBAQKYXS8tgEn2ojhnT6jz1iPMidI2VkugRiOSdZnv0kD3HzL0t573u+COwIN7s9nEr7c06m3/eTj7tiCdGy8Qj2R3wHD/Bsd8b3Kqev6BL1kM3QI1j7peY2p7MKb6q5FgGSOwJrjxzJ0Xq9bnPBXfJbCh0Wth4AEtdJjkwvQGXbI5DalNy6pPpEIlMk2YXiaYhfBwZ4fgUDlHrAdOVrFIYh8pz9FFjKAqWnqoLO1BEyRVfKypNMHqkrFoPshtP+NLJKxIoXxQq71cpEYv+iZqMFREYpgtzjAZgE6nBfVhQCWznE41p4RMt8GZiKulDX0INnQqHI1QI1SHrgFsXD9mWz/+vlK/7+3ezj/fd4t/0PY5o6XRiz39CYujH5HQwO0m5D4wpdhP8r4m9KEGoLAG1MPtr9Gq1ifzlvb3RWSYGdOQugh994nn/X7lpCZ65KUSPFiOIKoUI13xuuX25yhUQ1FTyNmxdukcziqzze6vOLHpBzc/BxHMVWN1Qi4s54TExuXuSrnA4iHWYoAn0hN76olFqrrqnjtapaVN27ekFbaoZQAUdqJ8+jGE969e5hKk68KezB59TYRyU3Fv0l7AqhS8yAGg3UbeoKYD8X2jG9ZDpb/DXq4mlT4bNH1TXwPntUY/dxuZv32aO67aAiRblpcCEsH+9RVcJecAhMDqlpQdGdKNv3Pw/iJ5WbFgAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-github-media-type": "github.v3; param=full; format=json", "x-oauth-scopes": "admin:public_key, gist, repo, user", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "x-accepted-oauth-scopes": "repo", "etag": "W/\"13a47a4d1a5c47a7a39be7630d80c17c\"", "cache-control": "private, max-age=60, s-maxage=60", "status": "200 OK", "x-ratelimit-remaining": "4991", "x-served-by": "a6882e5cd2513376cb9481dbcd83f3a2", "access-control-expose-headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "97E45D32:14F4C:367C294:56ACB87A", "access-control-allow-credentials": "true", "last-modified": "Sat, 04 Apr 2015 15:58:51 GMT", "date": "Sat, 30 Jan 2016 13:19:54 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains; preload", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1454161385"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/github3py/test_rename1"}, "recorded_at": "2016-01-30T13:19:55"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.golden-comet-preview+json", "User-Agent": "github3.py/1.0.0a2", "Accept-Charset": "utf-8", "Connection": "keep-alive", "Content-Type": "application/json", "Authorization": "token "}, "method": "GET", "uri": "https://api.github.com/repos/github3py/test_rename1/import/issues?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA9WRuw7CMAxF/8UrpbHb8ki+gw2hKrQRRKI0StwBIf6d0AgYQQgG1ivr2NdnfQbbgiqlXEjMILDmIYAC27nes2khg8EfYrBndkEJoZ3Nd5b3wzZv+k544/ogUlC6k2ATuPbmqDtDIkGEDWEwQaQdEZjiOsX1l/CRO95iufenz6ER03ijY/Nac6xdIM2nSFOqViTVjFRBE0SFeHuMa98bHJt+ftP9gQSXLOmqECXNf6sr7fhXXcsVVaqQivCFrsfg0+uXdBVw2VwBSH+sCl8DAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-github-media-type": "github.golden-comet-preview; format=json", "x-oauth-scopes": "admin:public_key, gist, repo, user", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "x-accepted-oauth-scopes": "", "etag": "W/\"48dbaef3f5b20510df98e3f2cbe50005\"", "cache-control": "private, max-age=60, s-maxage=60", "status": "200 OK", "x-ratelimit-remaining": "4990", "x-served-by": "a7f8a126c9ed3f1c4715a34c0ddc7290", "access-control-expose-headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "97E45D32:14F4C:367C2C9:56ACB87A", "access-control-allow-credentials": "true", "date": "Sat, 30 Jan 2016 13:19:54 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains; preload", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1454161385"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/github3py/test_rename1/import/issues?per_page=100"}, "recorded_at": "2016-01-30T13:19:55"}], "recorded_with": "betamax/0.5.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 57b2d42ae..5d8a7ad3d 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -612,6 +612,19 @@ def test_imported_issue(self): assert isinstance(imported_issue, github3.repos.issue_import.ImportedIssue) + def test_imported_issues(self): + """Test the ability to retrieve imported issues.""" + self.token_login() + cassette_name = self.cassette_name('imported_issues') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('github3py', 'test_rename1') + imported_issues = list(repository.imported_issues()) + + assert len(imported_issues) > 0 + for imported_issue in imported_issues: + assert isinstance(imported_issue, + github3.repos.issue_import.ImportedIssue) + def test_import_issue(self): """Test the ability to import an issue.""" self.token_login() diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 3b027ca32..e31305d64 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -1175,6 +1175,19 @@ def test_hooks(self): headers={} ) + def test_imported_issues(self): + """Verify the request for retreiving imported issues.""" + i = self.instance.imported_issues(since='2015-03-15') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('import/issues'), + params={'per_page': 100, 'since': '2015-03-15'}, + headers={ + 'Accept': 'application/vnd.github.golden-comet-preview+json' + } + ) + def test_issue_events(self): """Test the ability to iterate over a repository's issue events.""" i = self.instance.issue_events() @@ -1504,6 +1517,12 @@ def test_import_issue(self): body='Foobar body', created_at='2014-03-16T17:15:42Z') + def test_imported_issues(self): + """ + Show that a user must be authenticated to retrieve imported issues. + """ + self.assert_requires_auth(self.instance.imported_issues) + def test_imported_issue(self): """ Show that a user must be authenticated to retrieve an imported issue. From f1a0b94f28873655af505ebee67889b4409658df Mon Sep 17 00:00:00 2001 From: Matt Chung Date: Thu, 4 Feb 2016 07:10:29 +0000 Subject: [PATCH 2/3] Included gist link in docstring for imported_issues --- github3/repos/repo.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 673139af8..01689ff1a 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -534,11 +534,11 @@ def commits(self, sha=None, path=None, author=None, number=-1, etag=None, :param str etag: (optional), ETag from a previous request to the same endpoint :param since: (optional), Only commits after this date will - be returned. This can be a `datetime` or an `ISO8601` formatted + be returned. This can be a ``datetime`` or an ``ISO8601`` formatted date string. :type since: datetime or string :param until: (optional), Only commits before this date will - be returned. This can be a `datetime` or an `ISO8601` formatted + be returned. This can be a ``datetime`` or an ``ISO8601`` formatted date string. :type until: datetime or string @@ -1283,12 +1283,14 @@ def imported_issue(self, imported_issue_id): @requires_auth def imported_issues(self, number=-1, since=None, etag=None): - """Retrieve imported issues + """Retrieve the collection of imported issues via the API. + + See also: https://gist.github.com/jonmagic/5282384165e0f86ef105 :param int number: (optional), number of imported issues to return. Default: -1 returns all branches :param since: (optional), Only commits after this date will - be returned. This can be a `datetime` or an `ISO8601` formatted + be returned. This can be a ``datetime`` or an ``ISO8601`` formatted date string. :param str etag: (optional), ETag from a previous request to the same endpoint @@ -1297,7 +1299,7 @@ def imported_issues(self, number=-1, since=None, etag=None): """ data = { - 'since': since + 'since': timestamp_parameter(since) } self._remove_none(data) @@ -1423,7 +1425,7 @@ def issues(self, milestone=None, state=None, assignee=None, mentioned=None, ('created', 'updated', 'comments', 'created') :param str direction: (optional), accepted values: ('asc', 'desc') :param since: (optional), Only issues after this date will - be returned. This can be a `datetime` or an `ISO8601` formatted + be returned. This can be a ``datetime`` or an ``ISO8601`` formatted date string, e.g., 2012-05-20T23:10:27Z :type since: datetime or string :param int number: (optional), Number of issues to return. From 8b9b37dcb5378eab0805b1c5ab44a880b2aa1741 Mon Sep 17 00:00:00 2001 From: Matt Chung Date: Fri, 5 Feb 2016 07:55:06 +0000 Subject: [PATCH 3/3] Updated since parameter for imported_issues --- github3/repos/repo.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 01689ff1a..d94486cec 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1289,9 +1289,10 @@ def imported_issues(self, number=-1, since=None, etag=None): :param int number: (optional), number of imported issues to return. Default: -1 returns all branches - :param since: (optional), Only commits after this date will - be returned. This can be a ``datetime`` or an ``ISO8601`` formatted - date string. + :param since: (optional), Only imported issues after this date will + be returned. This can be a ``datetime`` instance, ISO8601 + formatted date string, or a string formatted like so: + ``2016-02-04`` i.e. ``%Y-%m-%d`` :param str etag: (optional), ETag from a previous request to the same endpoint :returns: generator of :class:`ImportedIssue