1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.maven.resolver.internal.ant.tasks; 20 21 import org.apache.maven.resolver.internal.ant.AntRepoSys; 22 import org.apache.maven.resolver.internal.ant.types.RemoteRepository; 23 import org.apache.tools.ant.BuildException; 24 import org.apache.tools.ant.types.Reference; 25 26 /** 27 * Ant task to deploy artifacts to a remote Maven repository. 28 * <p> 29 * This task uploads artifacts, POM files, and optionally metadata such as licenses or dependencies 30 * to a remote repository using Maven Resolver. It mimics the behavior of {@code mvn deploy} 31 * but is integrated into Ant build scripts. 32 * </p> 33 * 34 * <h2>Usage Example:</h2> 35 * <pre>{@code 36 * <repo:deploy> 37 * <repo:artifact file='build/libs/my-lib.jar' 38 * groupId='com.example' 39 * artifactId='my-lib' 40 * version='1.0.0' 41 * packaging='jar'/> 42 * <repo:repository id="snapshots" url='https://my.repo.com/snapshots'> 43 * <repo:authentication username='user' password='pass'/> 44 * </repo:repository> 45 * </repo:deploy> 46 * }</pre> 47 * * If you have used the pom task to register an existing POM, or you used the 48 * createPom task to generate and register a POM, you can instead do this: 49 * <pre>{@code 50 * <repo:artifacts id='remoteArtifacts'> 51 * <repo:artifact refid='jar'/> 52 * <repo:artifact refid='sourceJar'/> 53 * <repo:artifact refid='javadocJar'/> 54 * </repo:artifacts> 55 * <repo:deploy artifactsref='remoteArtifacts'> 56 * <repo:remoteRepo id='localNexus', url='http://localhost:8081/repository/repo/'/> 57 * </repo:deploy> 58 * }</pre> 59 * <h2>Attributes:</h2> 60 * <ul> 61 * <li><strong>failOnMissingPom</strong> — whether to fail if no POM information is provided (default: true)</li> 62 * </ul> 63 * 64 * <h2>Nested Elements:</h2> 65 * <ul> 66 * <li>{@code <artifact>} — specifies the artifact file and its coordinates to be deployed</li> 67 * <li>{@code <pom>} — (optional) provides the POM file to upload, or one will be generated</li> 68 * <li>{@code <repository>} — defines the target repository for deployment</li> 69 * </ul> 70 * 71 * <h2>Behavior:</h2> 72 * <ul> 73 * <li>If no POM is provided, a basic one will be generated using the artifact's metadata</li> 74 * <li>Uploads artifacts using Maven's supported protocols (e.g., HTTP/S with authentication)</li> 75 * <li>Supports deployment to both snapshot and release repositories</li> 76 * </ul> 77 * 78 * <p> 79 * This task is typically used in CI/CD pipelines or custom release scripts that need to publish artifacts from Ant. 80 * </p> 81 * 82 * @see org.apache.maven.resolver.internal.ant.tasks.CreatePom 83 * @see org.apache.maven.resolver.internal.ant.types.Artifact 84 * @see org.apache.maven.resolver.internal.ant.types.Pom 85 * @see org.apache.maven.resolver.internal.ant.types.RemoteRepository 86 */ 87 public class Deploy extends AbstractDistTask { 88 89 private RemoteRepository repository; 90 91 private RemoteRepository snapshotRepository; 92 93 /** 94 * Default constructor for the Deploy task. 95 * <p> 96 * Initializes a new instance of the Deploy task. 97 * </p> 98 */ 99 public Deploy() {} 100 101 @Override 102 protected void validate() { 103 super.validate(); 104 105 if (repository == null) { 106 throw new BuildException("You must specify the <remoteRepo id=\"...\" url=\"...\"> element" 107 + " to denote the target repository for the deployment"); 108 } else { 109 repository.validate(this); 110 } 111 if (snapshotRepository != null) { 112 snapshotRepository.validate(this); 113 } 114 } 115 116 /** 117 * Allows ant to add a remote repository which artifacts will be deployed to. 118 * <p> 119 * This method is invoked by Ant when a {@code <repository>} nested element is defined 120 * inside the {@code <deploy>} task. Each repository must specify a unique {@code id} 121 * and a deployment {@code url}, and may optionally include layout and authentication information. 122 * </p> 123 * 124 * <p> 125 * Multiple repositories can be specified, though typically only one is used for deployment. 126 * </p> 127 * 128 * <b>Example:</b> 129 * <pre>{@code 130 * <deploy> 131 * <artifact ... /> 132 * <repository id="release" 133 * url="https://repo.example.com/releases" 134 * layout="default"> 135 * <authentication username="user" password="pass"/> 136 * </repository> 137 * </deploy> 138 * }</pre> 139 * 140 * @param repository the remote repository configuration to add 141 * 142 * @see org.apache.maven.resolver.internal.ant.types.RemoteRepository 143 * @see #execute() 144 */ 145 public void addRemoteRepo(RemoteRepository repository) { 146 if (this.repository != null) { 147 throw new BuildException("You must not specify multiple <remoteRepo> elements"); 148 } 149 this.repository = repository; 150 } 151 152 /** 153 * Sets a reference to a predefined {@code <repository>} element to be used as the deployment target. 154 * <p> 155 * This allows the {@code <deploy>} task to reuse a {@link org.apache.maven.resolver.internal.ant.types.RemoteRepository} 156 * definition declared elsewhere in the build script using an {@code id} and {@code refid}. 157 * </p> 158 * 159 * <p> 160 * This is functionally equivalent to defining a {@code <repository>} nested element inline, but enables 161 * reuse across multiple deployment tasks. 162 * </p> 163 * 164 * <b>Example:</b> 165 * <pre>{@code 166 * <repository id="release.repo" url="https://repo.example.com/releases" layout="default"> 167 * <authentication username="deploy" password="secret"/> 168 * </repository> 169 * 170 * <deploy> 171 * <artifact ... /> 172 * <remoteRepo refid="release.repo"/> 173 * </deploy> 174 * }</pre> 175 * 176 * @param ref the Ant reference to a {@code <repository>} definition 177 * 178 * @see org.apache.maven.resolver.internal.ant.types.RemoteRepository 179 * @see #addRemoteRepo(RemoteRepository) 180 */ 181 public void setRemoteRepoRef(Reference ref) { 182 if (repository == null) { 183 repository = new RemoteRepository(); 184 repository.setProject(getProject()); 185 } 186 repository.setRefid(ref); 187 } 188 189 /** 190 * Adds a snapshot repository to which snapshot artifacts will be deployed. 191 * <p> 192 * This method is invoked by Ant when a {@code <snapshotRepository>} nested element is defined 193 * within the {@code <deploy>} task. It provides a separate deployment target specifically 194 * for artifacts whose version ends with {@code -SNAPSHOT}. 195 * </p> 196 * 197 * <p> 198 * If no snapshot repository is provided, and a regular {@code <repository>} is defined, 199 * all artifacts (including snapshots) will be deployed to that single repository. 200 * </p> 201 * 202 * <b>Example:</b> 203 * <pre>{@code 204 * <deploy> 205 * <artifact ... /> 206 * 207 * <repository id="release.repo" url="https://repo.example.com/releases"/> 208 * 209 * <snapshotRepository id="snapshot.repo" url="https://repo.example.com/snapshots"> 210 * <authentication username="deploy" password="secret"/> 211 * </snapshotRepository> 212 * </deploy> 213 * }</pre> 214 * 215 * @param snapshotRepository the snapshot repository configuration to use for {@code -SNAPSHOT} artifacts 216 * 217 * @see org.apache.maven.resolver.internal.ant.types.RemoteRepository 218 * @see #addRemoteRepo(RemoteRepository) 219 */ 220 public void addSnapshotRepo(RemoteRepository snapshotRepository) { 221 if (this.snapshotRepository != null) { 222 throw new BuildException("You must not specify multiple <snapshotRepo> elements"); 223 } 224 this.snapshotRepository = snapshotRepository; 225 } 226 227 /** 228 * Sets a reference to a predefined {@code <snapshotRepository>} element. 229 * <p> 230 * This allows the {@code <deploy>} task to reuse an existing 231 * {@link org.apache.maven.resolver.internal.ant.types.RemoteRepository} configuration 232 * for deploying snapshot artifacts (i.e., versions ending in {@code -SNAPSHOT}). 233 * </p> 234 * 235 * <p> 236 * This is equivalent to defining a {@code <snapshotRepository>} nested element, 237 * but enables reuse across multiple tasks or modules by referencing a shared definition 238 * declared elsewhere in the build file. 239 * </p> 240 * 241 * <b>Example:</b> 242 * <pre>{@code 243 * <repository id="snap.repo" url="https://repo.example.com/snapshots" layout="default"> 244 * <authentication username="deploy" password="secret"/> 245 * </repository> 246 * 247 * <deploy> 248 * <artifact ... /> 249 * <snapshotRepository refid="snap.repo"/> 250 * </deploy> 251 * }</pre> 252 * 253 * @param ref an Ant {@link org.apache.tools.ant.types.Reference} to a snapshot repository definition 254 * 255 * @see org.apache.maven.resolver.internal.ant.types.RemoteRepository 256 * @see #addSnapshotRepo(RemoteRepository) 257 */ 258 public void setSnapshotRepoRef(Reference ref) { 259 if (snapshotRepository == null) { 260 snapshotRepository = new RemoteRepository(); 261 snapshotRepository.setProject(getProject()); 262 } 263 snapshotRepository.setRefid(ref); 264 } 265 266 @Override 267 public void execute() throws BuildException { 268 validate(); 269 270 AntRepoSys.getInstance(getProject()).deploy(this, getPom(), getArtifacts(), repository, snapshotRepository); 271 } 272 }