├── .gitattributes ├── .mvn ├── maven.config └── extensions.xml ├── src ├── main │ ├── webapp │ │ └── help │ │ │ ├── project │ │ │ ├── subpathonly.html │ │ │ ├── depot.html │ │ │ ├── dontPopContent.html │ │ │ ├── cleanreftree.html │ │ │ ├── stream.html │ │ │ ├── directoryoffset.html │ │ │ ├── snapshot.html │ │ │ ├── server.html │ │ │ ├── purge.html │ │ │ ├── ignore-stream-parent.html │ │ │ ├── update.html │ │ │ ├── revert.html │ │ │ ├── workspace-subpath.html │ │ │ ├── filterforpollscm.html │ │ │ ├── snapshot-format.html │ │ │ ├── subpath.html │ │ │ ├── reftree.html │ │ │ └── workspace.html │ │ │ ├── use-promote-listen.html │ │ │ ├── server-disable.html │ │ │ ├── use-color.html │ │ │ ├── use-nonexpiring-login.html │ │ │ ├── poll-on-master.html │ │ │ ├── minimise-login-operations.html │ │ │ ├── use-restricted-show-streams.html │ │ │ ├── sync-operations.html │ │ │ └── validTransactionTypes.html │ ├── resources │ │ ├── index.jelly │ │ ├── jenkins │ │ │ └── plugins │ │ │ │ └── accurev │ │ │ │ └── AccurevTool │ │ │ │ └── config.groovy │ │ └── hudson │ │ │ └── plugins │ │ │ └── accurev │ │ │ ├── AccurevSCM │ │ │ ├── global.groovy │ │ │ ├── AccurevServer │ │ │ │ └── config.groovy │ │ │ └── config.jelly │ │ │ └── AccurevChangeLogSet │ │ │ ├── digest.jelly │ │ │ └── index.jelly │ └── java │ │ ├── hudson │ │ └── plugins │ │ │ └── accurev │ │ │ ├── parsers │ │ │ ├── output │ │ │ │ ├── ParseIgnoreOutput.java │ │ │ │ ├── ParseOutputToStream.java │ │ │ │ ├── ParseOutputToFile.java │ │ │ │ ├── ParseAccuRevVersion.java │ │ │ │ ├── ParseLastFewLines.java │ │ │ │ ├── ParseInfoToLoginName.java │ │ │ │ └── ParsePopulate.java │ │ │ └── xml │ │ │ │ ├── ParseUpdate.java │ │ │ │ ├── ParseShowDepots.java │ │ │ │ ├── ParseFiles.java │ │ │ │ ├── ParseLsRules.java │ │ │ │ ├── ParseGetConfig.java │ │ │ │ ├── ParseRefTreeExternalFile.java │ │ │ │ ├── ParseShowWorkspaces.java │ │ │ │ ├── ParseShowReftrees.java │ │ │ │ ├── ParseShowStreams.java │ │ │ │ └── ParseHistory.java │ │ │ ├── GetConfigWebURL.java │ │ │ ├── AccurevElement.java │ │ │ ├── AccuRevHiddenParametersAction.java │ │ │ ├── RefTreeExternalFile.java │ │ │ ├── cmd │ │ │ ├── Command.java │ │ │ ├── Synctime.java │ │ │ ├── ShowDepots.java │ │ │ ├── SetProperty.java │ │ │ ├── FilesCmd.java │ │ │ ├── PopulateCmd.java │ │ │ ├── Update.java │ │ │ ├── ShowStreams.java │ │ │ ├── Login.java │ │ │ ├── ChangeLogCmd.java │ │ │ └── History.java │ │ │ ├── RemoteWorkspaceDetails.java │ │ │ ├── ByteArrayStream.java │ │ │ ├── delegates │ │ │ ├── Relocation.java │ │ │ ├── SnapshotDelegate.java │ │ │ ├── StreamDelegate.java │ │ │ ├── ReftreeDelegate.java │ │ │ └── WorkspaceDelegate.java │ │ │ ├── DetermineRemoteHostname.java │ │ │ ├── AccurevChangeLogSet.java │ │ │ ├── AccurevReferenceTree.java │ │ │ ├── AccurevWorkspace.java │ │ │ ├── XmlParserFactory.java │ │ │ ├── XmlConsolidateStreamChangeLog.java │ │ │ ├── AccurevMode.java │ │ │ ├── AccurevStream.java │ │ │ ├── AccurevTransaction.java │ │ │ └── CheckForChanges.java │ │ └── jenkins │ │ └── plugins │ │ └── accurev │ │ ├── util │ │ ├── UUIDUtils.java │ │ └── AccurevUtils.java │ │ ├── AccurevPlugin.java │ │ └── AccurevTool.java └── test │ ├── resources │ └── hudson │ │ └── plugins │ │ └── accurev │ │ └── accurev.yaml │ └── java │ ├── hudson │ └── plugins │ │ └── accurev │ │ ├── ConfigurationAsCodeTest.java │ │ ├── CheckForChangesTest.java │ │ ├── MigrateIDAndCredentialTest.java │ │ └── AccurevSCMTest.java │ └── jenkins │ └── plugins │ └── accurev │ └── AccurevToolTest.java ├── .gitignore ├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ ├── cd.yaml │ ├── jenkins-security-scan.yml │ └── maven.yml ├── Jenkinsfile ├── LICENSE ├── README.md └── pom.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.java eol=lf 3 | *.groovy eol=lf 4 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -Dchangelist.format=%d.v%s -------------------------------------------------------------------------------- /src/main/webapp/help/project/subpathonly.html: -------------------------------------------------------------------------------- 1 |
2 |

Populate just the specified sub-path, without building its directory tree.

3 |
4 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/depot.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Select the Depot field and choose the depot you want to use for the current job. 4 |

5 |
6 | -------------------------------------------------------------------------------- /src/main/webapp/help/use-promote-listen.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Build trigger 4 |

5 | Instruct how to use post promote as trigger 6 |

7 |
8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .accurev 2 | .acignore 3 | target 4 | work 5 | .classpath 6 | .project 7 | .settings 8 | *.iml 9 | .DS_Store 10 | pom.xml.releaseBackup 11 | release.properties 12 | .idea/ 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | 8 | [*.{xml,html,jelly,java,groovy}] 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/dontPopContent.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | When the check box is on, AccuRev POP Command is not Populating the elements. If check box is 4 | off then AccuRev 5 | POP Command is Populating the elements. 6 |

7 |
8 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/cleanreftree.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | When this check box is marked, AccuRev Plug-In for Jenkins deletes any external files (that is, 4 | files that are 5 | not under source control) in the reference tree. 6 |

7 |
8 | -------------------------------------------------------------------------------- /src/main/webapp/help/server-disable.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If checked, the plugin will be disabled for this particular server and builds will be Aborted. 4 |

5 | This can be used when any AccuRev server is under maintenance. 6 |

7 |
8 | -------------------------------------------------------------------------------- /src/main/webapp/help/use-color.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If checked, plugin will reset the color on stream when build is starting. 4 |

5 | This can be used by custom post step to color the build according to build result (red, green, 6 | yellow...). 7 |

8 |
9 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | AccuRev SCM provider. This plugin allows Jenkins jobs to pull data from AccuRev streams and enables build automation with the AccuRev SCM server. 4 |
5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | open-pull-requests-limit: 10 8 | target-branch: master 9 | - package-ecosystem: github-actions 10 | directory: "/" 11 | schedule: 12 | interval: monthly 13 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/stream.html: -------------------------------------------------------------------------------- 1 |
2 |

Enter the Stream name / Workspace name by typing.

3 |

Input field offers auto complete suggestion

4 |

Note: Build will be generated from Stream or Workspace, as per the user's 5 | selection.

6 |
7 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/directoryoffset.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | The relative directory path from the default Jenkins workspace location where the files from the 4 | stream, 5 | workspace, or reftree should be retrieved from. Leave this field 6 | blank if you want to continue using the Jenkins default workspace location. 7 |

8 |
9 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/snapshot.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | When this check box is marked, AccuRev Plug-In for Jenkins creates a snapshot of the target 4 | stream, then 5 | populates and builds from that snapshot. 6 |

7 |

8 | NOTE: If the snapshot name already exists, the process fails and the build stops. 9 |

10 |
11 | -------------------------------------------------------------------------------- /src/main/resources/jenkins/plugins/accurev/AccurevTool/config.groovy: -------------------------------------------------------------------------------- 1 | package jenkins.plugins.accurev.AccurevTool 2 | 3 | /** 4 | * Initialized by josep on 21-01-2017. 5 | */ 6 | 7 | f = namespace("/lib/form") 8 | 9 | f.entry(field: "name", title: _("Name")) { 10 | f.textbox() 11 | } 12 | f.entry(field: "home", title: _("Path to AccuRev executable")) { 13 | f.textbox() 14 | } 15 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/server.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Select the Server field and choose the AccuRev server whose depots and streams you are 4 | using for your 5 | builds. The available AccuRev servers are those that have been 6 | configured in the Jenkins (Manage Jenkins > Configure Systems > AccuRev > Servers) 7 | settings. 8 |

