Left a question below ^^ Diff comments:
> diff --git a/lpbuildd/target/build_craft.py b/lpbuildd/target/build_craft.py > index 69106a8..524d60f 100644 > --- a/lpbuildd/target/build_craft.py > +++ b/lpbuildd/target/build_craft.py > @@ -196,157 +196,144 @@ class BuildCraft( > name = key[len("CARGO_"):-len("_READ_AUTH")] > # Extract token from user:token format > token = value.split(":", 1)[1] > - cargo_vars[f"CARGO_REGISTRIES_{name}_TOKEN"] = f"Bearer > {token}" > + cargo_vars[f"CARGO_REGISTRIES_{name}_TOKEN"] = ( > + f"Bearer {token}" > + ) > > if cargo_vars: > # Tell Cargo to use token-based authentication from environment > - cargo_vars["CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"] = > "cargo:token" > - > + cargo_vars["CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"] = ( > + "cargo:token" > + ) > + > return cargo_vars > > def setup_maven_credentials(self): > - """Set up Maven credential files if needed. > - > + """Set up Maven credential files for Artifactory virtual repository. > + > Creates a Maven settings.xml file with: > - 1. Server configurations for authentication > - - One for release repository > - - One for snapshot repository > - - Uses credentials from MAVEN_*_READ_AUTH variables > - > - 2. Profile configurations for each repository > - - Defines both release and snapshot repositories > - - Configures plugin repositories > - - Controls snapshot behavior > - > - 3. Mirror configurations > - - Redirects all repository requests through Artifactory > - - Ensures dependencies are fetched through our proxy > - > - The resulting settings.xml allows Maven to: > - - Authenticate with private repositories > - - Use the correct URLs for artifacts > - - Handle both release and snapshot dependencies > - - Use plugin repositories with authentication > - > - It is up to the user to activate the profile they want to use > - in the command line (this is done inside sourcecraft.yaml). > + 1. Server configuration for authentication > + 2. Profile configuration for the virtual repository > + 3. Mirror configuration to redirect all requests through Artifactory > + > + Note: Multi-tenant Maven setups are complex due to how mirrors work. > + Instead, we use a single Artifactory virtual repository that shadows > + Maven Central and other remote repositories as needed. > """ > env_vars = dict( > - pair.split("=", maxsplit=1) > + pair.split("=", maxsplit=1) > for pair in self.args.environment_variables > ) > - > + > # Extract Maven-specific variables > - maven_vars = {k: v for k, v in env_vars.items() if > k.startswith("MAVEN_")} > + maven_vars = { > + k: v for k, v in env_vars.items() if k.startswith("MAVEN_") > + } > if not maven_vars: > + logger.info("No Maven environment variables found") > return > > # Create .m2 directory for Maven configuration > m2_dir = os.path.join(self.buildd_path, ".m2") > self.backend.run(["mkdir", "-p", m2_dir]) > > - # Parse repository URLs and credentials from environment variables > - repositories = {} > + # Parse single repository URL and credentials from env vars > + repository = {} > for key, value in maven_vars.items(): > if key.endswith("_URL"): > - repo_name = key[6:-4].lower() # Remove MAVEN_ and _URL > - repositories.setdefault(repo_name, {})["url"] = value > + repository["url"] = value > elif key.endswith("_READ_AUTH"): > - repo_name = key[6:-10].lower() # Remove MAVEN_ and > _READ_AUTH > user, token = value.split(":") > - repositories.setdefault(repo_name, {})["username"] = user > - repositories.setdefault(repo_name, {})["password"] = token > - > - # Create settings.xml with server configurations > - settings_xml = """<?xml version="1.0" encoding="UTF-8"?> > -<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" > - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > - xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 > http://maven.apache.org/xsd/settings-1.0.0.xsd"> > - <servers> > -""" > - # Add authentication for both release and snapshot repositories > - for name, repo in repositories.items(): > - if "username" in repo and "password" in repo: > - settings_xml += f""" <server> > - <id>{name}</id> > - <username>{repo['username']}</username> > - <password>{repo['password']}</password> > - </server> > - <server> > - <id>{name}-snapshots</id> > - <username>{repo['username']}</username> > - <password>{repo['password']}</password> > - </server> > -""" > - > - # Add profile configurations for repository definitions > - settings_xml += """ </servers> > - <profiles> > -""" > - for name, repo in repositories.items(): > - if "url" in repo: > - # Each profile contains both release and snapshot > repositories > - settings_xml += f""" <profile> > - <id>{name}</id> > - <repositories> > - <repository> > - <id>{name}</id> > - <name>{name}</name> > - <url>{repo['url']}</url> > - <snapshots> > - <enabled>false</enabled> > - </snapshots> > - </repository> > - <repository> > - <id>{name}-snapshots</id> > - <name>{name}</name> > - <url>{repo['url']}</url> > - <snapshots> > - <enabled>true</enabled> > - </snapshots> > - </repository> > - </repositories> > - <pluginRepositories> > - <pluginRepository> > - <id>{name}</id> > - <name>{name}</name> > - <url>{repo['url']}</url> > - <snapshots> > - <enabled>false</enabled> > - </snapshots> > - </pluginRepository> > - <pluginRepository> > - <id>{name}-snapshots</id> > - <name>{name}</name> > - <url>{repo['url']}</url> > - <snapshots> > - <enabled>true</enabled> > - </snapshots> > - </pluginRepository> > - </pluginRepositories> > - </profile> > -""" > - > - # Add mirror configurations to ensure all requests go through > Artifactory > - settings_xml += """ </profiles> > - <mirrors> > -""" > - for name, repo in repositories.items(): > - if "url" in repo: > - settings_xml += f""" <mirror> > - <id>{name}</id> > - <name>Maven Repository Manager running on {name}</name> > - <url>{repo['url']}</url> > - <mirrorOf>*</mirrorOf> > - </mirror> > -""" > - > - settings_xml += """ </mirrors> > -</settings> > -""" > + repository["username"] = user > + repository["password"] = token > + > + # Get repository name from environment variable > + # (e.g., MAVEN_ARTIFACTORY_URL -> artifactory) > + repo_name = None > + for key in maven_vars.keys(): Do we need another loop over maven_vars.keys()? There is already another loop up above with items() that is also parsing some variables, can't we connect them? Or is it done due to a reason like readability etc? > + if key.endswith("_URL"): > + repo_name = key[6:-4].lower() # Remove MAVEN_ and _URL > + break > + > + if not repo_name or not repository.get("url"): > + return > + > + # Generate Maven settings.xml > + settings_xml = self._generate_maven_settings_xml(repo_name, > repository) > + > 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): > + """Generate Maven settings.xml for single virtual repository. > + > + :param repo_name: Name/ID of the repository > + :param repository: Dict with repository configuration > + :return: XML content as string > + """ > + # XML header > + header = ( > + '<?xml version="1.0" encoding="UTF-8"?>\n' > + '<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"\n' > + ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' > + ) > + > + schema = ( > + ' xsi:schemaLocation="' > + "http://maven.apache.org/SETTINGS/1.0.0 " > + 'http://maven.apache.org/xsd/settings-1.0.0.xsd">\n' > + ) > + > + # Servers section for authentication > + servers = " <servers>\n" > + if "username" in repository and "password" in repository: > + servers += ( > + " <server>\n" > + f" <id>{repo_name}</id>\n" > + f" > <username>{repository['username']}</username>\n" > + f" > <password>{repository['password']}</password>\n" > + " </server>\n" > + ) > + servers += " </servers>\n" > + > + # Profiles section with virtual repository > + profiles = " <profiles>\n" > + profiles += ( > + " <profile>\n" > + f" <id>{repo_name}</id>\n" > + " <repositories>\n" > + " <repository>\n" > + f" <id>{repo_name}</id>\n" > + f" <name>Artifactory Virtual Repo</name>\n" > + f" <url>{repository['url']}</url>\n" > + " </repository>\n" > + " </repositories>\n" > + " <pluginRepositories>\n" > + " <pluginRepository>\n" > + f" <id>{repo_name}</id>\n" > + f" <name>Artifactory Virtual Repo</name>\n" > + f" <url>{repository['url']}</url>\n" > + " </pluginRepository>\n" > + " </pluginRepositories>\n" > + " </profile>\n" > + ) > + profiles += " </profiles>\n" > + > + # Mirrors section - redirect all requests through Artifactory > + mirrors = ( > + " <mirrors>\n" > + " <mirror>\n" > + f" <id>{repo_name}</id>\n" > + f" <name>Artifactory Virtual Repo</name>\n" > + f" <url>{repository['url']}</url>\n" > + " <mirrorOf>*</mirrorOf>\n" > + " </mirror>\n" > + " </mirrors>\n" > + ) > + > + # Combine all parts > + return header + schema + servers + profiles + mirrors + "</settings>" > + > def build(self): > """Running build phase...""" > # Set up credential files before building -- https://code.launchpad.net/~ruinedyourlife/launchpad-buildd/+git/launchpad-buildd/+merge/490002 Your team Launchpad code reviewers is requested to review the proposed merge of ~ruinedyourlife/launchpad-buildd:maven-virtual-remote into launchpad-buildd:master. _______________________________________________ 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