001package org.apache.maven.scm.provider.jazz.command.checkin; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.util.List; 024 025import org.apache.maven.scm.ScmException; 026import org.apache.maven.scm.ScmFileSet; 027import org.apache.maven.scm.ScmVersion; 028import org.apache.maven.scm.command.add.AddScmResult; 029import org.apache.maven.scm.command.checkin.AbstractCheckInCommand; 030import org.apache.maven.scm.command.checkin.CheckInScmResult; 031import org.apache.maven.scm.provider.ScmProviderRepository; 032import org.apache.maven.scm.provider.jazz.command.JazzConstants; 033import org.apache.maven.scm.provider.jazz.command.JazzScmCommand; 034import org.apache.maven.scm.provider.jazz.command.add.JazzAddCommand; 035import org.apache.maven.scm.provider.jazz.command.consumer.DebugLoggerConsumer; 036import org.apache.maven.scm.provider.jazz.command.consumer.ErrorConsumer; 037import org.apache.maven.scm.provider.jazz.command.status.JazzStatusCommand; 038import org.apache.maven.scm.provider.jazz.repository.JazzScmProviderRepository; 039import org.codehaus.plexus.util.StringUtils; 040import org.codehaus.plexus.util.cli.StreamConsumer; 041 042// The Maven SCM Plugin "checkin" goal is equivalent to the RTC "checkin" command. 043// 044// This implementation of the Maven SCM Plugin "checkin" goal creates a change set with the message provided. 045// It then uses the Jazz "scm "checkin" command to check the files into a remote workspace. 046// If there is a flow target defined and the pushChanges flag is true (the default), then the remote workspace 047// will be delivered ("scm deliver") to the flow target (a stream or other workspace). 048// 049// Set the pushChanges flag to false, if you do not want the repository workspace delivered. 050// 051// NOTE: At this point, only a SINGLE flow target is supported. Jazz itself, allows for more than one. 052// 053// The differences between this and the "add" goal, are: 054// - The add goal will only checkin into the remote repository workspace. 055// - The add goal will never deliver. 056// - The add goal does not create a change set. 057// 058// This is the best we can do to mimic the implementations of the other providers, that provide a working 059// "add" function (eg "svn add"). 060// 061// Add may have had been able to use the "scm share" command, but that is recusive and only takes directory 062// names; we are not able to specify specific or single files. 063// 064// See the following links for additional information on the RTC "checkin" command. 065// RTC 2.0.0.2: 066// http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_checkin.html 067// RTC 3.0: 068// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_checkin.html 069// RTC 3.0.1: 070// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_checkin.html 071// 072// See the following links for additional information on the RTC "deliver" command. 073// RTC 2.0.0.2: 074// http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_deliver.html 075// RTC 3.0: 076// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_deliver.html 077// RTC 3.0.1: 078// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_deliver.html 079// 080 081/** 082 * @author <a href="mailto:ChrisGWarp@gmail.com">Chris Graham</a> 083 */ 084public class JazzCheckInCommand 085 extends AbstractCheckInCommand 086{ 087 088 /** 089 * {@inheritDoc} 090 */ 091 protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repository, ScmFileSet fileSet, 092 String message, ScmVersion scmVersion ) 093 throws ScmException 094 { 095 if ( scmVersion != null && StringUtils.isNotEmpty( scmVersion.getName() ) ) 096 { 097 throw new ScmException( "This provider command can't handle tags." ); 098 } 099 100 if ( getLogger().isDebugEnabled() ) 101 { 102 getLogger().debug( "Executing checkin command..." ); 103 } 104 105 // Create a changeset. We need to do this, as otherwise the information contained in the message 106 // will be lost forever. 107 JazzScmCommand createChangesetCmd = createCreateChangesetCommand( repository, fileSet, message ); 108 DebugLoggerConsumer outputConsumer = new DebugLoggerConsumer( getLogger() ); 109 ErrorConsumer errConsumer = new ErrorConsumer( getLogger() ); 110 111 int status = createChangesetCmd.execute( outputConsumer, errConsumer ); 112 if ( status != 0 ) 113 { 114 return new CheckInScmResult( createChangesetCmd.getCommandString(), 115 "Error code for Jazz SCM create changeset command - " + status, 116 errConsumer.getOutput(), false ); 117 } 118 119 // As we just created a change set, we now need to call the status command so we can parse the 120 // newly created change set. 121 122 JazzStatusCommand statusCommand = new JazzStatusCommand(); 123 statusCommand.setLogger( getLogger() ); 124 statusCommand.executeStatusCommand( repository, fileSet ); 125 126 // NOTE: For isPushChangesAndHaveFlowTargets() to work, a scm status call must have been called first!!! 127 // As the Workspace name and alias, and the Flow Target name and alias are needed. 128 129 // Check to see if we've got a flow target and had a workItem defined (via -DworkItem=XXXX) 130 JazzScmProviderRepository jazzRepo = (JazzScmProviderRepository) repository; 131 if ( jazzRepo.isPushChangesAndHaveFlowTargets() && StringUtils.isNotEmpty( jazzRepo.getWorkItem() ) ) 132 { 133 List<Integer> changeSetAliases = jazzRepo.getOutgoingChangeSetAliases(); 134 if ( changeSetAliases != null && !changeSetAliases.isEmpty() ) 135 { 136 for ( Integer changeSetAlias : changeSetAliases ) 137 { 138 // Associate a work item if we need too. 139 JazzScmCommand changesetAssociateCmd = createChangesetAssociateCommand( repository, 140 changeSetAlias ); 141 outputConsumer = new DebugLoggerConsumer( getLogger() ); 142 errConsumer = new ErrorConsumer( getLogger() ); 143 144 status = changesetAssociateCmd.execute( outputConsumer, errConsumer ); 145 if ( status != 0 ) 146 { 147 return new CheckInScmResult( changesetAssociateCmd.getCommandString(), 148 "Error code for Jazz SCM changeset associate command - " + status, 149 errConsumer.getOutput(), false ); 150 } 151 } 152 } 153 } 154 155 // Now check in the files themselves. 156 return executeCheckInCommand( repository, fileSet, scmVersion ); 157 } 158 159 protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet, 160 ScmVersion scmVersion ) 161 throws ScmException 162 { 163 // Call the Add command to perform the checkin into the repository workspace. 164 JazzAddCommand addCommand = new JazzAddCommand(); 165 addCommand.setLogger( getLogger() ); 166 AddScmResult addResult = addCommand.executeAddCommand( repo, fileSet ); 167 168 // Now, if it has a flow target, deliver it. 169 JazzScmProviderRepository jazzRepo = (JazzScmProviderRepository) repo; 170 if ( jazzRepo.isPushChangesAndHaveFlowTargets() ) 171 { 172 // Push if we need too 173 JazzScmCommand deliverCmd = createDeliverCommand( (JazzScmProviderRepository) repo, fileSet ); 174 StreamConsumer deliverConsumer = 175 new DebugLoggerConsumer( getLogger() ); // No need for a dedicated consumer for this 176 ErrorConsumer errConsumer = new ErrorConsumer( getLogger() ); 177 178 int status = deliverCmd.execute( deliverConsumer, errConsumer ); 179 if ( status != 0 ) 180 { 181 return new CheckInScmResult( deliverCmd.getCommandString(), 182 "Error code for Jazz SCM deliver command - " + status, 183 errConsumer.getOutput(), false ); 184 } 185 } 186 187 // Return what was added. 188 return new CheckInScmResult( addResult.getCommandLine(), addResult.getAddedFiles() ); 189 } 190 191 public JazzScmCommand createCreateChangesetCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message ) 192 { 193 JazzScmCommand command = 194 new JazzScmCommand( JazzConstants.CMD_CREATE, JazzConstants.CMD_SUB_CHANGESET, repo, false, fileSet, 195 getLogger() ); 196 command.addArgument( message ); 197 198 return command; 199 } 200 201 public JazzScmCommand createChangesetAssociateCommand( ScmProviderRepository repo, Integer changeSetAlias ) 202 { 203 JazzScmCommand command = 204 new JazzScmCommand( JazzConstants.CMD_CHANGESET, JazzConstants.CMD_SUB_ASSOCIATE, repo, false, null, 205 getLogger() ); 206 // Add the change set alias 207 JazzScmProviderRepository jazzRepo = (JazzScmProviderRepository) repo; 208 // SCM-812 - Jazz SCM Alias Id's roll over to zero, not 1000 as advertised. 209 // So, we need to add the changeSetAlias with leading zeros. 210 command.addArgument( StringUtils.leftPad( changeSetAlias.toString(), 4, "0" ) ); 211 // Add the work item number 212 command.addArgument( jazzRepo.getWorkItem() ); 213 return command; 214 } 215 216 public JazzScmCommand createCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet ) 217 { 218 JazzScmCommand command = 219 new JazzScmCommand( JazzConstants.CMD_CHECKIN, null, repo, false, fileSet, getLogger() ); 220 221 // TODO, this was taken out to quickly test how the release plugin works. 222 // The release plugin has the fileSet.getbaseDir() as the project it is checking in 223 // This happens to be a folder under the sandbox root, and so the checkin would fail because it needs 224 // to check in at the sandbox root level (not sub folders) 225 // The SCM Plugin has a basedir parameter that you can pass it, so everythig works ok from the scm-plugin alone 226 // but the release-plugin doesn't look like it lets you do that. (or I didn't have enough time 227 // to figure out how to do it properly). 228 229 // if (fileSet != null) { 230 // command.addArgument(JazzConstants.LOAD_ROOT_DIRECTORY_ARG); 231 // command.addArgument(fileSet.getBasedir().getAbsolutePath()); 232 // } 233 234 List<File> files = fileSet.getFileList(); 235 if ( files != null && !files.isEmpty() ) 236 { 237 for ( File file : files ) 238 { 239 command.addArgument( file.getPath() ); // Check in only the files specified 240 } 241 } 242 else 243 { 244 command.addArgument( "." ); // This will check in all local changes 245 } 246 247 return command; 248 } 249 250 // Create the JazzScmCommand to execute the "scm deliver ..." command 251 // This will deliver the changes to the flow target (stream or other workspace). 252 public JazzScmCommand createDeliverCommand( JazzScmProviderRepository repo, ScmFileSet fileSet ) 253 { 254 JazzScmCommand command = new JazzScmCommand( JazzConstants.CMD_DELIVER, repo, fileSet, getLogger() ); 255 256 if ( repo.getWorkspace() != null && !repo.getWorkspace().equals( "" ) ) 257 { 258 command.addArgument( JazzConstants.ARG_DELIVER_SOURCE ); 259 command.addArgument( repo.getWorkspace() ); 260 } 261 262 if ( repo.getFlowTarget() != null && !repo.getFlowTarget().equals( "" ) ) 263 { 264 command.addArgument( JazzConstants.ARG_DELIVER_TARGET ); 265 command.addArgument( repo.getFlowTarget() ); 266 } 267 268 // This command is needed so that the deliver operation will work. 269 // Files that are not under source control (a--) [temp files etc] 270 // will cause the deliver operation to fail with the error: 271 // "Cannot deliver because there are one or more items that are not checked in. 272 // Check in the changes or rerun with --overwrite-uncommitted." 273 // However, from the maven perspective, we only need files that are 274 // under source control to be delivered. Maven has already checked 275 // for this (via the status command). 276 // 277 // So we add this argument to allow the deliver to work. 278 command.addArgument( JazzConstants.ARG_OVERWRITE_UNCOMMITTED ); 279 280 return command; 281 } 282}