Quentin Debhi has proposed merging ~ruinedyourlife/launchpad-buildd:maven-virtual-remote into launchpad-buildd:master.
Commit message: Allow maven to pull plugins from AF and disallow external access Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~ruinedyourlife/launchpad-buildd/+git/launchpad-buildd/+merge/490354 -- Your team Launchpad code reviewers is requested to review the proposed merge of ~ruinedyourlife/launchpad-buildd:maven-virtual-remote into launchpad-buildd:master.
diff --git a/lpbuildd/target/build_craft.py b/lpbuildd/target/build_craft.py index 1e01c97..81cb27f 100644 --- a/lpbuildd/target/build_craft.py +++ b/lpbuildd/target/build_craft.py @@ -1,5 +1,6 @@ import logging import os +from urllib.parse import urlparse from lpbuildd.target.backend import check_path_escape from lpbuildd.target.build_snap import SnapChannelsAction @@ -122,7 +123,7 @@ class BuildCraft( "snap", "install", "--classic", - "--channel=latest/edge/craftctl", + "--channel=latest/edge", "sourcecraft", ] ) @@ -208,13 +209,14 @@ class BuildCraft( return cargo_vars - def setup_maven_credentials(self): + def setup_maven_credentials(self, proxy_env=None): """Set up Maven credential files for Artifactory virtual repository. Creates a Maven settings.xml file with: 1. Server configuration for authentication 2. Profile configuration for the virtual repository 3. Mirror configuration to redirect all requests through Artifactory + 4. Proxy configuration for HTTP requests Note: Multi-tenant Maven setups are complex due to how mirrors work. Instead, we use a single Artifactory virtual repository that shadows @@ -234,7 +236,7 @@ class BuildCraft( return # Create .m2 directory for Maven configuration - m2_dir = os.path.join(self.buildd_path, ".m2") + m2_dir = os.path.join("/root", ".m2") self.backend.run(["mkdir", "-p", m2_dir]) # Parse single repository URL, credentials, and name from env vars @@ -254,17 +256,23 @@ class BuildCraft( if not repo_name or not repository.get("url"): return + # Extract proxy URL from environment if available + proxy_url = None + if proxy_env and "http_proxy" in proxy_env: + proxy_url = proxy_env["http_proxy"] + # Generate Maven settings.xml - settings_xml = self._generate_maven_settings_xml(repo_name, repository) + settings_xml = self._generate_maven_settings_xml(repo_name, repository, proxy_url) with self.backend.open(os.path.join(m2_dir, "settings.xml"), "w") as f: f.write(settings_xml) - def _generate_maven_settings_xml(self, repo_name, repository): + def _generate_maven_settings_xml(self, repo_name, repository, proxy_url=None): """Generate Maven settings.xml for single virtual repository. :param repo_name: Name/ID of the repository :param repository: Dict with repository configuration + :param proxy_url: Optional proxy URL for Maven to use :return: XML content as string """ # XML header @@ -292,6 +300,23 @@ class BuildCraft( ) servers += " </servers>\n" + # Proxies section for HTTP proxy configuration + proxies = " <proxies>\n" + if proxy_url: + # Parse proxy URL to extract host, port, and credentials + parsed_proxy = urlparse(proxy_url) + + proxies += ( + " <proxy>\n" + " <id>default</id>\n" + " <active>true</active>\n" + " <protocol>http</protocol>\n" + f" <host>{parsed_proxy.hostname}</host>\n" + f" <port>{parsed_proxy.port or 80}</port>\n" + " </proxy>\n" + ) + proxies += " </proxies>\n" + # Profiles section with virtual repository profiles = " <profiles>\n" profiles += ( @@ -328,23 +353,25 @@ class BuildCraft( ) # Combine all parts - return header + schema + servers + profiles + mirrors + "</settings>" + return header + schema + servers + proxies + profiles + mirrors + "</settings>" def build(self): """Running build phase...""" + env = self.build_proxy_environment( + proxy_url=self.args.proxy_url, + use_fetch_service=self.args.use_fetch_service, + ) + # Set up credential files before building cargo_env = self.setup_cargo_credentials() - self.setup_maven_credentials() + self.setup_maven_credentials(proxy_env=env) logger.info("Running build phase...") build_context_path = os.path.join( "/home/buildd", self.args.name, self.args.build_path ) check_path_escape(self.buildd_path, build_context_path) - env = self.build_proxy_environment( - proxy_url=self.args.proxy_url, - use_fetch_service=self.args.use_fetch_service, - ) + if cargo_env: env.update(cargo_env) if self.args.launchpad_instance: diff --git a/lpbuildd/target/tests/test_build_craft.py b/lpbuildd/target/tests/test_build_craft.py index 0e83514..98f2623 100644 --- a/lpbuildd/target/tests/test_build_craft.py +++ b/lpbuildd/target/tests/test_build_craft.py @@ -130,7 +130,7 @@ class TestBuildCraft(TestCase): RanSnap( "install", "--classic", - "--channel=latest/edge/craftctl", + "--channel=latest/edge", "sourcecraft", ), RanCommand(["mkdir", "-p", "/home/buildd"]), @@ -159,7 +159,7 @@ class TestBuildCraft(TestCase): RanSnap( "install", "--classic", - "--channel=latest/edge/craftctl", + "--channel=latest/edge", "sourcecraft", ), RanCommand(["mkdir", "-p", "/home/buildd"]), @@ -216,7 +216,7 @@ class TestBuildCraft(TestCase): RanSnap( "install", "--classic", - "--channel=latest/edge/craftctl", + "--channel=latest/edge", "sourcecraft", ), RanCommand(["mkdir", "-p", "/home/buildd"]), @@ -258,7 +258,7 @@ class TestBuildCraft(TestCase): RanSnap( "install", "--classic", - "--channel=latest/edge/craftctl", + "--channel=latest/edge", "sourcecraft", ), RanCommand(["mkdir", "-p", "/home/buildd"]), @@ -310,7 +310,7 @@ class TestBuildCraft(TestCase): RanSnap( "install", "--classic", - "--channel=latest/edge/craftctl", + "--channel=latest/edge", "sourcecraft", ), RanCommand(["rm", "-rf", "/var/lib/apt/lists"]), @@ -410,7 +410,7 @@ class TestBuildCraft(TestCase): RanSnap( "install", "--classic", - "--channel=latest/edge/craftctl", + "--channel=latest/edge", "sourcecraft", ), RanCommand(["rm", "-rf", "/var/lib/apt/lists"]), @@ -1305,7 +1305,7 @@ class TestBuildCraft(TestCase): build_craft.build() # Check that .m2/settings.xml was created correctly - maven_settings_path = "/home/buildd/test-image/.m2/settings.xml" + maven_settings_path = "/root/.m2/settings.xml" self.assertTrue(build_craft.backend.path_exists(maven_settings_path)) with build_craft.backend.open(maven_settings_path) as f: settings_content = f.read() @@ -1359,7 +1359,7 @@ class TestBuildCraft(TestCase): build_craft.backend.run.calls, MatchesListwise( [ - RanCommand(["mkdir", "-p", "/home/buildd/test-image/.m2"]), + RanCommand(["mkdir", "-p", "/root/.m2"]), RanBuildCommand( ["sourcecraft", "pack", "-v", "--destructive-mode"], cwd="/home/buildd/test-image/.", @@ -1384,7 +1384,7 @@ class TestBuildCraft(TestCase): build_craft.build() # Check that .m2/settings.xml was NOT created - maven_settings_path = "/home/buildd/test-image/.m2/settings.xml" + maven_settings_path = "/root/.m2/settings.xml" self.assertFalse(build_craft.backend.path_exists(maven_settings_path)) # Verify only the build command was run (no mkdir for .m2)
_______________________________________________ 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