001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.release.plugin.mojos;
018
019import org.apache.commons.lang3.StringUtils;
020import org.apache.commons.release.plugin.SharedFunctions;
021import org.apache.maven.plugin.AbstractMojo;
022import org.apache.maven.plugin.MojoExecutionException;
023import org.apache.maven.plugin.MojoFailureException;
024import org.apache.maven.plugins.annotations.Component;
025import org.apache.maven.plugins.annotations.LifecyclePhase;
026import org.apache.maven.plugins.annotations.Mojo;
027import org.apache.maven.plugins.annotations.Parameter;
028import org.apache.maven.project.MavenProject;
029import org.apache.maven.scm.ScmException;
030import org.apache.maven.scm.ScmFileSet;
031import org.apache.maven.scm.command.checkin.CheckInScmResult;
032import org.apache.maven.scm.command.checkout.CheckOutScmResult;
033import org.apache.maven.scm.command.remove.RemoveScmResult;
034import org.apache.maven.scm.manager.BasicScmManager;
035import org.apache.maven.scm.manager.ScmManager;
036import org.apache.maven.scm.provider.ScmProvider;
037import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
038import org.apache.maven.scm.provider.svn.svnexe.SvnExeScmProvider;
039import org.apache.maven.scm.repository.ScmRepository;
040import org.apache.maven.settings.Settings;
041import org.apache.maven.settings.crypto.SettingsDecrypter;
042
043import java.io.File;
044import java.util.Arrays;
045import java.util.List;
046
047/**
048 * This class checks out the dev distribution location, checkes whether anything exists in the
049 * distribution location, and if it is non-empty it deletes all of the resources there.
050 *
051 * @author chtompki
052 * @since 1.6
053 */
054@Mojo(name = "clean-staging",
055        defaultPhase = LifecyclePhase.POST_CLEAN,
056        threadSafe = true,
057        aggregator = true)
058public class CommonsStagingCleanupMojo extends AbstractMojo {
059
060    /**
061     * The {@link MavenProject} object is essentially the context of the maven build at
062     * a given time.
063     */
064    @Parameter(defaultValue = "${project}", required = true)
065    private MavenProject project;
066
067    /**
068     * The main working directory for the plugin, namely <code>target/commons-release-plugin</code>, but
069     * that assumes that we're using the default maven <code>${project.build.directory}</code>.
070     */
071    @Parameter(defaultValue = "${project.build.directory}/commons-release-plugin", property = "commons.outputDirectory")
072    private File workingDirectory;
073
074    /**
075     * The location to which to checkout the dist subversion repository under our working directory, which
076     * was given above. We then do an SVN delete on all of the directories in this repository.
077     */
078    @Parameter(defaultValue = "${project.build.directory}/commons-release-plugin/scm-cleanup",
079            property = "commons.distCleanupDirectory")
080    private File distCleanupDirectory;
081
082    /**
083     * A boolean that determines whether or not we actually commit the files up to the subversion repository.
084     * If this is set to <code>true</code>, we do all but make the commits. We do checkout the repository in question
085     * though.
086     */
087    @Parameter(property = "commons.release.dryRun", defaultValue = "false")
088    private Boolean dryRun;
089
090    /**
091     * The url of the subversion repository to which we wish the artifacts to be staged. Typically this would need to
092     * be of the form: <code>scm:svn:https://dist.apache.org/repos/dist/dev/commons/foo/version-RC#</code>. Note. that
093     * the prefix to the substring <code>https</code> is a requirement.
094     */
095    @Parameter(defaultValue = "", property = "commons.distSvnStagingUrl")
096    private String distSvnStagingUrl;
097
098    /**
099     * A parameter to generally avoid running unless it is specifically turned on by the consuming module.
100     */
101    @Parameter(defaultValue = "false", property = "commons.release.isDistModule")
102    private Boolean isDistModule;
103
104    /**
105     * The ID of the server (specified in settings.xml) which should be used for dist authentication.
106     * This will be used in preference to {@link #username}/{@link #password}.
107     */
108    @Parameter(property = "commons.distServer")
109    private String distServer;
110
111    /**
112     * The username for the distribution subversion repository. This is typically your Apache id.
113     */
114    @Parameter(property = "user.name")
115    private String username;
116
117    /**
118     * The password associated with {@link CommonsDistributionStagingMojo#username}.
119     */
120    @Parameter(property = "user.password")
121    private String password;
122
123    /**
124     * Maven {@link Settings}.
125     */
126    @Parameter(defaultValue = "${settings}", readonly = true, required = true)
127    private Settings settings;
128
129    /**
130     * Maven {@link SettingsDecrypter} component.
131     */
132    @Component
133    private SettingsDecrypter settingsDecrypter;
134
135    @Override
136    public void execute() throws MojoExecutionException, MojoFailureException {
137        if (!isDistModule) {
138            getLog().info("This module is marked as a non distribution "
139                    + "or assembly module, and the plugin will not run.");
140            return;
141        }
142        if (StringUtils.isEmpty(distSvnStagingUrl)) {
143            getLog().warn("commons.distSvnStagingUrl is not set, the commons-release-plugin will not run.");
144            return;
145        }
146        if (!workingDirectory.exists()) {
147            SharedFunctions.initDirectory(getLog(), workingDirectory);
148        }
149        try {
150            final ScmManager scmManager = new BasicScmManager();
151            scmManager.setScmProvider("svn", new SvnExeScmProvider());
152            final ScmRepository repository = scmManager.makeScmRepository(distSvnStagingUrl);
153            final ScmProvider provider = scmManager.getProviderByRepository(repository);
154            final SvnScmProviderRepository providerRepository = (SvnScmProviderRepository) repository
155                    .getProviderRepository();
156            SharedFunctions.setAuthentication(
157                    providerRepository,
158                    distServer,
159                    settings,
160                    settingsDecrypter,
161                    username,
162                    password
163            );
164            getLog().info("Checking out dist from: " + distSvnStagingUrl);
165            final ScmFileSet scmFileSet = new ScmFileSet(distCleanupDirectory);
166            final CheckOutScmResult checkOutResult = provider.checkOut(repository, scmFileSet);
167            if (!checkOutResult.isSuccess()) {
168                throw new MojoExecutionException("Failed to checkout files from SCM: "
169                        + checkOutResult.getProviderMessage() + " [" + checkOutResult.getCommandOutput() + "]");
170            }
171            final List<File> filesToRemove = Arrays.asList(distCleanupDirectory.listFiles());
172            if (filesToRemove.size() == 1) {
173                getLog().info("No files to delete");
174                return;
175            }
176            if (!dryRun) {
177                final ScmFileSet fileSet = new ScmFileSet(distCleanupDirectory, filesToRemove);
178                final RemoveScmResult removeScmResult = provider.remove(repository, fileSet,
179                        "Cleaning up staging area");
180                if (!removeScmResult.isSuccess()) {
181                    throw new MojoFailureException("Failed to remove files from SCM: "
182                            + removeScmResult.getProviderMessage()
183                            + " [" + removeScmResult.getCommandOutput() + "]");
184                }
185                getLog().info("Cleaning distribution area for: " + project.getArtifactId());
186                final CheckInScmResult checkInResult = provider.checkIn(
187                        repository,
188                        fileSet,
189                        "Cleaning distribution area for: " + project.getArtifactId()
190                );
191                if (!checkInResult.isSuccess()) {
192                    throw new MojoFailureException("Failed to commit files: " + removeScmResult.getProviderMessage()
193                            + " [" + removeScmResult.getCommandOutput() + "]");
194                }
195            } else {
196                getLog().info("Would have attempted to delete files from: " + distSvnStagingUrl);
197            }
198        } catch (final ScmException e) {
199            throw new MojoFailureException(e.getMessage());
200        }
201
202    }
203}