Merge ~nacc/git-ubuntu:gu-review into git-ubuntu:master

Proposed by Nish Aravamudan
Status: Merged
Approved by: Nish Aravamudan
Approved revision: 5c40be68759223bb4cae3c4b2eada937f684af2d
Merged at revision: a066105299c91a3aae098ea601eb82ddbc5529ca
Proposed branch: ~nacc/git-ubuntu:gu-review
Merge into: git-ubuntu:master
Prerequisite: ~nacc/git-ubuntu:bugfixes-after-refactor
Diff against target: 912 lines (+282/-77)
14 files modified
gitubuntu/__main__.py (+3/-1)
gitubuntu/build.py (+14/-7)
gitubuntu/buildsource.py (+1/-1)
gitubuntu/clone.py (+8/-5)
gitubuntu/importer.py (+34/-21)
gitubuntu/importlocal.py (+8/-6)
gitubuntu/importppa.py (+5/-3)
gitubuntu/lint.py (+7/-5)
gitubuntu/merge.py (+15/-11)
gitubuntu/queue.py (+4/-2)
gitubuntu/remote.py (+9/-3)
gitubuntu/review.py (+156/-0)
gitubuntu/submit.py (+12/-8)
gitubuntu/tag.py (+6/-4)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Andreas Hasenack Approve
Robie Basak Pending
Review via email: mp+330615@code.launchpad.net

This proposal supersedes a proposal from 2017-09-08.

Description of the change

This is probably not perfect, but it's basically (right now) just a wrapper around other commands, after the refactoring to call into them directly without the shell.

Bikesheddable.

Updated to reuse existing repo unless --clone is passed.

To post a comment you must log in.
Revision history for this message
Robie Basak (racb) : Posted in a previous version of this proposal
review: Needs Fixing
Revision history for this message
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:e0831bb2864a48129d9143f1b0e32831634101e8
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/26/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Tests
    FAILED: Build

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/26/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:ad8c802eddc58f40d22c304e5ad3468a2ebf1ce5
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/39/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Style Check

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/39/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:ad8c802eddc58f40d22c304e5ad3468a2ebf1ce5
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/43/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    FAILED: Integration Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/43/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:d672a163d7eb95e7385049daa1da11bdd777205a
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/56/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    SUCCESS: Integration Tests
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/56/rebuild

review: Approve (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:1b6612100ceab79c8fefded7075d3beb263f6bb1
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/60/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    SUCCESS: Integration Tests
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/60/rebuild

review: Approve (continuous-integration)
Revision history for this message
Andreas Hasenack (ahasenack) wrote : Posted in a previous version of this proposal

A few comments inline, just one needs-fixing really. The other one about making it work with an existing local repository is future work I think, for another branch.

There is no outstanding merge MP, so I tried running this review command against an open MP that is not a debian merge (cpaelzer's libvirt one) and also against an already-merged MP of mine (samba take 4), and got crashes in both cases. I understand this is somewhat work-in-progress, being the first new command to take advantage of the latest refactoring that is about to land. But I wonder: what do you think about having a way to hide these wip commands from --help?

review: Needs Fixing
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Got an error feeding it itself :) :
$ bin/git-ubuntu review https://code.launchpad.net/~nacc/usd-importer/+git/usd-importer/+merge/330615
Traceback (most recent call last):
  File "bin/git-ubuntu", line 22, in <module>
    main()
  File "/home/andreas/git/projects/usd-importer/gitubuntu/__main__.py", line 225, in main
    args.func(args)
  File "/home/andreas/git/projects/usd-importer/gitubuntu/review.py", line 61, in cli_main
    args.add_comment,
  File "/home/andreas/git/projects/usd-importer/gitubuntu/review.py", line 78, in main
    idx = target_url.index('~')
ValueError: substring not found

At that point, target_url is:
(Pdb) p target_url
'https://git.launchpad.net/usd-importer'

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Thanks for this. I have a few comments inline. Some can spawn new bugs and branches, others are suggestions/questions, and very few need a fix.

review: Needs Fixing
Revision history for this message
Nish Aravamudan (nacc) wrote :
Download full text (3.2 KiB)

On Tue, Sep 12, 2017 at 1:47 PM, Andreas Hasenack <email address hidden> wrote:
> Got an error feeding it itself :) :
> $ bin/git-ubuntu review https://code.launchpad.net/~nacc/usd-importer/+git/usd-importer/+merge/330615
> Traceback (most recent call last):
> File "bin/git-ubuntu", line 22, in <module>
> main()
> File "/home/andreas/git/projects/usd-importer/gitubuntu/__main__.py", line 225, in main
> args.func(args)
> File "/home/andreas/git/projects/usd-importer/gitubuntu/review.py", line 61, in cli_main
> args.add_comment,
> File "/home/andreas/git/projects/usd-importer/gitubuntu/review.py", line 78, in main
> idx = target_url.index('~')
> ValueError: substring not found
>
> At that point, target_url is:
> (Pdb) p target_url
> 'https://git.launchpad.net/usd-importer'

I'll add more safeguarding on the input.

