launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24509
[Merge] ~pappacena/launchpad:oci-api-create-project into launchpad:master
Thiago F. Pappacena has proposed merging ~pappacena/launchpad:oci-api-create-project into launchpad:master.
Commit message:
API operation to create a new OCIProject for a Distribution.
The feature is only enabled if we turn on the 'oci.project.create.enabled' feature flag.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/381189
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad:oci-api-create-project into launchpad:master.
diff --git a/lib/lp/_schema_circular_imports.py b/lib/lp/_schema_circular_imports.py
index 46247fc..a8d119e 100644
--- a/lib/lp/_schema_circular_imports.py
+++ b/lib/lp/_schema_circular_imports.py
@@ -329,6 +329,8 @@ patch_entry_return_type(ISourcePackagePublic, 'getBranch', IBranch)
patch_plain_parameter_type(ISourcePackageEdit, 'setBranch', 'branch', IBranch)
patch_reference_property(ISourcePackage, 'distribution', IDistribution)
+patch_entry_return_type(IDistribution, 'newOCIProject', IOCIProject)
+
# IPerson
patch_entry_return_type(IPerson, 'createRecipe', ISourcePackageRecipe)
patch_list_parameter_type(IPerson, 'createRecipe', 'distroseries',
diff --git a/lib/lp/registry/interfaces/distribution.py b/lib/lp/registry/interfaces/distribution.py
index a7106f6..886b02e 100644
--- a/lib/lp/registry/interfaces/distribution.py
+++ b/lib/lp/registry/interfaces/distribution.py
@@ -22,6 +22,7 @@ from lazr.restful.declarations import (
collection_default_content,
export_as_webservice_collection,
export_as_webservice_entry,
+ export_factory_operation,
export_operation_as,
export_read_operation,
exported,
@@ -655,6 +656,40 @@ class IDistributionPublic(
def userCanEdit(user):
"""Can the user edit this distribution?"""
+ # XXX: pappacena 2020-04-25: This method is sit on IDistributionPublic
+ # for now, until we workout the specific permission for creating OCI
+ # Projects.
+ @call_with(registrant=REQUEST_USER)
+ @operation_parameters(
+ ociprojectname=Text(
+ title=_("The OCI project name."),
+ description=_("The name that groups a set of OCI projects "
+ "together.")),
+ description=Text(
+ title=_("Description for this OCI project."),
+ description=_("A short description of this OCI project.")),
+ bug_reporting_guidelines=Text(
+ title=_("The guidelines to report a bug."),
+ description=_("What is the guideline to report a bug to this "
+ "OCI Project?")),
+ bug_reported_acknowledgement=Text(
+ title=_("Acknowledgement text for a bug reported."),
+ description=_("Acknowledgement text for a bug reported in this "
+ "OCI Project.")),
+ bugfiling_duplicate_search=Bool(
+ title=_("Show bug search before allowing to open a bug?"),
+ description=_("To avoid duplicate bugs, show to the user a bug "
+ "search before allowing them to create new bugs?"))
+ )
+ # Interface is actually IOCIProject. Fixed at _schema_circular_imports
+ @export_factory_operation(Interface, [])
+ @operation_for_version("devel")
+ def newOCIProject(
+ registrant, ociprojectname, description=None,
+ bug_reporting_guidelines=None, bug_reported_acknowledgement=None,
+ bugfiling_duplicate_search=False):
+ """Create an `IOCIProject` for this distro."""
+
class IDistribution(
IDistributionEditRestricted, IDistributionPublic, IHasBugSupervisor,
diff --git a/lib/lp/registry/model/distribution.py b/lib/lp/registry/model/distribution.py
index f78908b..d82a375 100644
--- a/lib/lp/registry/model/distribution.py
+++ b/lib/lp/registry/model/distribution.py
@@ -35,6 +35,7 @@ from storm.info import ClassAlias
from storm.store import Store
from zope.component import getUtility
from zope.interface import implementer
+from zope.security.interfaces import Unauthorized
from lp.answers.enums import QUESTION_STATUS_DEFAULT_SEARCH
from lp.answers.model.faq import (
@@ -130,6 +131,7 @@ from lp.registry.model.milestone import (
HasMilestonesMixin,
Milestone,
)
+from lp.registry.model.ociproject import OCI_PROJECT_ALLOW_CREATE
from lp.registry.model.oopsreferences import referenced_oops
from lp.registry.model.pillar import HasAliasMixin
from lp.registry.model.sourcepackagename import SourcePackageName
@@ -147,6 +149,7 @@ from lp.services.database.stormexpr import (
fti_search,
rank_by_fti,
)
+from lp.services.features import getFeatureFlag
from lp.services.helpers import shortlist
from lp.services.propertycache import (
cachedproperty,
@@ -1450,6 +1453,20 @@ class Distribution(SQLBase, BugTargetBase, MakesAnnouncements,
return True
return False
+ def newOCIProject(self, registrant, ociprojectname, description=None,
+ bug_reporting_guidelines=None, bug_reported_acknowledgement=None,
+ bugfiling_duplicate_search=False):
+ """Create an `IOCIProject` for this distro."""
+ if not getFeatureFlag(OCI_PROJECT_ALLOW_CREATE):
+ raise Unauthorized("Creating new OCI projects is not allowed.")
+ return getUtility(IOCIProjectSet).new(
+ pillar=self,
+ registrant=registrant, ociprojectname=ociprojectname,
+ description=description,
+ bug_reporting_guidelines=bug_reporting_guidelines,
+ bug_reported_acknowledgement=bug_reported_acknowledgement,
+ bugfiling_duplicate_search=bugfiling_duplicate_search)
+
@implementer(IDistributionSet)
class DistributionSet:
diff --git a/lib/lp/registry/model/ociproject.py b/lib/lp/registry/model/ociproject.py
index 0b1390a..55b3ce3 100644
--- a/lib/lp/registry/model/ociproject.py
+++ b/lib/lp/registry/model/ociproject.py
@@ -7,11 +7,13 @@ from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
+ 'OCI_PROJECT_ALLOW_CREATE',
'OCIProject',
'OCIProjectSet',
]
import pytz
+from six import string_types
from storm.locals import (
Bool,
DateTime,
@@ -44,6 +46,9 @@ from lp.services.database.interfaces import (
from lp.services.database.stormbase import StormBase
+OCI_PROJECT_ALLOW_CREATE = 'oci.project.create.enabled'
+
+
def oci_project_modified(oci_project, event):
"""Update the date_last_modified property when an OCIProject is modified.
@@ -140,6 +145,9 @@ class OCIProjectSet:
bug_reported_acknowledgement=None,
bugfiling_duplicate_search=False):
"""See `IOCIProjectSet`."""
+ if isinstance(ociprojectname, string_types):
+ ociprojectname = getUtility(IOCIProjectNameSet).getOrCreateByName(
+ ociprojectname)
store = IMasterStore(OCIProject)
target = OCIProject()
target.date_created = date_created
@@ -158,6 +166,7 @@ class OCIProjectSet:
target.ociprojectname = ociprojectname
target.description = description
target.bug_reporting_guidelines = bug_reporting_guidelines
+ target.bug_reported_acknowledgement = bug_reported_acknowledgement
target.enable_bugfiling_duplicate_search = bugfiling_duplicate_search
store.add(target)
return target
diff --git a/lib/lp/registry/tests/test_ociproject.py b/lib/lp/registry/tests/test_ociproject.py
index af1ca26..7e291ce 100644
--- a/lib/lp/registry/tests/test_ociproject.py
+++ b/lib/lp/registry/tests/test_ociproject.py
@@ -10,6 +10,7 @@ __metaclass__ = type
import json
from six import string_types
+from storm.store import Store
from testtools.matchers import (
ContainsDict,
Equals,
@@ -24,6 +25,12 @@ from lp.registry.interfaces.ociproject import (
IOCIProjectSet,
)
from lp.registry.interfaces.ociprojectseries import IOCIProjectSeries
+from lp.registry.model.ociproject import (
+ OCI_PROJECT_ALLOW_CREATE,
+ OCIProject,
+ )
+from lp.services.features.testing import FeatureFixture
+from lp.services.macaroons.testing import MatchesStructure
from lp.services.webapp.interfaces import OAuthPermission
from lp.testing import (
admin_logged_in,
@@ -142,6 +149,7 @@ class TestOCIProjectWebservice(TestCaseWithFactory):
self.webservice = webservice_for_person(
self.person, permission=OAuthPermission.WRITE_PUBLIC,
default_api_version="devel")
+ self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: 'on'}))
def getAbsoluteURL(self, target):
"""Get the webservice absolute URL of the given object or relative
@@ -215,3 +223,51 @@ class TestOCIProjectWebservice(TestCaseWithFactory):
ws_project = self.load_from_api(url)
self.assertEqual("old description", ws_project['description'])
+
+ def test_create_oci_project(self):
+ with person_logged_in(self.person):
+ distro = removeSecurityProxy(self.factory.makeDistribution(
+ owner=self.person))
+ url = api_url(distro)
+
+ obj = {
+ "ociprojectname": "someprojectname",
+ "description": "My OCI project",
+ "bug_reporting_guidelines": "Bug reporting guide",
+ "bug_reported_acknowledgement": "Bug reporting ack",
+ "bugfiling_duplicate_search": True,
+ }
+ resp = self.webservice.named_post(url, "newOCIProject", **obj)
+ self.assertEqual(201, resp.status, resp.body)
+
+ store = Store.of(distro)
+ result_set = [i for i in store.find(OCIProject)]
+
+ self.assertEqual(1, len(result_set))
+ self.assertThat(result_set[0], MatchesStructure(
+ ociprojectname=MatchesStructure(
+ name=Equals(obj["ociprojectname"])),
+ description=Equals(obj["description"]),
+ bug_reporting_guidelines=Equals(obj["bug_reporting_guidelines"]),
+ bug_reported_acknowledgement=Equals(
+ obj["bug_reported_acknowledgement"]),
+ enable_bugfiling_duplicate_search=Equals(
+ obj["bugfiling_duplicate_search"])
+ ))
+
+ def test_api_create_oci_project_is_disabled_by_feature_flag(self):
+ self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: ''}))
+ with person_logged_in(self.person):
+ distro = removeSecurityProxy(self.factory.makeDistribution(
+ owner=self.person))
+ url = api_url(distro)
+
+ obj = {
+ "ociprojectname": "someprojectname",
+ "description": "My OCI project",
+ "bug_reporting_guidelines": "Bug reporting guide",
+ "bug_reported_acknowledgement": "Bug reporting ack",
+ "bugfiling_duplicate_search": True,
+ }
+ resp = self.webservice.named_post(url, "newOCIProject", **obj)
+ self.assertEqual(401, resp.status, resp.body)
Follow ups