launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25542
[Merge] ~pappacena/launchpad:git-repo-async-privacy into launchpad:master
Thiago F. Pappacena has proposed merging ~pappacena/launchpad:git-repo-async-privacy into launchpad:master.
Commit message:
Doing repository privacy change in background, and blocking user from changing it while another change is in progress.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/392776
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad:git-repo-async-privacy into launchpad:master.
diff --git a/database/schema/security.cfg b/database/schema/security.cfg
index 11aba6f..290e7bc 100644
--- a/database/schema/security.cfg
+++ b/database/schema/security.cfg
@@ -2082,6 +2082,24 @@ public.webhookjob = SELECT, INSERT
public.xref = SELECT, INSERT, DELETE
type=user
+[privacy-change-jobs]
+groups=script
+public.accessartifact = SELECT, UPDATE, DELETE, INSERT
+public.accessartifactgrant = SELECT, UPDATE, DELETE, INSERT
+public.accesspolicyartifact = SELECT, UPDATE, DELETE, INSERT
+public.accesspolicygrant = SELECT, UPDATE, DELETE
+public.account = SELECT
+public.distribution = SELECT
+public.gitjob = SELECT, UPDATE
+public.gitrepository = SELECT, UPDATE
+public.gitsubscription = SELECT, UPDATE, DELETE
+public.job = SELECT, INSERT, UPDATE
+public.person = SELECT
+public.product = SELECT
+public.sharingjob = SELECT, INSERT, UPDATE
+public.teamparticipation = SELECT
+type=user
+
[sharing-jobs]
groups=script
public.accessartifactgrant = SELECT, UPDATE, DELETE
diff --git a/lib/lp/app/widgets/itemswidgets.py b/lib/lp/app/widgets/itemswidgets.py
index 1dbb59f..a644a96 100644
--- a/lib/lp/app/widgets/itemswidgets.py
+++ b/lib/lp/app/widgets/itemswidgets.py
@@ -189,25 +189,29 @@ class LaunchpadRadioWidgetWithDescription(LaunchpadRadioWidget):
"""Render an item of the list."""
text = html_escape(text)
id = '%s.%s' % (name, index)
+ extra_attr = {"disabled": "disabled"} if self.context.readonly else {}
elem = renderElement(u'input',
value=value,
name=name,
id=id,
cssClass=cssClass,
- type='radio')
+ type='radio',
+ **extra_attr)
return self._renderRow(text, value, id, elem)
def renderSelectedItem(self, index, text, value, name, cssClass):
"""Render a selected item of the list."""
text = html_escape(text)
id = '%s.%s' % (name, index)
+ extra_attr = {"disabled": "disabled"} if self.context.readonly else {}
elem = renderElement(u'input',
value=value,
name=name,
id=id,
cssClass=cssClass,
checked="checked",
- type='radio')
+ type='radio',
+ **extra_attr)
return self._renderRow(text, value, id, elem)
def renderExtraHint(self):
diff --git a/lib/lp/code/browser/gitrepository.py b/lib/lp/code/browser/gitrepository.py
index 2552ffb..029e7ba 100644
--- a/lib/lp/code/browser/gitrepository.py
+++ b/lib/lp/code/browser/gitrepository.py
@@ -483,6 +483,9 @@ class GitRepositoryView(InformationTypePortletMixin, LaunchpadView,
def warning_message(self):
if self.context.status == GitRepositoryStatus.CREATING:
return "This repository is being created."
+ if (self.context.status ==
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION):
+ return "This repository's information type is being changed."
return None
@property
@@ -573,6 +576,9 @@ class GitRepositoryEditFormView(LaunchpadEditFormView):
@cachedproperty
def schema(self):
info_types = self.getInformationTypesToShow()
+ read_only_info_type = (
+ self.context.status ==
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION)
class GitRepositoryEditSchema(Interface):
"""Defines the fields for the edit form.
@@ -582,7 +588,8 @@ class GitRepositoryEditFormView(LaunchpadEditFormView):
"""
use_template(IGitRepository, include=["default_branch"])
information_type = copy_field(
- IGitRepository["information_type"], readonly=False,
+ IGitRepository["information_type"],
+ readonly=read_only_info_type,
vocabulary=InformationTypeVocabulary(types=info_types))
name = copy_field(IGitRepository["name"], readonly=False)
owner = copy_field(IGitRepository["owner"], readonly=False)
@@ -785,6 +792,11 @@ class GitRepositoryEditView(CodeEditOwnerMixin, GitRepositoryEditFormView):
self.widgets["target"].hint = (
"This is the default repository for this target, so it "
"cannot be moved to another target.")
+ if (self.context.status ==
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION):
+ self.widgets["information_type"].hint = (
+ "Information type is being changed. The operation needs to "
+ "finish before you can changing it again.")
if self.context.default_branch:
self.widgets['default_branch'].context.required = True
diff --git a/lib/lp/code/browser/tests/test_gitrepository.py b/lib/lp/code/browser/tests/test_gitrepository.py
index 912965d..8a9af9f 100644
--- a/lib/lp/code/browser/tests/test_gitrepository.py
+++ b/lib/lp/code/browser/tests/test_gitrepository.py
@@ -60,6 +60,9 @@ from lp.code.enums import (
GitRepositoryType,
)
from lp.code.interfaces.gitcollection import IGitCollection
+from lp.code.interfaces.gitjob import (
+ IGitRepositoryTransitionToInformationTypeJobSource,
+ )
from lp.code.interfaces.gitrepository import IGitRepositorySet
from lp.code.interfaces.revision import IRevisionSet
from lp.code.model.gitjob import GitRefScanJob
@@ -161,6 +164,15 @@ class TestGitRepositoryView(BrowserTestCase):
self.assertTextMatchesExpressionIgnoreWhitespace(
r"""This repository is being created\..*""", text)
+ def test_changing_info_type_warning_message_is_present(self):
+ repository = removeSecurityProxy(self.factory.makeGitRepository())
+ repository.status = (
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION)
+ text = self.getMainText(repository, "+index", user=repository.owner)
+ self.assertTextMatchesExpressionIgnoreWhitespace(
+ r"""This repository's information type is being changed\..*""",
+ text)
+
def test_creating_warning_message_is_not_shown(self):
repository = removeSecurityProxy(self.factory.makeGitRepository())
repository.status = GitRepositoryStatus.AVAILABLE
@@ -1161,7 +1173,50 @@ class TestGitRepositoryEditView(TestCaseWithFactory):
browser.getControl("Change Git Repository").click()
with person_logged_in(person):
self.assertEqual(
- InformationType.USERDATA, repository.information_type)
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repository.status)
+ job_util = getUtility(
+ IGitRepositoryTransitionToInformationTypeJobSource)
+ jobs = list(job_util.iterReady())
+ self.assertEqual(1, len(jobs))
+ job = removeSecurityProxy(jobs[0])
+ self.assertEqual(repository, job.repository)
+ self.assertEqual(InformationType.USERDATA, job.information_type)
+ self.assertEqual(admin, job.user)
+
+ def test_information_type_in_ui_blocked_if_already_changing(self):
+ # The information_type of a repository can't be changed via the UI
+ # if the repository is already pending a info type change.
+ person = self.factory.makePerson()
+ repository = self.factory.makeGitRepository(owner=person)
+ removeSecurityProxy(repository).status = (
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION)
+ admin = getUtility(ILaunchpadCelebrities).admin.teamowner
+ browser = self.getUserBrowser(
+ canonical_url(repository) + "/+edit", user=admin)
+ # Make sure the privacy controls are all disabled in the UI.
+ controls = [
+ "Public", "Public Security", "Private Security", "Private",
+ "Proprietary", "Embargoed"]
+ self.assertTrue(
+ all(browser.getControl(i, index=0).disabled for i in controls))
+ expected_msg = (
+ "Information type is being changed. The operation needs to "
+ "finish before you can changing it again.")
+ self.assertIn(expected_msg, extract_text(browser.contents))
+
+ # Trying to change should have no effect in the backend, since the
+ # repository is already changing info type and this field is read-only.
+ browser.getControl("Private", index=1).click()
+ browser.getControl("Change Git Repository").click()
+ with person_logged_in(person):
+ self.assertEqual(
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repository.status)
+ job_util = getUtility(
+ IGitRepositoryTransitionToInformationTypeJobSource)
+ jobs = list(job_util.iterReady())
+ self.assertEqual(0, len(jobs))
def test_edit_view_ajax_render(self):
# An information type change request is processed as expected when
@@ -1184,7 +1239,17 @@ class TestGitRepositoryEditView(TestCaseWithFactory):
result = view.render()
self.assertEqual("", result)
self.assertEqual(
- repository.information_type, InformationType.PUBLICSECURITY)
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repository.status)
+ job_util = getUtility(
+ IGitRepositoryTransitionToInformationTypeJobSource)
+ jobs = list(job_util.iterReady())
+ self.assertEqual(1, len(jobs))
+ job = removeSecurityProxy(jobs[0])
+ self.assertEqual(repository, job.repository)
+ self.assertEqual(
+ InformationType.PUBLICSECURITY, job.information_type)
+ self.assertEqual(person, job.user)
def test_change_default_branch(self):
# An authorised user can change the default branch to one that
diff --git a/lib/lp/code/configure.zcml b/lib/lp/code/configure.zcml
index 898e645..fee38a9 100644
--- a/lib/lp/code/configure.zcml
+++ b/lib/lp/code/configure.zcml
@@ -1111,6 +1111,11 @@
provides="lp.code.interfaces.gitjob.IGitRepositoryModifiedMailJobSource">
<allow interface="lp.code.interfaces.gitjob.IGitRepositoryModifiedMailJobSource" />
</securedutility>
+ <securedutility
+ component="lp.code.model.gitjob.GitRepositoryTransitionToInformationTypeJob"
+ provides="lp.code.interfaces.gitjob.IGitRepositoryTransitionToInformationTypeJobSource">
+ <allow interface="lp.code.interfaces.gitjob.IGitRepositoryTransitionToInformationTypeJobSource" />
+ </securedutility>
<class class="lp.code.model.gitjob.GitRefScanJob">
<allow interface="lp.code.interfaces.gitjob.IGitJob" />
<allow interface="lp.code.interfaces.gitjob.IGitRefScanJob" />
@@ -1123,6 +1128,10 @@
<allow interface="lp.code.interfaces.gitjob.IGitJob" />
<allow interface="lp.code.interfaces.gitjob.IGitRepositoryModifiedMailJob" />
</class>
+ <class class="lp.code.model.gitjob.GitRepositoryTransitionToInformationTypeJob">
+ <allow interface="lp.code.interfaces.gitjob.IGitJob" />
+ <allow interface="lp.code.interfaces.gitjob.IGitRepositoryTransitionToInformationTypeJob" />
+ </class>
<lp:help-folder folder="help" name="+help-code" />
diff --git a/lib/lp/code/enums.py b/lib/lp/code/enums.py
index d2a9262..2edf401 100644
--- a/lib/lp/code/enums.py
+++ b/lib/lp/code/enums.py
@@ -167,6 +167,12 @@ class GitRepositoryStatus(DBEnumeratedType):
This repository is available to be used.
""")
+ PENDING_INFORMATION_TYPE_TRANSITION = DBItem(3, """
+ Information type transition pending
+
+ This repository's privacy setting is being changed.
+ """)
+
class GitObjectType(DBEnumeratedType):
"""Git Object Type
diff --git a/lib/lp/code/interfaces/gitjob.py b/lib/lp/code/interfaces/gitjob.py
index 4f31b19..bfe5525 100644
--- a/lib/lp/code/interfaces/gitjob.py
+++ b/lib/lp/code/interfaces/gitjob.py
@@ -1,4 +1,4 @@
-# Copyright 2015 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""GitJob interfaces."""
@@ -11,6 +11,8 @@ __all__ = [
'IGitRefScanJobSource',
'IGitRepositoryModifiedMailJob',
'IGitRepositoryModifiedMailJobSource',
+ 'IGitRepositoryTransitionToInformationTypeJob',
+ 'IGitRepositoryTransitionToInformationTypeJobSource',
'IReclaimGitRepositorySpaceJob',
'IReclaimGitRepositorySpaceJobSource',
]
@@ -93,3 +95,20 @@ class IGitRepositoryModifiedMailJobSource(IJobSource):
:param repository_delta: An `IGitRepositoryDelta` describing the
changes.
"""
+
+
+class IGitRepositoryTransitionToInformationTypeJob(IRunnableJob):
+ """A Job to change repository's information type."""
+
+
+class IGitRepositoryTransitionToInformationTypeJobSource(IJobSource):
+
+ def create(repository, user, information_type, verify_policy=True):
+ """Create a job to change git repository's information type.
+
+ :param repository: The `IGitRepository` that was modified.
+ :param information_type: The `InformationType` to transition to.
+ :param user: The `IPerson` who is making the change.
+ :param verify_policy: Check if the new information type complies
+ with the `IGitNamespacePolicy`.
+ """
diff --git a/lib/lp/code/model/gitjob.py b/lib/lp/code/model/gitjob.py
index 1eb87da..ba7b9f2 100644
--- a/lib/lp/code/model/gitjob.py
+++ b/lib/lp/code/model/gitjob.py
@@ -33,10 +33,12 @@ from zope.interface import (
provider,
)
+from lp.app.enums import InformationType
from lp.app.errors import NotFoundError
from lp.code.enums import (
GitActivityType,
GitPermissionType,
+ GitRepositoryStatus,
)
from lp.code.interfaces.githosting import IGitHostingClient
from lp.code.interfaces.gitjob import (
@@ -45,6 +47,8 @@ from lp.code.interfaces.gitjob import (
IGitRefScanJobSource,
IGitRepositoryModifiedMailJob,
IGitRepositoryModifiedMailJobSource,
+ IGitRepositoryTransitionToInformationTypeJob,
+ IGitRepositoryTransitionToInformationTypeJobSource,
IReclaimGitRepositorySpaceJob,
IReclaimGitRepositorySpaceJobSource,
)
@@ -100,6 +104,13 @@ class GitJobType(DBEnumeratedType):
modifications.
""")
+ REPOSITORY_TRANSITION_TO_INFO_TYPE = DBItem(3, """
+ Change repository's information type
+
+ This job runs when a user requests to change privacy settings of a
+ repository.
+ """)
+
@implementer(IGitJob)
class GitJob(StormBase):
@@ -393,3 +404,50 @@ class GitRepositoryModifiedMailJob(GitJobDerived):
def run(self):
"""See `IGitRepositoryModifiedMailJob`."""
self.getMailer().sendAll()
+
+
+@implementer(IGitRepositoryTransitionToInformationTypeJob)
+@provider(IGitRepositoryTransitionToInformationTypeJobSource)
+class GitRepositoryTransitionToInformationTypeJob(GitJobDerived):
+ """A Job to change git repository's information type."""
+
+ class_job_type = GitJobType.REPOSITORY_TRANSITION_TO_INFO_TYPE
+
+ config = config.IGitRepositoryTransitionToInformationTypeJobSource
+
+ @classmethod
+ def create(cls, repository, information_type, user, verify_policy=True):
+ """See `IGitRepositoryTransitionToInformationTypeJobSource`."""
+ metadata = {
+ "user": user.id,
+ "information_type": information_type.value,
+ "verify_policy": verify_policy,
+ }
+ git_job = GitJob(repository, cls.class_job_type, metadata)
+ job = cls(git_job)
+ job.celeryRunOnCommit()
+ return job
+
+ @property
+ def user(self):
+ return getUtility(IPersonSet).get(self.metadata["user"])
+
+ @property
+ def verify_policy(self):
+ return self.metadata["verify_policy"]
+
+ @property
+ def information_type(self):
+ return InformationType.items[self.metadata["information_type"]]
+
+ def run(self):
+ """See `IGitRepositoryTransitionToInformationTypeJob`."""
+ if (self.repository.status !=
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION):
+ raise AttributeError(
+ "The repository %s is not pending information type change." %
+ self.repository)
+
+ self.repository._transitionToInformationType(
+ self.information_type, self.user, self.verify_policy)
+ self.repository.status = GitRepositoryStatus.AVAILABLE
diff --git a/lib/lp/code/model/gitref.py b/lib/lp/code/model/gitref.py
index f7dc142..e2f788d 100644
--- a/lib/lp/code/model/gitref.py
+++ b/lib/lp/code/model/gitref.py
@@ -180,7 +180,7 @@ class GitRefMixin:
def transitionToInformationType(self, information_type, user,
verify_policy=True):
- return self.repository.transitionToInformationType(
+ return self.repository._transitionToInformationType(
information_type, user, verify_policy=verify_policy)
@property
diff --git a/lib/lp/code/model/gitrepository.py b/lib/lp/code/model/gitrepository.py
index f7a2a0b..b719e07 100644
--- a/lib/lp/code/model/gitrepository.py
+++ b/lib/lp/code/model/gitrepository.py
@@ -117,7 +117,10 @@ from lp.code.interfaces.gitcollection import (
IGitCollection,
)
from lp.code.interfaces.githosting import IGitHostingClient
-from lp.code.interfaces.gitjob import IGitRefScanJobSource
+from lp.code.interfaces.gitjob import (
+ IGitRefScanJobSource,
+ IGitRepositoryTransitionToInformationTypeJobSource,
+ )
from lp.code.interfaces.gitlookup import IGitLookup
from lp.code.interfaces.gitnamespace import (
get_git_namespace,
@@ -882,6 +885,24 @@ class GitRepository(StormBase, WebhookTargetMixin, GitIdentityMixin):
def transitionToInformationType(self, information_type, user,
verify_policy=True):
"""See `IGitRepository`."""
+ if self.status != GitRepositoryStatus.AVAILABLE:
+ raise CannotChangeInformationType(
+ "Cannot change privacy settings while git repository is "
+ "being changed.")
+ self.status = GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION
+ util = getUtility(
+ IGitRepositoryTransitionToInformationTypeJobSource)
+ return util.create(self, information_type, user, verify_policy)
+
+ def _transitionToInformationType(self, information_type, user,
+ verify_policy=True):
+ """Synchronously make the change in this repository's information
+ type.
+
+ External callers should use the async, public version of this
+ method, since it deals with the side effects of changing
+ repository's privacy changes.
+ """
if self.information_type == information_type:
return
if (verify_policy and
diff --git a/lib/lp/code/model/tests/test_gitcollection.py b/lib/lp/code/model/tests/test_gitcollection.py
index 447fcb4..372a633 100644
--- a/lib/lp/code/model/tests/test_gitcollection.py
+++ b/lib/lp/code/model/tests/test_gitcollection.py
@@ -599,7 +599,7 @@ class TestBranchMergeProposals(TestCaseWithFactory):
registrant = self.factory.makePerson()
mp1 = self.factory.makeBranchMergeProposalForGit(registrant=registrant)
naked_repository = removeSecurityProxy(mp1.target_git_repository)
- naked_repository.transitionToInformationType(
+ naked_repository._transitionToInformationType(
InformationType.USERDATA, registrant, verify_policy=False)
collection = self.all_repositories.visibleByUser(None)
proposals = collection.getMergeProposals()
diff --git a/lib/lp/code/model/tests/test_gitjob.py b/lib/lp/code/model/tests/test_gitjob.py
index 3f606c0..69cb653 100644
--- a/lib/lp/code/model/tests/test_gitjob.py
+++ b/lib/lp/code/model/tests/test_gitjob.py
@@ -25,13 +25,16 @@ from testtools.matchers import (
MatchesStructure,
)
import transaction
+from zope.component import getUtility
from zope.interface import providedBy
from zope.security.proxy import removeSecurityProxy
+from lp.app.enums import InformationType
from lp.code.adapters.gitrepository import GitRepositoryDelta
from lp.code.enums import (
GitGranteeType,
GitObjectType,
+ GitRepositoryStatus,
)
from lp.code.interfaces.branchmergeproposal import (
BRANCH_MERGE_PROPOSAL_WEBHOOKS_FEATURE_FLAG,
@@ -39,6 +42,7 @@ from lp.code.interfaces.branchmergeproposal import (
from lp.code.interfaces.gitjob import (
IGitJob,
IGitRefScanJob,
+ IGitRepositoryTransitionToInformationTypeJobSource,
IReclaimGitRepositorySpaceJob,
)
from lp.code.model.gitjob import (
@@ -47,9 +51,11 @@ from lp.code.model.gitjob import (
GitJobDerived,
GitJobType,
GitRefScanJob,
+ GitRepositoryTransitionToInformationTypeJob,
ReclaimGitRepositorySpaceJob,
)
from lp.code.tests.helpers import GitHostingFixture
+from lp.registry.errors import CannotChangeInformationType
from lp.services.config import config
from lp.services.database.constants import UTC_NOW
from lp.services.features.testing import FeatureFixture
@@ -362,6 +368,65 @@ class TestReclaimGitRepositorySpaceJob(TestCaseWithFactory):
self.assertEqual([(path,)], hosting_fixture.delete.extract_args())
+class TestGitRepositoryTransitionInformationType(TestCaseWithFactory):
+
+ layer = ZopelessDatabaseLayer
+
+ def test_block_multiple_requests_to_change_info_type(self):
+ repo = self.factory.makeGitRepository()
+ repo.transitionToInformationType(
+ InformationType.PRIVATESECURITY, repo.owner)
+ self.assertEqual(
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repo.status)
+ expected_msg = (
+ "Cannot change privacy settings while git repository is "
+ "being changed.")
+ self.assertRaisesRegex(
+ CannotChangeInformationType, expected_msg,
+ repo.transitionToInformationType,
+ InformationType.PROPRIETARY, repo.owner)
+
+ def test_avoid_transitioning_while_creating(self):
+ repo = self.factory.makeGitRepository()
+ removeSecurityProxy(repo).status = GitRepositoryStatus.CREATING
+ expected_msg = (
+ "Cannot change privacy settings while git repository is "
+ "being changed.")
+ self.assertRaisesRegex(
+ CannotChangeInformationType, expected_msg,
+ repo.transitionToInformationType,
+ InformationType.PROPRIETARY, repo.owner)
+
+ def test_run_changes_info_type(self):
+ repo = self.factory.makeGitRepository(
+ information_type=InformationType.PUBLIC)
+ # Change to a private info type and with verify_policy, so we hit as
+ # many database tables as possible.
+ repo.transitionToInformationType(
+ InformationType.PRIVATESECURITY, repo.owner, verify_policy=True)
+ self.assertEqual(
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repo.status)
+
+ job_util = getUtility(
+ IGitRepositoryTransitionToInformationTypeJobSource)
+ jobs = list(job_util.iterReady())
+ self.assertEqual(1, len(jobs))
+ with dbuser(GitRepositoryTransitionToInformationTypeJob.config.dbuser):
+ JobRunner(jobs).runAll()
+
+ self.assertEqual(GitRepositoryStatus.AVAILABLE, repo.status)
+ self.assertEqual(
+ InformationType.PRIVATESECURITY, repo.information_type)
+
+ # After the job finished, another change is possible.
+ repo.transitionToInformationType(InformationType.PUBLIC, repo.owner)
+ self.assertEqual(
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repo.status)
+
+
class TestDescribeRepositoryDelta(TestCaseWithFactory):
"""Tests for `describe_repository_delta`."""
diff --git a/lib/lp/code/model/tests/test_gitrepository.py b/lib/lp/code/model/tests/test_gitrepository.py
index 7d7464e..f69d1e3 100644
--- a/lib/lp/code/model/tests/test_gitrepository.py
+++ b/lib/lp/code/model/tests/test_gitrepository.py
@@ -809,7 +809,7 @@ class TestGitRepositoryDeletion(TestCaseWithFactory):
def test_private_subscription_does_not_disable_deletion(self):
# A private repository that has a subscription can be deleted.
- self.repository.transitionToInformationType(
+ removeSecurityProxy(self.repository)._transitionToInformationType(
InformationType.USERDATA, self.repository.owner,
verify_policy=False)
self.repository.subscribe(
@@ -2055,7 +2055,8 @@ class TestGitRepositoryModerate(TestCaseWithFactory):
repository.transitionToInformationType(
InformationType.PRIVATESECURITY, project.owner)
self.assertEqual(
- InformationType.PRIVATESECURITY, repository.information_type)
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repository.status)
def test_attribute_smoketest(self):
# Users with launchpad.Moderate can set attributes.
@@ -3400,7 +3401,7 @@ class TestGitRepositorySet(TestCaseWithFactory):
]
for repository, modified_date in zip(repositories, modified_dates):
removeSecurityProxy(repository).date_last_modified = modified_date
- removeSecurityProxy(repositories[0]).transitionToInformationType(
+ removeSecurityProxy(repositories[0])._transitionToInformationType(
InformationType.PRIVATESECURITY, repositories[0].registrant)
self.assertEqual(
[repositories[3], repositories[4], repositories[1],
@@ -3913,7 +3914,8 @@ class TestGitRepositoryWebservice(TestCaseWithFactory):
self.assertEqual(209, response.status)
with person_logged_in(ANONYMOUS):
self.assertEqual(
- InformationType.PUBLICSECURITY, repository_db.information_type)
+ GitRepositoryStatus.PENDING_INFORMATION_TYPE_TRANSITION,
+ repository_db.status)
def test_set_information_type_other_person(self):
# An unrelated user cannot change the information type.
diff --git a/lib/lp/code/xmlrpc/tests/test_git.py b/lib/lp/code/xmlrpc/tests/test_git.py
index dcbcee6..e884cd2 100644
--- a/lib/lp/code/xmlrpc/tests/test_git.py
+++ b/lib/lp/code/xmlrpc/tests/test_git.py
@@ -899,7 +899,7 @@ class TestGitAPI(TestGitAPIMixin, TestCaseWithFactory):
for _ in range(2)]
private_repository = code_imports[0].git_repository
removeSecurityProxy(
- private_repository).transitionToInformationType(
+ private_repository)._transitionToInformationType(
InformationType.PRIVATESECURITY, private_repository.owner)
with celebrity_logged_in("vcs_imports"):
jobs = [
@@ -1077,7 +1077,7 @@ class TestGitAPI(TestGitAPIMixin, TestCaseWithFactory):
for _ in range(2)]
private_repository = code_imports[0].git_repository
removeSecurityProxy(
- private_repository).transitionToInformationType(
+ private_repository)._transitionToInformationType(
InformationType.PRIVATESECURITY, private_repository.owner)
with celebrity_logged_in("vcs_imports"):
jobs = [
@@ -1687,7 +1687,7 @@ class TestGitAPI(TestGitAPIMixin, TestCaseWithFactory):
target_rcs_type=TargetRevisionControlSystems.GIT)
for _ in range(2)]
private_repository = code_imports[0].git_repository
- removeSecurityProxy(private_repository).transitionToInformationType(
+ removeSecurityProxy(private_repository)._transitionToInformationType(
InformationType.PRIVATESECURITY, private_repository.owner)
with celebrity_logged_in("vcs_imports"):
jobs = [
@@ -2012,7 +2012,7 @@ class TestGitAPI(TestGitAPIMixin, TestCaseWithFactory):
target_rcs_type=TargetRevisionControlSystems.GIT)
for _ in range(2)]
private_repository = code_imports[0].git_repository
- removeSecurityProxy(private_repository).transitionToInformationType(
+ removeSecurityProxy(private_repository)._transitionToInformationType(
InformationType.PRIVATESECURITY, private_repository.owner)
with celebrity_logged_in("vcs_imports"):
jobs = [
@@ -2268,7 +2268,7 @@ class TestGitAPI(TestGitAPIMixin, TestCaseWithFactory):
target_rcs_type=TargetRevisionControlSystems.GIT)
for _ in range(2)]
private_repository = code_imports[0].git_repository
- removeSecurityProxy(private_repository).transitionToInformationType(
+ removeSecurityProxy(private_repository)._transitionToInformationType(
InformationType.PRIVATESECURITY, private_repository.owner)
with celebrity_logged_in("vcs_imports"):
jobs = [
diff --git a/lib/lp/services/config/schema-lazr.conf b/lib/lp/services/config/schema-lazr.conf
index c16270a..681db58 100644
--- a/lib/lp/services/config/schema-lazr.conf
+++ b/lib/lp/services/config/schema-lazr.conf
@@ -1768,6 +1768,7 @@ job_sources:
ICommercialExpiredJobSource,
IExpiringMembershipNotificationJobSource,
IGitRepositoryModifiedMailJobSource,
+ IGitRepositoryTransitionToInformationTypeJobSource,
IMembershipNotificationJobSource,
IOCIRecipeRequestBuildsJobSource,
IOCIRegistryUploadJobSource,
@@ -1829,6 +1830,11 @@ module: lp.code.interfaces.gitjob
dbuser: send-branch-mail
crontab_group: MAIN
+[IGitRepositoryTransitionToInformationTypeJobSource]
+module: lp.code.interfaces.gitjob
+dbuser: privacy-change-jobs
+crontab_group: MAIN
+
[IInitializeDistroSeriesJobSource]
module: lp.soyuz.interfaces.distributionjob
dbuser: initializedistroseries
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index 57babc5..9d1f53b 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -1815,7 +1815,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
reviewer=reviewer, **optional_repository_args)
naked_repository = removeSecurityProxy(repository)
if information_type is not None:
- naked_repository.transitionToInformationType(
+ naked_repository._transitionToInformationType(
information_type, registrant, verify_policy=False)
return repository