>
> Diff comments:
>
>> diff --git a/gitubuntu/review.py b/gitubuntu/review.py
>> new file mode 100644
>> index 0000000..0acdbd3
>> --- /dev/null
>> +++ b/gitubuntu/review.py
>> @@ -0,0 +1,140 @@
>> +import argparse
>> +from contextlib import redirect_stdout
>> +import io
>> +import logging
>> +import os
>> +import shutil
>> +import sys
>> +import tempfile
>> +import urllib.parse
>> +import gitubuntu.clone
>> +import gitubuntu.lint
>> +from gitubuntu.__main__ import top_level_defaults
>> +from gitubuntu.git_repository import (
>> + GitUbuntuRepository,
>> + GitUbuntuRepositoryFetchError,
>> +)
>> +from gitubuntu.source_information import launchpad_login_auth
>> +
>> +
>> +def parse_args(subparsers=None, base_subparsers=None):
>> + kwargs = dict(
>> + description="Given a Launchpad MP URL, perform a review (EXPERIMENTAL)",
>> + formatter_class=argparse.RawTextHelpFormatter,
>> + epilog="An exit code of 0 indicates all checks passed",
>> + )
>> + if base_subparsers:
>> + kwargs["parents"] = base_subparsers
>> + if subparsers:
>> + parser = subparsers.add_parser("review", **kwargs)
>> + parser.set_defaults(func=cli_main)
>> + else:
>> + parser = argparse.ArgumentParser(**kwargs)
>> +
>> + parser.add_argument(
>> + "url",
>> + type=str,
>> + help="Full URL of Launchpad Merge Proposal to review",
>> + )
>> + parser.add_argument(
>> + '--clone',
>> + action='store_true',
>> + help="Create a new local repository by cloning, rather than "
>> + "using the repository at the current directory.",
>> + )
>> + parser.add_argument(
>> + '--add-comment',
>> + action='store_true',
>> + help="Add a comment to the MP with the lint results. "
>> + "This may also change the review state",
>> + )
>> +
>> + if not subparsers:
>> + return parser.parse_args()
>> + return "review - %s" % kwargs["description"]
>> +
>> +
>> +def cli_main(args):
>> + main(
>> + args.clone,
>> + args.url,
>> + args.add_comment,
>> + )
>> +
>> +def main(clone, url, add_comment):
>> + """Entry point to review
>> +
>> + Arguments:
>> + @clone: boolean to indicate a new repository should be cloned.
>
> "boolean to indicate *if* a new repos...

Read more...

Revision history for this message
Nish Aravamudan (nacc) wrote :
Download full text (7.3 KiB)

On Tue, Sep 12, 2017 at 2:20 PM, Andreas Hasenack <email address hidden> wrote:
> Review: Needs Fixing
>
> Thanks for this. I have a few comments inline. Some can spawn new bugs and branches, others are suggestions/questions, and very few need a fix.

Ok.

> Diff comments:
>
>> diff --git a/gitubuntu/review.py b/gitubuntu/review.py
>> new file mode 100644
>> index 0000000..0acdbd3
>> --- /dev/null
>> +++ b/gitubuntu/review.py
>> @@ -0,0 +1,140 @@
>> +import argparse
>> +from contextlib import redirect_stdout
>> +import io
>> +import logging
>> +import os
>> +import shutil
>> +import sys
>> +import tempfile
>> +import urllib.parse
>> +import gitubuntu.clone
>> +import gitubuntu.lint
>> +from gitubuntu.__main__ import top_level_defaults
>> +from gitubuntu.git_repository import (
>> + GitUbuntuRepository,
>> + GitUbuntuRepositoryFetchError,
>> +)
>> +from gitubuntu.source_information import launchpad_login_auth
>> +
>> +
>> +def parse_args(subparsers=None, base_subparsers=None):
>> + kwargs = dict(
>> + description="Given a Launchpad MP URL, perform a review (EXPERIMENTAL)",
>> + formatter_class=argparse.RawTextHelpFormatter,
>> + epilog="An exit code of 0 indicates all checks passed",
>> + )
>> + if base_subparsers:
>> + kwargs["parents"] = base_subparsers
>> + if subparsers:
>> + parser = subparsers.add_parser("review", **kwargs)
>> + parser.set_defaults(func=cli_main)
>> + else:
>> + parser = argparse.ArgumentParser(**kwargs)
>> +
>> + parser.add_argument(
>> + "url",
>> + type=str,
>> + help="Full URL of Launchpad Merge Proposal to review",
>> + )
>> + parser.add_argument(
>> + '--clone',
>> + action='store_true',
>> + help="Create a new local repository by cloning, rather than "
>> + "using the repository at the current directory.",
>> + )
>
> What do you think about --clone be the default? The most common scenario I think is to call the tool like this: "git ubuntu review <url>", which should just work. In other words, we would then have an option like --repository-path which you would give to point at an existing copy of the repository that contains the branch you want to review. This path would then be given to GitUbuntuRepository() later.

I was asked for the opposite in the discussion with Robie in a different bug.

I think the most common case is already having a repository setup if
you are using `git ubuntu review` (because you earlier worked on it).
We'll fetch/update the local repo and then do a lint.

But that's bikesheddable and can be a feature request. I don't feel
strongly either way.

>> + parser.add_argument(
>> + '--add-comment',
>> + action='store_true',
>> + help="Add a comment to the MP with the lint results. "
>> + "This may also change the review state",
>> + )
>> +
>> + if not subparsers:
>> + return parser.parse_args()
>> + return "review - %s" % kwargs["description"]
>> +
>> +
>> +def cli_main(args):
>> + main(
>> + args.clone,
>> + args.url,
>> + args.add_comment,
>> + )
>> +
>> +def main(clone, url, add...

Read more...

Revision history for this message
Nish Aravamudan (nacc) wrote :
Download full text (7.8 KiB)

On Tue, Sep 12, 2017 at 2:45 PM, Nish Aravamudan
<email address hidden> wrote:
> On Tue, Sep 12, 2017 at 2:20 PM, Andreas Hasenack <email address hidden> wrote:
>> Review: Needs Fixing
>>
>> Thanks for this. I have a few comments inline. Some can spawn new bugs and branches, others are suggestions/questions, and very few need a fix.
>
> Ok.
>
>> Diff comments:
>>
>>> diff --git a/gitubuntu/review.py b/gitubuntu/review.py
>>> new file mode 100644
>>> index 0000000..0acdbd3
>>> --- /dev/null
>>> +++ b/gitubuntu/review.py
>>> @@ -0,0 +1,140 @@
>>> +import argparse
>>> +from contextlib import redirect_stdout
>>> +import io
>>> +import logging
>>> +import os
>>> +import shutil
>>> +import sys
>>> +import tempfile
>>> +import urllib.parse
>>> +import gitubuntu.clone
>>> +import gitubuntu.lint
>>> +from gitubuntu.__main__ import top_level_defaults
>>> +from gitubuntu.git_repository import (
>>> + GitUbuntuRepository,
>>> + GitUbuntuRepositoryFetchError,
>>> +)
>>> +from gitubuntu.source_information import launchpad_login_auth
>>> +
>>> +
>>> +def parse_args(subparsers=None, base_subparsers=None):
>>> + kwargs = dict(
>>> + description="Given a Launchpad MP URL, perform a review (EXPERIMENTAL)",
>>> + formatter_class=argparse.RawTextHelpFormatter,
>>> + epilog="An exit code of 0 indicates all checks passed",
>>> + )
>>> + if base_subparsers:
>>> + kwargs["parents"] = base_subparsers
>>> + if subparsers:
>>> + parser = subparsers.add_parser("review", **kwargs)
>>> + parser.set_defaults(func=cli_main)
>>> + else:
>>> + parser = argparse.ArgumentParser(**kwargs)
>>> +
>>> + parser.add_argument(
>>> + "url",
>>> + type=str,
>>> + help="Full URL of Launchpad Merge Proposal to review",
>>> + )
>>> + parser.add_argument(
>>> + '--clone',
>>> + action='store_true',
>>> + help="Create a new local repository by cloning, rather than "
>>> + "using the repository at the current directory.",
>>> + )
>>
>> What do you think about --clone be the default? The most common scenario I think is to call the tool like this: "git ubuntu review <url>", which should just work. In other words, we would then have an option like --repository-path which you would give to point at an existing copy of the repository that contains the branch you want to review. This path would then be given to GitUbuntuRepository() later.
>
> I was asked for the opposite in the discussion with Robie in a different bug.
>
> I think the most common case is already having a repository setup if
> you are using `git ubuntu review` (because you earlier worked on it).
> We'll fetch/update the local repo and then do a lint.
>
> But that's bikesheddable and can be a feature request. I don't feel
> strongly either way.
>
>>> + parser.add_argument(
>>> + '--add-comment',
>>> + action='store_true',
>>> + help="Add a comment to the MP with the lint results. "
>>> + "This may also change the review state",
>>> + )
>>> +
>>> + if not subparsers:
>>> + return parser.parse_args()
>>> + return "review - %s" % kwargs["desc...

Read more...

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:78e9c717fd022d15decd566682c9963e5a320b20
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/64/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    FAILED: Unit Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/64/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:7b83eede9bddb160cdd6d38af08a1ffdad27b561
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/66/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    FAILED: Unit Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/66/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:85d4ccab06ed7720957ccbbc3a8eaa62ae240523
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/68/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Style Check

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/68/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:5ba6d95d2a8d35b543b6607bccbef25bdea3f53d
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/70/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    FAILED: Integration Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/70/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:4ca0b55715e465bfdf80a94afc468ec0abfa7181
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/72/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    SUCCESS: Integration Tests
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/72/rebuild

review: Approve (continuous-integration)
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

> >> Also, we should exit with e.code here, which is the linter exit status.
>
> Actually, hrm, I disagree with this last bit. The review subcommand
> succeeded even if the lint fails. That is, I'm not sure we would be
> able to distinguish a review iunternal error from a failed lint.

I raised this because you explicitly say this at the top;

        epilog="An exit code of 0 indicates all checks passed",

Conversely, if a check failed, it should return non-zero.

Revision history for this message
Nish Aravamudan (nacc) wrote :

On Wed, Sep 13, 2017 at 7:54 AM, Andreas Hasenack <email address hidden> wrote:
>> >> Also, we should exit with e.code here, which is the linter exit status.
>>
>> Actually, hrm, I disagree with this last bit. The review subcommand
>> succeeded even if the lint fails. That is, I'm not sure we would be
>> able to distinguish a review iunternal error from a failed lint.
>
> I raised this because you explicitly say this at the top;
>
> epilog="An exit code of 0 indicates all checks passed",
>
> Conversely, if a check failed, it should return non-zero.

C&P from lint.py :) Will drop.

~nacc/git-ubuntu:gu-review updated
1ff031b... by Nish Aravamudan

review: drop epilog from subparser

Will be squashed.

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:1ff031bbc995bd9403a2321ac6f3ec31269c8ef3
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/76/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    SUCCESS: Integration Tests
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/76/rebuild

review: Approve (continuous-integration)
~nacc/git-ubuntu:gu-review updated
d1f6a0c... by Nish Aravamudan

review: return main from cli_main

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

We can drop the sys import now in gitubuntu/review.py, and in other modules too:

$ pyflakes3 gitubuntu/|grep sys
gitubuntu/merge.py:7: 'sys' imported but unused
gitubuntu/buildsource.py:7: 'sys' imported but unused
gitubuntu/queue.py:6: 'sys' imported but unused
gitubuntu/tag.py:4: 'sys' imported but unused
gitubuntu/remote.py:7: 'sys' imported but unused
gitubuntu/review.py:7: 'sys' imported but unused

pyflakes3 actually shows many more unused modules, but let's leave that cleanup for another branch.

=1

review: Approve
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

er, I meant +1 :)

~nacc/git-ubuntu:gu-review updated
5c40be6... by Nish Aravamudan

review: drop unused sys

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:d1f6a0c52e201883798f75020305e7e89ca67f2d
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/77/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    SUCCESS: Integration Tests
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/77/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/gitubuntu/__main__.py b/gitubuntu/__main__.py
2index 5c79265..78acc15 100644
3--- a/gitubuntu/__main__.py
4+++ b/gitubuntu/__main__.py
5@@ -69,6 +69,7 @@ def main():
6 'remote': 'gitubuntu.remote',
7 'submit': 'gitubuntu.submit',
8 'lint': 'gitubuntu.lint',
9+ 'review': 'gitubuntu.review',
10 }
11
12 known_network_subcommands = {
13@@ -81,6 +82,7 @@ def main():
14 'queue',
15 'remote',
16 'submit',
17+ 'review',
18 }
19
20 parser = argparse.ArgumentParser(
21@@ -223,7 +225,7 @@ def main():
22 )
23 sys.exit(1)
24
25- args.func(args)
26+ sys.exit(args.func(args))
27 except KeyboardInterrupt:
28 sys.stderr.write('User abort\n')
29 sys.exit(130)
30diff --git a/gitubuntu/build.py b/gitubuntu/build.py
31index d3d292e..d78d5b5 100644
32--- a/gitubuntu/build.py
33+++ b/gitubuntu/build.py
34@@ -377,21 +377,23 @@ def check_repository():
35 cp = run(['git', 'status', '--porcelain'])
36 except CalledProcessError:
37 logging.error('Is the current directory a git repository?')
38- sys.exit(1)
39+ return False
40
41 if len(cp.stdout) > 0:
42 logging.warning(
43 "Working tree is not clean. `git status` output follows."
44 )
45 run(['git', 'status'], stdout=None)
46- sys.exit(1)
47+ return False
48
49 if not os.path.isfile('debian/changelog'):
50 logging.error(
51 "No debian/changelog found, is this a source "
52 "package repository? See `git ubuntu clone`."
53 )
54- sys.exit(1)
55+ return False
56+
57+ return True
58
59
60 def main(search_list, changelog, rem_args):
61@@ -400,10 +402,13 @@ def main(search_list, changelog, rem_args):
62 @param search_list: list of OrigSearchListEntry namedtuples
63 @param changelog: gitubuntu.git_repository.Changelog object for source package to build
64 @param rem_args: namespace object of remaining arguments to pass onto dpkg-buildpackage
65+
66+ Returns 0 if the build succeeds, 1 otherwise.
67 """
68- check_repository()
69+ if not check_repository():
70+ return 1
71
72- fetch_orig_and_build(search_list, changelog, rem_args)
73+ return fetch_orig_and_build(search_list, changelog, rem_args)
74
75
76 def parse_args(subparsers=None, base_subparsers=None):
77@@ -502,7 +507,7 @@ def cli_main(args):
78 native = is_native_package(changelog)
79 except NativenessMismatchError as e:
80 logging.error("%s" % e)
81- sys.exit(1)
82+ return 1
83
84 if native:
85 # No orig tarball required
86@@ -517,7 +522,7 @@ def cli_main(args):
87 orig_search_list = derive_orig_search_list_from_args(args)
88
89 # See http://pad.ubuntu.com/KKB1kMR0JH for logic
90- main(orig_search_list, changelog, rem_args)
91+ return main(orig_search_list, changelog, rem_args)
92
93
94 def derive_source_from_changelog(changelog):
95@@ -589,6 +594,8 @@ def fetch_orig_and_build(orig_search_list, changelog, rem_args=[]):
96 "but none produced a successful build."
97 )
98
99+ return 0
100+
101
102 class NativenessMismatchError(Exception): pass
103
104diff --git a/gitubuntu/buildsource.py b/gitubuntu/buildsource.py
105index 1735129..6f02bf0 100644
106--- a/gitubuntu/buildsource.py
107+++ b/gitubuntu/buildsource.py
108@@ -63,4 +63,4 @@ def cli_main(args):
109 args.rem_args += ['-sa']
110 if not args.sign:
111 args.rem_args += ['-us', '-uc']
112- build_cli_main(args)
113+ return build_cli_main(args)
114diff --git a/gitubuntu/clone.py b/gitubuntu/clone.py
115index c4d8dbd..ada365e 100644
116--- a/gitubuntu/clone.py
117+++ b/gitubuntu/clone.py
118@@ -50,7 +50,8 @@ def main(
119 If lp_user is None, value of `git config gitubuntu.lpuser` will be
120 used.
121
122- Returns the resulting GitUbuntuRepository object
123+ Returns the resulting GitUbuntuRepository object, if successful;
124+ None otherwise.
125 """
126 directory = (
127 os.path.abspath(directory)
128@@ -59,7 +60,7 @@ def main(
129 )
130 if os.path.isdir(directory):
131 logging.error('directory %s exists' % directory)
132- sys.exit(1)
133+ return None
134
135 local_repo = GitUbuntuRepository(
136 local_dir=directory,
137@@ -82,7 +83,7 @@ def main(
138 package
139 )
140 shutil.rmtree(local_repo.local_dir)
141- raise
142+ return None
143
144 try:
145 local_repo.add_lpuser_remote(pkgname=package)
146@@ -157,12 +158,14 @@ def cli_main(args):
147 except AttributeError:
148 lp_user = None
149
150- main(
151+ if main(
152 package=args.package,
153 directory=args.directory,
154 lp_user=lp_user,
155 proto=args.proto,
156- )
157+ ) is not None:
158+ return 0
159+ return 1
160
161
162 # vi: ts=4 expandtab
163diff --git a/gitubuntu/importer.py b/gitubuntu/importer.py
164index 6311047..6c84e50 100644
165--- a/gitubuntu/importer.py
166+++ b/gitubuntu/importer.py
167@@ -78,6 +78,10 @@ class GitUbuntuImportOrigError(GitUbuntuImportError):
168 pass
169
170
171+class ParentOverrideError(GitUbuntuImportError):
172+ pass
173+
174+
175 def dsc_to_tree_hash(repo, dsc_path):
176 '''Convert a dsc file into a git tree in the given repo
177
178@@ -179,6 +183,9 @@ def main(
179
180 If dl_cache is None, CACHE_PATH in the local repository will be
181 used.
182+
183+ Returns 0 on successful import (which includes non-fatal failures);
184+ 1 otherwise.
185 """
186 if owner == 'usd-import-team':
187 namespace = 'importer'
188@@ -327,7 +334,7 @@ def main(
189 if not history_found:
190 logging.error("No publication history for '%s' in debian or ubuntu. "
191 "Wrong source package name?", pkgname)
192- sys.exit(1)
193+ return 1
194
195 if not skip_applied:
196 import_publishes(
197@@ -400,6 +407,8 @@ def main(
198 time.sleep(retry_backoffs[i])
199 lp_git_repo.lp_refresh()
200
201+ return 0
202+
203
204 def get_changelog_for_commit(
205 repo,
206@@ -911,14 +920,13 @@ def override_parents(repo, spi, namespace):
207 'specified in override file.'
208 )
209 else:
210- logging.error('Specified publish parent override '
211- '(%s) for version (%s) not found in tags. '
212- 'Unable to proceed.' % (
213- _PARENT_OVERRIDES[spi.version]['publish_parent'],
214- spi.version
215- )
216- )
217- sys.exit(1)
218+ raise ParentOverrideError(
219+ "Specified publish parent override (%s) for version (%s) "
220+ "not found in tags. Unable to proceed." % (
221+ _PARENT_OVERRIDES[spi.version]['publish_parent'],
222+ spi.version
223+ )
224+ )
225
226 unapplied_changelog_parent_tag = repo.get_import_tag(
227 _PARENT_OVERRIDES[spi.version]['changelog_parent'],
228@@ -957,12 +965,13 @@ def override_parents(repo, spi, namespace):
229 'in override file.'
230 )
231 else:
232- logging.error('Specified changelog parent override (%s) '
233- 'for version (%s) not found in tags. Unable to proceed.',
234- _PARENT_OVERRIDES[spi.version]['changelog_parent'],
235- spi.version
236+ raise ParentOverrideError(
237+ "Specified changelog parent override (%s) for version "
238+ "(%s) not found in tags. Unable to proceed." % (
239+ _PARENT_OVERRIDES[spi.version]['changelog_parent'],
240+ spi.version,
241+ )
242 )
243- sys.exit(1)
244 return (
245 unapplied_publish_parent_commit,
246 unapplied_changelog_parent_commit,
247@@ -1159,12 +1168,16 @@ def import_unapplied_spi(repo, spi, namespace, skip_orig, ubuntu_sinfo):
248 spi.version
249 )
250
251- (
252- unapplied_publish_parent_commit,
253- unapplied_changelog_parent_commit,
254- _,
255- _
256- ) = override_parents(repo, spi, namespace)
257+ try:
258+ (
259+ unapplied_publish_parent_commit,
260+ unapplied_changelog_parent_commit,
261+ _,
262+ _
263+ ) = override_parents(repo, spi, namespace)
264+ except ParentOverrideError as e:
265+ logging.error("%s" % e)
266+ return 1
267 else:
268 # Get parent from publishing history (which is the last
269 # published version in the corresponding series)
270@@ -1601,7 +1614,7 @@ def cli_main(args):
271 except AttributeError:
272 dl_cache = None
273
274- main(
275+ return main(
276 pkgname=args.package,
277 owner=args.lp_owner,
278 no_clean=no_clean,
279diff --git a/gitubuntu/importlocal.py b/gitubuntu/importlocal.py
280index c237551..1f5b51d 100644
281--- a/gitubuntu/importlocal.py
282+++ b/gitubuntu/importlocal.py
283@@ -43,7 +43,7 @@ def main(
284 if len(repo.raw_repo.status()) != 0:
285 logging.error('Working tree must be clean to continue.')
286 run(['git', 'status'], stdout=None)
287- sys.exit(1)
288+ return 1
289
290 if os.path.exists(dsc_path):
291 dsc_path = os.path.abspath(dsc_path)
292@@ -58,10 +58,10 @@ def main(
293 dscs = glob.glob(os.path.join(dsc_dir, '*.dsc'))
294 if len(dscs) == 0:
295 logging.error('Unable to obtain DSC file.')
296- sys.exit(1)
297+ return 1
298 if len(dscs) > 1:
299 logging.error('Multiple DSCs found in temporary directory.')
300- sys.exit(1)
301+ return 1
302 dsc_path = os.path.join(dsc_dir, dscs[0])
303 os.chdir(oldcwd)
304 logging.debug('Importing DSC at local path %s', dsc_path)
305@@ -71,7 +71,7 @@ def main(
306 'Unable to verify orig tarball specified by DSC %s',
307 dsc_path,
308 )
309- sys.exit(1)
310+ return 1
311
312 pkgname = dsc['Source']
313
314@@ -180,7 +180,7 @@ def main(
315 logging.error('Unable to import orig tarball for %s: %s',
316 changelog_version, e)
317 raise
318- sys.exit(1)
319+ return 1
320
321 msg = (
322 b'Import unapplied version %b\n\nImported using git-ubuntu-import.' %
323@@ -283,6 +283,8 @@ def main(
324
325 repo.garbage_collect()
326
327+ return 0
328+
329 def parse_args(subparsers=None, base_subparsers=None):
330 kwargs = dict(description='Import a DSC file locally',
331 #usage='%(prog)s [options] -- ...',
332@@ -325,7 +327,7 @@ def cli_main(args):
333 except AttributeError:
334 directory = None
335
336- main(
337+ return main(
338 directory,
339 args.namespace,
340 args.dsc,
341diff --git a/gitubuntu/importppa.py b/gitubuntu/importppa.py
342index da57f53..d5dcb96 100644
343--- a/gitubuntu/importppa.py
344+++ b/gitubuntu/importppa.py
345@@ -60,7 +60,7 @@ def main(
346 "Specified PPA (%s) is not in the format ppa:<name>",
347 ppa,
348 )
349- sys.exit(1)
350+ return 1
351 # what other transformations?
352 namespace = ppa.replace(':', '_')
353
354@@ -148,7 +148,7 @@ def main(
355 pkgname,
356 ppa,
357 )
358- sys.exit(1)
359+ return 1
360
361 try:
362 for srcpkg_information in \
363@@ -179,6 +179,8 @@ def main(
364
365 repo.garbage_collect()
366
367+ return 0
368+
369
370 def parse_args(subparsers=None, base_subparsers=None):
371 kwargs = dict(description='Update a launchpad git tree based upon '
372@@ -238,7 +240,7 @@ def cli_main(args):
373 except AttributeError:
374 dl_cache = None
375
376- main(
377+ return main(
378 args.ppa,
379 args.package,
380 directory,
381diff --git a/gitubuntu/lint.py b/gitubuntu/lint.py
382index ac503b9..2e03ff2 100644
383--- a/gitubuntu/lint.py
384+++ b/gitubuntu/lint.py
385@@ -203,7 +203,7 @@ def parse_args(subparsers=None, base_subparsers=None):
386
387 def cli_main(args):
388 repo = GitUbuntuRepository(args.directory)
389- do_lint(
390+ return do_lint(
391 repo,
392 args.commitish,
393 args.lint_namespace,
394@@ -724,6 +724,8 @@ def do_lint(
395 branch.
396
397 If lint_namespace is None, it will be derived from @commitish.
398+
399+ Returns 0 if the lint succeeds; 1 otherwise.
400 """
401 global _verbose
402 _verbose = verbose
403@@ -736,7 +738,7 @@ def do_lint(
404 logging.error("%s is not a defined object in this git "
405 "repository: %s", commitish, e
406 )
407- sys.exit(1)
408+ return 1
409 else:
410 commitish_obj = repo.raw_repo.head
411 if repo.raw_repo.head_is_detached:
412@@ -750,7 +752,7 @@ def do_lint(
413 logging.error("HEAD is not detached, but unable to "
414 "determine what local branch HEAD points to."
415 )
416- sys.exit(1)
417+ return 1
418 commitish_id = str(commitish_obj.id)
419
420 if lint_namespace is None:
421@@ -787,7 +789,7 @@ def do_lint(
422
423 if lint_pass:
424 print("All lint checks passed")
425- sys.exit(0)
426+ return 0
427 else:
428 print("Some lint checks failed. Please investigate.")
429- sys.exit(1)
430+ return 1
431diff --git a/gitubuntu/merge.py b/gitubuntu/merge.py
432index cc16cc0..3baa748 100644
433--- a/gitubuntu/merge.py
434+++ b/gitubuntu/merge.py
435@@ -97,7 +97,7 @@ def parse_args(subparsers=None, base_subparsers=None):
436 return 'merge - %s' % kwargs['description']
437
438 def cli_main(args):
439- main(
440+ return main(
441 directory=args.directory,
442 commitish=args.commitish,
443 onto=args.onto,
444@@ -175,8 +175,9 @@ def do_start(repo, tag_prefix, commitish, merge_base_id, onto, force, tag_only):
445 do_tag(repo, tag_prefix, commitish, merge_base_id, onto, force)
446 if not tag_only:
447 do_reconstruct(repo, tag_prefix, commitish, merge_base_id, force)
448+ return 0
449 except (TagException, ReconstructException):
450- sys.exit(1)
451+ return 1
452
453 def do_merge_changelogs(repo, commitish, merge_base_id, onto):
454 # save merge_base_id:debian/changelog to tmp file
455@@ -329,7 +330,7 @@ def do_finish(repo, tag_prefix, commitish, merge_base_id, onto, release, bug, fo
456 "start` first? (Pass -f to force the merge).",
457 msg
458 )
459- sys.exit(1)
460+ return 1
461
462 # 1) git merge-changelogs old/ubuntu old/debian new/debian
463 do_merge_changelogs(repo, commitish, merge_base_id, onto)
464@@ -339,6 +340,7 @@ def do_finish(repo, tag_prefix, commitish, merge_base_id, onto, release, bug, fo
465 # (add flag to specify it?)
466 # 3) update-maintainer
467 do_update_maintainer(repo)
468+ return 0
469
470
471 def main(
472@@ -363,6 +365,8 @@ def main(
473 @bug: string bug number closed by this merge
474 @release: string Ubuntu release to target this merge to
475 @subcommand: string merge stage to run, one of 'start' or 'finish'
476+
477+ Returns 0 if the subcommand completes successfully; 1 otherwise.
478 """
479 repo = GitUbuntuRepository(directory)
480 tag_prefix = ''
481@@ -376,7 +380,7 @@ def main(
482 "%s is not a defined object in this git repository.",
483 commitish
484 )
485- sys.exit(1)
486+ return 1
487
488 commitish_version, _ = repo.get_changelog_versions_from_treeish(
489 str(commitish_obj.id),
490@@ -405,7 +409,7 @@ def main(
491 onto,
492 onto_version,
493 )
494- sys.exit(1)
495+ return 1
496 except KeyError:
497 logging.info("%s is not a defined object in this git repository.", onto)
498 logging.info(
499@@ -425,14 +429,14 @@ def main(
500 "Does it already exist (pass -f)?",
501 onto,
502 )
503- sys.exit(1)
504+ return 1
505 onto_obj = repo.get_commitish(onto)
506
507 cp = run(['git', 'status', '--porcelain'])
508 if len(cp.stdout) > 0:
509 logging.error('Working tree must be clean to continue:')
510 logging.error(decode_binary(cp.stdout))
511- sys.exit(1)
512+ return 1
513
514 merge_base_id = repo.raw_repo.merge_base(
515 onto_obj.id,
516@@ -444,7 +448,7 @@ def main(
517 onto,
518 commitish,
519 )
520- sys.exit(1)
521+ return 1
522
523 if merge_base_id == onto_obj.id:
524 logging.error(
525@@ -454,7 +458,7 @@ def main(
526 commitish,
527 onto,
528 )
529- sys.exit(1)
530+ return 1
531
532 merge_base_id = str(merge_base_id)
533 merge_base_version, _ = repo.get_changelog_versions_from_treeish(
534@@ -462,7 +466,7 @@ def main(
535 )
536
537 if subcommand == 'start':
538- do_start(
539+ return do_start(
540 repo,
541 tag_prefix,
542 commitish,
543@@ -472,7 +476,7 @@ def main(
544 tag_only,
545 )
546 elif subcommand == 'finish':
547- do_finish(
548+ return do_finish(
549 repo,
550 tag_prefix,
551 commitish,
552diff --git a/gitubuntu/queue.py b/gitubuntu/queue.py
553index 0cd0b44..1ff4d12 100644
554--- a/gitubuntu/queue.py
555+++ b/gitubuntu/queue.py
556@@ -108,7 +108,7 @@ def parse_args(subparsers=None, base_subparsers=None):
557 return 'queue - %s' % kwargs['description']
558
559 def cli_main(args):
560- main(
561+ return main(
562 args.directory,
563 args.subsubcommand,
564 args.fetch if args.subsubcommand == 'sync' else None,
565@@ -328,7 +328,7 @@ def main(
566 repo.fetch_base_remotes()
567 except GitUbuntuRepositoryFetchError:
568 logging.error('No objects found in remote pkg')
569- sys.exit(1)
570+ return 1
571
572 sync(
573 repo,
574@@ -345,3 +345,5 @@ def main(
575 # elif args.subsubcommand == 'reject':
576 elif subsubcommand == 'clean':
577 clean(repo)
578+
579+ return 0
580diff --git a/gitubuntu/remote.py b/gitubuntu/remote.py
581index db42168..b874737 100644
582--- a/gitubuntu/remote.py
583+++ b/gitubuntu/remote.py
584@@ -63,7 +63,7 @@ def cli_main(args):
585 else:
586 directory = os.getcwd()
587
588- main(
589+ return main(
590 args.subsubcommand,
591 args.user,
592 args.package,
593@@ -111,6 +111,8 @@ def do_add(repo, package, user, url=None, remote_name=None, no_fetch=False):
594 repo.raw_repo.remotes[remote_name].url,
595 )
596
597+ return 0
598+
599 def main(
600 subcommand,
601 user,
602@@ -140,6 +142,8 @@ def main(
603 If directory is None, the current directory is used.
604
605 If remote_name is None, the remote will be named @user.
606+
607+ Returns 0 if the subcommand succeeded; 1 otherwise.
608 """
609 if directory is None:
610 directory = os.path.abspath(os.getcwd())
611@@ -171,9 +175,11 @@ def main(
612 "Unable to determine source package name. Does "
613 "debian/changelog exist in the current branch?"
614 )
615- sys.exit(1)
616+ return 1
617
618 if subcommand == 'add':
619- do_add(repo, package, user, url, remote_name, no_fetch)
620+ return do_add(repo, package, user, url, remote_name, no_fetch)
621+
622+ return 1
623
624 # vi: ts=4 expandtab
625diff --git a/gitubuntu/review.py b/gitubuntu/review.py
626new file mode 100644
627index 0000000..8e252d5
628--- /dev/null
629+++ b/gitubuntu/review.py
630@@ -0,0 +1,156 @@
631+import argparse
632+from contextlib import redirect_stdout
633+import io
634+import logging
635+import os
636+import shutil
637+import tempfile
638+import urllib.parse
639+import gitubuntu.clone
640+import gitubuntu.lint
641+from gitubuntu.__main__ import top_level_defaults
642+from gitubuntu.git_repository import (
643+ GitUbuntuRepository,
644+ GitUbuntuRepositoryFetchError,
645+)
646+from gitubuntu.source_information import launchpad_login_auth
647+
648+
649+def parse_args(subparsers=None, base_subparsers=None):
650+ kwargs = dict(
651+ description="Given a Launchpad MP URL, perform a review (EXPERIMENTAL)",
652+ formatter_class=argparse.RawTextHelpFormatter,
653+ )
654+ if base_subparsers:
655+ kwargs["parents"] = base_subparsers
656+ if subparsers:
657+ parser = subparsers.add_parser("review", **kwargs)
658+ parser.set_defaults(func=cli_main)
659+ else:
660+ parser = argparse.ArgumentParser(**kwargs)
661+
662+ parser.add_argument(
663+ "url",
664+ type=str,
665+ help="Full URL of Launchpad Merge Proposal to review",
666+ )
667+ parser.add_argument(
668+ '--clone',
669+ action='store_true',
670+ help="Create a new local repository by cloning, rather than "
671+ "using the repository at the current directory.",
672+ )
673+ parser.add_argument(
674+ '--add-comment',
675+ action='store_true',
676+ help="Add a comment to the MP with the lint results. "
677+ "This may also change the review state",
678+ )
679+
680+ if not subparsers:
681+ return parser.parse_args()
682+ return "review - %s" % kwargs["description"]
683+
684+
685+def cli_main(args):
686+ return main(
687+ args.clone,
688+ args.url,
689+ args.add_comment,
690+ )
691+
692+def main(clone, url, add_comment):
693+ """Entry point to review
694+
695+ Arguments:
696+ @clone: if True, clone into a new local repository first.
697+ @url: string URL of MP to review
698+ @add_comment: if True, update the MP with the review results.
699+
700+ Returns 0 if the review completed successfully (this does not
701+ indicate the review resulted in an approval of the MP); 1 otherwise.
702+ """
703+ lp_path = urllib.parse.urlparse(url).path
704+ lp = launchpad_login_auth()
705+ mp = lp.load(lp_path)
706+ target_url = mp.target_git_repository.git_https_url
707+ target_branch = mp.target_git_path[len('refs/heads/'):]
708+ try:
709+ idx = target_url.index('~')
710+ target_user = target_url[idx+1:target_url.index('/', idx)]
711+ except ValueError:
712+ logging.error(
713+ "Unable to determine target user from %s",
714+ target_url,
715+ )
716+ return 1
717+ if target_user != 'usd-import-team':
718+ logging.error(
719+ "Performing arbitrary reviews is not yet supported (user %s "
720+ "specified).",
721+ target_user
722+ )
723+ return 1
724+
725+ source_url = mp.source_git_repository.git_https_url
726+ source_branch = mp.source_git_path[len('refs/heads/'):]
727+ try:
728+ idx = source_url.index('~')
729+ source_user = source_url[idx+1:source_url.index('/', idx)]
730+ except ValueError:
731+ logging.error(
732+ "Unable to determine source user from %s",
733+ source_url,
734+ )
735+ return 1
736+ srcpkg = target_url.split('/')[-1]
737+ if clone:
738+ repo = gitubuntu.clone.main(package=srcpkg)
739+ else:
740+ repo = GitUbuntuRepository('.')
741+ try:
742+ repo.fetch_base_remotes()
743+ except GitUbuntuRepositoryFetchError:
744+ return 1
745+ os.chdir(repo.local_dir)
746+ repo.add_remote(
747+ pkgname=srcpkg,
748+ repo_owner=source_user,
749+ remote_name=source_user,
750+ )
751+ try:
752+ repo.fetch_remote(remote_name=source_user)
753+ except GitUbuntuRepositoryFetchError:
754+ return 1
755+
756+ logging.info(
757+ "Linting merge of %s/%s into pkg/%s" % (
758+ source_user,
759+ source_branch,
760+ target_branch
761+ )
762+ )
763+ f = io.StringIO()
764+ with redirect_stdout(f):
765+ result = gitubuntu.lint.do_lint(
766+ repo=repo,
767+ commitish='%s/%s' % (source_user, source_branch),
768+ target_branch='pkg/%s' % target_branch,
769+ verbose=True,
770+ )
771+ lint_out = f.getvalue()
772+ logging.info('git ubuntu lint result:')
773+ print(lint_out, end='')
774+ if add_comment:
775+ if result == 0:
776+ vote='Approve'
777+ else:
778+ vote='Needs Fixing'
779+ logging.info("Adding a %s comment to the MP", vote)
780+ mp.createComment(
781+ content=lint_out,
782+ vote=vote,
783+ subject="Automated lint result",
784+ )
785+
786+ return 0
787diff --git a/gitubuntu/submit.py b/gitubuntu/submit.py
788index fb080f3..82267ad 100644
789--- a/gitubuntu/submit.py
790+++ b/gitubuntu/submit.py
791@@ -74,7 +74,7 @@ def cli_main(args):
792 except AttributeError:
793 user = None
794
795- main(
796+ return main(
797 directory=args.directory,
798 force=args.force,
799 target_user=args.target_user,
800@@ -116,6 +116,8 @@ def main(
801 used.
802
803 If branch is None, HEAD is used.
804+
805+ Returns 0 if the MP was created successfully; 1 otherwise.
806 """
807 repo = GitUbuntuRepository(directory, user, proto)
808
809@@ -129,7 +131,7 @@ def main(
810 else:
811 if repo.raw_repo.head_is_detached:
812 logging.error("Please create a local branch before submitting.")
813- sys.exit(1)
814+ return 1
815 source_branch = repo.raw_repo.head.name
816 commitish_string = 'HEAD'
817
818@@ -152,7 +154,7 @@ def main(
819 namespace,
820 )
821 if len(target_head_string) == 0:
822- sys.exit(1)
823+ return 1
824
825 logging.debug("target branch: %s", target_head_string)
826
827@@ -173,7 +175,7 @@ def main(
828 source_branch,
829 repo.lp_user,
830 )
831- sys.exit(1)
832+ return 1
833
834 lp = launchpad_login_auth()
835
836@@ -189,7 +191,7 @@ def main(
837 "Unable to find target repository (path=%s)",
838 path,
839 )
840- sys.exit(1)
841+ return 1
842
843 target_git_ref = target_git_repo.getRefByPath(
844 path='refs/heads/%s' % target_head_string
845@@ -209,7 +211,7 @@ def main(
846 "Unable to find source repository (path=%s)",
847 path,
848 )
849- sys.exit(1)
850+ return 1
851
852 source_git_ref = source_git_repo.getRefByPath(path=source_branch)
853 if source_git_ref == None:
854@@ -220,7 +222,7 @@ def main(
855 source_branch,
856 repo.lp_user,
857 )
858- sys.exit(1)
859+ return 1
860 logging.debug("Source git ref: %s", source_git_ref)
861
862 # create MP
863@@ -228,7 +230,7 @@ def main(
864 mp = source_git_ref.createMergeProposal(merge_target=target_git_ref)
865 except BadRequest as e:
866 logging.error("Unable to create merge proposal: %s", e)
867- sys.exit(1)
868+ return 1
869 # only take unique reviewers
870 for potential_reviewer in set(reviewers):
871 try:
872@@ -245,3 +247,5 @@ def main(
873 )
874 print("Your merge proposal is now available at: %s" % mp.web_link)
875 print("If it looks ok, please move it to the 'Needs Review' state.")
876+
877+ return 0
878diff --git a/gitubuntu/tag.py b/gitubuntu/tag.py
879index 99027c3..b11a658 100644
880--- a/gitubuntu/tag.py
881+++ b/gitubuntu/tag.py
882@@ -58,7 +58,7 @@ def parse_args(subparsers=None, base_subparsers=None):
883 return 'tag - %s' % kwargs['description']
884
885 def cli_main(args):
886- main(
887+ return main(
888 args.directory,
889 args.commitish,
890 args.force,
891@@ -122,11 +122,11 @@ def main(
892 "%s is not a defined object in this git repository.",
893 commitish
894 )
895- sys.exit(1)
896+ return 1
897
898 if len(repo.raw_repo.status()) != 0:
899 logging.error('Working tree must be clean to continue.')
900- sys.exit(1)
901+ return 1
902
903 version, _ = repo.get_changelog_versions_from_treeish(changelog_commitish)
904 dist = repo.get_changelog_distribution_from_treeish(changelog_commitish)
905@@ -146,4 +146,6 @@ def main(
906 msg,
907 )
908 except:
909- sys.exit(1)
910+ return 1
911+
912+ return 0

Subscribers

People subscribed via source and target branches