← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~ruinedyourlife/launchpad-buildd:maven-local-repo into launchpad-buildd:master

 

Quentin Debhi has proposed merging ~ruinedyourlife/launchpad-buildd:maven-local-repo into launchpad-buildd:master.

Commit message:
Maven local repos & exclusive mirrors

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~ruinedyourlife/launchpad-buildd/+git/launchpad-buildd/+merge/489582
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~ruinedyourlife/launchpad-buildd:maven-local-repo into launchpad-buildd:master.
diff --git a/lpbuildd/target/build_craft.py b/lpbuildd/target/build_craft.py
index 69106a8..0ff403f 100644
--- a/lpbuildd/target/build_craft.py
+++ b/lpbuildd/target/build_craft.py
@@ -326,18 +326,53 @@ class BuildCraft(
             </pluginRepositories>
         </profile>
 """
+                
+        # Add a local plugin repository profile
+        settings_xml += """        <profile>
+            <id>local-plugin-repo</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <pluginRepositories>
+                <pluginRepository>
+                    <id>local-plugin-repo</id>
+                    <name>Local Plugin Repository</name>
+                    <url>file:///usr/share/maven-repo</url>
+                </pluginRepository>
+            </pluginRepositories>
+        </profile>
+"""
+
+        # Add a local repository profile
+        settings_xml += """        <profile>
+            <id>local-repo</id>
+            <repositories>
+                <repository>
+                    <id>local-repo</id>
+                    <name>Local Repository</name>
+                    <url>file:///usr/share/maven-repo</url>
+                </repository>
+            </repositories>
+        </profile>
+"""
 
         # Add mirror configurations to ensure all requests go through Artifactory
+        # but exclude local repositories
         settings_xml += """    </profiles>
     <mirrors>
 """
         for name, repo in repositories.items():
             if "url" in repo:
+                other_ids = [
+                    f"!{other}" for other in repositories if other != name
+                ]
+                other_ids += ["!local-repo", "!local-plugin-repo"]
+                mirror_of = "*,{}".format(",".join(other_ids))
                 settings_xml += f"""        <mirror>
             <id>{name}</id>
             <name>Maven Repository Manager running on {name}</name>
             <url>{repo['url']}</url>
-            <mirrorOf>*</mirrorOf>
+            <mirrorOf>{mirror_of}</mirrorOf>
         </mirror>
 """
 
diff --git a/lpbuildd/target/tests/test_build_craft.py b/lpbuildd/target/tests/test_build_craft.py
index fe342c4..15fdba7 100644
--- a/lpbuildd/target/tests/test_build_craft.py
+++ b/lpbuildd/target/tests/test_build_craft.py
@@ -1332,7 +1332,7 @@ class TestBuildCraft(TestCase):
             
             # Check mirrors
             self.assertIn('        <mirror>', settings_content)
-            self.assertIn('            <mirrorOf>*</mirrorOf>', settings_content)
+            self.assertIn('            <mirrorOf>*,!local-repo,!local-plugin-repo</mirrorOf>', settings_content)
             
             # Verify activeProfiles section is not present
             self.assertNotIn('<activeProfiles>', settings_content)
@@ -1399,7 +1399,10 @@ class TestBuildCraft(TestCase):
                 
                 # Check mirrors with exact indentation
                 self.assertIn(f'            <id>{repo_name}</id>', settings_content)
-                self.assertIn('            <mirrorOf>*</mirrorOf>', settings_content)
+            
+            # Check that mirrors exclude each other and local repositories
+            self.assertIn('<mirrorOf>*,!artifactory2,!local-repo,!local-plugin-repo</mirrorOf>', settings_content)
+            self.assertIn('<mirrorOf>*,!artifactory1,!local-repo,!local-plugin-repo</mirrorOf>', settings_content)
             
             # Verify activeProfiles section is not present
             self.assertNotIn('<activeProfiles>', settings_content)
@@ -1417,3 +1420,182 @@ class TestBuildCraft(TestCase):
                 ]
             ),
         )
+
+    def test_build_with_local_repositories_only(self):
+        """Test that local repositories are configured when no external Maven repos are provided."""
+        args = [
+            "build-craft",
+            "--backend=fake",
+            "--series=xenial",
+            "--arch=amd64",
+            "1",
+            "--branch",
+            "lp:foo",
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY_URL=https://canonical.example.com/artifactory/api/maven/maven-upstream/";,
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY_READ_AUTH=user:token123",
+            "test-image",
+        ]
+        build_craft = parse_args(args=args).operation
+        build_craft.build()
+
+        # Check that .m2/settings.xml was created with local repositories
+        maven_settings_path = "/home/buildd/test-image/.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()
+            
+            # Check local plugin repository profile
+            self.assertIn('        <profile>', settings_content)
+            self.assertIn('            <id>local-plugin-repo</id>', settings_content)
+            self.assertIn('                <activeByDefault>true</activeByDefault>', settings_content)
+            self.assertIn('                <pluginRepository>', settings_content)
+            self.assertIn('                    <name>Local Plugin Repository</name>', settings_content)
+            self.assertIn('                    <url>file:///usr/share/maven-repo</url>', settings_content)
+            
+            # Check local repository profile (should not be activated by default)
+            self.assertIn('            <id>local-repo</id>', settings_content)
+            self.assertIn('                <repository>', settings_content)
+            self.assertIn('                    <name>Local Repository</name>', settings_content)
+            
+            # Should not have activation for local-repo
+            local_repo_section_start = settings_content.find('<id>local-repo</id>')
+            local_repo_section_end = settings_content.find('</profile>', local_repo_section_start)
+            local_repo_section = settings_content[local_repo_section_start:local_repo_section_end]
+            self.assertNotIn('<activation>', local_repo_section)
+
+    def test_build_with_maven_credentials_and_local_repos(self):
+        """Test that both external and local repositories are configured correctly."""
+        args = [
+            "build-craft",
+            "--backend=fake",
+            "--series=xenial",
+            "--arch=amd64",
+            "1",
+            "--branch",
+            "lp:foo",
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY_URL=https://canonical.example.com/artifactory/api/maven/maven-upstream/";,
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY_READ_AUTH=user:token123",
+            "test-image",
+        ]
+        build_craft = parse_args(args=args).operation
+        build_craft.build()
+
+        # Check that .m2/settings.xml was created correctly
+        maven_settings_path = "/home/buildd/test-image/.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()
+            
+            # Check external repository configuration
+            self.assertIn('            <id>artifactory</id>', settings_content)
+            self.assertIn('            <username>user</username>', settings_content)
+            self.assertIn('            <password>token123</password>', settings_content)
+            
+            # Check local repositories are still present
+            self.assertIn('            <id>local-plugin-repo</id>', settings_content)
+            self.assertIn('            <id>local-repo</id>', settings_content)
+            self.assertIn('file:///usr/share/maven-repo', settings_content)
+            
+            # Check mirror excludes local repositories
+            self.assertIn('<mirrors>', settings_content)
+            self.assertIn('            <mirrorOf>*,!local-repo,!local-plugin-repo</mirrorOf>', settings_content)
+
+    def test_build_with_multiple_maven_credentials_mirror_exclusions(self):
+        """Test that mirrors properly exclude each other and local repositories."""
+        args = [
+            "build-craft",
+            "--backend=fake",
+            "--series=xenial",
+            "--arch=amd64",
+            "1",
+            "--branch",
+            "lp:foo",
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY1_URL=https://canonical.example.com/artifactory/api/maven/maven-upstream1/";,
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY1_READ_AUTH=user1:token1",
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY2_URL=https://canonical.example.com/artifactory/api/maven/maven-upstream2/";,
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY2_READ_AUTH=user2:token2",
+            "test-image",
+        ]
+        build_craft = parse_args(args=args).operation
+        build_craft.build()
+
+        # Check that .m2/settings.xml was created correctly
+        maven_settings_path = "/home/buildd/test-image/.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()
+            
+            # Check that each mirror excludes the other repositories and local repos
+            # Find the mirrors section first
+            mirrors_start = settings_content.find('<mirrors>')
+            mirrors_end = settings_content.find('</mirrors>')
+            mirrors_section = settings_content[mirrors_start:mirrors_end]
+            
+            # artifactory1 mirror should exclude artifactory2, and local repos
+            artifactory1_mirror_start = mirrors_section.find('<id>artifactory1</id>')
+            artifactory1_mirror_end = mirrors_section.find('</mirror>', artifactory1_mirror_start)
+            artifactory1_mirror = mirrors_section[artifactory1_mirror_start:artifactory1_mirror_end]
+            self.assertIn('<mirrorOf>*,!artifactory2,!local-repo,!local-plugin-repo</mirrorOf>', artifactory1_mirror)
+            
+            # artifactory2 mirror should exclude artifactory1, and local repos
+            artifactory2_mirror_start = mirrors_section.find('<id>artifactory2</id>')
+            artifactory2_mirror_end = mirrors_section.find('</mirror>', artifactory2_mirror_start)
+            artifactory2_mirror = mirrors_section[artifactory2_mirror_start:artifactory2_mirror_end]
+            self.assertIn('<mirrorOf>*,!artifactory1,!local-repo,!local-plugin-repo</mirrorOf>', artifactory2_mirror)
+            
+            # Verify all repositories have both release and snapshot server configs
+            for repo_name in ['artifactory1', 'artifactory2']:
+                self.assertIn(f'            <id>{repo_name}</id>', settings_content)
+                self.assertIn(f'            <id>{repo_name}-snapshots</id>', settings_content)
+            
+            # Verify local repositories are configured
+            self.assertIn('            <id>local-plugin-repo</id>', settings_content)
+            self.assertIn('            <id>local-repo</id>', settings_content)
+
+    def test_build_maven_local_repo_file_path(self):
+        """Test that local repository paths use the correct file:// URL format."""
+        args = [
+            "build-craft",
+            "--backend=fake",
+            "--series=xenial",
+            "--arch=amd64",
+            "1",
+            "--branch",
+            "lp:foo",
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY_URL=https://canonical.example.com/artifactory/api/maven/maven-upstream/";,
+            "--environment-variable",
+            "MAVEN_ARTIFACTORY_READ_AUTH=user:token123",
+            "test-image",
+        ]
+        build_craft = parse_args(args=args).operation
+        build_craft.build()
+
+        # Check that .m2/settings.xml was created with correct file URLs
+        maven_settings_path = "/home/buildd/test-image/.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()
+            
+            # Should have exactly 2 occurrences of the local repo URL
+            file_url_count = settings_content.count('file:///usr/share/maven-repo')
+            self.assertEqual(2, file_url_count, 
+                "Should have local repo URL in both repository and pluginRepository")
+            
+            # Verify both repository and pluginRepository sections exist
+            self.assertIn('<repositories>', settings_content)
+            self.assertIn('<pluginRepositories>', settings_content)
+            
+            # Verify the local plugin repo is activated by default
+            local_plugin_section_start = settings_content.find('<id>local-plugin-repo</id>')
+            local_plugin_section_end = settings_content.find('</profile>', local_plugin_section_start)
+            local_plugin_section = settings_content[local_plugin_section_start:local_plugin_section_end]
+            self.assertIn('<activeByDefault>true</activeByDefault>', local_plugin_section)