1 package org.apache.maven.scm.provider.jazz.command.checkin;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.File;
23 import java.util.List;
24
25 import org.apache.maven.scm.ScmException;
26 import org.apache.maven.scm.ScmFileSet;
27 import org.apache.maven.scm.ScmVersion;
28 import org.apache.maven.scm.command.add.AddScmResult;
29 import org.apache.maven.scm.command.checkin.AbstractCheckInCommand;
30 import org.apache.maven.scm.command.checkin.CheckInScmResult;
31 import org.apache.maven.scm.provider.ScmProviderRepository;
32 import org.apache.maven.scm.provider.jazz.command.JazzConstants;
33 import org.apache.maven.scm.provider.jazz.command.JazzScmCommand;
34 import org.apache.maven.scm.provider.jazz.command.add.JazzAddCommand;
35 import org.apache.maven.scm.provider.jazz.command.consumer.DebugLoggerConsumer;
36 import org.apache.maven.scm.provider.jazz.command.consumer.ErrorConsumer;
37 import org.apache.maven.scm.provider.jazz.repository.JazzScmProviderRepository;
38 import org.codehaus.plexus.util.StringUtils;
39 import org.codehaus.plexus.util.cli.StreamConsumer;
40
41 // The Maven SCM Plugin "checkin" goal is equivalent to the RTC "checkin" command.
42 //
43 // This implementation of the Maven SCM Plugin "checkin" goal creates a change set with the message provided.
44 // It then uses the Jazz "scm "checkin" command to check the files into a remote workspace.
45 // If there is a flow target defined and the pushChanges flag is true (the default), then the remote workspace
46 // will be delivered ("scm deliver") to the flow target (a stream or other workspace).
47 //
48 // Set the pushChanges flag to false, if you do not want the repository workspace delivered.
49 //
50 // NOTE: At this point, only a SINGLE flow target is supported. Jazz itself, allows for more than one.
51 //
52 // The differences between this and the "add" goal, are:
53 // - The add goal will only checkin into the remote repository workspace.
54 // - The add goal will never deliver.
55 // - The add goal does not create a change set.
56 //
57 // This is the best we can do to mimic the implementations of the other providers, that provide a working
58 // "add" function (eg "svn add").
59 //
60 // Add may have had been able to use the "scm share" command, but that is recusive and only takes directory
61 // names; we are not able to specify specific or single files.
62 //
63 // See the following links for additional information on the RTC "checkin" command.
64 // RTC 2.0.0.2:
65 // http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_checkin.html
66 // RTC 3.0:
67 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_checkin.html
68 // RTC 3.0.1:
69 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_checkin.html
70 //
71 // See the following links for additional information on the RTC "deliver" command.
72 // RTC 2.0.0.2:
73 // http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_deliver.html
74 // RTC 3.0:
75 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_deliver.html
76 // RTC 3.0.1:
77 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_deliver.html
78 //
79
80 /**
81 * @author <a href="mailto:ChrisGWarp@gmail.com">Chris Graham</a>
82 */
83 public class JazzCheckInCommand
84 extends AbstractCheckInCommand
85 {
86
87 /**
88 * {@inheritDoc}
89 */
90 protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repository, ScmFileSet fileSet,
91 String message, ScmVersion scmVersion )
92 throws ScmException
93 {
94 if ( scmVersion != null && StringUtils.isNotEmpty( scmVersion.getName() ) )
95 {
96 throw new ScmException( "This provider command can't handle tags." );
97 }
98
99 if ( getLogger().isDebugEnabled() )
100 {
101 getLogger().debug( "Executing checkin command..." );
102 }
103
104 // Create a changeset. We need to do this, as otherwise the information contained in the message
105 // will be lost forever.
106 JazzScmCommand createChangesetCmd = createCreateChangesetCommand( repository, fileSet, message );
107 DebugLoggerConsumer outputConsumer = new DebugLoggerConsumer( getLogger() );
108 ErrorConsumer errConsumer = new ErrorConsumer( getLogger() );
109
110 int status = createChangesetCmd.execute( outputConsumer, errConsumer );
111 if ( status != 0 || errConsumer.hasBeenFed() )
112 {
113 return new CheckInScmResult( createChangesetCmd.getCommandString(),
114 "Error code for Jazz SCM create changeset command - " + status,
115 errConsumer.getOutput(), false );
116 }
117
118 // Now check in the files themselves.
119 return executeCheckInCommand( repository, fileSet, scmVersion );
120 }
121
122 protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet,
123 ScmVersion scmVersion )
124 throws ScmException
125 {
126 // Call the Add command to perform the checkin into the repository workspace.
127 JazzAddCommand addCommand = new JazzAddCommand();
128 addCommand.setLogger( getLogger() );
129 AddScmResult addResult = addCommand.executeAddCommand( repo, fileSet );
130
131 // Now, if it has a flow target, deliver it.
132 JazzScmProviderRepository jazzRepo = (JazzScmProviderRepository) repo;
133 if ( jazzRepo.isPushChangesAndHaveFlowTargets() )
134 {
135 // Push if we need too
136 JazzScmCommand deliverCmd = createDeliverCommand( (JazzScmProviderRepository) repo, fileSet );
137 StreamConsumer deliverConsumer =
138 new DebugLoggerConsumer( getLogger() ); // No need for a dedicated consumer for this
139 ErrorConsumer errConsumer = new ErrorConsumer( getLogger() );
140
141 int status = deliverCmd.execute( deliverConsumer, errConsumer );
142 if ( status != 0 || errConsumer.hasBeenFed() )
143 {
144 return new CheckInScmResult( deliverCmd.getCommandString(),
145 "Error code for Jazz SCM deliver command - " + status,
146 errConsumer.getOutput(), false );
147 }
148 }
149
150 // Return what was added.
151 return new CheckInScmResult( addResult.getCommandLine(), addResult.getAddedFiles() );
152 }
153
154 public JazzScmCommand createCreateChangesetCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message )
155 {
156 JazzScmCommand command =
157 new JazzScmCommand( JazzConstants.CMD_CREATE, JazzConstants.CMD_SUB_CHANGESET, repo, false, fileSet,
158 getLogger() );
159 command.addArgument( message );
160
161 return command;
162 }
163
164 public JazzScmCommand createCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet )
165 {
166 JazzScmCommand command =
167 new JazzScmCommand( JazzConstants.CMD_CHECKIN, null, repo, false, fileSet, getLogger() );
168
169 // TODO, this was taken out to quickly test how the release plugin works.
170 // The release plugin has the fileSet.getbaseDir() as the project it is checking in
171 // This happens to be a folder under the sandbox root, and so the checkin would fail because it needs
172 // to check in at the sandbox root level (not sub folders)
173 // The SCM Plugin has a basedir parameter that you can pass it, so everythig works ok from the scm-plugin alone
174 // but the release-plugin doesn't look like it lets you do that. (or I didn't have enough time
175 // to figure out how to do it properly).
176
177 // if (fileSet != null) {
178 // command.addArgument(JazzConstants.LOAD_ROOT_DIRECTORY_ARG);
179 // command.addArgument(fileSet.getBasedir().getAbsolutePath());
180 // }
181
182 List<File> files = fileSet.getFileList();
183 if ( files != null && !files.isEmpty() )
184 {
185 for ( File file : files )
186 {
187 command.addArgument( file.getPath() ); // Check in only the files specified
188 }
189 }
190 else
191 {
192 command.addArgument( "." ); // This will check in all local changes
193 }
194
195 return command;
196 }
197
198 // Create the JazzScmCommand to execute the "scm deliver ..." command
199 // This will deliver the changes to the flow target (stream or other workspace).
200 public JazzScmCommand createDeliverCommand( JazzScmProviderRepository repo, ScmFileSet fileSet )
201 {
202 JazzScmCommand command = new JazzScmCommand( JazzConstants.CMD_DELIVER, repo, fileSet, getLogger() );
203
204 if ( repo.getWorkspace() != null && !repo.getWorkspace().equals( "" ) )
205 {
206 command.addArgument( JazzConstants.ARG_DELIVER_SOURCE );
207 command.addArgument( repo.getWorkspace() );
208 }
209
210 if ( repo.getFlowTarget() != null && !repo.getFlowTarget().equals( "" ) )
211 {
212 command.addArgument( JazzConstants.ARG_DELIVER_TARGET );
213 command.addArgument( repo.getFlowTarget() );
214 }
215
216 // This command is needed so that the deliver operation will work.
217 // Files that are not under source control (a--) [temp files etc]
218 // will cause the deliver operation to fail with the error:
219 // "Cannot deliver because there are one or more items that are not checked in.
220 // Check in the changes or rerun with --overwrite-uncommitted."
221 // However, from the maven perspective, we only need files that are
222 // under source control to be delivered. Maven has already checked
223 // for this (via the status command).
224 //
225 // So we add this argument to allow the deliver to work.
226 command.addArgument( JazzConstants.ARG_OVERWRITE_UNCOMMITTED );
227
228 return command;
229 }
230 }