[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/remove-branch-commitsForDays into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-branch-commitsForDays into lp:launchpad. Commit message: Remove unused Branch.commitsForDays. Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/remove-branch-commitsForDays/+merge/308572 -- Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-branch-commitsForDays into lp:launchpad. === modified file 'lib/lp/code/interfaces/branch.py' --- lib/lp/code/interfaces/branch.py 2016-10-14 15:07:08 + +++ lib/lp/code/interfaces/branch.py 2016-10-15 02:40:17 + @@ -1002,15 +1002,6 @@ detail page. """ -def commitsForDays(since): -"""Get a list of commit counts for days since `since`. - -This method returns all commits for the branch, so this includes -revisions brought in through merges. - -:return: A list of tuples like (date, count). -""" - def checkUpgrade(): """Check whether an upgrade should be performed, and raise if not. === modified file 'lib/lp/code/model/branch.py' --- lib/lp/code/model/branch.py 2016-10-12 23:22:33 + +++ lib/lp/code/model/branch.py 2016-10-15 02:40:17 + @@ -25,10 +25,8 @@ from storm.expr import ( And, Coalesce, -Count, Desc, Join, -NamedFunc, Not, Or, Select, @@ -1367,21 +1365,6 @@ job = getUtility(IReclaimBranchSpaceJobSource).create(branch_id) job.celeryRunOnCommit() -def commitsForDays(self, since): -"""See `IBranch`.""" - -class DateTrunc(NamedFunc): -name = "date_trunc" - -results = Store.of(self).find( -(DateTrunc(u'day', Revision.revision_date), Count(Revision.id)), -Revision.id == BranchRevision.revision_id, -Revision.revision_date > since, -BranchRevision.branch == self) -results = results.group_by( -DateTrunc(u'day', Revision.revision_date)) -return sorted(results) - def checkUpgrade(self): if self.branch_type is not BranchType.HOSTED: raise CannotUpgradeNonHosted(self) === modified file 'lib/lp/code/model/tests/test_branch.py' --- lib/lp/code/model/tests/test_branch.py 2016-10-12 23:22:33 + +++ lib/lp/code/model/tests/test_branch.py 2016-10-15 02:40:17 + @@ -152,7 +152,6 @@ run_with_login, TestCase, TestCaseWithFactory, -time_counter, WebServiceTestCase, ) from lp.testing.factory import LaunchpadObjectFactory @@ -2700,73 +2699,6 @@ BranchLifecycleStatus.EXPERIMENTAL, branch.lifecycle_status) -class TestBranchCommitsForDays(TestCaseWithFactory): -"""Tests for `Branch.commitsForDays`.""" - -layer = DatabaseFunctionalLayer - -def setUp(self): -TestCaseWithFactory.setUp(self) -# Use a 30 day epoch for the tests. -self.epoch = datetime.now(tz=UTC) - timedelta(days=30) - -def date_generator(self, epoch_offset, delta=None): -if delta is None: -delta = timedelta(days=1) -return time_counter(self.epoch + timedelta(days=epoch_offset), delta) - -def test_empty_branch(self): -# A branch with no commits returns an empty list. -branch = self.factory.makeAnyBranch() -self.assertEqual([], branch.commitsForDays(self.epoch)) - -def test_commits_before_epoch_not_returned(self): -# Commits that occur before the epoch are not returned. -branch = self.factory.makeAnyBranch() -self.factory.makeRevisionsForBranch( -branch, date_generator=self.date_generator(-10)) -self.assertEqual([], branch.commitsForDays(self.epoch)) - -def test_commits_after_epoch_are_returned(self): -# Commits that occur after the epoch are returned. -branch = self.factory.makeAnyBranch() -self.factory.makeRevisionsForBranch( -branch, count=5, date_generator=self.date_generator(1)) -# There is one commit for each day starting from epoch + 1. -start = self.epoch + timedelta(days=1) -# Clear off the fractional parts of the day. -start = datetime(start.year, start.month, start.day) -commits = [] -for count in range(5): -commits.append((start + timedelta(days=count), 1)) -self.assertEqual(commits, branch.commitsForDays(self.epoch)) - -def test_commits_are_grouped(self): -# The commits are grouped to give counts of commits for the days. -branch = self.factory.makeAnyBranch() -start = self.epoch + timedelta(days=1) -# Add 8 commits starting from 5pm (+ whatever minutes). -# 5, 7, 9, 11pm, then 1, 3, 5, 7am for the following day. -start = start.replace(hour=17) -date_generator = time_counter(start, timedelta(hours=2)) -self.factory.makeRevisionsForBranch( -
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-new-view into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/codeimport-git-new-view into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-new-view/+merge/308545 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-worker-fixes into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/codeimport-git-worker-fixes into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-worker-fixes/+merge/308540 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-webservice into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/codeimport-git-webservice into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-webservice/+merge/308399 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-edit-views into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/codeimport-git-edit-views into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-edit-views/+merge/308398 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/remove-git-recipes-ff into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/remove-git-recipes-ff into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/remove-git-recipes-ff/+merge/308539 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-new-view into lp:launchpad
Review: Approve code Diff comments: > === modified file 'lib/lp/code/browser/codeimport.py' > --- lib/lp/code/browser/codeimport.py 2016-10-14 17:29:44 + > +++ lib/lp/code/browser/codeimport.py 2016-10-14 17:29:44 + > @@ -243,9 +250,10 @@ > git_repo_url = URIField( > title=_("Repo URL"), required=False, > description=_( > -"The URL of the git repository. The HEAD branch will be " > -"imported. You can import different branches by appending " > -"',branch=$name' to the URL."), > +"The URL of the git repository. For imports to Bazaar, the " s/git/Git/ > +"HEAD branch will be imported by default, but you can import " > +"different branches by appending ',branch=$name' to the URL. " > +"For imports to Git, the entire repository will be imported."), > allowed_schemes=["git", "http", "https"], > allow_userinfo=True, > allow_port=True, -- https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-new-view/+merge/308545 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-webservice into lp:launchpad
Review: Approve code Diff comments: > > === modified file 'lib/lp/code/interfaces/hasbranches.py' > --- lib/lp/code/interfaces/hasbranches.py 2016-09-07 02:46:20 + > +++ lib/lp/code/interfaces/hasbranches.py 2016-10-14 16:44:55 + > @@ -170,19 +174,31 @@ > @call_with(registrant=REQUEST_USER) > @export_factory_operation(Interface, []) # Really ICodeImport. > @operation_for_version('beta') > -def newCodeImport(registrant=None, branch_name=None, rcs_type=None, > - url=None, cvs_root=None, cvs_module=None, owner=None): > +def newCodeImport(registrant=None, branch_name=None, > + rcs_type=None, target_rcs_type=None, url=None, > + cvs_root=None, cvs_module=None, owner=None): > """Create a new code import. > > :param registrant: The IPerson to record as the registrant of the > -import > -:param branch_name: The name of the branch to create. > +import. > +:param branch_name: The name of the branch or repository to create. > :param rcs_type: The type of the foreign VCS. > +:param target_rcs_type: The type of the branch or repository to > +create (Bazaar or Git). > :param url: The URL to import from if the VCS type uses a single URL > (i.e. isn't CVS). > :param cvs_root: The CVSROOT for a CVS import. > :param cvs_module: The module to import for a CVS import. > -:param owner: Who should own the created branch, or None for it to > -be the same as the registrant, or the caller over the API. > +:param owner: Who should own the created branch or repository, or > +None for it to be the same as the registrant, or the caller over > +the API. > :returns: An instance of `ICodeImport`. > """ > + > + > +class IHasCodeImportsToBazaar(IHasCodeImports): > +"""Marker interface for targets that support code imports to Bazaar.""" > + > + > +class IHasCodeImportsToGit(IHasCodeImports): > +"""Marker interface for targets that support code imports to Git.""" Are these markers pulling their weight over just checking for IHasCodeImports and IHasBranches/IHasGitRepositories? -- https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-webservice/+merge/308399 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-edit-views into lp:launchpad
Review: Approve code Diff comments: > > === modified file 'lib/lp/code/browser/configure.zcml' > --- lib/lp/code/browser/configure.zcml2016-10-14 15:44:39 + > +++ lib/lp/code/browser/configure.zcml2016-10-14 16:43:43 + > @@ -881,6 +887,18 @@ > permission="launchpad.AnyPerson" > name="+edit-subscription" > template="../templates/gitrepository-edit-subscription.pt"/> > + +for="lp.code.interfaces.gitrepository.IGitRepository" > +class="lp.code.browser.gitrepository.GitRepositoryRequestImportView" > +permission="launchpad.AnyPerson" > +name="+request-import" > +template="../templates/inline-form-only-buttons.pt"/> > + +for="lp.code.interfaces.gitrepository.IGitRepository" > +class="lp.code.browser.gitrepository.GitRepositoryTryImportAgainView" > +permission="launchpad.AnyPerson" > +name="+try-again" > +template="../templates/inline-form-only-buttons.pt"/> Can you make these two AnyAllowedPerson? We need to update a whole lot of others to that, but we might as well not make the situation any worse. >provides="lp.services.webapp.interfaces.IBreadcrumb" > for="lp.code.interfaces.gitrepository.IGitRepository" > > === modified file 'lib/lp/code/browser/gitrepository.py' > --- lib/lp/code/browser/gitrepository.py 2016-10-14 15:44:39 + > +++ lib/lp/code/browser/gitrepository.py 2016-10-14 16:43:43 + > @@ -667,6 +677,83 @@ > return self, () > > > +class GitRepositoryRequestImportView(LaunchpadFormView): > +"""The view to provide an 'Import now' button on the repository index > page. > + > +This only appears on the page of a repository with an associated code > +import that is being actively imported and where there is a import > +scheduled at some point in the future. > +""" > + > +schema = IGitRepository > +field_names = [] > + > +form_style = "display: inline" > + > +@property > +def next_url(self): > +return canonical_url(self.context) > + > +@action("Import Now", name="request") > +def request_import_action(self, action, data): > +try: > +self.context.code_import.requestImport( > +self.user, error_if_already_requested=True) > +self.request.response.addNotification( > +"Import will run as soon as possible.") > +except CodeImportNotInReviewedState: > +self.request.response.addNotification( > +"This import is no longer being updated automatically.") > +except CodeImportAlreadyRunning: > +self.request.response.addNotification( > +"The import is already running.") > +except CodeImportAlreadyRequested as e: > +user = e.requesting_user > +adapter = queryAdapter(user, IPathAdapter, 'fmt') > +self.request.response.addNotification( > +structured("The import has already been requested by %s." % > + adapter.link(None))) > + > +@property > +def prefix(self): > +return "request%s" % self.context.id > + > +@property > +def action_url(self): > +return "%s/@@+request-import" % canonical_url(self.context) > + > + > +class GitRepositoryTryImportAgainView(LaunchpadFormView): > +"""The view to provide an 'Try again' button on the repository index > page. > + > +This only appears on the page of a repository with an associated code > +import that is marked as failing. > +""" > + > +schema = IGitRepository > +field_names = [] > + > +@property > +def next_url(self): > +return canonical_url(self.context) > + > +@action("Try Again", name="tryagain") > +def request_try_again(self, action, data): > +if (self.context.code_import.review_status != > +CodeImportReviewStatus.FAILING): > +self.request.response.addNotification( > +"The import is now %s." > +% self.context.code_import.review_status.name) > +else: > +self.context.code_import.tryFailingImportAgain(self.user) > +self.request.response.addNotification( > +"Import will be tried again as soon as possible.") > + > +@property > +def prefix(self): > +return "tryagain" These seem like direct copies of views from branch.py but with s/IBranch/IGitRepository/. The fact that they define a schema but then set field_names = [] also doesn't suggest to me that the schema actually matters. Can we just reuse the existing views, maybe moving them out to codeimport.py? > + > + > class GitRepositoryDeletionView(LaunchpadFormView): > > schema = IGitRepository -- https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-edit-views/+merge/308398 Your team Launchpad code reviewers is subscribed to branch
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-worker-fixes into lp:launchpad
Review: Approve code -- https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-worker-fixes/+merge/308540 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/remove-git-recipes-ff into lp:launchpad
Review: Approve code -- https://code.launchpad.net/~cjwatson/launchpad/remove-git-recipes-ff/+merge/308539 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-new-view into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/codeimport-git-new-view into lp:launchpad with lp:~cjwatson/launchpad/codeimport-git-worker-fixes as a prerequisite. Commit message: Extend CodeImportNewView to be able to create Git-to-Git code imports. Requested reviews: Launchpad code reviewers (launchpad-reviewers) Related bugs: Bug #1469459 in Launchpad itself: "import external code into a LP git repo (natively)" https://bugs.launchpad.net/launchpad/+bug/1469459 For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-new-view/+merge/308545 -- Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/codeimport-git-new-view into lp:launchpad. === modified file 'lib/lp/code/browser/codeimport.py' --- lib/lp/code/browser/codeimport.py 2016-10-14 17:29:44 + +++ lib/lp/code/browser/codeimport.py 2016-10-14 17:29:44 + @@ -57,7 +57,10 @@ RevisionControlSystems, TargetRevisionControlSystems, ) -from lp.code.errors import BranchExists +from lp.code.errors import ( +BranchExists, +GitRepositoryExists, +) from lp.code.interfaces.branch import ( IBranch, user_has_special_branch_access, @@ -71,6 +74,10 @@ ICodeImportSet, ) from lp.code.interfaces.codeimportmachine import ICodeImportMachineSet +from lp.code.interfaces.gitnamespace import ( +get_git_namespace, +IGitNamespacePolicy, +) from lp.registry.interfaces.product import IProduct from lp.registry.interfaces.role import IPersonRoles from lp.services.fields import URIField @@ -243,9 +250,10 @@ git_repo_url = URIField( title=_("Repo URL"), required=False, description=_( -"The URL of the git repository. The HEAD branch will be " -"imported. You can import different branches by appending " -"',branch=$name' to the URL."), +"The URL of the git repository. For imports to Bazaar, the " +"HEAD branch will be imported by default, but you can import " +"different branches by appending ',branch=$name' to the URL. " +"For imports to Git, the entire repository will be imported."), allowed_schemes=["git", "http", "https"], allow_userinfo=True, allow_port=True, @@ -253,6 +261,13 @@ allow_fragment=False, trailing_slash=False) +git_target_rcs_type = Choice( +title=_("Target version control system"), +description=_( +"The version control system that the source code should be " +"imported into on the Launchpad side."), +required=False, vocabulary=TargetRevisionControlSystems) + bzr_branch_url = URIField( title=_("Branch URL"), required=False, description=_("The URL of the Bazaar branch."), @@ -266,10 +281,10 @@ branch_name = copy_field( IBranch['name'], __name__='branch_name', -title=_('Branch Name'), +title=_('Name'), description=_( -"This will be used in the branch URL to identify the " -"imported branch. Examples: main, trunk."), +"This will be used in the branch or repository URL to identify " +"the import. Examples: main, trunk."), ) product = Choice( @@ -286,6 +301,7 @@ for_input = True custom_widget('rcs_type', LaunchpadRadioWidget) +custom_widget('git_target_rcs_type', LaunchpadRadioWidget) @property def initial_values(self): @@ -293,6 +309,7 @@ 'owner': self.user, 'rcs_type': RevisionControlSystems.BZR, 'branch_name': 'trunk', +'git_target_rcs_type': TargetRevisionControlSystems.BZR, } @property @@ -354,6 +371,9 @@ self.rcs_type_git = str(git_button) self.rcs_type_bzr = str(bzr_button) self.rcs_type_emptymarker = str(empty_marker) +# This widget is only conditionally required in the rcs_type == GIT +# case, but we still don't want a "(nothing selected)" item. +self.widgets['git_target_rcs_type']._displayItemForMissingValue = False def _getImportLocation(self, data): """Return the import location based on type.""" @@ -374,13 +394,18 @@ """Create the code import.""" product = self.getProduct(data) cvs_root, cvs_module, url = self._getImportLocation(data) +if data['rcs_type'] == RevisionControlSystems.GIT: +target_rcs_type = data.get( +'git_target_rcs_type', TargetRevisionControlSystems.BZR) +else: +target_rcs_type = TargetRevisionControlSystems.BZR return getUtility(ICodeImportSet).new( registrant=self.user, owner=data['owner'], context=product, branch_name=data['branch_name'], rcs_type=data['rcs_type'], -
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-worker-fixes into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/codeimport-git-worker-fixes into lp:launchpad with lp:~cjwatson/launchpad/codeimport-git-webservice as a prerequisite. Commit message: Miscellaneous tweaks to the Git-to-Git import worker, mainly logging. Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-worker-fixes/+merge/308540 -- Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/codeimport-git-worker-fixes into lp:launchpad. === modified file 'lib/lp/codehosting/codeimport/worker.py' --- lib/lp/codehosting/codeimport/worker.py 2016-10-12 15:30:09 + +++ lib/lp/codehosting/codeimport/worker.py 2016-10-14 16:53:56 + @@ -1002,7 +1002,6 @@ def _doImport(self): self._logger.info("Starting job.") -self._logger.info(config.codehosting.git_browse_root) try: self._opener_policy.checkOneURL(self.source_details.url) except BadUrl as e: @@ -1014,6 +1013,8 @@ if split.hostname: target_netloc = ":%s@%s" % ( self.source_details.macaroon.serialize(), split.hostname) +if split.port: +target_netloc += ":%s" % split.port else: target_netloc = "" target_url = urlunsplit([ @@ -1027,7 +1028,7 @@ except subprocess.CalledProcessError as e: self._logger.info( "Unable to get existing repository from hosting service: " -"%s" % e) +"git clone exited %s" % e.returncode) return CodeImportWorkerExitCode.FAILURE self._logger.info("Fetching remote repository.") try: @@ -1049,6 +1050,8 @@ try: self._runGit("push", "--mirror", target_url, cwd="repository") except subprocess.CalledProcessError as e: -self._logger.info("Unable to push to hosting service: %s" % e) +self._logger.info( +"Unable to push to hosting service: git push exited %s" % +e.returncode) return CodeImportWorkerExitCode.FAILURE return CodeImportWorkerExitCode.SUCCESS ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/remove-git-recipes-ff into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-git-recipes-ff into lp:launchpad. Commit message: Remove the Git recipes feature flag. Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/remove-git-recipes-ff/+merge/308539 This feature has been enabled everywhere relevant for a while now and is stable. -- Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-git-recipes-ff into lp:launchpad. === modified file 'lib/lp/code/browser/gitref.py' --- lib/lp/code/browser/gitref.py 2016-10-05 10:07:08 + +++ lib/lp/code/browser/gitref.py 2016-10-14 16:30:25 + @@ -43,8 +43,6 @@ from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference from lp.code.interfaces.gitref import IGitRef from lp.code.interfaces.gitrepository import IGitRepositorySet -from lp.code.interfaces.sourcepackagerecipe import GIT_RECIPES_FEATURE_FLAG -from lp.services.features import getFeatureFlag from lp.services.helpers import english_list from lp.services.propertycache import cachedproperty from lp.services.webapp import ( @@ -96,19 +94,13 @@ def create_recipe(self): # You can't create a recipe for a reference in a private repository. -enabled = ( -not self.context.private and -bool(getFeatureFlag(GIT_RECIPES_FEATURE_FLAG))) +enabled = not self.context.private text = "Create packaging recipe" return Link("+new-recipe", text, enabled=enabled, icon="add") class GitRefView(LaunchpadView, HasSnapsViewMixin): -related_features = { -"code.git.recipes.enabled": False, -} - @property def label(self): return self.context.display_name === modified file 'lib/lp/code/browser/gitrepository.py' --- lib/lp/code/browser/gitrepository.py 2016-10-14 15:44:39 + +++ lib/lp/code/browser/gitrepository.py 2016-10-14 16:30:25 + @@ -69,7 +69,6 @@ from lp.code.interfaces.gitnamespace import get_git_namespace from lp.code.interfaces.gitref import IGitRefBatchNavigator from lp.code.interfaces.gitrepository import IGitRepository -from lp.code.interfaces.sourcepackagerecipe import GIT_RECIPES_FEATURE_FLAG from lp.registry.interfaces.person import ( IPerson, IPersonSet, @@ -269,9 +268,7 @@ def create_recipe(self): # You can't create a recipe for a private repository. -enabled = ( -not self.context.private and -bool(getFeatureFlag(GIT_RECIPES_FEATURE_FLAG))) +enabled = not self.context.private text = "Create packaging recipe" return Link("+new-recipe", text, enabled=enabled, icon="add") @@ -302,10 +299,6 @@ class GitRepositoryView(InformationTypePortletMixin, LaunchpadView, HasSnapsViewMixin, CodeImportTargetMixin): -related_features = { -"code.git.recipes.enabled": False, -} - @property def page_title(self): return self.context.display_name === modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipe.py' --- lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2016-09-07 11:12:58 + +++ lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2016-10-14 16:30:25 + @@ -36,7 +36,6 @@ SourcePackageRecipeBuildView, ) from lp.code.interfaces.sourcepackagerecipe import ( -GIT_RECIPES_FEATURE_FLAG, MINIMAL_RECIPE_TEXT_BZR, MINIMAL_RECIPE_TEXT_GIT, ) @@ -49,7 +48,6 @@ from lp.registry.interfaces.series import SeriesStatus from lp.registry.interfaces.teammembership import TeamMembershipStatus from lp.services.database.constants import UTC_NOW -from lp.services.features.testing import FeatureFixture from lp.services.propertycache import clear_property_cache from lp.services.webapp import canonical_url from lp.services.webapp.escaping import html_escape @@ -209,10 +207,6 @@ branch_type = "repository" no_such_object_message = "is not a Git repository on Launchpad." -def setUp(self): -super(GitMixin, self).setUp() -self.useFixture(FeatureFixture({GIT_RECIPES_FEATURE_FLAG: u"on"})) - def makeBranch(self, **kwargs): return self.factory.makeGitRefs(**kwargs)[0] === modified file 'lib/lp/code/errors.py' --- lib/lp/code/errors.py 2016-10-05 09:29:41 + +++ lib/lp/code/errors.py 2016-10-14 16:30:25 + @@ -31,7 +31,6 @@ 'ClaimReviewFailed', 'DiffNotFound', 'GitDefaultConflict', -'GitRecipesFeatureDisabled', 'GitRepositoryCreationException', 'GitRepositoryCreationFault', 'GitRepositoryCreationForbidden', @@ -497,15 +496,6 @@ self.newest_supported = newest_supported -@error_status(httplib.UNAUTHORIZED) -class GitRecipesFeatureDisabled(Exception): -"""Only certain users can create new Git recipes.""" - -def __init__(self): -message = "You do not have permission
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-list-git into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/codeimport-list-git into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-list-git/+merge/308387 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-read-only-views into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/codeimport-git-read-only-views into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-read-only-views/+merge/308374 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/git-code-import-security-deletion into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/git-code-import-security-deletion into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/git-code-import-security-deletion/+merge/308319 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/git-code-import-security-deletion into lp:launchpad
Diff comments: > > === modified file 'lib/lp/code/interfaces/gitrepository.py' > --- lib/lp/code/interfaces/gitrepository.py 2016-10-05 09:54:42 + > +++ lib/lp/code/interfaces/gitrepository.py 2016-10-13 12:29:37 + > @@ -946,14 +951,24 @@ > return identities > > > -def user_has_special_git_repository_access(user): > +def user_has_special_git_repository_access(user, repository=None): > """Admins have special access. > > :param user: An `IPerson` or None. > +:param repository: An `IGitRepository` or None when checking collection > +access. > """ > if user is None: > return False > roles = IPersonRoles(user) > if roles.in_admin: > return True > -return False > +if repository is None: > +return False > +code_import = repository.code_import > +if code_import is None: > +return False > +return ( > +roles.in_vcs_imports > +or (IPersonRoles(repository.owner).in_vcs_imports > +and user.inTerm(code_import.registrant))) Granted that the Git side at least isn't tested, and the typo you noticed. As for why it's there, there used to be a comment about this but Curtis removed it during the last refactoring: # It used to be the case that all import branches were owned by the # special, restricted team ~vcs-imports. For these legacy code import # branches, we still want the code import registrant to be able to # edit them. Similarly, we still want vcs-imports members to be able # to edit those branches. This case is tested (lp.code.tests.test_branch.TestWriteToBranch.test_code_import_registrant_can_edit). There are still 34 distinct registrants of vcs-imports-owned branches on dogfood, quite a few of whom aren't privileged, so I think I should still leave this code there for the Bazaar case. However, I'll put the comment back so that it's less mystifying, and I'll drop this from the Git side since we have no legacy concerns there. -- https://code.launchpad.net/~cjwatson/launchpad/git-code-import-security-deletion/+merge/308319 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup into lp:launchpad
The proposal to merge lp:~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup into lp:launchpad has been updated. Status: Needs review => Merged For more details, see: https://code.launchpad.net/~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup/+merge/308494 -- Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/python-oops-wsgi/hide-macaroons into lp:python-oops-wsgi
Review: Approve Thanks, Colin. Nice catch. -- https://code.launchpad.net/~cjwatson/python-oops-wsgi/hide-macaroons/+merge/308489 Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/python-oops-wsgi/hide-macaroons into lp:python-oops-wsgi. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup into lp:launchpad
Review: Approve code -- https://code.launchpad.net/~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup/+merge/308494 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-list-git into lp:launchpad
Review: Approve code -- https://code.launchpad.net/~cjwatson/launchpad/codeimport-list-git/+merge/308387 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/codeimport-git-read-only-views into lp:launchpad
Review: Approve code Diff comments: > > === modified file 'lib/lp/code/browser/codeimport.py' > --- lib/lp/code/browser/codeimport.py 2016-10-06 15:59:34 + > +++ lib/lp/code/browser/codeimport.py 2016-10-13 12:55:20 + > @@ -543,6 +549,10 @@ > else: > raise AssertionError('Unknown rcs_type for code import.') > > +if (self.code_import.target_rcs_type == > +TargetRevisionControlSystems.GIT): I find the contrast between the == BZR above and the == GIT here disturbing. Perhaps != BZR? > +self.form_fields = self.form_fields.omit('whiteboard') > + > def _showButtonForStatus(self, status): > """If the status is different, and the user is super, show button.""" > return self._super_user and self.code_import.review_status != status > > === added file 'lib/lp/code/templates/gitrepository-import-details.pt' > --- lib/lp/code/templates/gitrepository-import-details.pt 1970-01-01 > 00:00:00 + > +++ lib/lp/code/templates/gitrepository-import-details.pt 2016-10-13 > 12:55:20 + > @@ -0,0 +1,95 @@ > + + xmlns:tal="http://xml.zope.org/namespaces/tal; > + xmlns:metal="http://xml.zope.org/namespaces/metal; > + xmlns:i18n="http://xml.zope.org/namespaces/i18n; > + tal:define="context_menu view/context/menu:context"> > + > + + condition="context/repository_type/enumvalue:IMPORTED"> > + > + + define="code_import repository/code_import"> > + > +Import Status: > + +tal:content="code_import/review_status/title"/> > + > + > + > + > +This repository is an import of the Git repository at > + > + + tal:content="code_import/url" />. > + > + > + . > + > + > + > + > + + condition="job"> > + > + > +An import is currently running on > +, > +and was started > + > + 2 hours ago > +. > + > + The last few lines of the job's output were: > + > + > + > + > + > + > +The next import is scheduled to run > + > + as soon as possible +condition="job/requesting_user"> > +(requested by > + + replace="structure job/requesting_user/fmt:link"> > + Some user. > +). > + > + > + > +in 2 hours > + . > + > + > + > + > + > + > + > +The import has been suspended because it failed > + content="modules/lp.services.config/config/codeimport/consecutive_failure_limit"/> > +or more times in succession. > + > + > + > + > + > +Last successful import was > + replace="code_import/date_last_successful/fmt:displaydate"> > + 2 hours ago > +. > + > + > + > + tal:condition="view/latest_code_import_results"> > + > + > + > + > + > + > + > + > + Is this non-trivially different from the branch equivalent? It's a reasonably complex bit of UI that would be nice to not duplicate. -- https://code.launchpad.net/~cjwatson/launchpad/codeimport-git-read-only-views/+merge/308374 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup into lp:launchpad. Commit message: Remove old-style authentication parameters handling from GitAPI.translatePath. Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup/+merge/308494 The corresponding turnip changes are on production now, so we can drop the compatibility code. -- Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/git-xmlrpc-auth-params-cleanup into lp:launchpad. === modified file 'lib/lp/code/xmlrpc/git.py' --- lib/lp/code/xmlrpc/git.py 2016-10-12 12:41:25 + +++ lib/lp/code/xmlrpc/git.py 2016-10-14 11:51:45 + @@ -295,20 +295,9 @@ else: raise -def translatePath(self, path, permission, requester_id, - can_authenticate=None): +def translatePath(self, path, permission, auth_params): """See `IGitAPI`.""" -if can_authenticate is None: -# XXX cjwatson 2016-10-06: Ugly compatibility hack. This method -# should be "translatePath(self, path, permission, *auth_args)" -# instead, but it may be called using mapply which doesn't -# support the *auth_args syntax. This can go away once turnip -# uses the new-style interface. -auth_params = requester_id -requester_id = auth_params.get("uid") -else: -auth_params = { -"uid": requester_id, "can-authenticate": can_authenticate} +requester_id = auth_params.get("uid") if requester_id is None: requester_id = LAUNCHPAD_ANONYMOUS if isinstance(path, str): === modified file 'lib/lp/code/xmlrpc/tests/test_git.py' --- lib/lp/code/xmlrpc/tests/test_git.py 2016-10-12 12:30:13 + +++ lib/lp/code/xmlrpc/tests/test_git.py 2016-10-14 11:51:45 + @@ -6,10 +6,6 @@ __metaclass__ = type from pymacaroons import Macaroon -from testscenarios import ( -load_tests_apply_scenarios, -WithScenarios, -) from zope.component import getUtility from zope.security.proxy import removeSecurityProxy @@ -47,34 +43,21 @@ from lp.xmlrpc import faults -class TestGitAPIMixin(WithScenarios): +class TestGitAPIMixin: """Helper methods for `IGitAPI` tests, and security-relevant tests.""" -scenarios = [ -("auth_params_flat", {"auth_params_dict": False}), -("auth_params_dict", {"auth_params_dict": True}), -] - def setUp(self): super(TestGitAPIMixin, self).setUp() self.git_api = GitAPI(None, None) self.hosting_fixture = self.useFixture(GitHostingFixture()) self.repository_set = getUtility(IGitRepositorySet) -def _translatePath(self, path, permission, auth_params): -if self.auth_params_dict: -return self.git_api.translatePath(path, permission, auth_params) -else: -return self.git_api.translatePath( -path, permission, auth_params.get("uid"), -auth_params.get("can-authenticate", False)) - def assertGitRepositoryNotFound(self, requester, path, permission="read", can_authenticate=False): """Assert that the given path cannot be translated.""" if requester is not None: requester = requester.id -fault = self._translatePath( +fault = self.git_api.translatePath( path, permission, {"uid": requester, "can-authenticate": can_authenticate}) self.assertEqual( @@ -90,7 +73,7 @@ auth_params = {"uid": requester, "can-authenticate": can_authenticate} if macaroon_raw is not None: auth_params["macaroon"] = macaroon_raw -fault = self._translatePath(path, permission, auth_params) +fault = self.git_api.translatePath(path, permission, auth_params) self.assertEqual(faults.PermissionDenied(message), fault) def assertUnauthorized(self, requester, path, @@ -99,7 +82,7 @@ """Assert that looking at the given path returns Unauthorized.""" if requester is not None: requester = requester.id -fault = self._translatePath( +fault = self.git_api.translatePath( path, permission, {"uid": requester, "can-authenticate": can_authenticate}) self.assertEqual(faults.Unauthorized(message), fault) @@ -109,7 +92,7 @@ """Assert that looking at the given path returns NotFound.""" if requester is not None: requester = requester.id -fault = self._translatePath( +fault = self.git_api.translatePath( path, permission, {"uid": requester, "can-authenticate": can_authenticate}) self.assertEqual(faults.NotFound(message), fault) @@ -121,7
Re: [Launchpad-reviewers] [Merge] lp:~cjwatson/launchpad/git-code-import-security-deletion into lp:launchpad
Review: Approve code Diff comments: > > === modified file 'lib/lp/code/interfaces/gitrepository.py' > --- lib/lp/code/interfaces/gitrepository.py 2016-10-05 09:54:42 + > +++ lib/lp/code/interfaces/gitrepository.py 2016-10-13 12:29:37 + > @@ -946,14 +951,24 @@ > return identities > > > -def user_has_special_git_repository_access(user): > +def user_has_special_git_repository_access(user, repository=None): > """Admins have special access. > > :param user: An `IPerson` or None. > +:param repository: An `IGitRepository` or None when checking collection > +access. > """ > if user is None: > return False > roles = IPersonRoles(user) > if roles.in_admin: > return True > -return False > +if repository is None: > +return False > +code_import = repository.code_import > +if code_import is None: > +return False > +return ( > +roles.in_vcs_imports > +or (IPersonRoles(repository.owner).in_vcs_imports > +and user.inTerm(code_import.registrant))) Registrant? Really? Can you delete that disjunct from user_has_special_branch_access too? I don't see how the repository owner's participation is relevant to anything. Especially since "inTerm" suggests it isn't tested. > > === modified file 'lib/lp/code/model/gitrepository.py' > --- lib/lp/code/model/gitrepository.py2016-10-05 09:29:41 + > +++ lib/lp/code/model/gitrepository.py2016-10-13 12:29:37 + > @@ -1250,6 +1261,17 @@ > self.affected_object.prerequisite_git_commit_sha1 = None > > > +class DeleteCodeImport(DeletionOperation): > +"""Deletion operation that deletes a repository's import.""" > + > +def __init__(self, code_import): > +DeletionOperation.__init__( > +self, code_import, msg("This is the import data for this > branch.")) s/branch/repository/g > + > +def __call__(self): > +getUtility(ICodeImportSet).delete(self.affected_object) > + > + > @implementer(IGitRepositorySet) > class GitRepositorySet: > """See `IGitRepositorySet`.""" -- https://code.launchpad.net/~cjwatson/launchpad/git-code-import-security-deletion/+merge/308319 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp
[Launchpad-reviewers] [Merge] lp:~cjwatson/python-oops-wsgi/hide-macaroons into lp:python-oops-wsgi
Colin Watson has proposed merging lp:~cjwatson/python-oops-wsgi/hide-macaroons into lp:python-oops-wsgi. Commit message: Hide sensitive information in HTTP_AUTHORIZATION headers. Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/python-oops-wsgi/hide-macaroons/+merge/308489 Full root and discharge macaroons show up in SCA OOPSes at the moment, and really shouldn't. -- Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/python-oops-wsgi/hide-macaroons into lp:python-oops-wsgi. === modified file 'oops_wsgi/hooks.py' --- oops_wsgi/hooks.py 2011-11-13 22:39:44 + +++ oops_wsgi/hooks.py 2016-10-14 10:40:34 + @@ -15,6 +15,8 @@ """oops creation and filtering hooks for working with WSGI.""" +import re + __all__ = [ 'copy_environ', 'hide_cookie', @@ -59,15 +61,25 @@ """If there is an HTTP_COOKIE entry in the report, hide its value. The entry is looked for either as a top level key or in the req_vars dict. - + The COOKIE header is often used to carry session tokens and thus permits folk analyzing crash reports to log in as an arbitrary user (e.g. your sysadmin users). + +The same goes for the AUTHORIZATION header, although in that case we +permit the authorization scheme to remain visible. """ if 'HTTP_COOKIE' in report: report['HTTP_COOKIE'] = '' if 'HTTP_COOKIE' in report.get('req_vars', {}): report['req_vars']['HTTP_COOKIE'] = '' +if 'HTTP_AUTHORIZATION' in report: +report['HTTP_AUTHORIZATION'] = re.sub( +r'(.*?)\s+.*', r'\1 ', report['HTTP_AUTHORIZATION']) +if 'HTTP_AUTHORIZATION' in report.get('req_vars', {}): +report['req_vars']['HTTP_AUTHORIZATION'] = re.sub( +r'(.*?)\s+.*', r'\1 ', +report['req_vars']['HTTP_AUTHORIZATION']) def install_hooks(config): === modified file 'oops_wsgi/tests/test_hooks.py' --- oops_wsgi/tests/test_hooks.py 2011-11-13 22:39:44 + +++ oops_wsgi/tests/test_hooks.py 2016-10-14 10:40:34 + @@ -62,6 +62,21 @@ hide_cookie(report, {}) self.assertEqual({'req_vars': {'HTTP_COOKIE': ''}}, report) +def test_hide_cookie_authorization_present_top_level(self): +report = {'HTTP_AUTHORIZATION': 'Macaroon root=foo, discharge=bar'} +hide_cookie(report, {}) +self.assertEqual({'HTTP_AUTHORIZATION': 'Macaroon '}, report) + +def test_hide_cookie_authorization_present_req_vars(self): +report = { +'req_vars': { +'HTTP_AUTHORIZATION': 'Macaroon root=foo, discharge=bar', +}, +} +hide_cookie(report, {}) +self.assertEqual( +{'req_vars': {'HTTP_AUTHORIZATION': 'Macaroon '}}, report) + def test_copy_environ_copied_variables(self): environ = { 'REQUEST_METHOD': 'GET', ___ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp