launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #32575
[Merge] ~tushar5526/launchpad:add-support-for-git-path-and-git-repository-url into launchpad:master
Tushar Gupta has proposed merging ~tushar5526/launchpad:add-support-for-git-path-and-git-repository-url into launchpad:master.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~tushar5526/launchpad/+git/launchpad/+merge/486448
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~tushar5526/launchpad:add-support-for-git-path-and-git-repository-url into launchpad:master.
diff --git a/lib/lp/charms/interfaces/charmrecipe.py b/lib/lp/charms/interfaces/charmrecipe.py
index 77dcf02..e947fd7 100644
--- a/lib/lp/charms/interfaces/charmrecipe.py
+++ b/lib/lp/charms/interfaces/charmrecipe.py
@@ -83,6 +83,7 @@ from lp.services.fields import (
PersonChoice,
PublicPersonChoice,
SnapBuildChannelsField,
+ URIField,
)
from lp.services.webhooks.interfaces import IWebhookTarget
from lp.snappy.validators.channels import channels_validator
@@ -622,22 +623,46 @@ class ICharmRecipeEditableAttributes(Interface):
)
)
- git_repository = ReferenceChoice(
- title=_("Git repository"),
- schema=IGitRepository,
- vocabulary="GitRepository",
- required=False,
- readonly=True,
- description=_(
- "A Git repository with a branch containing a charm recipe."
- ),
+ git_repository = exported(
+ ReferenceChoice(
+ title=_("Git repository"),
+ schema=IGitRepository,
+ vocabulary="GitRepository",
+ required=False,
+ readonly=True,
+ description=_(
+ "A Git repository with a branch containing a charm recipe."
+ ),
+ )
)
- git_path = TextLine(
- title=_("Git branch path"),
- required=False,
- readonly=True,
- description=_("The path of the Git branch containing a charm recipe."),
+ git_path = exported(
+ TextLine(
+ title=_("Git branch path"),
+ required=False,
+ readonly=True,
+ description=_(
+ "The path of the Git branch containing a charm recipe."
+ ),
+ )
+ )
+
+ git_repository_url = exported(
+ URIField(
+ title=_("Git repository URL"),
+ required=False,
+ readonly=True,
+ description=_(
+ "The URL of a Git repository with a branch containing a "
+ "charmcraft.yaml at the top level."
+ ),
+ allowed_schemes=["git", "http", "https"],
+ allow_userinfo=True,
+ allow_port=True,
+ allow_query=False,
+ allow_fragment=False,
+ trailing_slash=False,
+ )
)
git_ref = exported(
@@ -830,6 +855,9 @@ class ICharmRecipeSet(Interface):
"project",
"name",
"description",
+ "git_repository",
+ "git_repository_url",
+ "git_path",
"git_ref",
"build_path",
"auto_build",
@@ -846,6 +874,9 @@ class ICharmRecipeSet(Interface):
project,
name,
description=None,
+ git_repository=None,
+ git_repository_url=None,
+ git_path=None,
git_ref=None,
build_path=None,
require_virtualized=True,
diff --git a/lib/lp/charms/model/charmrecipe.py b/lib/lp/charms/model/charmrecipe.py
index 82ea9c3..dfea776 100644
--- a/lib/lp/charms/model/charmrecipe.py
+++ b/lib/lp/charms/model/charmrecipe.py
@@ -43,6 +43,7 @@ from lp.app.enums import (
PUBLIC_INFORMATION_TYPES,
InformationType,
)
+from lp.app.errors import IncompatibleArguments
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.buildmaster.builderproxy import FetchServicePolicy
from lp.buildmaster.enums import BuildStatus
@@ -88,7 +89,7 @@ from lp.code.interfaces.gitcollection import (
IAllGitRepositories,
IGitCollection,
)
-from lp.code.interfaces.gitref import IGitRef
+from lp.code.interfaces.gitref import IGitRef, IGitRefRemoteSet
from lp.code.interfaces.gitrepository import IGitRepository
from lp.code.model.gitcollection import GenericGitCollection
from lp.code.model.gitref import GitRef
@@ -284,6 +285,8 @@ class CharmRecipe(StormBase, WebhookTargetMixin):
)
git_repository = Reference(git_repository_id, "GitRepository.id")
+ git_repository_url = Unicode(name="git_repository_url", allow_none=True)
+
git_path = Unicode(name="git_path", allow_none=True)
build_path = Unicode(name="build_path", allow_none=True)
@@ -392,6 +395,10 @@ class CharmRecipe(StormBase, WebhookTargetMixin):
def _git_ref(self):
if self.git_repository is not None:
return self.git_repository.getRefByPath(self.git_path)
+ elif self.git_repository_url is not None:
+ return getUtility(IGitRefRemoteSet).new(
+ self.git_repository_url, self.git_path
+ )
else:
return None
@@ -405,9 +412,11 @@ class CharmRecipe(StormBase, WebhookTargetMixin):
"""See `ICharmRecipe`."""
if value is not None:
self.git_repository = value.repository
+ self.git_repository_url = value.repository_url
self.git_path = value.path
else:
self.git_repository = None
+ self.git_repository_url = None
self.git_path = None
get_property_cache(self)._git_ref = value
@@ -960,6 +969,9 @@ class CharmRecipeSet:
project,
name,
description=None,
+ git_repository=None,
+ git_repository_url=None,
+ git_path=None,
git_ref=None,
build_path=None,
require_virtualized=True,
@@ -986,6 +998,33 @@ class CharmRecipeSet:
"%s cannot create charm recipes owned by %s."
% (registrant.displayname, owner.displayname)
)
+ if (
+ sum(
+ [
+ git_repository is not None,
+ git_repository_url is not None,
+ git_ref is not None,
+ ]
+ )
+ > 1
+ ):
+ raise IncompatibleArguments(
+ "You cannot specify more than one of 'git_repository', "
+ "'git_repository_url', and 'git_ref'."
+ )
+ if (git_repository is None and git_repository_url is None) != (
+ git_path is None
+ ):
+ raise IncompatibleArguments(
+ "You must specify both or neither of "
+ "'git_repository'/'git_repository_url' and 'git_path'."
+ )
+ if git_repository is not None:
+ git_ref = git_repository.getRefByPath(git_path)
+ elif git_repository_url is not None:
+ git_ref = getUtility(IGitRefRemoteSet).new(
+ git_repository_url, git_path
+ )
if git_ref is None:
raise NoSourceForCharmRecipe
@@ -1073,7 +1112,12 @@ class CharmRecipeSet:
git_collection = removeSecurityProxy(getUtility(IAllGitRepositories))
git_recipes = _getRecipes(git_collection)
- return git_recipes
+ git_url_recipes = IStore(CharmRecipe).find(
+ CharmRecipe,
+ CharmRecipe.owner == person,
+ CharmRecipe.git_repository_url != None,
+ )
+ return git_recipes.union(git_url_recipes)
def findByProject(self, project, visible_by_user=None):
"""See `ICharmRecipeSet`."""
diff --git a/lib/lp/charms/tests/test_charmrecipe.py b/lib/lp/charms/tests/test_charmrecipe.py
index e837e4b..402d890 100644
--- a/lib/lp/charms/tests/test_charmrecipe.py
+++ b/lib/lp/charms/tests/test_charmrecipe.py
@@ -1706,6 +1706,17 @@ class TestCharmRecipeSet(TestCaseWithFactory):
FetchServicePolicy.STRICT, recipe.fetch_service_policy
)
+ def test_creation_git_url(self):
+ # A charm recipe can be backed directly by a URL for an external Git
+ # repository, rather than a Git repository hosted in Launchpad.
+ ref = self.factory.makeGitRefRemote()
+ components = self.makeCharmRecipeComponents(git_ref=ref)
+ charm_recipe = getUtility(ICharmRecipeSet).new(**components)
+ self.assertIsNone(charm_recipe.git_repository)
+ self.assertEqual(ref.repository_url, charm_recipe.git_repository_url)
+ self.assertEqual(ref.path, charm_recipe.git_path)
+ self.assertEqual(ref, charm_recipe.git_ref)
+
def test_creation_no_source(self):
# Attempting to create a charm recipe without a Git repository
# fails.
Follow ups