1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.release.phase;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.util.Arrays;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 import org.apache.maven.project.MavenProject;
34 import org.apache.maven.scm.ScmException;
35 import org.apache.maven.scm.ScmFile;
36 import org.apache.maven.scm.ScmFileSet;
37 import org.apache.maven.scm.command.status.StatusScmResult;
38 import org.apache.maven.scm.manager.NoSuchScmProviderException;
39 import org.apache.maven.scm.provider.ScmProvider;
40 import org.apache.maven.scm.repository.ScmRepository;
41 import org.apache.maven.scm.repository.ScmRepositoryException;
42 import org.apache.maven.shared.release.ReleaseExecutionException;
43 import org.apache.maven.shared.release.ReleaseFailureException;
44 import org.apache.maven.shared.release.ReleaseResult;
45 import org.apache.maven.shared.release.config.ReleaseDescriptor;
46 import org.apache.maven.shared.release.env.ReleaseEnvironment;
47 import org.apache.maven.shared.release.scm.ReleaseScmCommandException;
48 import org.apache.maven.shared.release.scm.ReleaseScmRepositoryException;
49 import org.apache.maven.shared.release.scm.ScmRepositoryConfigurator;
50 import org.apache.maven.shared.release.scm.ScmTranslator;
51 import org.codehaus.plexus.util.SelectorUtils;
52 import org.codehaus.plexus.util.StringUtils;
53
54 import static java.util.Objects.requireNonNull;
55
56
57
58
59
60
61 @Singleton
62 @Named("scm-check-modifications")
63 public class ScmCheckModificationsPhase extends AbstractReleasePhase {
64
65
66
67 private final ScmRepositoryConfigurator scmRepositoryConfigurator;
68
69
70
71
72 private final Map<String, ScmTranslator> scmTranslators;
73
74
75
76
77
78
79 private final Set<String> exclusionPatterns = new HashSet<>(Arrays.asList(
80 "**" + File.separator + "pom.xml.backup", "**" + File.separator + "pom.xml.tag",
81 "**" + File.separator + "pom.xml.next", "**" + File.separator + "pom.xml.branch",
82 "**" + File.separator + "release.properties", "**" + File.separator + "pom.xml.releaseBackup"));
83
84 @Inject
85 public ScmCheckModificationsPhase(
86 ScmRepositoryConfigurator scmRepositoryConfigurator, Map<String, ScmTranslator> scmTranslators) {
87 this.scmRepositoryConfigurator = requireNonNull(scmRepositoryConfigurator);
88 this.scmTranslators = requireNonNull(scmTranslators);
89 }
90
91 @Override
92 public ReleaseResult execute(
93 ReleaseDescriptor releaseDescriptor,
94 ReleaseEnvironment releaseEnvironment,
95 List<MavenProject> reactorProjects)
96 throws ReleaseExecutionException, ReleaseFailureException {
97 ReleaseResult relResult = new ReleaseResult();
98
99 List<String> additionalExcludes = releaseDescriptor.getCheckModificationExcludes();
100
101 if (additionalExcludes != null) {
102
103 for (String additionalExclude : additionalExcludes) {
104 exclusionPatterns.add(
105 additionalExclude.replace("\\", File.separator).replace("/", File.separator));
106 }
107 }
108
109 logInfo(relResult, "Verifying that there are no local modifications...");
110 logInfo(relResult, " ignoring changes on: " + StringUtils.join(exclusionPatterns.toArray(), ", "));
111
112 ScmRepository repository;
113 ScmProvider provider;
114 try {
115 repository = scmRepositoryConfigurator.getConfiguredRepository(
116 releaseDescriptor, releaseEnvironment.getSettings());
117
118 provider = scmRepositoryConfigurator.getRepositoryProvider(repository);
119 } catch (ScmRepositoryException e) {
120 throw new ReleaseScmRepositoryException(
121 e.getMessage() + " for URL: " + releaseDescriptor.getScmSourceUrl(), e.getValidationMessages());
122 } catch (NoSuchScmProviderException e) {
123 throw new ReleaseExecutionException("Unable to configure SCM repository: " + e.getMessage(), e);
124 }
125
126 StatusScmResult result;
127 try {
128 result = provider.status(repository, new ScmFileSet(new File(releaseDescriptor.getWorkingDirectory())));
129 } catch (ScmException e) {
130 throw new ReleaseExecutionException(
131 "An error occurred during the status check process: " + e.getMessage(), e);
132 }
133
134 if (!result.isSuccess()) {
135 throw new ReleaseScmCommandException("Unable to check for local modifications", result);
136 }
137
138 List<ScmFile> changedFiles = result.getChangedFiles();
139
140 if (!changedFiles.isEmpty()) {
141 ScmTranslator scmTranslator = scmTranslators.get(repository.getProvider());
142
143
144 for (Iterator<ScmFile> i = changedFiles.iterator(); i.hasNext(); ) {
145 ScmFile f = i.next();
146
147 String path;
148 if (scmTranslator != null) {
149 path = scmTranslator.toRelativePath(f.getPath());
150 } else {
151 path = f.getPath();
152 }
153
154
155 String fileName = path.replace("\\", File.separator).replace("/", File.separator);
156
157 for (String exclusionPattern : exclusionPatterns) {
158 if (SelectorUtils.matchPath(exclusionPattern, fileName)) {
159 logDebug(relResult, "Ignoring changed file: " + fileName);
160 i.remove();
161 break;
162 }
163 }
164 }
165 }
166
167 if (!changedFiles.isEmpty()) {
168 StringBuilder message = new StringBuilder();
169
170 for (ScmFile file : changedFiles) {
171 message.append(file.toString());
172 message.append("\n");
173 }
174
175 throw new ReleaseFailureException(
176 "Cannot prepare the release because you have local modifications : \n" + message);
177 }
178
179 relResult.setResultCode(ReleaseResult.SUCCESS);
180
181 return relResult;
182 }
183
184 @Override
185 public ReleaseResult simulate(
186 ReleaseDescriptor releaseDescriptor,
187 ReleaseEnvironment releaseEnvironment,
188 List<MavenProject> reactorProjects)
189 throws ReleaseExecutionException, ReleaseFailureException {
190
191 return execute(releaseDescriptor, releaseEnvironment, reactorProjects);
192 }
193 }