001/* 002 * JDrupes Builder 003 * Copyright (C) 2026 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.builder.mvnrepo; 020 021import com.google.common.flogger.FluentLogger; 022import java.util.Arrays; 023import java.util.EnumSet; 024import java.util.List; 025import java.util.Set; 026import org.eclipse.aether.artifact.Artifact; 027import org.jdrupes.builder.api.BuildContext; 028 029/// The base class for all Maven publishing destinations. 030/// 031/// It provides common functionality for managing repository credentials, 032/// supporting fallbacks to build context properties and Maven's `settings.xml`, 033/// and defining which [PublicationType] (SNAPSHOT or RELEASE) the destination 034/// accepts. 035/// 036public abstract class MvnPublishingDestination { 037 038 private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 039 private final Set<PublicationType> acceptedTypes; 040 private String repoUser; 041 private String repoPass; 042 private String id; 043 044 /// The versions of artifacts that can be published to this destination. 045 /// 046 public enum PublicationType { 047 /// The snapshot type. 048 SNAPSHOT, 049 /// The release type. 050 RELEASE 051 } 052 053 /// Initializes a new Maven publishing destination. 054 /// 055 /// @param publicationTypes the accepted publication types 056 /// 057 public MvnPublishingDestination(PublicationType... publicationTypes) { 058 acceptedTypes = EnumSet.copyOf(Arrays.asList(publicationTypes)); 059 } 060 061 /// Checks if the given publication type is accepted. 062 /// 063 /// @param type the type 064 /// @return true, if successful 065 /// 066 public boolean accepts(PublicationType type) { 067 return acceptedTypes.contains(type); 068 } 069 070 /// Sets the id. 071 /// 072 /// @param id the new id 073 /// @return this destination 074 /// 075 @SuppressWarnings("PMD.ShortMethodName") 076 public MvnPublishingDestination id(String id) { 077 this.id = id; 078 return this; 079 } 080 081 /// 082 /// Returns the id. 083 /// 084 /// @return the id 085 /// 086 @SuppressWarnings("PMD.ShortMethodName") 087 public String id() { 088 return id; 089 } 090 091 /// Sets the Maven repository credentials. 092 /// 093 /// @param user the user name 094 /// @param pass the password 095 /// @return this destination 096 /// 097 public MvnPublishingDestination credentials(String user, String pass) { 098 logger.atConfig().log("Using explicitly set credentials for %s", this); 099 this.repoUser = user; 100 this.repoPass = pass; 101 return this; 102 } 103 104 /// Returns the repository user set by [credentials] or a fallback. 105 /// 106 /// The fallback order is: 107 /// 108 /// 1. Look for properties `mvnrepo.user` and `mvnrepo.password` 109 /// in the properties provided by the [BuildContext]. 110 /// 111 /// 2. If an id is set, look for the user and password in the 112 /// `servers` section with this id in the Maven `settings.xml`. 113 /// 114 /// @param context the context 115 /// @return the user 116 /// 117 protected String repositoryUser(BuildContext context) { 118 fillInCredentials(context); 119 return repoUser; 120 } 121 122 /// Returns the repository password set by [credentials] or a fallback. 123 /// See [repositoryUser] for the fallback logic. 124 /// 125 /// @param context the context 126 /// @return the password 127 /// 128 protected String repositoryPassword(BuildContext context) { 129 fillInCredentials(context); 130 return repoPass; 131 } 132 133 @SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel") 134 private synchronized void fillInCredentials(BuildContext context) { 135 if (repoUser != null) { 136 return; 137 } 138 139 // Try properties 140 var user = context.property("mvnrepo.user", null); 141 if (user != null) { 142 logger.atConfig().log( 143 "Using credentials from properties for %s", this); 144 repoUser = user; 145 repoPass = context.property("mvnrepo.password", null); 146 return; 147 } 148 149 // Try settings 150 if (id != null 151 && MvnRepoLookup.mavenContext().settings().getServers().stream() 152 .filter(s -> id.equals(s.getId())).findFirst().map(s -> { 153 logger.atConfig().log( 154 "Using credentials from settings for %s", this); 155 repoUser = s.getUsername(); 156 repoPass = s.getPassword(); 157 return true; 158 }).orElse(false)) { 159 return; 160 } 161 162 // Fallback 163 repoUser = ""; 164 repoPass = ""; 165 } 166 167 /* default */ abstract void publish(BuildContext context, 168 MvnPublisher publisher, Artifact mainArtifact, 169 List<Artifact> toDeploy); 170}