9 |
10 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/output/ParseIgnoreOutput.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.output; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputParser; 4 | import java.io.InputStream; 5 | 6 | public final class ParseIgnoreOutput implements ICmdOutputParser { 7 | 8 | public Boolean parse(InputStream cmdOutput, Void context) { 9 | return Boolean.TRUE; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.7 6 | 7 | 8 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | /* `buildPlugin` step provided by: https://github.com/jenkins-infra/pipeline-library */ 4 | def recentLTS = "2.387.3" 5 | def configurations = [ 6 | [ platform: "linux", jdk: "11", jenkins: recentLTS ], 7 | [ platform: "windows", jdk: "11", jenkins: recentLTS ], 8 | [ platform: 'linux', jdk: 21], 9 | [ platform: 'windows', jdk: 17], 10 | ] 11 | buildPlugin(configurations: configurations) 12 | -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | 3 | name: cd 4 | on: 5 | workflow_dispatch: 6 | check_run: 7 | types: 8 | - completed 9 | 10 | jobs: 11 | maven-cd: 12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 13 | secrets: 14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} -------------------------------------------------------------------------------- /src/main/webapp/help/project/purge.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | option allows you to specify whether or not a failed build will result in the next subsequent 4 | build purging and 5 | re-populating 6 | the workspace. this used to be the default behavior however in some instances it is not wanted. 7 |

8 |

9 | Disabling this option may result in subsequent builds continuing to fail where they would 10 | normally have 11 | succeeded after a purge/populate. 12 |

13 |
14 | -------------------------------------------------------------------------------- /src/test/resources/hudson/plugins/accurev/accurev.yaml: -------------------------------------------------------------------------------- 1 | unclassified: 2 | accurev: 3 | pollOnMaster: true 4 | servers: 5 | - name: 'testserver1' 6 | host: 'testhost' 7 | port: 1234 8 | credentialsId: 'abc123' 9 | syncOperations: true 10 | minimiseLogins: true 11 | useNonexpiringLogin: true 12 | useRestrictedShowStreams: true 13 | useColor: true 14 | usePromoteListen: true 15 | serverDisabled: true 16 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/GetConfigWebURL.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.Serializable; 4 | 5 | public class GetConfigWebURL implements Serializable { 6 | 7 | private final String webURL; 8 | private static final long serialVersionUID = 1L; 9 | 10 | public GetConfigWebURL(String webURL) { 11 | this.webURL = webURL; 12 | } 13 | 14 | /** 15 | * Getter for property 'webURL'. 16 | * 17 | * @return Value for property 'webURL'. 18 | */ 19 | public String getWebURL() { 20 | return webURL; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/accurev/AccurevSCM/global.groovy: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.AccurevSCM 2 | 3 | import lib.FormTagLib 4 | 5 | def f = namespace(FormTagLib) 6 | 7 | f.section(title: "AccuRev") { 8 | f.entry(field: "pollOnMaster", title: "Poll on master", help: "/plugin/accurev/help/poll-on-master.html") { 9 | f.checkbox() 10 | } 11 | f.entry(title: _("AccuRev Servers")) { 12 | f.repeatableHeteroProperty( 13 | field: "servers", 14 | hasHeader: "true", 15 | addCaption: _("Add AccuRev Server") 16 | ) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/webapp/help/use-nonexpiring-login.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If checked, the plugin will add the '-n' flag to the 'accurev login' 4 | command when logging in. 5 |

6 | This flag requests a login session that will not expire after 7 | an arbitrary time period has elapsed. 8 | This is rarely an issue when using "traditional" authentication, but 9 | can be useful when using "accurev_login" or "custom" authentication 10 | on the server as these default to making login sessions time out and 11 | expire after 240 minutes. 12 |

13 |
14 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccurevElement.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | public class AccurevElement { 4 | 5 | private String location; 6 | private String status; 7 | 8 | public AccurevElement(String location, String status) { 9 | this.location = location; 10 | this.status = status; 11 | } 12 | 13 | public String getLocation() { 14 | return location; 15 | } 16 | 17 | public void setLocation(String location) { 18 | this.location = location; 19 | } 20 | 21 | public String getStatus() { 22 | return status; 23 | } 24 | 25 | public void setStatus(String status) { 26 | this.status = status; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/accurev/AccurevChangeLogSet/digest.jelly: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | No changes. 10 | 11 | 12 | Changes 13 |
    14 | 15 |
  1. 16 | ${cs.msg} 17 | ( 18 | detail 19 | ) 20 |
  2. 21 |
    22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Jenkins Security Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ opened, synchronize, reopened ] 9 | workflow_dispatch: 10 | 11 | permissions: 12 | security-events: write 13 | contents: read 14 | actions: read 15 | 16 | jobs: 17 | security-scan: 18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 19 | with: 20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 22 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/ignore-stream-parent.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If checked then, when checking for changes etc, the plugin will ignore 4 | the possibility that there have been changes in the parent stream that 5 | affect the contents of the stream being polled. 6 |
7 |
8 | This is purely a runtime optimisation for when AccuRev is being used 9 | as a normal VCS and not taking advantage of its stream inheritance. 10 |
11 | When used with reftree or workspaces this will be used to limit 12 | the number of hist commands issued to calculate the changelog. 13 | Upstream changes would be considered since we use update to determine 14 | actual changes. 15 |

16 |
17 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: Build on Jenkins ${{ matrix.jenkins-version }}, JDK ${{ matrix.java }} and ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | java: [11] 12 | jenkins-version: [2.361] 13 | os: [ubuntu-latest, windows-latest] 14 | 15 | steps: 16 | - uses: actions/checkout@v1 17 | - name: Set up JDK ${{ matrix.java }} 18 | uses: actions/setup-java@v4 19 | with: 20 | java-version: ${{ matrix.java }} 21 | distribution: "temurin" 22 | - name: Build with Maven 23 | run: | 24 | mvn install -B -V --no-transfer-progress ${{ matrix.flags }} 25 | -------------------------------------------------------------------------------- /src/main/java/jenkins/plugins/accurev/util/UUIDUtils.java: -------------------------------------------------------------------------------- 1 | package jenkins.plugins.accurev.util; 2 | 3 | import java.util.UUID; 4 | import org.apache.commons.lang.StringUtils; 5 | 6 | /** Initialized by josp on 21/09/16. */ 7 | public class UUIDUtils { 8 | 9 | public static boolean isValid(String uuid) { 10 | if (StringUtils.isEmpty(uuid)) { 11 | return false; 12 | } 13 | try { 14 | UUID fromStringUUID = UUID.fromString(uuid); 15 | String toStringUUID = fromStringUUID.toString(); 16 | return toStringUUID.equals(uuid); 17 | } catch (IllegalArgumentException e) { 18 | return false; 19 | } 20 | } 21 | 22 | public static boolean isNotValid(String uuid) { 23 | return !isValid(uuid); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/webapp/help/poll-on-master.html: -------------------------------------------------------------------------------- 1 |
2 |

If checked then:

3 | 13 |

If not checked then:

14 | 23 |

Do NOT enable this unless AccuRev is installed on the master node.

24 |
25 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccuRevHiddenParametersAction.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import hudson.EnvVars; 4 | import hudson.model.EnvironmentContributingAction; 5 | import hudson.model.InvisibleAction; 6 | import hudson.model.Run; 7 | 8 | public class AccuRevHiddenParametersAction extends InvisibleAction 9 | implements EnvironmentContributingAction { 10 | 11 | private final EnvVars values; 12 | 13 | public AccuRevHiddenParametersAction(EnvVars values) { 14 | this.values = values; 15 | } 16 | 17 | @Override 18 | public void buildEnvironment( 19 | @edu.umd.cs.findbugs.annotations.NonNull Run run, 20 | @edu.umd.cs.findbugs.annotations.NonNull EnvVars env) { 21 | env.putAll(values); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/update.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | By default, this plugin purges the workspace for every build. There are a number of operations 4 | which when performed in AccuRev, can make it impossible for a client to successfully complete 5 | an accurev update operation with the workspace populated. The sequence of purge, 6 | update, populate has not failed. The down side is that it is slower. 7 |

8 |

9 | Selecting this option will enable the plugin to skip the purge step and just use update 10 | (followed by a populate just in case any files went missing). NOTE: however, in order to 11 | allow Jenkins to recover from the "cannot complete update" situation a purge will always 12 | be performed if the last build failed. 13 |

14 |
15 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/RefTreeExternalFile.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.Serializable; 4 | 5 | public class RefTreeExternalFile implements Serializable { 6 | 7 | private final String location; 8 | private final String status; 9 | private static final long serialVersionUID = 1L; 10 | 11 | public RefTreeExternalFile(String location, String status) { 12 | this.location = location; 13 | this.status = status; 14 | } 15 | 16 | /** 17 | * Getter for property 'location'. 18 | * 19 | * @return Value for property 'location'. 20 | */ 21 | public String getLocation() { 22 | return location; 23 | } 24 | 25 | /** 26 | * Getter for property 'status'. 27 | * 28 | * @return Value for property 'status'. 29 | */ 30 | public String getStatus() { 31 | return status; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/Command.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 4 | import hudson.util.ArgumentListBuilder; 5 | import org.apache.commons.lang.StringUtils; 6 | 7 | public class Command { 8 | 9 | /** 10 | * Adds the server reference to the Arguments list. 11 | * 12 | * @param cmd The accurev command line. 13 | * @param server The Accurev server details. 14 | */ 15 | public static void addServer(ArgumentListBuilder cmd, AccurevServer server) { 16 | if (null != server && null != server.getHost() && StringUtils.isNotBlank(server.getHost())) { 17 | cmd.add("-H"); 18 | if (server.getPort() != 0) { 19 | cmd.add(server.getHost() + ":" + server.getPort()); 20 | } else { 21 | cmd.add(server.getHost()); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/revert.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | This option causes the AccuRev plugin to revert any overlapped entries in the workspace prior to 4 | performing an 5 | update of the workspace. Overlapped entries cause the update step to fail, which in turn causes 6 | the build to be 7 | marked 8 | as failed. (which in turn causes the next build to purge the workspace and therefore negate any 9 | purpose in using 10 | workspaces) 11 |

12 |

13 | this option is primarily useful in cases where you are using an AccuRev workspace and when 14 | performing a build on 15 | that workspace 16 | would cause artifacts to overlap in the parent stream. If you keep getting warnings and failed 17 | builds due to 18 | overlaps, and you don't 19 | want to purge the entire workspace on each build then you need this option. 20 |

21 |
22 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/output/ParseOutputToStream.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.output; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | 9 | public final class ParseOutputToStream 10 | implements AccurevLauncher.ICmdOutputParser { 11 | 12 | public Boolean parse(InputStream cmdOutput, OutputStream streamToCopyOutputTo) 13 | throws UnhandledAccurevCommandOutput, IOException { 14 | final byte[] buffer = new byte[4096]; 15 | int bytesRead = cmdOutput.read(buffer); 16 | while (bytesRead > 0) { 17 | streamToCopyOutputTo.write(buffer, 0, bytesRead); 18 | bytesRead = cmdOutput.read(buffer); 19 | } 20 | return Boolean.TRUE; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/webapp/help/minimise-login-operations.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If checked then, before issuing an "accurev login" command, the plugin will 4 | first issue an "accurev info" command to see if it is already logged in 5 | and then only issue the "accurev login" command if it is not already logged 6 | in as the desired user. 7 | If not checked, an "accurev login" command will be issued before each attempt 8 | to poll for changes and at the start of each build. 9 |

10 | This was introduced to work around the AccuRev client bug whereby a 11 | login will first log out all active logins on that host before logging 12 | in again, causing any other AccuRev commands running in other processes 13 | to fail due to the client (temporarily) not being logged in. 14 | For best effect, combine with the "-n" flag to ensure that, once logged in, 15 | the client stays logged in permanently. 16 |

17 |
18 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/output/ParseOutputToFile.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.output; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | public final class ParseOutputToFile implements ICmdOutputParser { 11 | 12 | public Boolean parse(InputStream cmdOutput, File fileToWriteTo) 13 | throws UnhandledAccurevCommandOutput, IOException { 14 | final byte[] buffer = new byte[4096]; 15 | try (FileOutputStream os = new FileOutputStream(fileToWriteTo)) { 16 | int bytesRead = cmdOutput.read(buffer); 17 | while (bytesRead > 0) { 18 | os.write(buffer, 0, bytesRead); 19 | bytesRead = cmdOutput.read(buffer); 20 | } 21 | } 22 | return Boolean.TRUE; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/workspace-subpath.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Some projects only use a portion of the workspace and, in such cases, it is not necessary to 4 | check out the 5 | entire workspace. For example, when accessing a large remote 6 | repository to build a sub-module. 7 |

8 | 9 |

10 | If you specify a sub-path, the plugin makes a "best effort" to ensure that only the sub-path is 11 | populated. This 12 | means that the files within the sub-path will be fetched, at 13 | least, but side-effects may result in files from other paths being fetched as well. 14 |

15 | 16 |

17 | Note that the changelog does not filter by sub-path. Thus, any change in the repository will 18 | trigger a build. 19 |

20 | 21 |

22 | When using a workspace, you must update the workspace which populates any changed files and not 23 | just the files 24 | in the sub-path. The subsequent populate ensures that all the 25 | files in the sub-path are fetched, at least. 26 |

27 |
28 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseUpdate.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import static jenkins.plugins.accurev.util.AccurevUtils.cleanAccurevPath; 4 | 5 | import hudson.plugins.accurev.AccurevLauncher; 6 | import java.io.IOException; 7 | import java.util.List; 8 | import org.xmlpull.v1.XmlPullParser; 9 | import org.xmlpull.v1.XmlPullParserException; 10 | 11 | /** @author raymond */ 12 | public class ParseUpdate implements AccurevLauncher.ICmdOutputXmlParser> { 13 | 14 | public Boolean parse(XmlPullParser parser, List context) 15 | throws AccurevLauncher.UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 16 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 17 | if (parser.getEventType() == XmlPullParser.START_TAG 18 | && "element".equalsIgnoreCase(parser.getName())) { 19 | String path = parser.getAttributeValue("", "location"); 20 | if (path != null) { 21 | context.add(cleanAccurevPath(path)); 22 | } 23 | } 24 | } 25 | return !context.isEmpty(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/webapp/help/use-restricted-show-streams.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If checked then, when issuing an "accurev show ... streams" 4 | command, the plugin will use the "-s streamname" option to 5 | restrict the output to just the stream in question, look at the result 6 | to determine the basis stream and then repeat for that 7 | stream's parent etc until the full ancestry is obtained. If not checked, 8 | when the plugin needs to know about the stream it is using, it'll simply 9 | get all of the streams from the server (which can involve a lot of 10 | data).
11 |
12 | This is best enabled on AccuRev servers with a lot of streams, 13 | snapshots, workspaces etc.
14 | When there are relatively few streams and snapshots aren't used, it is 15 | typically quicker to get all the streams that the server knows about in 16 | one single command. When there are a lot of them, it's often faster to 17 | send multiple commands that get the stream you want, and then its parent, 18 | and its parent etc until you reach the top of the chain. 19 |

20 |
21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jenkins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseShowDepots.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import java.io.IOException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import org.xmlpull.v1.XmlPullParser; 9 | import org.xmlpull.v1.XmlPullParserException; 10 | 11 | public final class ParseShowDepots implements ICmdOutputXmlParser, Void> { 12 | 13 | public List parse(XmlPullParser parser, Void context) 14 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 15 | final List depots = new ArrayList<>(); 16 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 17 | if (parser.getEventType() == XmlPullParser.START_TAG 18 | && "element".equalsIgnoreCase(parser.getName())) { 19 | final String name = parser.getAttributeValue("", "Name"); 20 | if (name != null) { 21 | depots.add(name); 22 | } 23 | } 24 | } 25 | return depots; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/output/ParseAccuRevVersion.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.output; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.io.Reader; 10 | import java.nio.charset.Charset; 11 | 12 | public final class ParseAccuRevVersion implements ICmdOutputParser { 13 | 14 | @Override 15 | public String parse(InputStream cmdOutput, Void context) 16 | throws UnhandledAccurevCommandOutput, IOException { 17 | final Reader stringReader = new InputStreamReader(cmdOutput, Charset.defaultCharset()); 18 | try (BufferedReader reader = new BufferedReader(stringReader)) { 19 | String line; 20 | while ((line = reader.readLine()) != null) { 21 | if (line.contains("AccuRev")) { 22 | return line.split("\\s+")[1]; 23 | } 24 | } 25 | } 26 | // TODO Auto-generated method stub 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/webapp/help/sync-operations.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If checked, all calls to the AccuRev CLI on a particular node will be 4 | synchronized. That is to say, only one CLI operation can be going on at 5 | any time, across all jobs on a given node. The default is synchronized, 6 | which is the plugin's original behavior. 7 |

8 | Note that login operations are always synchronized. 9 |

10 | This sync was supposedly for problems with older versions of the AccuRev 11 | CLI. If you have a recent version of AccuRev (4.7+, possibly earlier), 12 | but are using "traditional" authentication, 13 | it should be ok to turn off synchronization. This can speed up operations 14 | significantly in some scenarios, such as with multiple jobs with large 15 | checkouts. 16 | If you are using "accurev_login" or "custom" authentication, even on recent 17 | versions of AccuRev (e.g. 4.7.4 suffers from this), you need to ensure 18 | that you never run a "login" unless no other AccuRev operations are ongoing, 19 | otherwise those other AccuRev operations are likely to fail. 20 |

21 |
22 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/RemoteWorkspaceDetails.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.File; 4 | import java.io.Serializable; 5 | 6 | public class RemoteWorkspaceDetails implements Serializable { 7 | 8 | private final String hostName; 9 | private final String path; 10 | private final String fileSeparator; 11 | private static final long serialVersionUID = 1L; 12 | 13 | public RemoteWorkspaceDetails(String hostName, String path) { 14 | this.hostName = hostName; 15 | this.path = path; 16 | this.fileSeparator = File.separator; 17 | } 18 | 19 | /** 20 | * Getter for property 'hostName'. 21 | * 22 | * @return Value for property 'hostName'. 23 | */ 24 | public String getHostName() { 25 | return hostName; 26 | } 27 | 28 | /** 29 | * Getter for property 'path'. 30 | * 31 | * @return Value for property 'path'. 32 | */ 33 | public String getPath() { 34 | return path; 35 | } 36 | 37 | /** 38 | * Getter for property 'fileSeparator'. 39 | * 40 | * @return Value for property 'fileSeparator'. 41 | */ 42 | public String getFileSeparator() { 43 | return fileSeparator; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseFiles.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import static jenkins.plugins.accurev.util.AccurevUtils.cleanAccurevPath; 4 | 5 | import hudson.plugins.accurev.AccurevElement; 6 | import hudson.plugins.accurev.AccurevLauncher; 7 | import java.io.IOException; 8 | import java.util.List; 9 | import org.xmlpull.v1.XmlPullParser; 10 | import org.xmlpull.v1.XmlPullParserException; 11 | 12 | public class ParseFiles 13 | implements AccurevLauncher.ICmdOutputXmlParser> { 14 | 15 | @Override 16 | public Boolean parse(XmlPullParser parser, List context) 17 | throws AccurevLauncher.UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 18 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 19 | if (parser.getEventType() == XmlPullParser.START_TAG) { 20 | if ("element".equals(parser.getName())) { 21 | String location = cleanAccurevPath(parser.getAttributeValue("", "location")); 22 | String status = parser.getAttributeValue("", "status"); 23 | context.add(new AccurevElement(location, status)); 24 | } 25 | } 26 | } 27 | return context != null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/webapp/help/validTransactionTypes.html: -------------------------------------------------------------------------------- 1 |
2 |

WARNING: By changing the valid types of transactions you can miss 3 | vital changes made to your source code.

4 |

5 | By default, the AccuRev plugin will allow any type of transaction to trigger a build.
6 | This behavior is not always wanted, resulting in issue-triggered builds. 7 |

8 |

9 | To solve this you specify the types of transactions that you want to use.
10 | You enter the transaction types separated by commas like this:

11 | add,chstream,co,defcomp,defunct,keep,mkstream,move,promote,purge,dispatch

12 | The available transaction types are: 13 |

14 |
    15 |
  • add -
  • 16 |
  • chstream -
  • 17 |
  • co -
  • 18 |
  • defcomp -
  • 19 |
  • defunct -
  • 20 |
  • dispatch -
  • 21 |
  • keep -
  • 22 |
  • mkstream -
  • 23 |
  • move -
  • 24 |
  • promote -
  • 25 |
  • purge -
  • 26 |
  • dispatch -
  • 27 |
28 |

29 | Note that if you are only ever building the contents of streams, then 30 | polling for "promote" transactions is likely to suffice on its own. 31 |

32 |
33 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/output/ParseLastFewLines.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.output; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputParser; 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.InputStreamReader; 8 | import java.io.Reader; 9 | import java.nio.charset.Charset; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | 13 | /** Filters the output of any command and just returns the last few lines. */ 14 | public final class ParseLastFewLines implements ICmdOutputParser, Integer> { 15 | 16 | public List parse(InputStream cmdOutput, Integer numberOfLines) throws IOException { 17 | final LinkedList result = new LinkedList<>(); 18 | final Reader stringReader = new InputStreamReader(cmdOutput, Charset.defaultCharset()); 19 | int linesRemainingBeforeWeAreFull = numberOfLines; 20 | 21 | try (BufferedReader reader = new BufferedReader(stringReader)) { 22 | String line; 23 | while ((line = reader.readLine()) != null) { 24 | result.add(line); 25 | if (linesRemainingBeforeWeAreFull > 0) { 26 | linesRemainingBeforeWeAreFull--; 27 | } else { 28 | result.removeFirst(); 29 | } 30 | } 31 | } 32 | return result; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/filterforpollscm.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If the Poll SCM check box under the Build Triggers section is selected, you can 4 | use the Filter 5 | for Poll SCM field to specify the directories or files 6 | you want Jenkins to check before starting a build. Any changes made to the files or directories 7 | that you specify 8 | in the Filter for Poll SCM field will trigger a 9 | build in Jenkins. 10 |

11 | 12 |

13 | Directories and files must be specified in a comma-separated list and can use relative 14 | pathnames. For example, 15 | you could use: 16 |

17 | 18 |

19 | src/com/my-company/main/my-file.java,src/com/webapp/my-file2.xml,src/com/* 20 |

21 | 22 |

23 | where "src" is the immediate sub-folder under your stream or reference tree. 24 | 25 |

26 | 27 |

NOTE: If you select Poll SCM in the Build Triggers section of the Jenkins 28 | configuration page, but 29 | you do not specify any Filter for Poll SCM files or 30 | directories, then any files or directories you have specified in the Sub-path field are 31 | used as the 32 | filter for polling. In this case, changes made to elements in the 33 | sub-path will trigger a build in Jenkins. 34 |

35 |
36 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/Synctime.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevLauncher; 8 | import hudson.plugins.accurev.AccurevSCM; 9 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 10 | import hudson.util.ArgumentListBuilder; 11 | import java.io.IOException; 12 | import java.util.logging.Logger; 13 | 14 | public class Synctime extends Command { 15 | 16 | private static final Logger logger = Logger.getLogger(Synctime.class.getName()); 17 | 18 | // Analagous to the Synchronize Time option in the AccuRev GUI client. 19 | public static boolean synctime( // 20 | final AccurevSCM scm, 21 | final AccurevServer server, // 22 | final EnvVars accurevEnv, // 23 | final FilePath workspace, // 24 | final TaskListener listener, // 25 | final Launcher launcher) 26 | throws IOException { 27 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 28 | cmd.add("synctime"); 29 | addServer(cmd, server); 30 | return AccurevLauncher.runCommand( 31 | "Synctime command", 32 | scm.getAccurevTool(), 33 | launcher, 34 | cmd, 35 | scm.getOptionalLock(workspace), 36 | accurevEnv, 37 | workspace, 38 | listener, 39 | logger); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseLsRules.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import java.io.IOException; 6 | import java.util.HashMap; 7 | import org.xmlpull.v1.XmlPullParser; 8 | import org.xmlpull.v1.XmlPullParserException; 9 | 10 | final class ParseLsRules implements ICmdOutputXmlParser, Void> { 11 | 12 | public HashMap parse(final XmlPullParser parser, final Void context) 13 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 14 | // Parse the 'accurev lsrules' command, and build up the 15 | // include/exclude rules map 16 | final HashMap locationToKindMap = new HashMap<>(); 17 | // key: String location, val: String kind (incl / excl / incldo) 18 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 19 | if (parser.getEventType() == XmlPullParser.START_TAG 20 | && "element".equalsIgnoreCase(parser.getName())) { 21 | String kind = parser.getAttributeValue("", "kind"); 22 | String location = parser.getAttributeValue("", "location"); 23 | if (location != null && kind != null) { 24 | locationToKindMap.put(location, kind); 25 | } 26 | } 27 | } 28 | return locationToKindMap; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/snapshot-format.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | If the Create and build from snapshot check box is marked, you can specify the naming 4 | conventions for the 5 | snapshot in this field. The format you specify configures 6 | the manner in which the snapshot is named and it allows the use of environment variables using 7 | the same syntax 8 | as Apache Ant uses for property expansion. For example, a 9 | literal $ must be escaped by using $$, and 10 | ${name} 11 | resolves to the value of environment variable "name". 12 |

13 | 14 |

15 | The Snapshot Name Format can be set to any combination of literal text and environment 16 | variables, subject 17 | to naming restrictions for AccuRev snapshots. Specifically, 18 | the snapshot name must begin with a non-digit other than dot (.), and must not include either a 19 | slash (/) or a 20 | backslash (\). For example, "${ACCUREV_STREAM}_${BUILD_NUMBER}_Snapshot" 21 | would take the name of the stream being built, append an underscore, append the build number 22 | and, finally, 23 | append "_Snapshot", which would result in a snapshot name of the 24 | form "MyStreamName_1234_Snapshot". 25 |

26 | 27 |

28 | If this option is not set, the snapshot name defaults to 29 | "${JOB_NAME}_${BUILD_NUMBER}". 30 |

31 |
32 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseGetConfig.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import hudson.plugins.accurev.GetConfigWebURL; 6 | import java.io.EOFException; 7 | import java.io.IOException; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import org.xmlpull.v1.XmlPullParser; 11 | import org.xmlpull.v1.XmlPullParserException; 12 | 13 | public class ParseGetConfig implements ICmdOutputXmlParser, Void> { 14 | 15 | public Map parse(XmlPullParser parser, Void context) 16 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 17 | final Map getConfig = new HashMap<>(); 18 | getConfig.put("webuiURL", new GetConfigWebURL("")); 19 | try { 20 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 21 | if (parser.getEventType() == XmlPullParser.START_TAG 22 | && "webui".equalsIgnoreCase(parser.getName())) { 23 | final String webURL = parser.getAttributeValue("", "url"); 24 | if (webURL != null) { 25 | getConfig.put("webuiURL", new GetConfigWebURL(webURL)); 26 | } 27 | } 28 | } 29 | } catch (EOFException ignored) { 30 | // file not found 31 | } 32 | return getConfig; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseRefTreeExternalFile.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import hudson.plugins.accurev.RefTreeExternalFile; 6 | import java.io.IOException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import org.xmlpull.v1.XmlPullParser; 10 | import org.xmlpull.v1.XmlPullParserException; 11 | 12 | public class ParseRefTreeExternalFile 13 | implements ICmdOutputXmlParser, Void> { 14 | 15 | public Map parse(XmlPullParser parser, Void context) 16 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 17 | final Map externalFiles = new HashMap<>(); 18 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 19 | if (parser.getEventType() == XmlPullParser.START_TAG 20 | && "Element".equalsIgnoreCase(parser.getName())) { 21 | final String location = parser.getAttributeValue("", "location"); 22 | final String status = parser.getAttributeValue("", "status"); 23 | try { 24 | externalFiles.put(location, new RefTreeExternalFile(location, status)); 25 | } catch (NumberFormatException e) { 26 | throw new UnhandledAccurevCommandOutput(e); 27 | } 28 | } 29 | } 30 | return externalFiles; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/ByteArrayStream.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | 9 | /** Simple class to capture the output of something, and then allow that output to be read. */ 10 | public class ByteArrayStream implements Closeable { 11 | 12 | private final Output mOutputStream = new Output(); 13 | 14 | /** 15 | * Gets the {@link ByteArrayOutputStream} to which data can be written. 16 | * 17 | * @return See above. 18 | */ 19 | public ByteArrayOutputStream getOutput() { 20 | return mOutputStream; 21 | } 22 | 23 | /** 24 | * Gets an {@link InputStream} that'll contain all the data that was written to {@link 25 | * #getOutput()} thus far. 26 | * 27 | *

Note that it does NOT read any data written after this method completes and it is NOT 28 | * thread-safe (if data is being written to when this method gets called, behaviour is undefined). 29 | * 30 | * @return See above. 31 | */ 32 | public InputStream getInput() { 33 | return mOutputStream.toInputStream(); 34 | } 35 | 36 | public void close() throws IOException { 37 | mOutputStream.reset(); 38 | mOutputStream.close(); 39 | } 40 | 41 | private static final class Output extends ByteArrayOutputStream { 42 | 43 | /** Returns an {@link InputStream} of our data without copying the data. */ 44 | InputStream toInputStream() { 45 | return new ByteArrayInputStream(super.buf, 0, super.count); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/delegates/Relocation.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.delegates; 2 | 3 | import hudson.util.ArgumentListBuilder; 4 | import java.util.List; 5 | 6 | /** @author raymond */ 7 | public class Relocation { 8 | 9 | private final List relocationOptions; 10 | private final String newHost; 11 | private final String newPath; 12 | private final String newParent; 13 | 14 | public Relocation( 15 | List relocationOptions, String newHost, String newPath, String newParent) { 16 | this.relocationOptions = relocationOptions; 17 | this.newHost = newHost; 18 | this.newPath = newPath; 19 | this.newParent = newParent; 20 | } 21 | 22 | public boolean isRelocationRequired() { 23 | return !relocationOptions.isEmpty(); 24 | } 25 | 26 | public String getNewParent() { 27 | return newParent; 28 | } 29 | 30 | public String getNewPath() { 31 | return newPath; 32 | } 33 | 34 | public String getNewHost() { 35 | return newHost; 36 | } 37 | 38 | public boolean isPopRequired() { 39 | for (RelocationOption relocationOption : relocationOptions) { 40 | if (relocationOption.isPopRequired()) { 41 | return true; 42 | } 43 | } 44 | return false; 45 | } 46 | 47 | public void appendCommands(ArgumentListBuilder relocateCommand) { 48 | for (RelocationOption relocationOption : relocationOptions) { 49 | relocationOption.appendCommand(relocateCommand, this); 50 | } 51 | } 52 | 53 | public interface RelocationOption { 54 | 55 | boolean isPopRequired(); 56 | 57 | void appendCommand(ArgumentListBuilder cmd, Relocation relocation); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/ShowDepots.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.Launcher; 5 | import hudson.model.TaskListener; 6 | import hudson.plugins.accurev.AccurevLauncher; 7 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 8 | import hudson.plugins.accurev.XmlParserFactory; 9 | import hudson.plugins.accurev.parsers.xml.ParseShowDepots; 10 | import hudson.util.ArgumentListBuilder; 11 | import java.io.IOException; 12 | import java.util.List; 13 | import java.util.logging.Logger; 14 | import jenkins.model.Jenkins; 15 | import org.xmlpull.v1.XmlPullParserFactory; 16 | 17 | public class ShowDepots extends Command { 18 | 19 | public static List getDepots( // 20 | final AccurevServer server, final Logger descriptorLogger) throws IOException { 21 | 22 | Jenkins jenkins = Jenkins.get(); 23 | TaskListener listener = TaskListener.NULL; 24 | Launcher launcher = jenkins.createLauncher(listener); 25 | EnvVars accurevEnv = new EnvVars(); 26 | 27 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 28 | cmd.add("show"); 29 | addServer(cmd, server); 30 | cmd.add("-fx"); 31 | cmd.add("depots"); 32 | 33 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 34 | if (parser == null) { 35 | throw new IOException("No XML Parser"); 36 | } 37 | return AccurevLauncher.runCommand( 38 | "show depots command", 39 | "", 40 | launcher, 41 | cmd, 42 | null, 43 | accurevEnv, 44 | jenkins.getRootPath(), 45 | listener, 46 | descriptorLogger, 47 | parser, 48 | new ParseShowDepots(), 49 | null); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/DetermineRemoteHostname.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import hudson.remoting.Callable; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.net.InetAddress; 7 | import java.net.UnknownHostException; 8 | import org.jenkinsci.remoting.RoleChecker; 9 | 10 | public class DetermineRemoteHostname 11 | implements Callable { 12 | 13 | private final String path; 14 | private static final long serialVersionUID = 1L; 15 | 16 | public DetermineRemoteHostname(String path) { 17 | this.path = path; 18 | } 19 | 20 | /** {@inheritDoc} */ 21 | public RemoteWorkspaceDetails call() throws UnknownHostException { 22 | InetAddress addr = InetAddress.getLocalHost(); 23 | File f = new File(path); 24 | String path; 25 | try { 26 | path = f.getCanonicalPath(); 27 | } catch (IOException e) { 28 | path = f.getAbsolutePath(); 29 | } 30 | String ipPattern = 31 | "^(([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))\\.){3}([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))$"; 32 | String hostName = addr.getCanonicalHostName(); // try full hostname 33 | if (hostName.matches(ipPattern)) { 34 | hostName = addr.getHostName(); // try hostname 35 | } 36 | // Accurev does not accept IP addresses so we are going to throw an error. 37 | if (hostName.matches(ipPattern)) { 38 | throw new UnknownHostException("Found IP, but need HostName, ensure proper FQDN."); 39 | } 40 | return new RemoteWorkspaceDetails(hostName, path); 41 | } 42 | 43 | @Override 44 | public void checkRoles(RoleChecker roleChecker) throws SecurityException { 45 | // TODO: Implement Role check 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccurevChangeLogSet.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import hudson.model.Run; 4 | import hudson.scm.ChangeLogSet; 5 | import java.util.Collection; 6 | import java.util.Collections; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import org.kohsuke.stapler.export.Exported; 10 | import org.kohsuke.stapler.export.ExportedBean; 11 | 12 | /** 13 | * Created by IntelliJ IDEA. 14 | * 15 | * @author connollys 16 | * @since 10-Oct-2007 13:12:40 17 | */ 18 | @ExportedBean(defaultVisibility = 999) 19 | public final class AccurevChangeLogSet extends ChangeLogSet { 20 | 21 | private final List transactions; 22 | 23 | AccurevChangeLogSet(Run build, List transactions) { 24 | // TODO: Implement RepositoryBrowser? 25 | super(build, null); 26 | if (transactions == null) { 27 | throw new NullPointerException("Cannot have a null transaction list"); 28 | } 29 | this.transactions = Collections.unmodifiableList(transactions); 30 | for (AccurevTransaction transaction : transactions) { 31 | transaction.setParent(this); 32 | } 33 | } 34 | 35 | public boolean isEmptySet() { 36 | return transactions.isEmpty(); 37 | } 38 | 39 | public Iterator iterator() { 40 | return transactions.iterator(); 41 | } 42 | 43 | public Collection getLogs() { 44 | return transactions; 45 | } 46 | 47 | public java.lang.Object[] toArray() { 48 | if (transactions == null) { 49 | return new java.lang.Object[0]; 50 | } 51 | 52 | return transactions.toArray(); 53 | } 54 | 55 | @Exported 56 | public String getKind() { 57 | return "accurev"; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/output/ParseInfoToLoginName.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.output; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.io.Reader; 10 | import java.nio.charset.Charset; 11 | 12 | public final class ParseInfoToLoginName implements ICmdOutputParser { 13 | 14 | public String parse(InputStream cmdOutput, Void context) 15 | throws UnhandledAccurevCommandOutput, IOException { 16 | final String usernameHeading = "Principal:"; 17 | final String controlCharsOrSpaceRegex = "[ \\x00-\\x1F\\x7F]+"; 18 | final Reader stringReader = new InputStreamReader(cmdOutput, Charset.defaultCharset()); 19 | try (BufferedReader reader = new BufferedReader(stringReader)) { 20 | String line; 21 | while ((line = reader.readLine()) != null) { 22 | if (line.contains("not logged in")) { 23 | return null; 24 | } 25 | final String[] parts = line.split(controlCharsOrSpaceRegex); 26 | for (int i = 0; i < parts.length; i++) { 27 | final String part = parts[i]; 28 | if (usernameHeading.equals(part)) { 29 | if ((i + 1) < parts.length) { 30 | return parts[i + 1]; // returns username 31 | } 32 | } 33 | } 34 | } 35 | } 36 | throw new UnhandledAccurevCommandOutput( 37 | "Output did not contain " 38 | + usernameHeading 39 | + " " 40 | + controlCharsOrSpaceRegex 41 | + " "); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/hudson/plugins/accurev/ConfigurationAsCodeTest.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.core.Is.is; 5 | 6 | import io.jenkins.plugins.casc.ConfigurationAsCode; 7 | import io.jenkins.plugins.casc.ConfiguratorException; 8 | import org.junit.Rule; 9 | import org.junit.Test; 10 | import org.jvnet.hudson.test.JenkinsRule; 11 | 12 | public class ConfigurationAsCodeTest { 13 | 14 | @Rule public JenkinsRule r = new JenkinsRule(); 15 | 16 | @Test 17 | public void shouldSupportConfigurationAsCode() throws Exception { 18 | configureJenkins("accurev.yaml"); 19 | 20 | AccurevSCM.AccurevSCMDescriptor desc = AccurevSCM.configuration(); 21 | 22 | assertThat(desc.isPollOnMaster(), is(true)); 23 | assertThat(desc.getServers().size(), is(1)); 24 | 25 | AccurevSCM.AccurevServer server1 = desc.getServers().get(0); 26 | 27 | assertThat(server1.getName(), is("testserver1")); 28 | assertThat(server1.getHost(), is("testhost")); 29 | assertThat(server1.getPort(), is(1234)); 30 | assertThat(server1.getCredentialsId(), is("abc123")); 31 | assertThat(server1.isSyncOperations(), is(true)); 32 | assertThat(server1.isMinimiseLogins(), is(true)); 33 | assertThat(server1.isUseNonexpiringLogin(), is(true)); 34 | assertThat(server1.isUseRestrictedShowStreams(), is(true)); 35 | assertThat(server1.isUseColor(), is(true)); 36 | assertThat(server1.isUsePromoteListen(), is(true)); 37 | assertThat(server1.isServerDisabled(), is(true)); 38 | } 39 | 40 | private void configureJenkins(final String fileName) throws ConfiguratorException { 41 | ConfigurationAsCode.get() 42 | .configure(ConfigurationAsCodeTest.class.getResource(fileName).toString()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/subpath.html: -------------------------------------------------------------------------------- 1 |

2 |

3 | Some projects only use a portion of the stream or reference tree and, in these instances, it is 4 | not necessary to 5 | check out the entire contents of the repository, such as 6 | when you are accessing, for example, a large remote repository to build a sub-module. In such 7 | cases, it may be 8 | useful to set up a sub-path. If you specify a sub-path, the 9 | plugin makes a "best effort" to ensure that only the sub-path is populated. This means that the 10 | files within the 11 | sub-path will be fetched, at least, although side-effects 12 | may result in files from other locations being fetched as well. 13 |

14 | 15 |

16 | Directories and files must be specified in a comma-separated list and can use relative 17 | pathnames. For example, 18 | you could use: 19 |

20 | 21 |

22 | src/com/my-company/main/my-file.java,src/com/*,src/com/webapp/my-file2.xml 23 |

24 |

25 | where "src" is the immediate sub-folder under your stream or reference tree. 26 |

27 |

28 | NOTES: 29 |

30 |
    31 |
  • The Sub-path option only works if you configure it before the first build is 32 | triggered. 33 |
  • 34 |
  • If you specify a sub-path and you also select Poll SCM in the Build Triggers 35 | section of the 36 | Jenkins configuration page, but you do not specify any Filter 37 | for Poll SCM files or directories, then the sub-path files and directories are used as 38 | the filter 39 | for polling. In this case, changes made to elements in the 40 | sub-path will trigger a build in Jenkins. 41 |
  • 42 |
43 |

44 | . 45 |

46 |
47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jenkins AccuRev Plugin 2 | 3 | [![Build Status](https://ci.jenkins.io/job/Plugins/job/accurev-plugin/job/master/badge/icon)](https://ci.jenkins.io/job/Plugins/job/accurev-plugin/job/master/) 4 | [![Jenkins Plugin](https://img.shields.io/jenkins/plugin/v/accurev.svg)](https://plugins.jenkins.io/accurev) 5 | [![GitHub release](https://img.shields.io/github/release/jenkinsci/accurev-plugin.svg?label=changelog)](https://github.com/jenkinsci/accurev-plugin/releases/latest) 6 | [![Jenkins Plugin Installs](https://img.shields.io/jenkins/plugin/i/accurev.svg?color=blue)](https://plugins.jenkins.io/accurev) 7 | 8 | This plugin allows you to use [AccuRev](https://www.microfocus.com/en-us/products/accurev/overview) as a SCM. 9 | 10 | ## Adopt this plugin 11 | 12 | This plugin is up for adoption, it needs an activate maintainer who actively uses AccuRev. 13 | 14 | ## Bug Reports 15 | 16 | File bug reports [here](http://issues.jenkins-ci.org/secure/IssueNavigator.jspa?mode=hide&reset=true&jqlQuery=project+%3D+JENKINS+AND+status+in+%28Open%2C+%22In+Progress%22%2C+Reopened%29+AND+component+%3D+%27accurev-plugin%27) 17 | 18 | ## Development 19 | 20 | Start the local Jenkins instance: 21 | 22 | ```bash 23 | mvn hpi:run 24 | ``` 25 | 26 | ### How to install 27 | 28 | Run 29 | 30 | ```bash 31 | mvn clean package 32 | ``` 33 | 34 | to create the plugin .hpi file. 35 | 36 | 37 | To install: 38 | 39 | 1. copy the resulting ./target/accurev.hpi file to the $JENKINS_HOME/plugins directory. Don't forget to restart Jenkins afterwards. 40 | 41 | 2. or use the plugin management console (http://example.com:8080/pluginManager/advanced) to upload the hpi file. You have to restart Jenkins in order to find the pluing in the installed plugins list. 42 | 43 | ## Plugin releases 44 | 45 | ```bash 46 | mvn release:prepare release:perform -B 47 | ``` 48 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseShowWorkspaces.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import hudson.plugins.accurev.AccurevWorkspace; 6 | import java.io.IOException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import org.xmlpull.v1.XmlPullParser; 10 | import org.xmlpull.v1.XmlPullParserException; 11 | 12 | public final class ParseShowWorkspaces 13 | implements ICmdOutputXmlParser, Void> { 14 | 15 | public Map parse(XmlPullParser parser, Void context) 16 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 17 | final Map workspaces = new HashMap<>(); 18 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 19 | if (parser.getEventType() == XmlPullParser.START_TAG 20 | && "Element".equalsIgnoreCase(parser.getName())) { 21 | final String name = parser.getAttributeValue("", "Name"); 22 | final String storage = parser.getAttributeValue("", "Storage"); 23 | final String host = parser.getAttributeValue("", "Host"); 24 | final String streamNumber = parser.getAttributeValue("", "Stream"); 25 | final String depot = parser.getAttributeValue("", "depot"); 26 | try { 27 | final Long streamNumberOrNull = streamNumber == null ? null : Long.valueOf(streamNumber); 28 | workspaces.put( 29 | name, new AccurevWorkspace(depot, streamNumberOrNull, name, host, storage)); 30 | } catch (NumberFormatException e) { 31 | throw new UnhandledAccurevCommandOutput(e); 32 | } 33 | } 34 | } 35 | return workspaces; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/hudson/plugins/accurev/CheckForChangesTest.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import org.junit.Test; 9 | 10 | /** Initialized by josep on 29-01-2017. */ 11 | public class CheckForChangesTest { 12 | 13 | @Test 14 | public void testPathWithMatch() { 15 | Collection serverPaths = new ArrayList<>(); 16 | serverPaths.add("/home/joseph/test/hi-lib-dal-mongo/somefile.java"); 17 | Collection filters = new ArrayList<>(); 18 | filters.add("*/hi-lib-dal-mongo/*"); 19 | assertTrue(CheckForChanges.changesMatchFilter(serverPaths, filters)); 20 | } 21 | 22 | @Test 23 | public void testPathMatcher() { 24 | assertTrue(CheckForChanges.pathMatcher("/home/joseph/some.java", "*.java")); 25 | assertTrue( 26 | CheckForChanges.pathMatcher( 27 | "/home/joseph/test/hi-lib-dal-mongo/test/somefile.java", 28 | "*/joseph/*/hi-lib-dal-mongo*")); 29 | } 30 | 31 | @Test 32 | public void testStringWithoutWildcard() { 33 | Collection serverPaths = new ArrayList<>(); 34 | serverPaths.add("/home/joseph/test/hi-lib-dal-mongo/somefile.java"); 35 | Collection filters = new ArrayList<>(); 36 | filters.add("hi-lib-dal"); 37 | assertFalse(CheckForChanges.changesMatchFilter(serverPaths, filters)); 38 | } 39 | 40 | @Test 41 | public void testStringWithFileWildcard() { 42 | Collection serverPaths = new ArrayList<>(); 43 | serverPaths.add("/home/joseph/test/hi-lib-dal-mongo/somefile.java"); 44 | Collection filters = new ArrayList<>(); 45 | filters.add("*.java"); 46 | assertTrue(CheckForChanges.changesMatchFilter(serverPaths, filters)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseShowReftrees.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import hudson.plugins.accurev.AccurevReferenceTree; 6 | import java.io.IOException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import org.xmlpull.v1.XmlPullParser; 10 | import org.xmlpull.v1.XmlPullParserException; 11 | 12 | public class ParseShowReftrees 13 | implements ICmdOutputXmlParser, Void> { 14 | 15 | public Map parse(XmlPullParser parser, Void context) 16 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 17 | final Map reftrees = new HashMap<>(); 18 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 19 | if (parser.getEventType() == XmlPullParser.START_TAG 20 | && "Element".equalsIgnoreCase(parser.getName())) { 21 | final String name = parser.getAttributeValue("", "Name"); 22 | final String storage = parser.getAttributeValue("", "Storage"); 23 | final String host = parser.getAttributeValue("", "Host"); 24 | final String streamNumber = parser.getAttributeValue("", "Stream"); 25 | final String depot = parser.getAttributeValue("", "depot"); 26 | try { 27 | final Long streamNumberOrNull = streamNumber == null ? null : Long.valueOf(streamNumber); 28 | reftrees.put( 29 | name, new AccurevReferenceTree(depot, streamNumberOrNull, name, host, storage)); 30 | } catch (NumberFormatException e) { 31 | throw new UnhandledAccurevCommandOutput(e); 32 | } 33 | } 34 | } 35 | return reftrees; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jenkins/plugins/accurev/util/AccurevUtils.java: -------------------------------------------------------------------------------- 1 | package jenkins.plugins.accurev.util; 2 | 3 | import static org.apache.commons.lang.time.DateUtils.MILLIS_PER_SECOND; 4 | 5 | import edu.umd.cs.findbugs.annotations.CheckForNull; 6 | import hudson.FilePath; 7 | import hudson.model.Computer; 8 | import hudson.model.Node; 9 | import java.util.Date; 10 | import jenkins.model.Jenkins; 11 | 12 | public class AccurevUtils { 13 | 14 | public static String cleanAccurevPath(String str) { 15 | return str.replace("\\", "/").replaceFirst("^/[.]/", ""); 16 | } 17 | 18 | @CheckForNull 19 | public static Node workspaceToNode(FilePath workspace) { 20 | Computer computer = workspace.toComputer(); 21 | Node node = null; 22 | if (null != computer) { 23 | node = computer.getNode(); 24 | } 25 | return null != node ? node : Jenkins.get(); 26 | } 27 | 28 | public static String getRootPath(FilePath workspace) { 29 | Node n = workspaceToNode(workspace); 30 | String path = null; 31 | FilePath filePath = null; 32 | if (null != n) { 33 | filePath = n.getRootPath(); 34 | } 35 | if (null != filePath) { 36 | path = filePath.getRemote(); 37 | } 38 | return path; 39 | } 40 | 41 | /** 42 | * Converts an Accurev timestamp into a {@link Date} 43 | * 44 | * @param timeInSeconds The accurev timestamp. 45 | * @return A {@link Date} set to the time for the accurev timestamp. 46 | */ 47 | public static Date convertAccurevTimestamp(@CheckForNull String timeInSeconds) { 48 | if (timeInSeconds == null) { 49 | return null; 50 | } 51 | try { 52 | final long time = Long.parseLong(timeInSeconds); 53 | final long date = time * MILLIS_PER_SECOND; 54 | return new Date(date); 55 | } catch (NumberFormatException e) { 56 | return null; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/SetProperty.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevLauncher; 8 | import hudson.plugins.accurev.AccurevSCM; 9 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 10 | import hudson.util.ArgumentListBuilder; 11 | import java.io.IOException; 12 | import java.util.logging.Logger; 13 | 14 | public class SetProperty extends Command { 15 | 16 | private static final Logger logger = Logger.getLogger(SetProperty.class.getName()); 17 | 18 | public static void setproperty( 19 | final AccurevSCM scm, 20 | final FilePath workspace, // 21 | final TaskListener listener, // 22 | final Launcher launcher, 23 | final EnvVars accurevEnv, 24 | final AccurevServer server, 25 | final String streamOrWorkspaceName, 26 | final String colorCode, 27 | final String propertyName) 28 | throws IOException { 29 | 30 | String propertyValue = 31 | ""; 32 | 33 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 34 | cmd.add("setproperty"); 35 | Command.addServer(cmd, server); 36 | cmd.add("-s"); 37 | cmd.add(streamOrWorkspaceName); 38 | cmd.add("-r"); 39 | cmd.add(propertyName); 40 | cmd.add(propertyValue); 41 | boolean runCommand = 42 | AccurevLauncher.runCommand( 43 | "setproperty background color", 44 | scm.getAccurevTool(), 45 | launcher, 46 | cmd, 47 | scm.getOptionalLock(workspace), 48 | accurevEnv, 49 | workspace, 50 | listener, 51 | logger, 52 | true); 53 | if (!runCommand) { 54 | throw new IOException("Command failed"); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/accurev/AccurevSCM/AccurevServer/config.groovy: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.AccurevSCM.AccurevServer 2 | 3 | import lib.CredentialsTagLib 4 | import lib.FormTagLib 5 | 6 | def f = namespace(FormTagLib) 7 | def c = namespace(CredentialsTagLib) 8 | 9 | f.entry(field: "name", title: _("Name")) { 10 | f.textbox() 11 | } 12 | f.entry(field: "host", title: _("Host")) { 13 | f.textbox() 14 | } 15 | f.entry(field: "port", title: _("Port")) { 16 | f.number(clazz: "number", min: 0, max: 65535, step: 1, default: 5050) 17 | } 18 | f.entry(field: "credentialsId", title: _("Credentials")) { 19 | c.select() 20 | } 21 | f.entry() { 22 | f.validateButton(method: "test", title: "Test Connection", with: "name,host,port,credentialsId") 23 | } 24 | f.advanced { 25 | f.entry(field: "syncOperations", title: _("Synchronize AccuRev CLI Operations"), help: "/plugin/accurev/help/sync-operations.html") { 26 | f.checkbox() 27 | } 28 | f.entry(field: "minimiseLogins", title: _("Minimise AccuRev Login Operations"), help: "/plugin/accurev/help/minimise-login-operations.html") { 29 | f.checkbox() 30 | } 31 | f.entry(field: "useNonexpiringLogin", title: _("Use Non-expiring Login"), help: "/plugin/accurev/help/use-nonexpiring-login.html") { 32 | f.checkbox() 33 | } 34 | f.entry(field: "useRestrictedShowStreams", title: _("Show one stream at a time"), help: "/plugin/accurev/help/use-restricted-show-streams.html") { 35 | f.checkbox() 36 | } 37 | f.entry(field: "useColor", title: _("Enable reset Color"), help: "/plugin/accurev/help/use-color.html") { 38 | f.checkbox() 39 | } 40 | f.entry(field: "usePromoteListen", title: _("Enable Post Promote Listener"), help: "/plugin/accurev/help/use-promote-listen.html") { 41 | f.checkbox() 42 | } 43 | f.entry(field: "uuid", title: _("ID")) { 44 | f.textbox(disabled: true) 45 | } 46 | f.entry(field: "serverDisabled", title: "Disable Plugin for this server ", help: "/plugin/accurev/help/server-disable.html") { 47 | f.checkbox() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/reftree.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | By default, AccuRev Plug-in for Jenkins checks out the latest changes without using a reference 4 | tree. When not 5 | using a reference tree, AccuRev Plug-in for Jenkins uses the 6 | accurev pop -R command to extract all the files. However, there may be situations 7 | when the use of a 8 | reference tree is preferred, such as when you want to use 9 | the latest versions of files that you do not intend to modify. You can think of a reference tree 10 | as a read-only 11 | portal to the AccuRev data repository. 12 |

13 | 14 |

If the Use Reference Tree check box is marked, AccuRev Plug-in for Jenkins attempts to 15 | use the reference 16 | tree specified in the Reference Tree text box. (You 17 | must create a reference tree in AccuRev before you can specify it here.) AccuRev Plug-in for 18 | Jenkins manages the 19 | process of migrating the reference tree to the appropriate 20 | build machine and relocating the reference tree to use the correct location. Note that these 21 | changes are 22 | recorded in the AccuRev repository.

23 |

24 | When using a reference tree, the following AccuRev commands are used: 25 |

26 | 27 |
    28 |
  • accurev show refs confirms that the reference tree is valid and has the correct 29 | parent stream. 30 |
  • 31 |
  • accurev chref is run if the reference tree is in the wrong directory or on the 32 | wrong machine. 33 | (Optional) 34 |
  • 35 |
  • accurev update refreshes the reference tree. If the update fails, AccuRev 36 | Plug-in for Jenkins 37 | uses the accurev update -9 command to update the 38 | reference tree. 39 |
  • 40 |
  • accurev pop -O -R ensures that all files are populated and that the reference 41 | tree always 42 | contains the fresh update. 43 |
  • 44 |
45 |
46 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccurevReferenceTree.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.Serializable; 4 | 5 | public class AccurevReferenceTree implements Serializable { 6 | 7 | private final String depot; 8 | private final Long streamNumber; 9 | private final String name; 10 | private final String host; 11 | private final String storage; 12 | private AccurevStream stream = null; 13 | private static final long serialVersionUID = 1L; 14 | 15 | public AccurevReferenceTree( 16 | String depot, Long streamNumber, String name, String host, String storage) { 17 | this.depot = depot; 18 | this.streamNumber = streamNumber; 19 | this.name = name; 20 | this.host = host; 21 | this.storage = storage; 22 | } 23 | 24 | /** 25 | * Getter for property 'depot'. 26 | * 27 | * @return Value for property 'depot'. 28 | */ 29 | public String getDepot() { 30 | return depot; 31 | } 32 | 33 | /** 34 | * Getter for property 'streamNumber'. 35 | * 36 | * @return Value for property 'streamNumber'. 37 | */ 38 | public Long getStreamNumber() { 39 | return streamNumber; 40 | } 41 | 42 | /** 43 | * Getter for property 'name'. 44 | * 45 | * @return Value for property 'name'. 46 | */ 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | /** 52 | * Getter for property 'host'. 53 | * 54 | * @return Value for property 'host'. 55 | */ 56 | public String getHost() { 57 | return host; 58 | } 59 | 60 | /** 61 | * Getter for property 'storage'. 62 | * 63 | * @return Value for property 'storage'. 64 | */ 65 | public String getStorage() { 66 | return storage; 67 | } 68 | 69 | /** 70 | * Getter for property 'stream'. 71 | * 72 | * @return Value for property 'stream'. 73 | */ 74 | public AccurevStream getStream() { 75 | return stream; 76 | } 77 | 78 | /** 79 | * Setter for property 'stream'. 80 | * 81 | * @param stream Value to set for property 'stream'. 82 | */ 83 | public void setStream(AccurevStream stream) { 84 | this.stream = stream; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccurevWorkspace.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * 8 | * @author connollys 9 | * @since 03-Dec-2007 13:17:39 10 | */ 11 | public class AccurevWorkspace implements Serializable { 12 | 13 | private final String depot; 14 | private final Long streamNumber; 15 | private final String name; 16 | private final String host; 17 | private final String storage; 18 | private AccurevStream stream = null; 19 | private static final long serialVersionUID = 1L; 20 | 21 | public AccurevWorkspace( 22 | String depot, Long streamNumber, String name, String host, String storage) { 23 | this.depot = depot; 24 | this.streamNumber = streamNumber; 25 | this.name = name; 26 | this.host = host; 27 | this.storage = storage; 28 | } 29 | 30 | /** 31 | * Getter for property 'depot'. 32 | * 33 | * @return Value for property 'depot'. 34 | */ 35 | public String getDepot() { 36 | return depot; 37 | } 38 | 39 | /** 40 | * Getter for property 'streamNumber'. 41 | * 42 | * @return Value for property 'streamNumber'. 43 | */ 44 | public Long getStreamNumber() { 45 | return streamNumber; 46 | } 47 | 48 | /** 49 | * Getter for property 'name'. 50 | * 51 | * @return Value for property 'name'. 52 | */ 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | /** 58 | * Getter for property 'host'. 59 | * 60 | * @return Value for property 'host'. 61 | */ 62 | public String getHost() { 63 | return host; 64 | } 65 | 66 | /** 67 | * Getter for property 'storage'. 68 | * 69 | * @return Value for property 'storage'. 70 | */ 71 | public String getStorage() { 72 | return storage; 73 | } 74 | 75 | /** 76 | * Getter for property 'stream'. 77 | * 78 | * @return Value for property 'stream'. 79 | */ 80 | public AccurevStream getStream() { 81 | return stream; 82 | } 83 | 84 | /** 85 | * Setter for property 'stream'. 86 | * 87 | * @param stream Value to set for property 'stream'. 88 | */ 89 | public void setStream(AccurevStream stream) { 90 | this.stream = stream; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/output/ParsePopulate.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.output; 2 | 3 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputParser; 4 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 5 | import java.io.BufferedReader; 6 | import java.io.BufferedWriter; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.OutputStream; 11 | import java.io.OutputStreamWriter; 12 | import java.io.Reader; 13 | import java.io.Writer; 14 | import java.nio.charset.Charset; 15 | 16 | /** 17 | * Filters the output of the populate command and just shows a summary of the output. Helps prevent 18 | * build logs being clogged up with the checkout. 19 | */ 20 | public final class ParsePopulate implements ICmdOutputParser { 21 | 22 | public Boolean parse(InputStream cmdOutput, OutputStream streamToCopyOutputTo) 23 | throws UnhandledAccurevCommandOutput, IOException { 24 | final String lineStartDirectory = "Creating dir:"; 25 | final String lineStartElement = "Populating element"; 26 | int countOfDirectories = 0; 27 | int countOfElements = 0; 28 | final Reader stringReader = new InputStreamReader(cmdOutput, Charset.defaultCharset()); 29 | final Writer stringWriter = 30 | new OutputStreamWriter(streamToCopyOutputTo, Charset.defaultCharset()); 31 | final BufferedWriter lineWriter = new BufferedWriter(stringWriter); 32 | try (BufferedReader reader = new BufferedReader(stringReader)) { 33 | String line; 34 | while ((line = reader.readLine()) != null) { 35 | if (line.startsWith(lineStartElement)) { 36 | countOfElements++; 37 | } else if (line.startsWith(lineStartDirectory)) { 38 | countOfDirectories++; 39 | } else { 40 | lineWriter.write(line); 41 | lineWriter.newLine(); 42 | } 43 | } 44 | final String msg = 45 | "Populated " + countOfElements + " elements and " + countOfDirectories + " directories."; 46 | streamToCopyOutputTo.write(msg.getBytes(Charset.defaultCharset())); 47 | } finally { 48 | lineWriter.flush(); 49 | } 50 | return Boolean.TRUE; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/FilesCmd.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevElement; 8 | import hudson.plugins.accurev.AccurevLauncher; 9 | import hudson.plugins.accurev.AccurevSCM; 10 | import hudson.plugins.accurev.XmlParserFactory; 11 | import hudson.plugins.accurev.parsers.xml.ParseFiles; 12 | import hudson.util.ArgumentListBuilder; 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.logging.Logger; 17 | import org.xmlpull.v1.XmlPullParserFactory; 18 | 19 | public class FilesCmd extends Command { 20 | 21 | private static final Logger logger = Logger.getLogger(Login.class.getName()); 22 | 23 | public static List checkFiles( 24 | final AccurevSCM scm, 25 | final AccurevSCM.AccurevServer server, 26 | final EnvVars accurevEnv, 27 | final FilePath workspace, 28 | final TaskListener listener, 29 | final Launcher launcher, 30 | FilePath file) 31 | throws IOException { 32 | final String commandDescription = "files command"; 33 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 34 | cmd.add("files"); 35 | addServer(cmd, server); 36 | cmd.add("-fx"); 37 | cmd.add("-s", scm.getStream()); 38 | cmd.add("-l", file.getRemote()); 39 | 40 | // returns username 41 | final ArrayList list = new ArrayList<>(1); 42 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 43 | if (parser == null) { 44 | throw new IOException("No XML Parser"); 45 | } 46 | final Boolean filesFound = 47 | AccurevLauncher.runCommand( 48 | commandDescription, 49 | scm.getAccurevTool(), 50 | launcher, 51 | cmd, 52 | scm.getOptionalLock(workspace), 53 | accurevEnv, 54 | workspace, 55 | listener, 56 | logger, 57 | parser, 58 | new ParseFiles(), 59 | list); 60 | if (filesFound == null) { 61 | throw new IOException("FilesCmd command failed."); 62 | } 63 | return list; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/webapp/help/project/workspace.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | By default, this plugin checks out the latest changes without using a workspace. This removes 4 | the need to 5 | manually create a workspace for each project, and removes the need for the plugin to make 6 | transactions 7 | while moving the workspace from slave to slave as the build migrates from slave to slave. 8 |

9 | 10 |

11 | However, there may be situations when the use of a workspace is preferred. If you want to use a 12 | workspace, 13 | select this option and enter the name of an existing workspace in the Workspace field. 14 | The plugin can 15 | manage 16 | migrating the workspace to the appropriate build machine and re-parenting the workspace to use 17 | the correct 18 | parent 19 | stream (Jenkins considers the Stream field value as the parent stream). Note that 20 | workspace changes 21 | (accurev chws) are logged as AccuRev transactions. 22 |

23 | 24 |

When not using a workspace, the following AccuRev commands will be used:

25 |
    26 |
  • accurev pop -O -R . to extract all the files. Note: this command will not work 27 | if the 28 | directory that the files are being extracted to is the child of an active AccuRev workspace. 29 |
  • 30 |
31 |

When using a workspace, the following AccuRev commands are used:

32 |
    33 |
  • accurev show wspaces to validate that the workspace is valid and has the 34 | correct parent stream 35 |
  • 36 |
37 |

If the workspace needs to be relocated or if the host machine needs to be updated, the 38 | following AccuRev commands 39 | are also used:

40 |
    41 |
  • accurev chws
  • 42 |
  • accurev update -9
  • 43 |
  • accurev pop -O -R .
  • 44 |
45 |

Otherwise, the following commands are run:

46 |
    47 |
  • accurev chws (if re-parenting is required)
  • 48 |
  • accurev update
  • 49 |
50 |

Note: If you decide to stop using an AccuRev workspace after having run a build, you 51 | must manually move 52 | the AccuRev workspace directory.

53 |
54 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/XmlParserFactory.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | import java.util.WeakHashMap; 6 | import java.util.logging.Logger; 7 | import org.xmlpull.v1.XmlPullParser; 8 | import org.xmlpull.v1.XmlPullParserException; 9 | import org.xmlpull.v1.XmlPullParserFactory; 10 | 11 | /** Utility class that provides {@link XmlPullParserFactory}s. */ 12 | public class XmlParserFactory { 13 | 14 | private static final Logger logger = Logger.getLogger(AccurevSCM.class.getName()); 15 | private static final Map PARSER_FACTORY_CACHE = 16 | new WeakHashMap<>(1); 17 | 18 | /** 19 | * Gets a new {@link XmlPullParser} configured for parsing Accurev XML files. 20 | * 21 | * @return a new {@link XmlPullParser} configured for parsing Accurev XML files. 22 | * @throws XmlPullParserException when things go wrong/ 23 | * @throws IOException Handle it above 24 | */ 25 | static XmlPullParser newParser() throws XmlPullParserException, IOException { 26 | XmlPullParserFactory factory = null; 27 | XmlPullParser parser = null; 28 | if (null != getFactory()) { 29 | factory = getFactory(); 30 | } 31 | if (null != factory) { 32 | parser = factory.newPullParser(); 33 | } 34 | return parser; 35 | } 36 | 37 | /** 38 | * Gets a new {@link XmlPullParserFactory} configured for parsing Accurev XML files. 39 | * 40 | * @return a new {@link XmlPullParserFactory} configured for parsing Accurev XML files, or 41 | * null if things go wrong. 42 | * @throws IOException Handle it above 43 | */ 44 | public static XmlPullParserFactory getFactory() throws IOException { 45 | synchronized (PARSER_FACTORY_CACHE) { 46 | final XmlPullParserFactory existingFactory = 47 | PARSER_FACTORY_CACHE.get(XmlPullParserFactory.class); 48 | if (existingFactory != null) { 49 | return existingFactory; 50 | } 51 | XmlPullParserFactory newFactory; 52 | try { 53 | newFactory = XmlPullParserFactory.newInstance(); 54 | } catch (XmlPullParserException ex) { 55 | AccurevLauncher.logException( 56 | "Unable to create new " + XmlPullParserFactory.class.getSimpleName(), ex, logger, null); 57 | return null; 58 | } 59 | newFactory.setNamespaceAware(false); 60 | newFactory.setValidating(false); 61 | PARSER_FACTORY_CACHE.put(XmlPullParserFactory.class, newFactory); 62 | return newFactory; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/accurev/AccurevChangeLogSet/index.jelly: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 |

No changes

10 |
11 | 12 |

Summary

13 |
    14 | 15 |
  1. 16 | 17 |
  2. 18 |
    19 |
20 | 21 | 22 | 23 | 55 | 56 | 57 | 60 | 61 | 62 | 63 | 64 | 65 |
24 | 25 |
26 | 27 | 28 | 29 | AccuWork Issue Number - ${cs.issueNum} 30 |
31 |
32 | 33 | AccuWork Issue Number - 34 | ${cs.issueNum} 35 | 36 |
37 |
38 | 39 |
40 | Transaction 41 | 42 | ${cs.id} 43 | 44 | ${cs.id} 45 | 46 | 47 | by 48 | ${cs.author} 49 | : 50 | 51 |
52 | ${cs.msg} 53 |
54 |
58 | 59 | ${p}
66 |
67 |
68 |
69 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/delegates/SnapshotDelegate.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.delegates; 2 | 3 | import hudson.EnvVars; 4 | import hudson.model.Run; 5 | import hudson.plugins.accurev.AccurevLauncher; 6 | import hudson.plugins.accurev.AccurevSCM; 7 | import hudson.plugins.accurev.cmd.Command; 8 | import hudson.util.ArgumentListBuilder; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.util.logging.Logger; 12 | import org.apache.commons.lang.StringUtils; 13 | 14 | /** @author raymond */ 15 | public class SnapshotDelegate extends StreamDelegate { 16 | 17 | private static final Logger logger = Logger.getLogger(SnapshotDelegate.class.getName()); 18 | private static final String DEFAULT_SNAPSHOT_NAME_FORMAT = "${JOB_NAME}_${BUILD_NUMBER}"; 19 | private String snapshotName; 20 | 21 | public SnapshotDelegate(AccurevSCM scm) { 22 | super(scm); 23 | } 24 | 25 | private String calculateSnapshotName(final Run build) 26 | throws IOException, InterruptedException { 27 | String snapshotNameFormat = scm.getSnapshotNameFormat(); 28 | final String actualFormat = 29 | StringUtils.isBlank(snapshotNameFormat) 30 | ? DEFAULT_SNAPSHOT_NAME_FORMAT 31 | : snapshotNameFormat.trim(); 32 | final EnvVars environment = build.getEnvironment(listener); 33 | return environment.expand(actualFormat); 34 | } 35 | 36 | @Override 37 | protected boolean checkout(Run build, File changeLogFile) 38 | throws IOException, InterruptedException { 39 | snapshotName = calculateSnapshotName(build); 40 | listener.getLogger().println("Creating snapshot: " + snapshotName + "..."); 41 | build.getEnvironment(listener).put("ACCUREV_SNAPSHOT", snapshotName); 42 | // snapshot command: accurev mksnap -H -s -b -t now 43 | final ArgumentListBuilder mksnapcmd = new ArgumentListBuilder(); 44 | mksnapcmd.add("mksnap"); 45 | Command.addServer(mksnapcmd, server); 46 | mksnapcmd.add("-s"); 47 | mksnapcmd.add(snapshotName); 48 | mksnapcmd.add("-b"); 49 | mksnapcmd.add(localStream); 50 | mksnapcmd.add("-t"); 51 | mksnapcmd.add("now"); 52 | if (!AccurevLauncher.runCommand( 53 | "Create snapshot command", 54 | scm.getAccurevTool(), 55 | launcher, 56 | mksnapcmd, 57 | scm.getOptionalLock(jenkinsWorkspace), 58 | accurevEnv, 59 | jenkinsWorkspace, 60 | listener, 61 | logger, 62 | true)) { 63 | return false; 64 | } 65 | listener.getLogger().println("Snapshot created successfully."); 66 | return true; 67 | } 68 | 69 | @Override 70 | protected boolean isSteamColorEnabled() { 71 | return false; 72 | } 73 | 74 | @Override 75 | protected String getPopulateFromMessage() { 76 | return "from snapshot"; 77 | } 78 | 79 | @Override 80 | protected String getPopulateStream() { 81 | return snapshotName; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/XmlConsolidateStreamChangeLog.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.WeakHashMap; 10 | import java.util.logging.Logger; 11 | import javax.xml.stream.XMLOutputFactory; 12 | import javax.xml.stream.XMLStreamException; 13 | import javax.xml.stream.XMLStreamWriter; 14 | 15 | /** */ 16 | public class XmlConsolidateStreamChangeLog { 17 | 18 | private static final Logger logger = Logger.getLogger(AccurevSCM.class.getName()); 19 | private static final Map, XMLOutputFactory> OUTPUT_FACTORY_CACHE = 20 | new WeakHashMap<>(1); 21 | 22 | static XMLOutputFactory getFactory() { 23 | synchronized (OUTPUT_FACTORY_CACHE) { 24 | final XMLOutputFactory existingFactory = OUTPUT_FACTORY_CACHE.get(XMLOutputFactory.class); 25 | if (existingFactory != null) { 26 | return existingFactory; 27 | } 28 | XMLOutputFactory newFactory = XMLOutputFactory.newFactory(); 29 | OUTPUT_FACTORY_CACHE.put(XMLOutputFactory.class, newFactory); 30 | return newFactory; 31 | } 32 | } 33 | 34 | public static File getStreamChangeLogFile(File changelogFile, AccurevStream stream) { 35 | File dir = changelogFile.getParentFile(); 36 | return new File(dir, stream.getName() + "_" + changelogFile.getName()); 37 | } 38 | 39 | public static File getUpdateChangeLogFile(File changelogFile) { 40 | File dir = changelogFile.getParentFile(); 41 | return new File(dir, "update_" + changelogFile.getName()); 42 | } 43 | 44 | public static void createChangeLog( 45 | List streamFiles, File changeLogFile, String updateFile) throws IOException { 46 | try (FileOutputStream changeLogStream = new FileOutputStream(changeLogFile)) { 47 | XMLOutputFactory outputFactory = getFactory(); 48 | XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(changeLogStream); 49 | streamWriter.writeStartDocument(); 50 | streamWriter.writeStartElement("ChangeLogs"); 51 | if (updateFile != null) { 52 | streamWriter.writeStartElement("UpdateLog"); 53 | streamWriter.writeCharacters(updateFile); 54 | streamWriter.writeEndElement(); 55 | } 56 | for (String streamFile : streamFiles) { 57 | streamWriter.writeStartElement("ChangeLog"); 58 | streamWriter.writeCharacters(streamFile); 59 | streamWriter.writeEndElement(); 60 | } 61 | streamWriter.writeEndElement(); 62 | streamWriter.writeEndDocument(); 63 | } catch (FileNotFoundException | XMLStreamException ex) { 64 | AccurevLauncher.logException( 65 | "Unable to create consolidated changelog " 66 | + XmlConsolidateStreamChangeLog.class.getSimpleName(), 67 | ex, 68 | logger, 69 | null); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/jenkins/plugins/accurev/AccurevToolTest.java: -------------------------------------------------------------------------------- 1 | package jenkins.plugins.accurev; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import hudson.EnvVars; 6 | import hudson.model.Node; 7 | import hudson.model.TaskListener; 8 | import hudson.slaves.DumbSlave; 9 | import hudson.tools.CommandInstaller; 10 | import hudson.tools.InstallSourceProperty; 11 | import hudson.tools.ToolInstallation; 12 | import hudson.tools.ToolInstaller; 13 | import hudson.tools.ToolProperty; 14 | import hudson.util.StreamTaskListener; 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import org.junit.Before; 19 | import org.junit.Test; 20 | import org.jvnet.hudson.test.JenkinsRule; 21 | 22 | /** Initialized by josep on 22-01-2017. */ 23 | public class AccurevToolTest { 24 | 25 | @org.junit.Rule public JenkinsRule j = new JenkinsRule(); 26 | 27 | private AccurevTool accurevTool; 28 | 29 | public static AccurevTool createTool(String name) throws IOException { 30 | List installers = new ArrayList(); 31 | installers.add(new CommandInstaller(null, "accurev", "./")); 32 | 33 | List> properties = 34 | new ArrayList>(); 35 | properties.add(new InstallSourceProperty(installers)); 36 | 37 | return new AccurevTool(name, "./", properties); 38 | } 39 | 40 | @Before 41 | public void setUp() throws Exception { 42 | AccurevTool.onLoaded(); 43 | accurevTool = AccurevTool.getDefaultInstallation(); 44 | } 45 | 46 | @Test 47 | public void testForNode() throws Exception { 48 | DumbSlave slave = j.createSlave(); 49 | slave.setMode(Node.Mode.EXCLUSIVE); 50 | TaskListener log = StreamTaskListener.fromStdout(); 51 | AccurevTool newTool = accurevTool.forNode(slave, log); 52 | assertEquals(accurevTool.getHome(), newTool.getHome()); 53 | } 54 | 55 | @Test 56 | public void testForEnvironment() throws Exception { 57 | EnvVars environment = new EnvVars(); 58 | AccurevTool newTool = accurevTool.forEnvironment(environment); 59 | assertEquals(accurevTool.getHome(), newTool.getHome()); 60 | } 61 | 62 | @Test 63 | public void testGetDescriptor() throws Exception { 64 | AccurevTool.DescriptorImpl descriptor = accurevTool.getDescriptor(); 65 | assertEquals("AccuRev", descriptor.getDisplayName()); 66 | } 67 | 68 | @Test 69 | public void testGetInstallationFromDescriptor() throws Exception { 70 | AccurevTool.DescriptorImpl descriptor = accurevTool.getDescriptor(); 71 | assertEquals(null, descriptor.getInstallation("")); 72 | assertEquals(null, descriptor.getInstallation("not-a-valid-accurev-install")); 73 | } 74 | 75 | @Test 76 | public void testGetDefaultInstallationFromDescriptor() throws Exception { 77 | AccurevTool newTool = AccurevTool.getDefaultInstallation(); 78 | assertEquals(accurevTool.getHome(), newTool.getHome()); 79 | assertEquals(accurevTool.getName(), newTool.getName()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseShowStreams.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import static jenkins.plugins.accurev.util.AccurevUtils.convertAccurevTimestamp; 4 | 5 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 6 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 7 | import hudson.plugins.accurev.AccurevStream; 8 | import hudson.plugins.accurev.AccurevStream.StreamType; 9 | import java.io.IOException; 10 | import java.util.Date; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import org.xmlpull.v1.XmlPullParser; 14 | import org.xmlpull.v1.XmlPullParserException; 15 | 16 | public final class ParseShowStreams 17 | implements ICmdOutputXmlParser, String> { 18 | 19 | public Map parse(XmlPullParser parser, String depot) 20 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 21 | final Map streams = new HashMap<>(); 22 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 23 | if (parser.getEventType() == XmlPullParser.START_TAG 24 | && "stream".equalsIgnoreCase(parser.getName())) { 25 | final String streamName = parser.getAttributeValue("", "name"); 26 | 27 | final String streamNumberStr = parser.getAttributeValue("", "streamNumber"); 28 | final String basisStreamName = parser.getAttributeValue("", "basis"); 29 | final String basisStreamNumberStr = parser.getAttributeValue("", "basisStreamNumber"); 30 | final String streamTypeStr = parser.getAttributeValue("", "type"); 31 | final String streamIsDynamic = parser.getAttributeValue("", "isDynamic"); 32 | final String streamTimeString = parser.getAttributeValue("", "time"); 33 | final Date streamTime = 34 | streamTimeString == null ? null : convertAccurevTimestamp(streamTimeString); 35 | final String streamStartTimeString = parser.getAttributeValue("", "startTime"); 36 | final Date streamStartTime = 37 | streamTimeString == null ? null : convertAccurevTimestamp(streamStartTimeString); 38 | try { 39 | final Long streamNumber = streamNumberStr == null ? null : Long.valueOf(streamNumberStr); 40 | final Long basisStreamNumber = 41 | basisStreamNumberStr == null ? null : Long.valueOf(basisStreamNumberStr); 42 | final StreamType streamType = AccurevStream.StreamType.parseStreamType(streamTypeStr); 43 | final boolean isDynamic = 44 | streamIsDynamic != null && Boolean.parseBoolean(streamIsDynamic); 45 | final AccurevStream stream = 46 | new AccurevStream( // 47 | streamName, // 48 | streamNumber, // 49 | depot, // 50 | basisStreamName, // 51 | basisStreamNumber, // 52 | isDynamic, // 53 | streamType, // 54 | streamTime, // 55 | streamStartTime); 56 | streams.put(streamName, stream); 57 | } catch (NumberFormatException e) { 58 | throw new UnhandledAccurevCommandOutput(e); 59 | } 60 | } 61 | } 62 | return streams; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/jenkins/plugins/accurev/AccurevPlugin.java: -------------------------------------------------------------------------------- 1 | package jenkins.plugins.accurev; 2 | 3 | import static hudson.init.InitMilestone.COMPLETED; 4 | import static hudson.init.InitMilestone.EXTENSIONS_AUGMENTED; 5 | import static hudson.init.InitMilestone.JOB_LOADED; 6 | 7 | import com.cloudbees.plugins.credentials.SystemCredentialsProvider; 8 | import hudson.init.Initializer; 9 | import hudson.model.Project; 10 | import hudson.plugins.accurev.AccurevSCM; 11 | import hudson.plugins.accurev.AccurevSCM.AccurevSCMDescriptor; 12 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 13 | import java.util.logging.Logger; 14 | import jenkins.model.Jenkins; 15 | import jenkins.plugins.accurev.util.UUIDUtils; 16 | 17 | /** Initialized by josp on 21/09/16. */ 18 | @SuppressWarnings("unused") // Used for initialization/migration purpose 19 | public class AccurevPlugin { 20 | 21 | private static final Logger LOGGER = Logger.getLogger(AccurevPlugin.class.getName()); 22 | 23 | /** 24 | * We need ensure that migrator will run after jobs are loaded Launches migration after plugin and 25 | * jobs already initialized. Expected milestone: @Initializer(after = JOB_LOADED) 26 | * 27 | * @throws Exception Exceptions 28 | */ 29 | @Initializer(after = JOB_LOADED, before = COMPLETED) 30 | public static void migrateJobsToServerUUID() throws Exception { 31 | final Jenkins jenkins = Jenkins.get(); 32 | boolean changed = false; 33 | AccurevSCMDescriptor descriptor = jenkins.getDescriptorByType(AccurevSCMDescriptor.class); 34 | for (Project p : jenkins.getAllItems(Project.class)) { 35 | if (p.getScm() instanceof AccurevSCM) { 36 | AccurevSCM scm = (AccurevSCM) p.getScm(); 37 | String serverUUID = scm.getServerUUID(); 38 | if (UUIDUtils.isNotValid(serverUUID) || descriptor.getServer(serverUUID) == null) { 39 | AccurevServer server = descriptor.getServer(scm.getServerName()); 40 | if (server == null) { 41 | LOGGER.warning( 42 | "No server found with that name, Project: " 43 | + p.getName() 44 | + " Server Name: " 45 | + scm.getServerName()); 46 | } else { 47 | changed = true; 48 | String uuid = server.getUuid(); 49 | scm.setServerUUID(uuid); 50 | p.save(); 51 | } 52 | } 53 | } 54 | } 55 | if (changed) { 56 | descriptor.save(); 57 | } 58 | } 59 | 60 | /** 61 | * We need ensure that migrator will after Extensions are augmented Launches migration if servers 62 | * still uses username and password Expected milestone: @Initializer(after = EXTENSIONS_AUGMENTED) 63 | * 64 | * @throws Exception Exceptions 65 | */ 66 | @Initializer(after = EXTENSIONS_AUGMENTED) 67 | public static void migrateServersToCredentials() throws Exception { 68 | boolean changed = false; 69 | AccurevSCMDescriptor descriptor = AccurevSCM.configuration(); 70 | boolean migratedCredentials = false; 71 | for (AccurevServer server : descriptor.getServers()) { 72 | if (server.migrateCredentials()) { 73 | changed = true; 74 | } 75 | } 76 | if (changed) { 77 | descriptor.save(); 78 | SystemCredentialsProvider.getInstance().save(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/hudson/plugins/accurev/MigrateIDAndCredentialTest.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import com.cloudbees.plugins.credentials.CredentialsMatchers; 9 | import com.cloudbees.plugins.credentials.CredentialsProvider; 10 | import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; 11 | import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; 12 | import hudson.model.FreeStyleProject; 13 | import hudson.plugins.accurev.AccurevSCM.AccurevSCMDescriptor; 14 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 15 | import hudson.security.ACL; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import jenkins.model.Jenkins; 19 | import jenkins.plugins.accurev.AccurevPlugin; 20 | import org.apache.commons.lang.StringUtils; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.jvnet.hudson.test.JenkinsRule; 24 | 25 | @SuppressWarnings("deprecation") 26 | public class MigrateIDAndCredentialTest { 27 | 28 | @org.junit.Rule public JenkinsRule j = new JenkinsRule(); 29 | 30 | private AccurevSCMDescriptor descriptor; 31 | private AccurevSCM scm; 32 | 33 | @Before 34 | public void setUp() throws Exception { 35 | AccurevServer server = new AccurevServer(null, "test", "localhost"); 36 | server.setUsername("bob"); 37 | server.setPassword("OBF:1rwf1x1b1rwf"); 38 | scm = new AccurevSCM(server.getName(), "test", "test"); 39 | scm.setServerName("test"); 40 | FreeStyleProject accurevTest = j.createFreeStyleProject("accurevTest"); 41 | accurevTest.setScm(scm); 42 | descriptor = scm.getDescriptor(); 43 | List servers = new ArrayList<>(); 44 | servers.add(server); 45 | descriptor.setServers(servers); 46 | } 47 | 48 | @Test 49 | public void testMigrateCredential() throws Exception { 50 | AccurevServer server = AccurevSCM.configuration().getServers().get(0); 51 | boolean migrated = server.migrateCredentials(); 52 | StandardUsernamePasswordCredentials credentials = 53 | CredentialsMatchers.firstOrNull( 54 | CredentialsProvider.lookupCredentials( 55 | StandardUsernamePasswordCredentials.class, 56 | Jenkins.getInstance(), 57 | ACL.SYSTEM, 58 | URIRequirementBuilder.fromUri("").withHostnamePort("localhost", 5050).build()), 59 | CredentialsMatchers.withUsername("bob")); 60 | assertTrue(migrated); 61 | assertNotNull(server.getCredentialsId()); 62 | assertNotNull(server.getCredentials()); 63 | assertEquals(server.getCredentials().getUsername(), credentials.getUsername()); 64 | assertEquals(server.getCredentials().getPassword(), credentials.getPassword()); 65 | assertNull(server.username); 66 | assertNull(server.password); 67 | } 68 | 69 | @Test 70 | public void testMigrateToServerUUID() throws Exception { 71 | AccurevPlugin.migrateJobsToServerUUID(); 72 | AccurevServer server = AccurevSCM.configuration().getServers().get(0); 73 | assertTrue(StringUtils.equals(server.getUuid(), scm.getServerUUID())); 74 | assertNotNull(descriptor.getServer(scm.getServerUUID())); 75 | assertNotNull(scm.getServer()); 76 | assertEquals(descriptor.getServer(scm.getServerUUID()), scm.getServer()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/PopulateCmd.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevLauncher; 8 | import hudson.plugins.accurev.AccurevSCM; 9 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 10 | import hudson.plugins.accurev.parsers.output.ParsePopulate; 11 | import hudson.util.ArgumentListBuilder; 12 | import java.io.IOException; 13 | import java.util.Date; 14 | import java.util.StringTokenizer; 15 | import java.util.logging.Logger; 16 | import org.apache.commons.lang.StringUtils; 17 | 18 | public class PopulateCmd extends Command { 19 | 20 | private static final Logger logger = Logger.getLogger(PopulateCmd.class.getName()); 21 | 22 | private Date _startDateOfPopulate; 23 | 24 | /** @return Date */ 25 | public Date get_startDateOfPopulate() { 26 | return (Date) _startDateOfPopulate.clone(); 27 | } 28 | 29 | /** 30 | * @param scm Accurev SCm 31 | * @param launcher launcher 32 | * @param listener listener 33 | * @param server server 34 | * @param streamName stream Name 35 | * @param overwrite overwrite 36 | * @param fromMessage from Messge 37 | * @param workspace Accurev Workspace 38 | * @param accurevEnv Accurev Environment 39 | * @param files list of files to be populated 40 | * @return boolean 41 | * @throws IOException Handle it above 42 | */ 43 | public boolean populate( 44 | AccurevSCM scm, 45 | Launcher launcher, 46 | TaskListener listener, 47 | AccurevServer server, 48 | String streamName, 49 | boolean overwrite, 50 | String fromMessage, 51 | FilePath workspace, 52 | EnvVars accurevEnv, 53 | FilePath files) 54 | throws IOException { 55 | listener.getLogger().println("Populating " + fromMessage + "..."); 56 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 57 | cmd.add("pop"); 58 | addServer(cmd, server); 59 | 60 | if (streamName != null) { 61 | cmd.add("-v"); 62 | cmd.add(streamName); 63 | 64 | if (scm.getSubPathOnly()) { 65 | cmd.add("-D"); 66 | } 67 | } 68 | 69 | cmd.add("-L"); 70 | cmd.add(workspace.getRemote()); 71 | 72 | // Add the file containing list to be populated 73 | if (files != null) { 74 | cmd.add("-l"); 75 | cmd.add(files.getRemote()); 76 | } 77 | 78 | if (overwrite) { 79 | cmd.add("-O"); 80 | } 81 | 82 | cmd.add("-R"); 83 | if (StringUtils.isBlank(scm.getSubPath())) { 84 | cmd.add("."); 85 | } else { 86 | final StringTokenizer st = new StringTokenizer(scm.getSubPath(), ","); 87 | while (st.hasMoreElements()) { 88 | String path = st.nextToken().trim(); 89 | path = path.replace("*", ""); 90 | cmd.add(path); 91 | } 92 | } 93 | _startDateOfPopulate = new Date(); 94 | final Boolean success = 95 | AccurevLauncher.runCommand( 96 | "Populate " + fromMessage + " command", 97 | scm.getAccurevTool(), 98 | launcher, 99 | cmd, 100 | scm.getOptionalLock(workspace), 101 | accurevEnv, 102 | workspace, 103 | listener, 104 | logger, 105 | new ParsePopulate(), 106 | listener.getLogger()); 107 | if (success == null || !success) { 108 | return false; 109 | } 110 | listener.getLogger().println("Populate completed successfully."); 111 | return true; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccurevMode.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import hudson.plugins.accurev.delegates.AbstractModeDelegate; 4 | import hudson.plugins.accurev.delegates.ReftreeDelegate; 5 | import hudson.plugins.accurev.delegates.SnapshotDelegate; 6 | import hudson.plugins.accurev.delegates.StreamDelegate; 7 | import hudson.plugins.accurev.delegates.WorkspaceDelegate; 8 | 9 | /** Determines the delegate used for building */ 10 | public enum AccurevMode { 11 | WORKSPACE(true) { 12 | @Override 13 | protected AbstractModeDelegate createDelegate(AccurevSCM accurevSCM) { 14 | return new WorkspaceDelegate(accurevSCM); 15 | } 16 | 17 | @Override 18 | protected boolean isMode(AccurevSCM accurevSCM) { 19 | return "wspace".equals(accurevSCM.getWspaceORreftree()); 20 | } 21 | 22 | @Override 23 | public boolean isWorkspace() { 24 | return true; 25 | } 26 | }, 27 | REF_TREE(true) { 28 | @Override 29 | protected AbstractModeDelegate createDelegate(AccurevSCM accurevSCM) { 30 | return new ReftreeDelegate(accurevSCM); 31 | } 32 | 33 | @Override 34 | protected boolean isMode(AccurevSCM accurevSCM) { 35 | return "reftree".equals(accurevSCM.getWspaceORreftree()); 36 | } 37 | 38 | @Override 39 | public boolean isReftree() { 40 | return true; 41 | } 42 | }, 43 | SNAPSHOT(false) { 44 | @Override 45 | protected AbstractModeDelegate createDelegate(AccurevSCM accurevSCM) { 46 | return new SnapshotDelegate(accurevSCM); 47 | } 48 | 49 | @Override 50 | protected boolean isMode(AccurevSCM accurevSCM) { 51 | return !WORKSPACE.isMode(accurevSCM) 52 | && !REF_TREE.isMode(accurevSCM) 53 | && accurevSCM.isUseSnapshot(); 54 | } 55 | 56 | public boolean isNoWorkspaceOrRefTree() { 57 | return true; 58 | } 59 | }, 60 | STREAM(false) { 61 | @Override 62 | protected AbstractModeDelegate createDelegate(AccurevSCM accurevSCM) { 63 | return new StreamDelegate(accurevSCM); 64 | } 65 | 66 | @Override 67 | protected boolean isMode(AccurevSCM accurevSCM) { 68 | return !WORKSPACE.isMode(accurevSCM) 69 | && !REF_TREE.isMode(accurevSCM) 70 | && !accurevSCM.isUseSnapshot(); 71 | } 72 | 73 | @Override 74 | public boolean isNoWorkspaceOrRefTree() { 75 | return true; 76 | } 77 | }; 78 | 79 | private final boolean requiresWorkspace; 80 | 81 | AccurevMode(boolean requiresWorkspace) { 82 | this.requiresWorkspace = requiresWorkspace; 83 | } 84 | 85 | public static AbstractModeDelegate findDelegate(AccurevSCM accurevSCM) { 86 | AccurevMode accurevMode = findMode(accurevSCM); 87 | return accurevMode.createDelegate(accurevSCM); 88 | } 89 | 90 | public static AccurevMode findMode(AccurevSCM accurevSCM) { 91 | AccurevMode retVal = null; 92 | for (AccurevMode accurevMode : values()) { 93 | if (accurevMode.isMode(accurevSCM)) { 94 | retVal = accurevMode; 95 | break; 96 | } 97 | } 98 | return retVal; 99 | } 100 | 101 | public boolean isRequiresWorkspace() { 102 | return requiresWorkspace; 103 | } 104 | 105 | public boolean isWorkspace() { 106 | return false; 107 | } 108 | 109 | public boolean isReftree() { 110 | return false; 111 | } 112 | 113 | public boolean isNoWorkspaceOrRefTree() { 114 | return false; 115 | } 116 | 117 | protected abstract boolean isMode(AccurevSCM accurevSCM); 118 | 119 | protected abstract AbstractModeDelegate createDelegate(AccurevSCM accurevSCM); 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/parsers/xml/ParseHistory.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.parsers.xml; 2 | 3 | import static jenkins.plugins.accurev.util.AccurevUtils.convertAccurevTimestamp; 4 | 5 | import hudson.plugins.accurev.AccurevLauncher.ICmdOutputXmlParser; 6 | import hudson.plugins.accurev.AccurevLauncher.UnhandledAccurevCommandOutput; 7 | import hudson.plugins.accurev.AccurevTransaction; 8 | import java.io.IOException; 9 | import java.util.List; 10 | import jenkins.plugins.accurev.util.AccurevUtils; 11 | import org.xmlpull.v1.XmlPullParser; 12 | import org.xmlpull.v1.XmlPullParserException; 13 | 14 | public final class ParseHistory implements ICmdOutputXmlParser> { 15 | 16 | public Boolean parse(XmlPullParser parser, List context) 17 | throws UnhandledAccurevCommandOutput, IOException, XmlPullParserException { 18 | AccurevTransaction resultTransaction = null; 19 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 20 | if (parser.getEventType() == XmlPullParser.START_TAG) { 21 | if ("transaction".equalsIgnoreCase(parser.getName())) { 22 | resultTransaction = new AccurevTransaction(); 23 | // parse transaction-values 24 | resultTransaction.setId((parser.getAttributeValue("", "id"))); 25 | resultTransaction.setAction(parser.getAttributeValue("", "type")); 26 | resultTransaction.setDate(convertAccurevTimestamp(parser.getAttributeValue("", "time"))); 27 | resultTransaction.setUser(parser.getAttributeValue("", "user")); 28 | } else if ("comment".equalsIgnoreCase(parser.getName()) && resultTransaction != null) { 29 | // parse comments 30 | resultTransaction.setMsg(parser.nextText()); 31 | } else if ("version".equalsIgnoreCase(parser.getName()) && resultTransaction != null) { 32 | // parse path & convert it to standard format 33 | String path = parser.getAttributeValue("", "path"); 34 | if (path != null) { 35 | path = AccurevUtils.cleanAccurevPath(path); 36 | } 37 | resultTransaction.addAffectedPath(path); 38 | } 39 | } 40 | } 41 | context.add(resultTransaction); 42 | return resultTransaction != null; 43 | } 44 | 45 | public Boolean parseAll(XmlPullParser parser, List context) 46 | throws IOException, XmlPullParserException { 47 | AccurevTransaction resultTransaction = null; 48 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 49 | if (parser.getEventType() == XmlPullParser.START_TAG) { 50 | if ("transaction".equalsIgnoreCase(parser.getName())) { 51 | resultTransaction = new AccurevTransaction(); 52 | // parse transaction-values 53 | resultTransaction.setId(parser.getAttributeValue("", "id")); 54 | resultTransaction.setAction(parser.getAttributeValue("", "type")); 55 | resultTransaction.setDate( 56 | AccurevUtils.convertAccurevTimestamp(parser.getAttributeValue("", "time"))); 57 | resultTransaction.setUser(parser.getAttributeValue("", "user")); 58 | } else if ("comment".equalsIgnoreCase(parser.getName()) && resultTransaction != null) { 59 | // parse comments 60 | resultTransaction.setMsg(parser.nextText()); 61 | } else if ("version".equalsIgnoreCase(parser.getName()) && resultTransaction != null) { 62 | // parse path & convert it to standard format 63 | String path = parser.getAttributeValue("", "path"); 64 | if (path != null) path = AccurevUtils.cleanAccurevPath(path); 65 | resultTransaction.addAffectedPath(path); 66 | } 67 | } else if (parser.getEventType() == XmlPullParser.END_TAG) { 68 | if ("transaction".equalsIgnoreCase(parser.getName()) && resultTransaction != null) { 69 | // a transaction parsed 70 | context.add(resultTransaction); 71 | resultTransaction = null; 72 | } 73 | } 74 | } 75 | return Boolean.valueOf((context != null)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.jenkins-ci.plugins 6 | plugin 7 | 4.75 8 | 9 | 10 | 11 | accurev 12 | hpi 13 | ${revision}${changelist} 14 | Jenkins AccuRev plugin 15 | This plugin allows you to use AccuRev as a SCM. 16 | https://github.com/jenkinsci/accurev-plugin 17 | 18 | 0.7.25 19 | -SNAPSHOT 20 | 2.387.3 21 | Max 22 | Low 23 | 24 | 25 | 26 | 27 | casz 28 | Joseph Petersen 29 | 30 | 31 | 32 | 33 | 34 | repo.jenkins-ci.org 35 | https://repo.jenkins-ci.org/public/ 36 | 37 | 38 | 39 | 40 | 41 | 42 | io.jenkins.tools.bom 43 | bom-2.387.x 44 | 2543.vfb_1a_5fb_9496d 45 | import 46 | pom 47 | 48 | 49 | 50 | 51 | 52 | 53 | repo.jenkins-ci.org 54 | https://repo.jenkins-ci.org/public/ 55 | 56 | 57 | 58 | 59 | io.jenkins.plugins 60 | commons-lang3-api 61 | 62 | 63 | org.jenkins-ci.plugins 64 | credentials 65 | 66 | 67 | junit 68 | junit 69 | test 70 | 71 | 72 | org.mockito 73 | mockito-core 74 | test 75 | 76 | 77 | io.jenkins 78 | configuration-as-code 79 | test 80 | 81 | 82 | 83 | org.apache.commons 84 | commons-lang3 85 | 86 | 87 | 88 | 89 | 90 | 91 | scm:git:https://github.com/jenkinsci/accurev-plugin.git 92 | scm:git:git@github.com:jenkinsci/accurev-plugin.git 93 | https://github.com/jenkinsci/accurev-plugin 94 | ${scmTag} 95 | 96 | 97 | 98 | 99 | 100 | com.coveo 101 | fmt-maven-plugin 102 | 2.5.1 103 | 104 | 105 | 106 | format 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | The MIT license 117 | https://www.opensource.org/licenses/mit-license.php 118 | repo 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/delegates/StreamDelegate.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.delegates; 2 | 3 | import hudson.model.Job; 4 | import hudson.model.Run; 5 | import hudson.plugins.accurev.AccurevLauncher; 6 | import hudson.plugins.accurev.AccurevSCM; 7 | import hudson.plugins.accurev.AccurevStream; 8 | import hudson.plugins.accurev.CheckForChanges; 9 | import hudson.plugins.accurev.cmd.ShowStreams; 10 | import hudson.plugins.accurev.parsers.output.ParseAccuRevVersion; 11 | import hudson.scm.PollingResult; 12 | import hudson.util.ArgumentListBuilder; 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.util.Date; 16 | import java.util.Map; 17 | import java.util.logging.Logger; 18 | 19 | /** @author raymond */ 20 | public class StreamDelegate extends AbstractModeDelegate { 21 | 22 | private static final Logger logger = Logger.getLogger(StreamDelegate.class.getName()); 23 | 24 | public StreamDelegate(AccurevSCM scm) { 25 | super(scm); 26 | } 27 | 28 | @Override 29 | protected boolean checkout(Run build, File changeLogFile) 30 | throws IOException, InterruptedException { 31 | return true; 32 | } 33 | 34 | @Override 35 | protected String getPopulateFromMessage() { 36 | return "from stream"; 37 | } 38 | 39 | @Override 40 | protected String getPopulateStream() { 41 | return localStream; 42 | } 43 | 44 | @Override 45 | protected boolean isSteamColorEnabled() { 46 | return true; 47 | } 48 | 49 | @Override 50 | protected String getStreamColorStream() { 51 | return localStream; 52 | } 53 | 54 | @Override 55 | protected String getStreamColor() { 56 | return "#FFFFFF"; 57 | } 58 | 59 | @Override 60 | protected PollingResult checkForChanges(Job project) 61 | throws IOException, InterruptedException { 62 | final Run lastBuild = project.getLastBuild(); 63 | if (lastBuild == null) { 64 | listener.getLogger().println("Project has never been built"); 65 | return PollingResult.BUILD_NOW; 66 | } 67 | final Date buildDate = lastBuild.getTimestamp().getTime(); 68 | try { 69 | localStream = scm.getPollingStream(project, listener); 70 | } catch (IllegalArgumentException ex) { 71 | listener.getLogger().println(ex.getMessage()); 72 | return PollingResult.NO_CHANGES; 73 | } 74 | final Map streams = 75 | ShowStreams.getStreams( 76 | scm, localStream, server, accurevEnv, jenkinsWorkspace, listener, launcher); 77 | if (streams == null) { 78 | listener 79 | .getLogger() 80 | .println("Could not retrieve any Streams from AccuRev, please check credentials"); 81 | return PollingResult.NO_CHANGES; 82 | } 83 | AccurevStream stream = streams.get(localStream); 84 | 85 | if (stream == null) { 86 | listener 87 | .getLogger() 88 | .println("Tried to find '" + localStream + "' Stream, could not found it."); 89 | return PollingResult.NO_CHANGES; 90 | } 91 | // command to get version of accurev 92 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 93 | String ACCUREV_VERSION = 94 | AccurevLauncher.runCommand( 95 | "Accurev version command", 96 | scm.getAccurevTool(), 97 | launcher, 98 | cmd, 99 | null, 100 | accurevEnv, 101 | jenkinsWorkspace, 102 | listener, 103 | logger, 104 | new ParseAccuRevVersion(), 105 | null); 106 | listener 107 | .getLogger() 108 | .println( // 109 | "Accurev Client Version: " + ACCUREV_VERSION); 110 | int version = Integer.parseInt(ACCUREV_VERSION.substring(0, ACCUREV_VERSION.indexOf("."))); 111 | if (version < 7) { 112 | listener 113 | .getLogger() 114 | .println( // 115 | "Upgrade AccuRev Client for improved performance"); 116 | } 117 | // There may be changes in a parent stream that we need to factor in. 118 | do { 119 | if (CheckForChanges.checkStreamForChanges( 120 | server, 121 | accurevEnv, 122 | jenkinsWorkspace, 123 | listener, 124 | launcher, 125 | stream, 126 | buildDate, 127 | logger, 128 | scm, 129 | version)) { 130 | return PollingResult.BUILD_NOW; 131 | } 132 | stream = stream.getParent(); 133 | } while (stream != null 134 | && stream.isReceivingChangesFromParent() 135 | && !scm.isIgnoreStreamParent()); 136 | return PollingResult.NO_CHANGES; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/accurev/AccurevSCM/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |
6 | AccuRev Configurations 7 | 8 | 10 | 11 | 12 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | 63 | 64 | 65 | 66 | 69 | 70 | 74 | 75 | 76 | 77 |
78 |
79 |
80 |
81 | -------------------------------------------------------------------------------- /src/test/java/hudson/plugins/accurev/AccurevSCMTest.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import static jenkins.plugins.accurev.AccurevToolTest.createTool; 4 | import static org.hamcrest.core.Is.is; 5 | import static org.junit.Assert.assertThat; 6 | import static org.mockito.ArgumentMatchers.any; 7 | import static org.mockito.ArgumentMatchers.anyMap; 8 | import static org.mockito.Mockito.doCallRealMethod; 9 | import static org.mockito.Mockito.mock; 10 | import static org.mockito.Mockito.when; 11 | 12 | import com.cloudbees.plugins.credentials.CredentialsProvider; 13 | import com.cloudbees.plugins.credentials.CredentialsStore; 14 | import hudson.model.FreeStyleProject; 15 | import hudson.model.Run; 16 | import hudson.plugins.accurev.AccurevSCM.AccurevSCMDescriptor; 17 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import jenkins.plugins.accurev.AccurevTool; 24 | import org.junit.Before; 25 | import org.junit.Rule; 26 | import org.junit.Test; 27 | import org.jvnet.hudson.test.JenkinsRule; 28 | 29 | public class AccurevSCMTest { 30 | 31 | @Rule public JenkinsRule rule = new JenkinsRule(); 32 | 33 | private AccurevSCM scm; 34 | private AccurevServer oldServer; 35 | private FreeStyleProject accurevTest; 36 | private AccurevSCMDescriptor descriptor; 37 | private CredentialsStore store; 38 | 39 | @SuppressWarnings("deprecation") 40 | @Before 41 | public void setUp() throws Exception { 42 | store = CredentialsProvider.lookupStores(rule.jenkins).iterator().next(); 43 | oldServer = new AccurevServer(null, "accurevOldServer", "accurevbox.example.org"); 44 | oldServer.setUsername("bob"); 45 | oldServer.setPassword("OBF:1rwf1x1b1rwf"); 46 | descriptor = rule.get(AccurevSCMDescriptor.class); 47 | List servers = new ArrayList<>(); 48 | servers.add(oldServer); 49 | descriptor.setServers(servers); 50 | scm = new AccurevSCM("accurevOldServer", "test", "test"); 51 | accurevTest = rule.createFreeStyleProject("accurevTest"); 52 | accurevTest.setScm(scm); 53 | } 54 | 55 | @SuppressWarnings("deprecation") 56 | @Test 57 | public void shouldSetEnvironmentVariablesWithAccurevSCM() throws IOException { 58 | AccurevSCM scm = mockSCMForBuildEnvVars(); 59 | 60 | when(scm.getServer()).thenReturn(oldServer); 61 | 62 | when(scm.getStream()).thenReturn("testStream"); 63 | 64 | Run run = mock(Run.class); 65 | Map environment = new HashMap<>(); 66 | scm.buildEnvironment(run, environment); 67 | 68 | assertThat(environment.get("ACCUREV_SERVER_HOSTNAME"), is("accurevbox.example.org")); 69 | assertThat(environment.get("ACCUREV_SERVER_PORT"), is("5050")); 70 | assertThat(environment.get("ACCUREV_STREAM"), is("testStream")); 71 | } 72 | 73 | private AccurevSCM mockSCMForBuildEnvVars() { 74 | AccurevSCM scm = mock(AccurevSCM.class); 75 | doCallRealMethod().when(scm).buildEnvironment(any(Run.class), anyMap()); 76 | return scm; 77 | } 78 | 79 | @Test 80 | public void testConfigRoundtrip() throws Exception { 81 | 82 | // setup global config - add another server to test that part 83 | List serverList = descriptor.getServers(); 84 | serverList.add(new AccurevServer(null, "otherServerName", "otherServerHost")); 85 | descriptor.setServers(serverList); 86 | 87 | accurevTest.setScm(scm); 88 | rule.configRoundtrip(accurevTest); 89 | rule.assertEqualDataBoundBeans(scm, accurevTest.getScm()); 90 | } 91 | 92 | @Test 93 | public void testConfigAccurevToolRoundtrip() throws Exception { 94 | AccurevTool.DescriptorImpl tools = 95 | rule.jenkins.getDescriptorByType(AccurevTool.DescriptorImpl.class); 96 | AccurevTool test1 = createTool("test1"); 97 | AccurevTool test2 = createTool("test2"); 98 | tools.setInstallations(test1, test2); 99 | 100 | scm.setAccurevTool("test2"); 101 | accurevTest.setScm(scm); 102 | rule.configRoundtrip(accurevTest); 103 | rule.assertEqualDataBoundBeans(scm, accurevTest.getScm()); 104 | } 105 | 106 | @Test 107 | public void testConfigWspaceRoundtrip() throws Exception { 108 | 109 | scm.setWspaceORreftree("wspace"); 110 | scm.setWorkspace("testWorkspace1"); 111 | 112 | accurevTest.setScm(scm); 113 | rule.configRoundtrip(accurevTest); 114 | rule.assertEqualDataBoundBeans(scm, accurevTest.getScm()); 115 | } 116 | 117 | @Test 118 | public void testConfigReftreeRoundtrip() throws Exception { 119 | 120 | scm.setWspaceORreftree("reftree"); 121 | scm.setReftree("testRefTree1"); 122 | 123 | accurevTest.setScm(scm); 124 | rule.configRoundtrip(accurevTest); 125 | rule.assertEqualDataBoundBeans(scm, accurevTest.getScm()); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/Update.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevLauncher; 8 | import hudson.plugins.accurev.AccurevSCM; 9 | import hudson.plugins.accurev.XmlParserFactory; 10 | import hudson.plugins.accurev.parsers.output.ParseOutputToFile; 11 | import hudson.plugins.accurev.parsers.xml.ParseUpdate; 12 | import hudson.util.ArgumentListBuilder; 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.Collection; 18 | import java.util.List; 19 | import java.util.logging.Logger; 20 | import org.xmlpull.v1.XmlPullParserFactory; 21 | 22 | /** @author raymond */ 23 | public class Update extends Command { 24 | 25 | private static final Logger logger = Logger.getLogger(Update.class.getName()); 26 | private static final String FFPSCM_DELIM = ","; 27 | 28 | private static ArgumentListBuilder createCommand( 29 | final AccurevSCM.AccurevServer server, // 30 | final boolean preview, 31 | final String reftree, 32 | final boolean minus9) { 33 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 34 | cmd.add("update"); 35 | addServer(cmd, server); 36 | cmd.add("-fx"); 37 | if (reftree != null) { 38 | cmd.add("-r"); 39 | cmd.add(reftree); 40 | } 41 | if (minus9) { 42 | cmd.add("-9"); 43 | } 44 | 45 | if (preview) { 46 | cmd.add("-i"); 47 | } 48 | return cmd; 49 | } 50 | 51 | public static Boolean hasChanges( 52 | AccurevSCM scm, // 53 | AccurevSCM.AccurevServer server, // 54 | EnvVars accurevEnv, // 55 | FilePath workspace, // 56 | TaskListener listener, // 57 | Launcher launcher, // 58 | String reftree) 59 | throws IOException { 60 | 61 | List files = new ArrayList<>(); 62 | final ArgumentListBuilder cmd = createCommand(server, true, reftree, false); 63 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 64 | if (parser == null) { 65 | throw new IOException("No XML Parser"); 66 | } 67 | Boolean transactionFound = 68 | AccurevLauncher.runCommand( 69 | "Update command", 70 | scm.getAccurevTool(), 71 | launcher, 72 | cmd, 73 | scm.getOptionalLock(workspace), 74 | accurevEnv, 75 | workspace, 76 | listener, 77 | logger, 78 | parser, 79 | new ParseUpdate(), 80 | files); 81 | if (transactionFound != null && transactionFound) { 82 | String filterForPollSCM = scm.getFilterForPollSCM(); 83 | String subPath = scm.getSubPath(); 84 | Collection filterPaths = null; 85 | String filterList = null; 86 | if (filterForPollSCM != null && !(filterForPollSCM.isEmpty())) { 87 | filterList = filterForPollSCM; 88 | } else if (subPath != null && !(subPath.isEmpty())) { 89 | filterList = subPath; 90 | } 91 | 92 | if (filterList != null && !filterList.isEmpty()) { 93 | filterList = filterList.replace(", ", ","); 94 | filterPaths = new ArrayList<>(Arrays.asList(filterList.split(FFPSCM_DELIM))); 95 | } 96 | 97 | if (filterPaths != null) { 98 | transactionFound = false; 99 | for (String Filter_For_Poll_SCM1 : filterPaths) { 100 | for (String file : files) { 101 | if (file.contains(Filter_For_Poll_SCM1)) { 102 | transactionFound = true; 103 | break; 104 | } 105 | } 106 | if (transactionFound) { 107 | break; 108 | } 109 | } 110 | } 111 | } else { 112 | return false; 113 | } 114 | return transactionFound; 115 | } 116 | 117 | public static boolean performUpdate( 118 | final AccurevSCM scm, // 119 | final AccurevSCM.AccurevServer server, // 120 | final EnvVars accurevEnv, // 121 | final FilePath workspace, // 122 | final TaskListener listener, // 123 | final Launcher launcher, // 124 | final String reftree, 125 | File changelogFile) 126 | throws IOException { 127 | final ArgumentListBuilder cmd = createCommand(server, false, reftree, false); 128 | final Boolean result = 129 | AccurevLauncher.runCommand( 130 | "Update command", 131 | scm.getAccurevTool(), 132 | launcher, 133 | cmd, 134 | scm.getOptionalLock(workspace), 135 | accurevEnv, 136 | workspace, 137 | listener, 138 | logger, 139 | new ParseOutputToFile(), 140 | changelogFile); 141 | if (result == null) { 142 | return false; 143 | } 144 | return result; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/jenkins/plugins/accurev/AccurevTool.java: -------------------------------------------------------------------------------- 1 | package jenkins.plugins.accurev; 2 | 3 | import static hudson.init.InitMilestone.EXTENSIONS_AUGMENTED; 4 | 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | import hudson.EnvVars; 7 | import hudson.Extension; 8 | import hudson.init.Initializer; 9 | import hudson.model.EnvironmentSpecific; 10 | import hudson.model.Node; 11 | import hudson.model.TaskListener; 12 | import hudson.slaves.NodeSpecific; 13 | import hudson.tools.ToolDescriptor; 14 | import hudson.tools.ToolInstallation; 15 | import hudson.tools.ToolProperty; 16 | import hudson.util.FormValidation; 17 | import java.io.File; 18 | import java.io.IOException; 19 | import java.util.Collections; 20 | import java.util.List; 21 | import java.util.logging.Logger; 22 | import jenkins.model.Jenkins; 23 | import net.sf.json.JSONObject; 24 | import org.jenkinsci.Symbol; 25 | import org.kohsuke.stapler.DataBoundConstructor; 26 | import org.kohsuke.stapler.QueryParameter; 27 | import org.kohsuke.stapler.StaplerRequest; 28 | 29 | /** Initialized by josep on 21-01-2017. */ 30 | public class AccurevTool extends ToolInstallation 31 | implements NodeSpecific, EnvironmentSpecific { 32 | 33 | private static final String DEFAULT = "Default"; 34 | private static final long serialVersionUID = 1; 35 | private static final Logger LOGGER = Logger.getLogger(AccurevTool.class.getName()); 36 | 37 | /** 38 | * Constructor for AccurevTool 39 | * 40 | * @param name Tool name 41 | * @param home Tool location (usually "accurev") 42 | * @param properties {@link java.util.List} of properties for this tool 43 | */ 44 | @DataBoundConstructor 45 | public AccurevTool(String name, String home, List> properties) { 46 | super(name, home, properties); 47 | } 48 | 49 | private static AccurevTool[] getInstallations(DescriptorImpl descriptor) { 50 | 51 | if (descriptor == null) { 52 | return new AccurevTool[0]; 53 | } else { 54 | return descriptor.getInstallations(); 55 | } 56 | } 57 | 58 | /** 59 | * Returns the default installation. 60 | * 61 | * @return default installation 62 | */ 63 | public static AccurevTool getDefaultInstallation() { 64 | Jenkins jenkinsInstance = Jenkins.get(); 65 | DescriptorImpl AccurevTools = 66 | jenkinsInstance.getDescriptorByType(AccurevTool.DescriptorImpl.class); 67 | AccurevTool tool = AccurevTools.getInstallation(AccurevTool.DEFAULT); 68 | if (tool != null) { 69 | return tool; 70 | } else { 71 | AccurevTool[] installations = AccurevTools.getInstallations(); 72 | if (installations.length > 0) { 73 | return installations[0]; 74 | } else { 75 | onLoaded(); 76 | return AccurevTools.getInstallations()[0]; 77 | } 78 | } 79 | } 80 | 81 | @Initializer(after = EXTENSIONS_AUGMENTED) 82 | public static void onLoaded() { 83 | // Creates default tool installation if needed. Uses "accurev" or migrates data from previous 84 | // versions 85 | 86 | Jenkins jenkinsInstance = Jenkins.get(); 87 | 88 | DescriptorImpl descriptor = (DescriptorImpl) jenkinsInstance.getDescriptor(AccurevTool.class); 89 | AccurevTool[] installations = getInstallations(descriptor); 90 | 91 | if (installations != null && installations.length > 0) { 92 | // No need to initialize if there's already something 93 | return; 94 | } 95 | 96 | String defaultAccurevExe = "accurev"; 97 | AccurevTool tool = new AccurevTool(DEFAULT, defaultAccurevExe, Collections.emptyList()); 98 | if (descriptor != null) { 99 | descriptor.setInstallations(tool); 100 | descriptor.save(); 101 | } 102 | } 103 | 104 | public AccurevTool forNode(@NonNull Node node, TaskListener log) 105 | throws IOException, InterruptedException { 106 | return new AccurevTool(getName(), translateFor(node, log), Collections.emptyList()); 107 | } 108 | 109 | public AccurevTool forEnvironment(EnvVars environment) { 110 | return new AccurevTool(getName(), environment.expand(getHome()), Collections.emptyList()); 111 | } 112 | 113 | @Override 114 | public DescriptorImpl getDescriptor() { 115 | Jenkins jenkinsInstance = Jenkins.get(); 116 | return (DescriptorImpl) jenkinsInstance.getDescriptorOrDie(getClass()); 117 | } 118 | 119 | @Extension 120 | @Symbol("accurevTool") 121 | public static final class DescriptorImpl extends ToolDescriptor { 122 | 123 | public DescriptorImpl() { 124 | super(); 125 | load(); 126 | } 127 | 128 | @Override 129 | @NonNull 130 | public String getDisplayName() { 131 | return "AccuRev"; 132 | } 133 | 134 | @SuppressWarnings("SuspiciousToArrayCall") 135 | @Override 136 | public boolean configure(StaplerRequest req, JSONObject json) throws FormException { 137 | setInstallations(req.bindJSONToList(clazz, json.get("tool")).toArray(new AccurevTool[0])); 138 | save(); 139 | return true; 140 | } 141 | 142 | public FormValidation doCheckHome(@QueryParameter File value) { 143 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); 144 | String path = value.getPath(); 145 | 146 | return FormValidation.validateExecutable(path); 147 | } 148 | 149 | public AccurevTool getInstallation(String name) { 150 | for (AccurevTool i : getInstallations()) { 151 | if (i.getName().equals(name)) { 152 | return i; 153 | } 154 | } 155 | return null; 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccurevStream.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import java.io.IOException; 4 | import java.io.ObjectInputStream; 5 | import java.io.Serializable; 6 | import java.util.Date; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by IntelliJ IDEA. 12 | * 13 | * @author connollys 14 | * @since 03-Dec-2007 10:58:32 15 | */ 16 | public class AccurevStream implements Serializable { 17 | 18 | private static final long serialVersionUID = 8004696899509026973L; 19 | private final String name; 20 | private final Long number; 21 | private final String depot; 22 | private final String basisName; 23 | private final Long basisNumber; 24 | private final boolean dynamic; 25 | private final StreamType type; 26 | private final Date time; 27 | private final Date startTime; 28 | private transient AccurevStream parent; 29 | private transient Set children = new HashSet<>(); 30 | 31 | public AccurevStream( 32 | String name, 33 | Long number, 34 | String depot, 35 | String basisName, 36 | Long basisNumber, 37 | boolean dynamic, 38 | StreamType type, 39 | Date time, 40 | Date startTime) { 41 | this.name = name; 42 | this.number = number; 43 | this.depot = depot; 44 | this.basisName = basisName; 45 | this.basisNumber = basisNumber; 46 | this.dynamic = dynamic; 47 | this.type = type; 48 | this.time = time == null ? null : (Date) time.clone(); 49 | this.startTime = startTime == null ? null : (Date) startTime.clone(); 50 | } 51 | 52 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 53 | in.defaultReadObject(); 54 | 55 | children = new HashSet<>(); 56 | } 57 | 58 | /** 59 | * Getter for property 'name'. 60 | * 61 | * @return Value for property 'name'. 62 | */ 63 | public String getName() { 64 | return name; 65 | } 66 | 67 | /** 68 | * Getter for property 'number'. 69 | * 70 | * @return Value for property 'number'. 71 | */ 72 | public Long getNumber() { 73 | return number; 74 | } 75 | 76 | /** 77 | * Getter for property 'depot'. 78 | * 79 | * @return Value for property 'depot'. 80 | */ 81 | public String getDepot() { 82 | return depot; 83 | } 84 | 85 | /** 86 | * Getter for property 'basisName'. 87 | * 88 | * @return Value for property 'basisName'. 89 | */ 90 | public String getBasisName() { 91 | return basisName; 92 | } 93 | 94 | /** 95 | * Getter for property 'basisNumber'. 96 | * 97 | * @return Value for property 'basisNumber'. 98 | */ 99 | public Long getBasisNumber() { 100 | return basisNumber; 101 | } 102 | 103 | /** 104 | * Getter for property 'dynamic'. 105 | * 106 | * @return Value for property 'dynamic'. 107 | */ 108 | public boolean isDynamic() { 109 | return dynamic; 110 | } 111 | 112 | /** 113 | * Getter for property 'type'. 114 | * 115 | * @return Value for property 'type'. 116 | */ 117 | public StreamType getType() { 118 | return type; 119 | } 120 | 121 | /** 122 | * Getter for property 'time'. 123 | * 124 | * @return Value for property 'time'. 125 | */ 126 | public Date getTime() { 127 | return (Date) time.clone(); 128 | } 129 | 130 | /** 131 | * Getter for property 'startTime'. 132 | * 133 | * @return Value for property 'startTime'. 134 | */ 135 | public Date getStartTime() { 136 | return (Date) startTime.clone(); 137 | } 138 | 139 | /** 140 | * Getter for property 'parent'. 141 | * 142 | * @return Value for property 'parent'. 143 | */ 144 | public AccurevStream getParent() { 145 | return parent; 146 | } 147 | 148 | /** 149 | * Setter for property 'parent'. 150 | * 151 | * @param parent Value to set for property 'parent'. 152 | */ 153 | public void setParent(AccurevStream parent) { 154 | if (this.parent != parent) { 155 | if (this.parent != null) { 156 | this.parent.getChildren().remove(this); 157 | } 158 | this.parent = parent; 159 | if (this.parent != null) { 160 | this.parent.getChildren().add(this); 161 | } 162 | } 163 | } 164 | 165 | /** 166 | * Getter for property 'children'. 167 | * 168 | * @return Value for property 'children'. 169 | */ 170 | public Set getChildren() { 171 | return children; 172 | } 173 | 174 | /** 175 | * Returns true if and only if the stream propagates changes from it's parent. 176 | * 177 | * @return true if and only if the stream propagates changes from it's parent. 178 | */ 179 | public boolean isReceivingChangesFromParent() { 180 | switch (type) { 181 | case WORKSPACE: 182 | return true; 183 | case PASSTHROUGH: 184 | return true; 185 | case SNAPSHOT: 186 | return false; 187 | case GATED: 188 | return true; 189 | case STAGING: 190 | return true; 191 | case NORMAL: 192 | // TODO need to add an optimization, namely check to see if a time is present, has it 193 | // changed 194 | // since last we checked. 195 | return time == null; 196 | default: 197 | return false; 198 | } 199 | } 200 | 201 | public enum StreamType { 202 | NORMAL("normal"), 203 | SNAPSHOT("snapshot"), 204 | WORKSPACE("workspace"), 205 | PASSTHROUGH("passthrough"), 206 | GATED("gated"), 207 | STAGING("staging"), 208 | ; 209 | private final String type; 210 | 211 | StreamType(String type) { 212 | this.type = type; 213 | } 214 | 215 | public static StreamType parseStreamType(String streamType) { 216 | for (StreamType value : values()) { 217 | if (value.type.equalsIgnoreCase(streamType)) { 218 | return value; 219 | } 220 | } 221 | throw new NumberFormatException("Unknown stream type: " + streamType); 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/ShowStreams.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import edu.umd.cs.findbugs.annotations.CheckForNull; 4 | import hudson.EnvVars; 5 | import hudson.FilePath; 6 | import hudson.Launcher; 7 | import hudson.model.TaskListener; 8 | import hudson.plugins.accurev.AccurevLauncher; 9 | import hudson.plugins.accurev.AccurevSCM; 10 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 11 | import hudson.plugins.accurev.AccurevStream; 12 | import hudson.plugins.accurev.XmlParserFactory; 13 | import hudson.plugins.accurev.parsers.xml.ParseShowStreams; 14 | import hudson.util.ArgumentListBuilder; 15 | import java.io.IOException; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.concurrent.locks.ReentrantLock; 19 | import java.util.logging.Logger; 20 | import org.xmlpull.v1.XmlPullParserFactory; 21 | 22 | public class ShowStreams extends Command { 23 | 24 | private static final Logger LOGGER = Logger.getLogger(ShowStreams.class.getName()); 25 | 26 | @CheckForNull 27 | public static Map getStreams( // 28 | final AccurevSCM scm, // 29 | final String nameOfStreamRequired, // 30 | final AccurevServer server, // 31 | final EnvVars accurevEnv, // 32 | final FilePath workspace, // 33 | final TaskListener listener, // 34 | final Launcher launcher) 35 | throws IOException { 36 | final Map streams; 37 | if (scm.isIgnoreStreamParent()) { 38 | streams = getOneStream(nameOfStreamRequired, accurevEnv, workspace, listener, launcher, scm); 39 | } else if (server.isUseRestrictedShowStreams()) { 40 | streams = 41 | getAllAncestorStreams( 42 | nameOfStreamRequired, scm, accurevEnv, workspace, listener, launcher); 43 | } else { 44 | streams = 45 | getAllStreams( 46 | scm, 47 | server, 48 | scm.getDepot(), 49 | scm.getOptionalLock(workspace), 50 | accurevEnv, 51 | workspace, 52 | listener, 53 | launcher); 54 | } 55 | return streams; 56 | } 57 | 58 | public static Map getAllStreams( // 59 | AccurevSCM scm, 60 | final AccurevServer server, // 61 | final String depot, // 62 | final ReentrantLock lock, // 63 | final EnvVars accurevEnv, // 64 | final FilePath workspace, // 65 | final TaskListener listener, // 66 | final Launcher launcher) 67 | throws IOException { 68 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 69 | cmd.add("show"); 70 | addServer(cmd, server); 71 | cmd.add("-fx"); 72 | cmd.add("-p"); 73 | cmd.add(depot); 74 | cmd.add("streams"); 75 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 76 | if (parser == null) { 77 | throw new IOException("No XML Parser"); 78 | } 79 | final Map streams = 80 | AccurevLauncher.runCommand( 81 | "Show streams command", 82 | scm.getAccurevTool(), 83 | launcher, 84 | cmd, 85 | lock, 86 | accurevEnv, 87 | workspace, 88 | listener, 89 | LOGGER, 90 | parser, 91 | new ParseShowStreams(), 92 | depot); 93 | setParents(streams); 94 | return streams; 95 | } 96 | 97 | private static Map getAllAncestorStreams( // 98 | final String nameOfStreamRequired, // 99 | final AccurevSCM scm, 100 | final EnvVars accurevEnv, // 101 | final FilePath workspace, // 102 | final TaskListener listener, // 103 | final Launcher launcher) 104 | throws IOException { 105 | final Map streams = new HashMap<>(); 106 | String streamName = nameOfStreamRequired; 107 | while (streamName != null && !streamName.isEmpty()) { 108 | final Map oneStream = 109 | getOneStream(streamName, accurevEnv, workspace, listener, launcher, scm); 110 | final AccurevStream theStream = oneStream == null ? null : oneStream.get(streamName); 111 | streamName = null; 112 | if (theStream != null) { 113 | if (theStream.getBasisName() != null) { 114 | streamName = theStream.getBasisName(); 115 | } else if (theStream.getBasisNumber() != null) { 116 | streamName = theStream.getBasisNumber().toString(); 117 | } 118 | streams.putAll(oneStream); 119 | } 120 | } 121 | setParents(streams); 122 | return streams; 123 | } 124 | 125 | private static Map getOneStream( // 126 | final String streamName, // 127 | final EnvVars accurevEnv, // 128 | final FilePath workspace, // 129 | final TaskListener listener, // 130 | final Launcher launcher, 131 | AccurevSCM scm) 132 | throws IOException { 133 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 134 | cmd.add("show"); 135 | addServer(cmd, scm.getServer()); 136 | cmd.add("-fx"); 137 | cmd.add("-p"); 138 | cmd.add(scm.getDepot()); 139 | cmd.add("-s"); 140 | cmd.add(streamName); 141 | cmd.add("streams"); 142 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 143 | if (parser == null) { 144 | throw new IOException("No XML Parser"); 145 | } 146 | return AccurevLauncher.runCommand( 147 | "Restricted show streams command", 148 | scm.getAccurevTool(), 149 | launcher, 150 | cmd, 151 | scm.getOptionalLock(workspace), 152 | accurevEnv, 153 | workspace, 154 | listener, 155 | LOGGER, 156 | parser, 157 | new ParseShowStreams(), 158 | scm.getDepot()); 159 | } 160 | 161 | private static void setParents(Map streams) { 162 | // build the tree 163 | if (streams != null && streams.size() > 1) { 164 | streams 165 | .values() 166 | .stream() 167 | .filter(stream -> stream.getBasisName() != null) 168 | .forEach(stream -> stream.setParent(streams.get(stream.getBasisName()))); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/Login.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; 4 | import hudson.EnvVars; 5 | import hudson.FilePath; 6 | import hudson.Launcher; 7 | import hudson.model.TaskListener; 8 | import hudson.plugins.accurev.AccurevLauncher; 9 | import hudson.plugins.accurev.AccurevSCM; 10 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 11 | import hudson.plugins.accurev.parsers.output.ParseInfoToLoginName; 12 | import hudson.util.ArgumentListBuilder; 13 | import hudson.util.Secret; 14 | import java.io.IOException; 15 | import java.util.concurrent.locks.ReentrantLock; 16 | import java.util.logging.Logger; 17 | import jenkins.model.Jenkins; 18 | import org.apache.commons.lang.StringUtils; 19 | 20 | public class Login extends Command { 21 | 22 | private static final Logger logger = Logger.getLogger(Login.class.getName()); 23 | 24 | /** 25 | * @return The currently logged in user "Principal" name, which may be "(not logged in)" if not 26 | * logged in.
27 | * Returns null on failure. 28 | */ 29 | private static String getLoggedInUsername( // 30 | String accurevTool, 31 | final AccurevServer server, // 32 | final EnvVars accurevEnv, // 33 | final FilePath workspace, // 34 | final TaskListener listener, // 35 | final Launcher launcher) 36 | throws IOException { 37 | final String commandDescription = "info command"; 38 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 39 | cmd.add("info"); 40 | addServer(cmd, server); 41 | // returns username 42 | return AccurevLauncher.runCommand( 43 | commandDescription, 44 | accurevTool, 45 | launcher, 46 | cmd, 47 | null, 48 | accurevEnv, 49 | workspace, 50 | listener, 51 | logger, 52 | new ParseInfoToLoginName(), 53 | null); 54 | } 55 | 56 | public static boolean ensureLoggedInToAccurev( 57 | AccurevSCM scm, 58 | AccurevServer server, 59 | EnvVars accurevEnv, 60 | FilePath pathToRunCommandsIn, 61 | TaskListener listener, 62 | Launcher launcher) 63 | throws IOException { 64 | String accurevTool = scm == null ? null : scm.getAccurevTool(); 65 | if (server == null) { 66 | listener.getLogger().println("Authentication failure - Server is empty"); 67 | return false; 68 | } 69 | final String requiredUsername = server.getUsername(); 70 | if (StringUtils.isBlank(requiredUsername)) { 71 | listener.getLogger().println("Authentication failure - Username blank"); 72 | return false; 73 | } 74 | ReentrantLock lock = 75 | (scm == null) ? AccurevSCM.MASTER_LOCK : scm.getMandatoryLock(pathToRunCommandsIn); 76 | lock.lock(); 77 | 78 | try { 79 | final boolean loginRequired; 80 | if (server.isMinimiseLogins()) { 81 | final String currentUsername = 82 | getLoggedInUsername( 83 | accurevTool, server, accurevEnv, pathToRunCommandsIn, listener, launcher); 84 | if (StringUtils.isEmpty(currentUsername)) { 85 | loginRequired = true; 86 | listener.getLogger().println("Not currently authenticated with AccuRev server"); 87 | } else { 88 | loginRequired = !currentUsername.equals(requiredUsername); 89 | listener 90 | .getLogger() 91 | .println( 92 | "Currently authenticated with AccuRev server as '" 93 | + currentUsername 94 | + (loginRequired ? "', login required" : "', not logging in again.")); 95 | } 96 | } else { 97 | loginRequired = true; 98 | } 99 | if (loginRequired) { 100 | return accurevLogin( 101 | accurevTool, server, accurevEnv, pathToRunCommandsIn, listener, launcher); 102 | } 103 | } finally { 104 | lock.unlock(); 105 | } 106 | return true; 107 | } 108 | 109 | private static boolean accurevLogin( 110 | String accurevTool, 111 | final AccurevServer server, // 112 | final EnvVars accurevEnv, // 113 | final FilePath workspace, // 114 | final TaskListener listener, // 115 | final Launcher launcher) 116 | throws IOException { 117 | StandardUsernamePasswordCredentials credentials = server.getCredentials(); 118 | if (credentials == null) { 119 | listener.getLogger().println("Credentials not found"); 120 | return false; 121 | } 122 | if (StringUtils.isBlank(credentials.getUsername())) { 123 | listener.getLogger().println("Credentials username cannot be blank"); 124 | return false; 125 | } 126 | listener.getLogger().println("Authenticating with AccuRev server..."); 127 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 128 | cmd.add("login"); 129 | addServer(cmd, server); 130 | if (server.isUseNonexpiringLogin()) { 131 | cmd.add("-n"); 132 | } 133 | cmd.add(credentials.getUsername()); 134 | if (StringUtils.isEmpty(Secret.toString(credentials.getPassword()))) { 135 | if (launcher.isUnix()) { 136 | cmd.add("", true); 137 | } else { 138 | cmd.addQuoted("", true); 139 | } 140 | } else { 141 | cmd.add(server.getPassword(), true); 142 | } 143 | final boolean success = 144 | AccurevLauncher.runCommand( 145 | "login", accurevTool, launcher, cmd, null, accurevEnv, workspace, listener, logger); 146 | if (success) { 147 | listener.getLogger().println("Authentication completed successfully."); 148 | return true; 149 | } else { 150 | return false; 151 | } 152 | } 153 | 154 | /** 155 | * @param server Accurev Server 156 | * @return boolean whether am successful 157 | * @throws IOException failing IO This method is called from doFillStreams and doFillDepots while 158 | * configuring the job 159 | */ 160 | public static boolean accurevLoginFromGlobalConfig( // 161 | final AccurevServer server) throws IOException { 162 | 163 | Jenkins jenkins = Jenkins.get(); 164 | TaskListener listener = TaskListener.NULL; 165 | Launcher launcher = jenkins.createLauncher(listener); 166 | EnvVars accurevEnv = new EnvVars(); 167 | 168 | return ensureLoggedInToAccurev( 169 | null, server, accurevEnv, jenkins.getRootPath(), listener, launcher); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/AccurevTransaction.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import hudson.model.User; 5 | import hudson.scm.ChangeLogSet; 6 | import hudson.scm.EditType; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.Date; 10 | import java.util.List; 11 | import org.apache.commons.lang.StringUtils; 12 | import org.kohsuke.stapler.export.Exported; 13 | import org.kohsuke.stapler.export.ExportedBean; 14 | 15 | /** One commit. */ 16 | @ExportedBean(defaultVisibility = 999) 17 | public final class AccurevTransaction extends ChangeLogSet.Entry { 18 | 19 | private static final String FIELD_SEPARATOR = ", "; 20 | private static final String EQ = "="; 21 | private final List affectedPaths = new ArrayList<>(); 22 | private final List affectedRawPaths = new ArrayList<>(); 23 | private final List fileRevisions = new ArrayList<>(); 24 | // private String revision; 25 | private User author; 26 | private Date date; 27 | private String msg; 28 | private String action; 29 | private String id; 30 | private String issueNum; 31 | private String webuiURLforTrans; 32 | private String webuiURLforIssue; 33 | 34 | @Exported 35 | public String getIssueNum() { 36 | return issueNum; 37 | } 38 | 39 | public void setIssueNum(String issueNum) { 40 | this.issueNum = issueNum; 41 | } 42 | 43 | @Exported 44 | public String getWebuiURLforTrans() { 45 | return webuiURLforTrans; 46 | } 47 | 48 | public void setWebuiURLforTrans(String webuiURLforTrans) { 49 | this.webuiURLforTrans = webuiURLforTrans; 50 | } 51 | 52 | /*@Exported 53 | public String getRevision() { 54 | return revision; 55 | }*/ 56 | 57 | @Exported 58 | public String getWebuiURLforIssue() { 59 | return webuiURLforIssue; 60 | } 61 | 62 | public void setWebuiURLforIssue(String webuiURLforIssue) { 63 | this.webuiURLforIssue = webuiURLforIssue; 64 | } 65 | 66 | public void addFileRevision(String revision) { 67 | fileRevisions.add(revision); 68 | } 69 | 70 | @Exported 71 | public User getAuthor() { 72 | return author; 73 | } 74 | 75 | /** 76 | * Returns a set of paths in the workspace that was affected by this change. Contains string like 77 | * 'foo/bar/zot'. No leading/trailing '/', and separator must be normalized to '/'. 78 | * 79 | * @return never null. 80 | */ 81 | @Exported 82 | public Collection getAffectedPaths() { 83 | return affectedPaths; 84 | } 85 | 86 | public List getAffectedRawPaths() { 87 | return affectedRawPaths; 88 | } 89 | 90 | @Exported 91 | public Collection getFileRevisions() { 92 | return fileRevisions; 93 | } 94 | 95 | @Exported 96 | @SuppressFBWarnings( 97 | value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", 98 | justification = "We hope that AccurevTransaction.author is not null here... Need to fix.") 99 | public String getUser() { // digester wants read/write property, even though it never reads. Duh. 100 | return author.getDisplayName(); 101 | } 102 | 103 | public void setUser(String author) { 104 | this.author = User.getById(author, true); 105 | } 106 | 107 | @Exported 108 | @SuppressFBWarnings( 109 | value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", 110 | justification = "We hope that AccurevTransaction.date is not null here... Need to fix.") 111 | public Date getDate() { 112 | return (Date) date.clone(); 113 | } 114 | 115 | public void setDate(Date date) { 116 | this.date = (Date) date.clone(); 117 | } 118 | 119 | @Exported 120 | public String getMsg() { 121 | return (StringUtils.isEmpty(msg) ? "" : msg); 122 | } 123 | 124 | public void setMsg(String msg) { 125 | this.msg = msg; 126 | } 127 | 128 | protected void setParent(ChangeLogSet parent) { 129 | super.setParent(parent); // Needed since parent method is protected 130 | } 131 | 132 | @Exported 133 | @SuppressFBWarnings( 134 | value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", 135 | justification = "We hope that AccurevTransaction.action is not null here... Need to fix.") 136 | public EditType getEditType() { 137 | if (action.equals("promote")) { 138 | return EditType.EDIT; 139 | } 140 | if (action.equals("defunct")) { 141 | return EditType.DELETE; 142 | } 143 | if (action.equals("chstream")) { 144 | return EditType.EDIT; 145 | } 146 | if (action.equals("add")) { 147 | return EditType.ADD; 148 | } 149 | return EditType.EDIT; 150 | } 151 | 152 | public void addAffectedPath(String path) { 153 | affectedPaths.add(path); 154 | } 155 | 156 | public void addAffectedRawPath(String path) { 157 | affectedRawPaths.add(path); 158 | } 159 | 160 | /** 161 | * Getter for action Enables accurate filtering by AccuRev transaction type since the metod 162 | * getEditType censors the actual type. 163 | * 164 | * @return transaction type of the AccuRev transaction 165 | */ 166 | @Exported 167 | public String getAction() { 168 | return action; 169 | } 170 | 171 | public void setAction(String action) { 172 | this.action = action; 173 | if ("chstream".equals(action) && StringUtils.isEmpty(msg)) { 174 | msg = "Changed Parent Stream"; 175 | } 176 | } 177 | 178 | /** 179 | * Getter for id Enables logging with AccuRev transaction id 180 | * 181 | * @return transaction id of the AccuRev transaction 182 | */ 183 | @Exported 184 | public String getId() { 185 | return id; 186 | } 187 | 188 | /** 189 | * Setter for id 190 | * 191 | * @param id transaction id of the AccuRev transaction 192 | */ 193 | public void setId(String id) { 194 | this.id = id; 195 | } 196 | 197 | @Override 198 | public String toString() { 199 | return '[' 200 | + // 201 | "id" 202 | + EQ 203 | + id 204 | + // 205 | FIELD_SEPARATOR 206 | + // 207 | "date" 208 | + EQ 209 | + date 210 | + // 211 | FIELD_SEPARATOR 212 | + // 213 | "author" 214 | + EQ 215 | + author 216 | + // 217 | FIELD_SEPARATOR 218 | + // 219 | "action" 220 | + EQ 221 | + action 222 | + // 223 | FIELD_SEPARATOR 224 | + // 225 | "msg" 226 | + EQ 227 | + getMsg() 228 | + // 229 | ']'; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/ChangeLogCmd.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevLauncher; 8 | import hudson.plugins.accurev.AccurevSCM; 9 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 10 | import hudson.plugins.accurev.GetConfigWebURL; 11 | import hudson.plugins.accurev.XmlParserFactory; 12 | import hudson.plugins.accurev.parsers.output.ParseOutputToFile; 13 | import hudson.plugins.accurev.parsers.xml.ParseGetConfig; 14 | import hudson.util.ArgumentListBuilder; 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.text.SimpleDateFormat; 18 | import java.util.Date; 19 | import java.util.Map; 20 | import java.util.logging.Logger; 21 | import javax.xml.parsers.DocumentBuilder; 22 | import javax.xml.parsers.DocumentBuilderFactory; 23 | import javax.xml.parsers.ParserConfigurationException; 24 | import javax.xml.transform.Transformer; 25 | import javax.xml.transform.TransformerException; 26 | import javax.xml.transform.TransformerFactory; 27 | import javax.xml.transform.dom.DOMSource; 28 | import javax.xml.transform.stream.StreamResult; 29 | import org.w3c.dom.Document; 30 | import org.w3c.dom.Element; 31 | import org.w3c.dom.NodeList; 32 | import org.xml.sax.SAXException; 33 | import org.xmlpull.v1.XmlPullParserFactory; 34 | 35 | public class ChangeLogCmd { 36 | 37 | public static boolean captureChangelog( 38 | AccurevServer server, 39 | EnvVars accurevEnv, 40 | FilePath workspace, 41 | TaskListener listener, 42 | Launcher launcher, 43 | Date buildDate, 44 | Date startDate, 45 | String stream, 46 | File changelogFile, 47 | Logger logger, 48 | AccurevSCM scm, 49 | Map webURL) 50 | throws IOException { 51 | final String accurevACSYNCEnvVar = "AC_SYNC"; 52 | if (!accurevEnv.containsKey(accurevACSYNCEnvVar)) { 53 | final String accurevACSYNC = "IGNORE"; 54 | accurevEnv.put(accurevACSYNCEnvVar, accurevACSYNC); 55 | listener 56 | .getLogger() 57 | .println("Setting " + accurevACSYNCEnvVar + " to \"" + accurevACSYNC + '"'); 58 | } 59 | ArgumentListBuilder cmd = new ArgumentListBuilder(); 60 | cmd.add("hist"); 61 | Command.addServer(cmd, server); 62 | cmd.add("-fx"); 63 | cmd.add("-a"); 64 | cmd.add("-s"); 65 | cmd.add(stream); 66 | cmd.add("-t"); 67 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 68 | String dateRange = formatter.format(buildDate); 69 | if (startDate != null) { 70 | dateRange += "-" + formatter.format(startDate); 71 | } else { 72 | dateRange += ".100"; 73 | } 74 | cmd.add(dateRange); // if this breaks windows there's going to be fun 75 | final String commandDescription = "Changelog command"; 76 | final Boolean success = 77 | AccurevLauncher.runCommand( 78 | commandDescription, 79 | scm.getAccurevTool(), 80 | launcher, 81 | cmd, 82 | scm.getOptionalLock(workspace), 83 | accurevEnv, 84 | workspace, 85 | listener, 86 | logger, 87 | new ParseOutputToFile(), 88 | changelogFile); 89 | if (success == null || !success) { 90 | return false; 91 | } 92 | // ============================================================================================== 93 | // See the content of changelogfile 94 | 95 | if (changelogFile != null) { 96 | applyWebURL(webURL, changelogFile, scm); 97 | } 98 | // ============================================================================================= 99 | listener.getLogger().println("Changelog calculated successfully."); 100 | return true; 101 | } 102 | 103 | /** 104 | * Retrieve the settings.xml file to get the webURL. 105 | * 106 | * @param server Server 107 | * @param accurevEnv Accurev Environment 108 | * @param workspace Workspace 109 | * @param listener listener 110 | * @param launcher Launcher 111 | * @param logger logger 112 | * @param scm Accurev SCM 113 | * @return webURL 114 | * @throws IOException Handle it above 115 | */ 116 | public static Map retrieveWebURL( 117 | AccurevServer server, 118 | EnvVars accurevEnv, 119 | FilePath workspace, 120 | TaskListener listener, 121 | Launcher launcher, 122 | Logger logger, 123 | AccurevSCM scm) 124 | throws IOException { 125 | final ArgumentListBuilder getConfigCmd = new ArgumentListBuilder(); 126 | getConfigCmd.add("getconfig"); 127 | Command.addServer(getConfigCmd, server); 128 | getConfigCmd.add("-s"); 129 | getConfigCmd.add("-r"); 130 | getConfigCmd.add("settings.xml"); 131 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 132 | if (parser == null) { 133 | throw new IOException("No XML Parser"); 134 | } 135 | 136 | return AccurevLauncher.runCommand( 137 | "Get config to fetch webURL", 138 | scm.getAccurevTool(), 139 | launcher, 140 | getConfigCmd, 141 | scm.getOptionalLock(workspace), 142 | accurevEnv, 143 | workspace, 144 | listener, 145 | logger, 146 | parser, 147 | new ParseGetConfig(), 148 | null); 149 | } 150 | 151 | /** 152 | * Parses changelog to apply the given webURL 153 | * 154 | * @param webURL webURL 155 | * @param changelogFile changeLogFile 156 | * @param scm Accurev SCM 157 | */ 158 | private static void applyWebURL( 159 | Map webURL, File changelogFile, AccurevSCM scm) { 160 | 161 | if (webURL == null || webURL.isEmpty()) { 162 | return; 163 | } 164 | 165 | GetConfigWebURL webuiURL = webURL.get("webuiURL"); 166 | DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 167 | DocumentBuilder documentBuilder; 168 | try { 169 | documentBuilder = documentBuilderFactory.newDocumentBuilder(); 170 | Document document = documentBuilder.parse(changelogFile); 171 | 172 | NodeList nodes = document.getElementsByTagName("transaction"); 173 | 174 | Element depotElement = document.createElement("depot"); 175 | if (nodes != null && nodes.getLength() > 0) { 176 | nodes.item(0).getParentNode().insertBefore(depotElement, nodes.item(0)); 177 | } 178 | 179 | depotElement.appendChild(document.createTextNode(scm.getDepot())); 180 | 181 | Element webuiElement = document.createElement("webuiURL"); 182 | if (nodes != null && nodes.getLength() > 0) { 183 | nodes.item(0).getParentNode().insertBefore(webuiElement, nodes.item(0)); 184 | } 185 | 186 | if (webuiURL != null) { 187 | webuiElement.appendChild( 188 | document.createTextNode( 189 | (webuiURL.getWebURL().endsWith("/") 190 | ? (webuiURL.getWebURL().substring(0, webuiURL.getWebURL().length() - 1)) 191 | : (webuiURL.getWebURL())))); 192 | } else { 193 | webuiElement.appendChild(document.createTextNode("")); 194 | } 195 | 196 | DOMSource source = new DOMSource(document); 197 | 198 | TransformerFactory transformerFactory = TransformerFactory.newInstance(); 199 | Transformer transformer = transformerFactory.newTransformer(); 200 | StreamResult result = new StreamResult(changelogFile); 201 | transformer.transform(source, result); 202 | } catch (ParserConfigurationException 203 | | IOException 204 | | SAXException 205 | | TransformerException ignored) { 206 | 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/cmd/History.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.cmd; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevLauncher; 8 | import hudson.plugins.accurev.AccurevSCM; 9 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 10 | import hudson.plugins.accurev.AccurevTransaction; 11 | import hudson.plugins.accurev.XmlParserFactory; 12 | import hudson.plugins.accurev.parsers.xml.ParseHistory; 13 | import hudson.util.ArgumentListBuilder; 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.logging.Logger; 18 | import org.xmlpull.v1.XmlPullParserFactory; 19 | 20 | public class History extends Command { 21 | 22 | private static final Logger logger = Logger.getLogger(History.class.getName()); 23 | 24 | /** 25 | * @param scm Accurev SCM 26 | * @param server server 27 | * @param accurevEnv Accurev Enviroment 28 | * @param workspace workspace 29 | * @param listener listener 30 | * @param launcher launcher 31 | * @param stream stream 32 | * @param transactionType Transaction type Specify what type of transaction to search for (can be 33 | * null) 34 | * @return the latest transaction of the specified type from the selected stream 35 | * @throws IOException if no transaction was found 36 | */ 37 | public static AccurevTransaction getLatestTransaction( // 38 | final AccurevSCM scm, // 39 | final AccurevServer server, // 40 | final EnvVars accurevEnv, // 41 | final FilePath workspace, // 42 | final TaskListener listener, // 43 | final Launcher launcher, // 44 | final String stream, // 45 | final String transactionType) 46 | throws IOException { 47 | // initialize code that extracts the latest transaction of a certain 48 | // type using -k flag 49 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 50 | cmd.add("hist"); 51 | addServer(cmd, server); 52 | cmd.add("-fx"); 53 | cmd.add("-p"); 54 | cmd.add(scm.getDepot()); 55 | cmd.add("-s"); 56 | cmd.add(stream); 57 | cmd.add("-t"); 58 | cmd.add("now.1"); 59 | if (transactionType != null) { 60 | cmd.add("-k"); 61 | cmd.add(transactionType); 62 | } 63 | 64 | // execute code that extracts the latest transaction 65 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 66 | if (parser == null) { 67 | throw new IOException("No XML Parser"); 68 | } 69 | final List transaction = new ArrayList<>(1); 70 | final Boolean transactionFound = 71 | AccurevLauncher.runCommand( 72 | "History command", 73 | scm.getAccurevTool(), 74 | launcher, 75 | cmd, 76 | scm.getOptionalLock(workspace), 77 | accurevEnv, 78 | workspace, 79 | listener, 80 | logger, 81 | parser, 82 | new ParseHistory(), 83 | transaction); 84 | if (transactionFound == null) { 85 | final String msg = 86 | "History command failed when trying to get the latest transaction of type " 87 | + transactionType; 88 | throw new IOException(msg); 89 | } 90 | if (transactionFound) { 91 | return transaction.get(0); 92 | } else { 93 | return null; 94 | } 95 | } 96 | 97 | /** 98 | * @param scm Accurev SCM 99 | * @param server server 100 | * @param accurevEnv Accurev Enviroment 101 | * @param workspace workspace 102 | * @param listener listener 103 | * @param launcher launcher 104 | * @param stream stream 105 | * @param lastTransaction lastTransaction 106 | * @return all the transaction for a given stream 107 | * @throws IOException if no transaction was found 108 | */ 109 | public static List getTransactionsAfterLastTransaction( // 110 | final AccurevSCM scm, // 111 | final AccurevServer server, // 112 | final EnvVars accurevEnv, // 113 | final FilePath workspace, // 114 | final TaskListener listener, // 115 | final Launcher launcher, // 116 | final String stream, 117 | final int lastTransaction) 118 | throws IOException { 119 | // initialize code that extracts the latest transaction of a certain 120 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 121 | cmd.add("hist"); 122 | addServer(cmd, server); 123 | cmd.add("-fx"); 124 | cmd.add("-p"); 125 | cmd.add(scm.getDepot()); 126 | cmd.add("-s"); 127 | cmd.add(stream); 128 | // Filter the history command to get all the transactions greater than the last transaction 129 | if (lastTransaction > 0) { 130 | cmd.add("-t"); 131 | cmd.add("now-" + (lastTransaction + 1)); 132 | } 133 | // execute code that extracts the latest transaction 134 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 135 | if (parser == null) { 136 | throw new IOException("No XML Parser"); 137 | } 138 | final List transactions = new ArrayList<>(); 139 | final Boolean transactionFound = 140 | AccurevLauncher.runHistCommandForAll( 141 | "History command", 142 | scm.getAccurevTool(), 143 | launcher, 144 | cmd, 145 | scm.getOptionalLock(workspace), 146 | accurevEnv, 147 | workspace, 148 | listener, 149 | logger, 150 | parser, 151 | new ParseHistory(), 152 | transactions); 153 | if (transactionFound == null) { 154 | throw new IOException("History command failed when trying to get all the transactionse "); 155 | } 156 | return transactions; 157 | } 158 | 159 | /** 160 | * @param scm Accurev SCM 161 | * @param server server 162 | * @param accurevEnv Accurev Enviroment 163 | * @param workspace workspace 164 | * @param listener listener 165 | * @param launcher launcher 166 | * @param stream stream 167 | * @param dateRange lastTransaction 168 | * @param transactionTypes 169 | * @return all the transaction for a given stream 170 | * @throws IOException if no transaction was found 171 | */ 172 | public static List getTransactionsRange( // 173 | final AccurevSCM scm, // 174 | final AccurevServer server, // 175 | final EnvVars accurevEnv, // 176 | final FilePath workspace, // 177 | final TaskListener listener, // 178 | final Launcher launcher, // 179 | final String stream, 180 | final String transactionTypes, 181 | final String dateRange) 182 | throws IOException { 183 | // initialize code that extracts the latest transaction of a certain 184 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 185 | cmd.add("hist"); 186 | addServer(cmd, server); 187 | cmd.add("-fx"); 188 | cmd.add("-p"); 189 | cmd.add(scm.getDepot()); 190 | cmd.add("-s"); 191 | cmd.add(stream); 192 | // Filter the history command to get all the transactions between last build date and now 193 | if (dateRange != null) { 194 | cmd.add("-t"); 195 | cmd.add("now-" + (dateRange)); 196 | } 197 | 198 | if (transactionTypes != null) { 199 | cmd.add("-k"); 200 | cmd.add(transactionTypes); 201 | } 202 | // execute code that extracts the latest transaction 203 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 204 | if (parser == null) { 205 | throw new IOException("No XML Parser"); 206 | } 207 | final List transactions = new ArrayList<>(); 208 | final Boolean transactionFound = 209 | AccurevLauncher.runHistCommandForAll( 210 | "History command", 211 | scm.getAccurevTool(), 212 | launcher, 213 | cmd, 214 | scm.getOptionalLock(workspace), 215 | accurevEnv, 216 | workspace, 217 | listener, 218 | logger, 219 | parser, 220 | new ParseHistory(), 221 | transactions); 222 | if (transactionFound == null) { 223 | throw new IOException("History command failed when trying to get all the transactionse "); 224 | } 225 | return transactions; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/CheckForChanges.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev; 2 | 3 | import hudson.EnvVars; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.TaskListener; 7 | import hudson.plugins.accurev.AccurevSCM.AccurevServer; 8 | import hudson.plugins.accurev.cmd.History; 9 | import java.io.IOException; 10 | import java.text.SimpleDateFormat; 11 | import java.util.Arrays; 12 | import java.util.Collection; 13 | import java.util.Date; 14 | import java.util.HashSet; 15 | import java.util.List; 16 | import java.util.Set; 17 | import java.util.logging.Level; 18 | import java.util.logging.Logger; 19 | import org.apache.commons.collections.CollectionUtils; 20 | import org.apache.commons.io.FilenameUtils; 21 | import org.apache.commons.io.IOCase; 22 | import org.apache.commons.lang.StringUtils; 23 | 24 | public class CheckForChanges { 25 | 26 | /** 27 | * @param server server 28 | * @param accurevEnv accurev environment 29 | * @param workspace workspace 30 | * @param listener listener 31 | * @param launcher launcher 32 | * @param stream stream 33 | * @param buildDate build Date 34 | * @param logger logger 35 | * @param scm Accurev SCm 36 | * @param version 37 | * @return if there are any new transactions in the stream since the last build was done 38 | */ 39 | // stream param is of type AccurevStream 40 | public static boolean checkStreamForChanges( 41 | AccurevServer server, 42 | EnvVars accurevEnv, 43 | FilePath workspace, 44 | TaskListener listener, 45 | Launcher launcher, 46 | AccurevStream stream, 47 | Date buildDate, 48 | Logger logger, 49 | AccurevSCM scm, 50 | int version) { 51 | String filterForPollSCM = scm.getFilterForPollSCM(); 52 | String subPath = scm.getSubPath(); 53 | List validTransactionTypes; 54 | if (stream.getType().name().equalsIgnoreCase("workspace")) { 55 | validTransactionTypes = AccurevSCM.DEFAULT_VALID_WORKSPACE_TRANSACTION_TYPES; 56 | } else { 57 | validTransactionTypes = AccurevSCM.DEFAULT_VALID_STREAM_TRANSACTION_TYPES; 58 | } 59 | String transactionTypes = String.join(",", validTransactionTypes); 60 | listener 61 | .getLogger() 62 | .println( // 63 | "Checking transactions of type " 64 | + transactionTypes 65 | + // 66 | " in stream [" 67 | + stream.getName() 68 | + "]"); 69 | boolean isTransLatestThanBuild = false; 70 | Set serverPaths = new HashSet(); 71 | Set pollingFilters = getListOfPollingFilters(filterForPollSCM, subPath); 72 | 73 | // AR version 7+ supports combined transaction type hist call. 74 | if (version < 7) { 75 | AccurevTransaction latestCodeChangeTransaction = new AccurevTransaction(); 76 | latestCodeChangeTransaction.setDate(AccurevSCM.NO_TRANS_DATE); 77 | 78 | // query AccuRev for the latest transactions of each kind defined in transactionTypes using 79 | // getTimeOfLatestTransaction 80 | for (final String transactionType : validTransactionTypes) { 81 | try { 82 | final AccurevTransaction tempTransaction = 83 | History.getLatestTransaction( 84 | scm, 85 | server, 86 | accurevEnv, 87 | workspace, 88 | listener, 89 | launcher, 90 | stream.getName(), 91 | transactionType); 92 | if (tempTransaction != null) { 93 | listener 94 | .getLogger() 95 | .println( 96 | "Last transaction of type [" + transactionType + "] is " + tempTransaction); 97 | 98 | if (latestCodeChangeTransaction.getDate().before(tempTransaction.getDate())) { 99 | // check the affected 100 | serverPaths.addAll(tempTransaction.getAffectedPaths()); 101 | if (tempTransaction.getAffectedPaths().size() > 0) { 102 | if (!changesMatchFilter(serverPaths, pollingFilters)) { 103 | // Continue to next transaction (that may have a match) 104 | continue; 105 | } 106 | } 107 | } 108 | latestCodeChangeTransaction = tempTransaction; 109 | if (latestCodeChangeTransaction.getDate().equals(AccurevSCM.NO_TRANS_DATE)) { 110 | listener.getLogger().println("No last transaction found."); 111 | } 112 | // log last transaction information if retrieved 113 | if (buildDate != null && buildDate.before(latestCodeChangeTransaction.getDate())) { 114 | listener.getLogger().println("Last valid trans " + latestCodeChangeTransaction); 115 | isTransLatestThanBuild = true; 116 | } 117 | 118 | } else { 119 | listener.getLogger().println("No transactions of type [" + transactionType + "]"); 120 | } 121 | } catch (Exception e) { 122 | final String msg = 123 | "getLatestTransaction failed when checking the stream " 124 | + stream.getName() 125 | + " for changes with transaction type " 126 | + transactionType; 127 | listener.getLogger().println(msg); 128 | e.printStackTrace(listener.getLogger()); 129 | logger.log(Level.WARNING, msg, e); 130 | } 131 | } 132 | return isTransLatestThanBuild; 133 | } else { 134 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 135 | String dateRange = formatter.format(buildDate); 136 | 137 | List tempTransaction; 138 | try { 139 | // history for all transaction types in time range from last build - now. 140 | tempTransaction = 141 | History.getTransactionsRange( 142 | scm, 143 | server, 144 | accurevEnv, 145 | workspace, 146 | listener, 147 | launcher, 148 | stream.getName(), 149 | transactionTypes, 150 | dateRange); 151 | if (!tempTransaction.isEmpty()) { 152 | for (AccurevTransaction t : tempTransaction) { 153 | if (t.getAffectedPaths().isEmpty() 154 | && (t.getAction().equals("mkstream") 155 | || t.getAction().equals("chstream") 156 | || t.getAction().equals("defcomp"))) { 157 | listener.getLogger().println("Last valid transaction " + tempTransaction); 158 | isTransLatestThanBuild = true; 159 | } else { 160 | serverPaths.addAll(t.getAffectedPaths()); 161 | } 162 | } 163 | } 164 | 165 | if (serverPaths.size() > 0) { 166 | if (changesMatchFilter(serverPaths, pollingFilters)) { 167 | isTransLatestThanBuild = true; 168 | listener.getLogger().println("Last valid transaction " + tempTransaction); 169 | } 170 | } 171 | } catch (IOException e) { 172 | 173 | final String msg = 174 | "getLatestTransaction failed when checking the stream " 175 | + stream.getName() 176 | + " for changes with transaction type " 177 | + transactionTypes; 178 | listener.getLogger().println(msg); 179 | e.printStackTrace(listener.getLogger()); 180 | logger.log(Level.WARNING, msg, e); 181 | } 182 | return isTransLatestThanBuild; 183 | } 184 | } 185 | 186 | public static boolean changesMatchFilter( 187 | Collection serverPaths, Collection filters) { 188 | if (CollectionUtils.isEmpty(filters)) { 189 | // No filters, so always a match. 190 | return true; 191 | } 192 | 193 | for (String path : serverPaths) { 194 | path = sanitizeSlashes(path); 195 | for (String filter : filters) { 196 | if (pathMatcher(path, filter)) { 197 | return true; 198 | } 199 | } 200 | } 201 | return false; 202 | } 203 | 204 | public static boolean pathMatcher(String path, String wildcard) { 205 | return FilenameUtils.wildcardMatch(path, wildcard, IOCase.INSENSITIVE); 206 | } 207 | 208 | private static Set getListOfPollingFilters(String filterForPollSCM, String subPath) { 209 | if (StringUtils.isNotBlank(filterForPollSCM)) { 210 | return splitAndSanitizeFilters(filterForPollSCM); 211 | } 212 | 213 | return splitAndSanitizeFilters(subPath); 214 | } 215 | 216 | private static Set splitAndSanitizeFilters(String input) { 217 | if (StringUtils.isBlank(input)) { 218 | return null; 219 | } 220 | 221 | final char DELIMITER = ','; 222 | final String STRIP_CHARS = " \t\n\r/"; 223 | String[] filters = StringUtils.split(sanitizeSlashes(input), DELIMITER); 224 | filters = StringUtils.stripAll(filters, STRIP_CHARS); 225 | 226 | return new HashSet<>(Arrays.asList(filters)); 227 | } 228 | 229 | private static String sanitizeSlashes(String input) { 230 | return input.replace('\\', '/'); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/delegates/ReftreeDelegate.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.delegates; 2 | 3 | import hudson.model.Job; 4 | import hudson.model.Run; 5 | import hudson.plugins.accurev.AccurevLauncher; 6 | import hudson.plugins.accurev.AccurevReferenceTree; 7 | import hudson.plugins.accurev.AccurevSCM; 8 | import hudson.plugins.accurev.DetermineRemoteHostname; 9 | import hudson.plugins.accurev.RemoteWorkspaceDetails; 10 | import hudson.plugins.accurev.XmlConsolidateStreamChangeLog; 11 | import hudson.plugins.accurev.XmlParserFactory; 12 | import hudson.plugins.accurev.cmd.Command; 13 | import hudson.plugins.accurev.cmd.Update; 14 | import hudson.plugins.accurev.delegates.Relocation.RelocationOption; 15 | import hudson.plugins.accurev.parsers.xml.ParseShowReftrees; 16 | import hudson.scm.PollingResult; 17 | import hudson.util.ArgumentListBuilder; 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.logging.Logger; 24 | import org.apache.commons.lang.StringUtils; 25 | import org.xmlpull.v1.XmlPullParserFactory; 26 | 27 | /** @author raymond */ 28 | public class ReftreeDelegate extends AbstractModeDelegate { 29 | 30 | private static final Logger logger = Logger.getLogger(ReftreeDelegate.class.getName()); 31 | protected boolean popRequired = false; 32 | private File updateLogFile; 33 | 34 | public ReftreeDelegate(AccurevSCM scm) { 35 | super(scm); 36 | } 37 | 38 | public String getSCMRefTree() { 39 | return scm.getReftree(); 40 | } 41 | 42 | @Override 43 | protected PollingResult checkForChanges(Job project) 44 | throws IOException, InterruptedException { 45 | try { 46 | Relocation relocation = checkForRelocation(); 47 | if (relocation.isRelocationRequired()) { 48 | listener.getLogger().println("Relocation required triggering build"); 49 | return PollingResult.BUILD_NOW; 50 | } else { 51 | if (Update.hasChanges( 52 | scm, server, accurevEnv, accurevWorkingSpace, listener, launcher, getSCMRefTree())) { 53 | return PollingResult.BUILD_NOW; 54 | } else { 55 | return PollingResult.NO_CHANGES; 56 | } 57 | } 58 | } catch (IllegalArgumentException ex) { 59 | listener.fatalError(ex.getMessage()); 60 | return PollingResult.NO_CHANGES; 61 | } 62 | } 63 | 64 | protected Relocation checkForRelocation() throws IOException, InterruptedException { 65 | final Map reftrees = getReftrees(); 66 | String reftree = scm.getReftree(); 67 | if (reftrees == null) { 68 | throw new IllegalArgumentException( 69 | "Cannot determine reference tree configuration information"); 70 | } 71 | if (!reftrees.containsKey(reftree)) { 72 | throw new IllegalArgumentException("The specified reference tree does not appear to exist!"); 73 | } 74 | AccurevReferenceTree accurevReftree = reftrees.get(reftree); 75 | if (!scm.getDepot().equals(accurevReftree.getDepot())) { 76 | throw new IllegalArgumentException( 77 | "The specified reference tree, " 78 | + reftree 79 | + ", is based in the depot " 80 | + accurevReftree.getDepot() 81 | + " not " 82 | + scm.getDepot()); 83 | } 84 | 85 | RemoteWorkspaceDetails remoteDetails = getRemoteWorkspaceDetails(); 86 | 87 | List relocationOptions = new ArrayList<>(); 88 | 89 | for (RefTreeRelocation refTreeRelocation : RefTreeRelocation.values()) { 90 | if (refTreeRelocation.isRequired(accurevReftree, remoteDetails)) { 91 | relocationOptions.add(refTreeRelocation); 92 | } 93 | } 94 | return new Relocation( 95 | relocationOptions, remoteDetails.getHostName(), accurevWorkingSpace.getRemote(), null); 96 | } 97 | 98 | protected RemoteWorkspaceDetails getRemoteWorkspaceDetails() throws InterruptedException { 99 | try { 100 | return jenkinsWorkspace.act(new DetermineRemoteHostname(accurevWorkingSpace.getRemote())); 101 | } catch (IOException e) { 102 | e.printStackTrace(listener.getLogger()); 103 | throw new IllegalArgumentException("Unable to validate reference tree host."); 104 | } 105 | } 106 | 107 | /** 108 | * Builds a command which gets executed and retrieves the following return data 109 | * 110 | * @return Map with Reference Tree name as key and Reference Tree Object as value. 111 | * @throws IOException Failed to execute command or Parse data. 112 | */ 113 | private Map getReftrees() throws IOException { 114 | listener.getLogger().println("Getting a list of reference trees..."); 115 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 116 | cmd.add("show"); 117 | Command.addServer(cmd, server); 118 | cmd.add("-fx"); 119 | cmd.add("refs"); 120 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 121 | if (parser == null) { 122 | throw new IOException("No XML Parser"); 123 | } 124 | return AccurevLauncher.runCommand( 125 | "Show ref trees command", 126 | scm.getAccurevTool(), 127 | launcher, 128 | cmd, 129 | scm.getOptionalLock(jenkinsWorkspace), 130 | accurevEnv, 131 | jenkinsWorkspace, 132 | listener, 133 | logger, 134 | parser, 135 | new ParseShowReftrees(), 136 | null); 137 | } 138 | 139 | @Override 140 | protected boolean checkout(Run build, File changeLogFile) 141 | throws IOException, InterruptedException { 142 | if (!validateCheckout(build)) { 143 | return false; 144 | } 145 | Relocation relocation = checkForRelocation(); 146 | if (relocation.isRelocationRequired()) { 147 | if (!relocate(relocation)) { 148 | return false; 149 | } 150 | if (!populate(build, popRequired)) { 151 | return false; 152 | } 153 | } 154 | 155 | return doUpdate(changeLogFile); 156 | } 157 | 158 | private boolean doUpdate(File changeLogFile) throws IOException { 159 | updateLogFile = XmlConsolidateStreamChangeLog.getUpdateChangeLogFile(changeLogFile); 160 | return Update.performUpdate( 161 | scm, 162 | server, 163 | accurevEnv, 164 | accurevWorkingSpace, 165 | listener, 166 | launcher, 167 | getSCMRefTree(), 168 | updateLogFile); 169 | } 170 | 171 | @Override 172 | protected String getUpdateFileName() { 173 | return updateLogFile.getName(); 174 | } 175 | 176 | protected String getPopulateFromMessage() { 177 | return "from reftree"; 178 | } 179 | 180 | @Override 181 | protected String getPopulateStream() { 182 | return null; 183 | } 184 | 185 | private boolean relocate(Relocation relocation) throws IOException, InterruptedException { 186 | ArgumentListBuilder relocateCommand = getRelocateCommand(); 187 | popRequired = relocation.isPopRequired(); 188 | if (popRequired) { 189 | listener.getLogger().println("Clearing path: " + accurevWorkingSpace.getRemote()); 190 | accurevWorkingSpace.deleteContents(); 191 | } 192 | relocation.appendCommands(relocateCommand); 193 | 194 | return AccurevLauncher.runCommand( 195 | "relocation command", 196 | scm.getAccurevTool(), 197 | launcher, 198 | relocateCommand, 199 | scm.getOptionalLock(accurevWorkingSpace), 200 | accurevEnv, 201 | accurevWorkingSpace, 202 | listener, 203 | logger, 204 | true); 205 | } 206 | 207 | protected ArgumentListBuilder getRelocateCommand() { 208 | ArgumentListBuilder chrefcmd = new ArgumentListBuilder(); 209 | chrefcmd.add("chref"); 210 | Command.addServer(chrefcmd, server); 211 | chrefcmd.add("-r"); 212 | chrefcmd.add(getSCMRefTree()); 213 | return chrefcmd; 214 | } 215 | 216 | protected boolean validateCheckout(Run build) { 217 | String reftree = getSCMRefTree(); 218 | if (StringUtils.isEmpty(reftree)) { 219 | listener.fatalError("Must specify a reference tree"); 220 | return false; 221 | } 222 | return true; 223 | } 224 | 225 | @Override 226 | protected void buildEnvVarsCustom(Run build, Map env) { 227 | env.put("ACCUREV_REFTREE", scm.getReftree()); 228 | } 229 | 230 | private enum RefTreeRelocation implements RelocationOption { 231 | HOST { 232 | @Override 233 | protected boolean isRequired( 234 | AccurevReferenceTree accurevReftree, RemoteWorkspaceDetails remoteDetails) { 235 | return !accurevReftree.getHost().equals(remoteDetails.getHostName()); 236 | } 237 | 238 | public void appendCommand(ArgumentListBuilder cmd, Relocation relocation) { 239 | cmd.add("-m"); 240 | cmd.add(relocation.getNewHost()); 241 | } 242 | }, 243 | STORAGE { 244 | @Override 245 | protected boolean isRequired( 246 | AccurevReferenceTree accurevReftree, RemoteWorkspaceDetails remoteDetails) { 247 | String oldStorage = 248 | accurevReftree 249 | .getStorage() 250 | .replace("/", remoteDetails.getFileSeparator()) 251 | .replace("\\", remoteDetails.getFileSeparator()); 252 | return !new File(oldStorage).equals(new File(remoteDetails.getPath())); 253 | } 254 | 255 | public void appendCommand(ArgumentListBuilder cmd, Relocation relocation) { 256 | cmd.add("-l"); 257 | cmd.add(relocation.getNewPath()); 258 | } 259 | }; 260 | 261 | public boolean isPopRequired() { 262 | return true; 263 | } 264 | 265 | protected abstract boolean isRequired( 266 | AccurevReferenceTree accurevReftree, RemoteWorkspaceDetails remoteDetails); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/accurev/delegates/WorkspaceDelegate.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.accurev.delegates; 2 | 3 | import hudson.model.Job; 4 | import hudson.model.Run; 5 | import hudson.plugins.accurev.AccurevLauncher; 6 | import hudson.plugins.accurev.AccurevSCM; 7 | import hudson.plugins.accurev.AccurevStream; 8 | import hudson.plugins.accurev.AccurevWorkspace; 9 | import hudson.plugins.accurev.RemoteWorkspaceDetails; 10 | import hudson.plugins.accurev.XmlParserFactory; 11 | import hudson.plugins.accurev.cmd.Command; 12 | import hudson.plugins.accurev.cmd.ShowStreams; 13 | import hudson.plugins.accurev.delegates.Relocation.RelocationOption; 14 | import hudson.plugins.accurev.parsers.xml.ParseShowWorkspaces; 15 | import hudson.scm.PollingResult; 16 | import hudson.util.ArgumentListBuilder; 17 | import java.io.File; 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.logging.Logger; 23 | import org.apache.commons.lang.StringUtils; 24 | import org.xmlpull.v1.XmlPullParserFactory; 25 | 26 | /** @author raymond */ 27 | public class WorkspaceDelegate extends ReftreeDelegate { 28 | 29 | private static final Logger logger = Logger.getLogger(WorkspaceDelegate.class.getName()); 30 | 31 | public WorkspaceDelegate(AccurevSCM scm) { 32 | super(scm); 33 | } 34 | 35 | @Override 36 | public String getSCMRefTree() { 37 | return null; 38 | } 39 | 40 | @Override 41 | protected PollingResult checkForChanges(Job project) 42 | throws IOException, InterruptedException, IllegalArgumentException { 43 | localStream = scm.getPollingStream(project, listener); 44 | return super.checkForChanges(project); 45 | } 46 | 47 | @Override 48 | protected Relocation checkForRelocation() throws IOException, InterruptedException { 49 | String depot = scm.getDepot(); 50 | String _accurevWorkspace = scm.getWorkspace(); 51 | Map workspaces = getWorkspaces(); 52 | Map streams = 53 | ShowStreams.getStreams( 54 | scm, _accurevWorkspace, server, accurevEnv, jenkinsWorkspace, listener, launcher); 55 | 56 | if (workspaces == null) { 57 | throw new IllegalArgumentException("Cannot determine workspace configuration information"); 58 | } 59 | if (!workspaces.containsKey(_accurevWorkspace)) { 60 | throw new IllegalArgumentException("The specified workspace does not appear to exist!"); 61 | } 62 | AccurevWorkspace accurevWorkspace = workspaces.get(_accurevWorkspace); 63 | if (!depot.equals(accurevWorkspace.getDepot())) { 64 | throw new IllegalArgumentException( 65 | "The specified workspace, " 66 | + _accurevWorkspace 67 | + ", is based in the depot " 68 | + accurevWorkspace.getDepot() 69 | + " not " 70 | + depot); 71 | } 72 | 73 | if (scm.isIgnoreStreamParent()) { 74 | if (!streams.isEmpty()) { 75 | AccurevStream workspaceStream = streams.values().iterator().next(); 76 | accurevWorkspace.setStream(workspaceStream); 77 | String workspaceBasisStream = workspaceStream.getBasisName(); 78 | if (streams.containsKey(workspaceBasisStream)) { 79 | workspaceStream.setParent(streams.get(workspaceBasisStream)); 80 | } else { 81 | Map workspaceBasis = 82 | ShowStreams.getStreams( 83 | scm, 84 | workspaceBasisStream, 85 | server, 86 | accurevEnv, 87 | jenkinsWorkspace, 88 | listener, 89 | launcher); 90 | if (workspaceBasis == null) { 91 | throw new IllegalArgumentException("Could not determine the workspace basis stream"); 92 | } 93 | workspaceStream.setParent(workspaceBasis.get(workspaceBasisStream)); 94 | } 95 | } else { 96 | throw new IllegalArgumentException("Workspace stream not found " + _accurevWorkspace); 97 | } 98 | } else { 99 | for (AccurevStream accurevStream : streams.values()) { 100 | if (accurevWorkspace.getStreamNumber().equals(accurevStream.getNumber())) { 101 | accurevWorkspace.setStream(accurevStream); 102 | break; 103 | } 104 | } 105 | } 106 | 107 | final RemoteWorkspaceDetails remoteDetails = getRemoteWorkspaceDetails(); 108 | 109 | List relocationOptions = new ArrayList<>(); 110 | for (WorkspaceRelocation workspaceRelocationvalue : WorkspaceRelocation.values()) { 111 | if (workspaceRelocationvalue.isRequired(accurevWorkspace, remoteDetails, localStream)) { 112 | relocationOptions.add(workspaceRelocationvalue); 113 | } 114 | } 115 | return new Relocation( 116 | relocationOptions, 117 | remoteDetails.getHostName(), 118 | accurevWorkingSpace.getRemote(), 119 | localStream); 120 | } 121 | 122 | /** 123 | * Builds a command which gets executed and retrieves the following return data 124 | * 125 | * @return Map with Workspace name as key and Workspace Object as value. 126 | * @throws IOException Failed to execute command or Parse data. 127 | */ 128 | private Map getWorkspaces() throws IOException { 129 | listener.getLogger().println("Getting a list of workspaces..."); 130 | String depot = scm.getDepot(); 131 | final ArgumentListBuilder cmd = new ArgumentListBuilder(); 132 | cmd.add("show"); 133 | Command.addServer(cmd, server); 134 | cmd.add("-fx"); 135 | cmd.add("-p"); 136 | cmd.add(depot); 137 | cmd.add("wspaces"); 138 | XmlPullParserFactory parser = XmlParserFactory.getFactory(); 139 | if (parser == null) { 140 | throw new IOException("No XML Parser"); 141 | } 142 | return AccurevLauncher.runCommand( 143 | "Show workspaces command", 144 | scm.getAccurevTool(), 145 | launcher, 146 | cmd, 147 | scm.getOptionalLock(jenkinsWorkspace), 148 | accurevEnv, 149 | jenkinsWorkspace, 150 | listener, 151 | logger, 152 | parser, 153 | new ParseShowWorkspaces(), 154 | null); 155 | } 156 | 157 | @Override 158 | protected boolean validateCheckout(Run build) { 159 | String workspace = scm.getWorkspace(); 160 | if (StringUtils.isEmpty(workspace)) { 161 | listener.fatalError("Must specify a workspace"); 162 | return false; 163 | } 164 | return true; 165 | } 166 | 167 | @Override 168 | protected String getPopulateFromMessage() { 169 | return "from workspace"; 170 | } 171 | 172 | @Override 173 | protected ArgumentListBuilder getRelocateCommand() { 174 | ArgumentListBuilder chwscmd = new ArgumentListBuilder(); 175 | chwscmd.add("chws"); 176 | Command.addServer(chwscmd, server); 177 | chwscmd.add("-w"); 178 | chwscmd.add(scm.getWorkspace()); 179 | return chwscmd; 180 | } 181 | 182 | @Override 183 | protected boolean isSteamColorEnabled() { 184 | return true; 185 | } 186 | 187 | @Override 188 | protected String getStreamColorStream() { 189 | return scm.getWorkspace(); 190 | } 191 | 192 | @Override 193 | protected String getStreamColor() { 194 | return "#FFEBB4"; 195 | } 196 | 197 | @Override 198 | protected String getChangeLogStream() { 199 | return scm.getWorkspace(); 200 | } 201 | 202 | @Override 203 | protected void buildEnvVarsCustom(Run build, Map env) { 204 | env.put("ACCUREV_WORKSPACE", scm.getWorkspace()); 205 | } 206 | 207 | private enum WorkspaceRelocation implements RelocationOption { 208 | HOST { 209 | @Override 210 | protected boolean isRequired( 211 | AccurevWorkspace accurevWorkspace, 212 | RemoteWorkspaceDetails remoteDetails, 213 | String localStream) { 214 | return !accurevWorkspace.getHost().equalsIgnoreCase(remoteDetails.getHostName()); 215 | } 216 | 217 | public void appendCommand(ArgumentListBuilder cmd, Relocation relocation) { 218 | cmd.add("-m"); 219 | cmd.add(relocation.getNewHost()); 220 | } 221 | }, 222 | STORAGE { 223 | @Override 224 | protected boolean isRequired( 225 | AccurevWorkspace accurevWorkspace, 226 | RemoteWorkspaceDetails remoteDetails, 227 | String localStream) { 228 | String oldStorage = 229 | accurevWorkspace 230 | .getStorage() 231 | .replace("/", remoteDetails.getFileSeparator()) 232 | .replace("\\", remoteDetails.getFileSeparator()); 233 | return !new File(oldStorage).equals(new File(remoteDetails.getPath())); 234 | } 235 | 236 | public void appendCommand(ArgumentListBuilder cmd, Relocation relocation) { 237 | cmd.add("-l"); 238 | cmd.add(relocation.getNewPath()); 239 | } 240 | }, 241 | REPARENT { 242 | @Override 243 | protected boolean isRequired( 244 | AccurevWorkspace accurevWorkspace, 245 | RemoteWorkspaceDetails remoteDetails, 246 | String localStream) { 247 | return !localStream.equals(accurevWorkspace.getStream().getParent().getName()); 248 | } 249 | 250 | @Override 251 | public boolean isPopRequired() { 252 | return false; 253 | } 254 | 255 | public void appendCommand(ArgumentListBuilder cmd, Relocation relocation) { 256 | cmd.add("-b"); 257 | cmd.add(relocation.getNewParent()); 258 | } 259 | }; 260 | 261 | public boolean isPopRequired() { 262 | return true; 263 | } 264 | 265 | protected abstract boolean isRequired( 266 | AccurevWorkspace accurevWorkspace, 267 | RemoteWorkspaceDetails remoteDetails, 268 | String localStream); 269 | } 270 | } 271 | --------------------------------------------------------------------------------