launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #32535
[Merge] ~ilkeremrekoc/launchpad:maven-cargo-metadata into launchpad:master
İlker Emre Koç has proposed merging ~ilkeremrekoc/launchpad:maven-cargo-metadata into launchpad:master.
Commit message:
Add metadata to the published craft packages
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~ilkeremrekoc/launchpad/+git/launchpad/+merge/486190
There isn't a reliable way to put the necessary metadata to Artifactory
during publishing of Cargo and Maven builds. As a result, we will
instead, add these metadata right after publishing instead.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~ilkeremrekoc/launchpad:maven-cargo-metadata into launchpad:master.
diff --git a/lib/lp/crafts/model/craftrecipebuildjob.py b/lib/lp/crafts/model/craftrecipebuildjob.py
index 8133aeb..11b9f1c 100644
--- a/lib/lp/crafts/model/craftrecipebuildjob.py
+++ b/lib/lp/crafts/model/craftrecipebuildjob.py
@@ -11,11 +11,14 @@ __all__ = [
import json
import os
+import re
import subprocess
import tempfile
from configparser import NoSectionError
import transaction
+import yaml
+from artifactory import ArtifactoryPath
from lazr.delegates import delegate_to
from lazr.enum import DBEnumeratedType, DBItem
from storm.databases.postgres import JSON
@@ -273,7 +276,9 @@ class CraftPublishingJob(CraftRecipeBuildJobDerived):
)
# Publish the Rust crate
- self._publish_rust_crate(crate_dir, env_vars)
+ self._publish_rust_crate(
+ crate_dir, env_vars, crate_file.filename
+ )
elif jar_file is not None and pom_file is not None:
# Download the jar file
jar_path = os.path.join(tmpdir, jar_file.filename)
@@ -297,6 +302,7 @@ class CraftPublishingJob(CraftRecipeBuildJobDerived):
self._publish_maven_artifact(
tmpdir,
env_vars,
+ jar_file.filename,
jar_path,
pom_path,
)
@@ -312,7 +318,7 @@ class CraftPublishingJob(CraftRecipeBuildJobDerived):
transaction.commit()
raise
- def _publish_rust_crate(self, extract_dir, env_vars):
+ def _publish_rust_crate(self, extract_dir, env_vars, artifact_name):
"""Publish Rust crates from the extracted crate directory.
:param extract_dir: Path to the extracted crate directory
@@ -373,8 +379,10 @@ class CraftPublishingJob(CraftRecipeBuildJobDerived):
if result.returncode != 0:
raise Exception(f"Failed to publish crate: {result.stderr}")
+ self._publish_properties(cargo_publish_url, artifact_name)
+
def _publish_maven_artifact(
- self, work_dir, env_vars, jar_path=None, pom_path=None
+ self, work_dir, env_vars, artifact_name, jar_path=None, pom_path=None
):
"""Publish Maven artifacts.
@@ -435,6 +443,8 @@ class CraftPublishingJob(CraftRecipeBuildJobDerived):
f"Failed to publish Maven artifact: {result.stderr}"
)
+ self._publish_properties(maven_publish_url, artifact_name)
+
def _get_maven_settings_xml(self, username, password):
"""Generate Maven settings.xml content.
@@ -488,3 +498,69 @@ class CraftPublishingJob(CraftRecipeBuildJobDerived):
# Combine all parts
return header + schema + servers + profiles + active_profiles
+
+ def _publish_properties(
+ self, publish_url: str, artifact_name: str
+ ) -> None:
+ """Publish properties to the artifact in Artifactory."""
+
+ new_properties = {}
+
+ new_properties["soss.commit_id"] = self.build.revision_id
+ new_properties["soss.source_url"] = self._recipe_git_url()
+ new_properties["soss.type"] = "source"
+ new_properties["soss.license"] = self._get_license_metadata()
+
+ artifact = config.artifactory.base_url.aql(
+ "items.find",
+ {
+ "repo": self._extract_repository_name(publish_url),
+ "name": artifact_name,
+ },
+ ".include",
+ # We don't use "repo", but the AQL documentation says that
+ # non-admin users must include all of "name", "repo",
+ # and "path" in the include directive.
+ ["repo", "path", "name"],
+ )
+
+ path = ArtifactoryPath(artifact["path"], artifact["name"])
+ path.set_properties(new_properties)
+
+ def _extract_repository_name(self, url: str) -> str:
+ # Remove trailing slash if present
+ url = url.rstrip("/")
+
+ # Use regex to match the last part after the last slash
+ match = re.search(r"/([^/]+)$", url)
+
+ if match:
+ return match.group(1)
+ else:
+ raise Exception(
+ "Couldn't parse repository name from publishing URL"
+ )
+
+ def _recipe_git_url(self) -> str | None:
+ """Get the recipe git URL."""
+
+ craft_recipe = self.build.recipe
+ if craft_recipe.git_repository is not None:
+ return craft_recipe.git_repository.git_https_url
+ elif craft_recipe.git_repository_url is not None:
+ return craft_recipe.git_repository_url
+ else:
+ return None
+
+ def _get_license_metadata(self) -> str:
+ """Get the license metadata from the build files."""
+ for _, lfa, _ in self.build.getFiles():
+ if lfa.filename == "metadata.yaml":
+ lfa.open()
+ try:
+ content = lfa.read().decode("utf-8")
+ metadata = yaml.safe_load(content)
+ return metadata.get("license")
+ finally:
+ lfa.close()
+ return "unknown"
References