(items.size());
for (Item item : items) {
paths.add(item.getPath());
}
return paths;
}
@Override
public Collection extends hudson.scm.ChangeLogSet.AffectedFile> getAffectedFiles() {
return items;
}
@Override
public ChangeLogSet getParent() {
return (ChangeLogSet)super.getParent();
}
@Override
public User getAuthor() {
if(authorUser == null) {
authorUser = User.get(userString);
}
return authorUser;
}
@Override
public String getMsg() {
return comment;
}
@Exported
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
/**
* Returns a human readable display name of the changeset number.
*
*
* This method is primarily intended for visualization of the data.
*/
@Exported
public String getCommitId() {
return version;
}
@Exported
public String getDomain() {
return domain;
}
@Exported
public String getUser() {
return userString;
}
public void setUser(String user) {
String[] split = user.split("\\\\");
if (split.length == 2) {
this.domain = split[0];
this.userString = split[1];
} else {
this.userString = user;
this.domain = null;
}
}
@Exported
public Date getDate() {
if (date != null) {
return new Date(date.getTime());
}
return null;
}
public void setDateStr(String dateStr) throws ParseException {
date = DateUtil.TFS_DATETIME_FORMATTER.get().parse(dateStr);
}
@Exported
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public void setCheckedInBy(String checkedInByUserString) {
if (checkedInByUserString != null) {
String[] split = checkedInByUserString.split("\\\\");
if (split.length == 2) {
this.checkedInByUserString = split[1];
} else {
this.checkedInByUserString = checkedInByUserString;
}
}
}
public String getCheckedInBy() {
return checkedInByUserString;
}
public User getCheckedInByUser() {
if (checkedInByUser == null) {
checkedInByUser = User.get(checkedInByUserString);
}
return checkedInByUser;
}
public void setCheckedInByUser(User checkedInBy) {
this.checkedInByUser = checkedInBy;
}
@Exported
public List- getItems() {
return items;
}
public void add(ChangeSet.Item item) {
items.add(item);
item.setParent(this);
}
@Override
protected void setParent(hudson.scm.ChangeLogSet parent) {
super.setParent(parent);
}
@ExportedBean(defaultVisibility=999)
public static class Item implements hudson.scm.ChangeLogSet.AffectedFile {
private String path;
private String action;
private ChangeSet parent;
public Item() {
this("","");
}
public Item(String path, String action) {
this.path = path;
this.action = action;
}
public ChangeSet getParent() {
return parent;
}
void setParent(ChangeSet parent) {
this.parent = parent;
}
@Exported
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Exported
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
@Exported
public EditType getEditType() {
if (action.equalsIgnoreCase("delete")) {
return EditType.DELETE;
}
if (action.equalsIgnoreCase("add")) {
return EditType.ADD;
}
return EditType.EDIT;
}
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ClonePersistenceStoreProvider.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.microsoft.tfs.core.config.persistence.PersistenceStoreProvider;
import com.microsoft.tfs.core.persistence.FilesystemPersistenceStore;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
public class ClonePersistenceStoreProvider implements PersistenceStoreProvider {
private final FilesystemPersistenceStore cacheStore;
private final FilesystemPersistenceStore configurationStore;
private final FilesystemPersistenceStore logStore;
private final String hostName;
public ClonePersistenceStoreProvider(final PersistenceStoreProvider sourcePersistenceStoreProvider, final String hostName) {
this.hostName = hostName;
final FilesystemPersistenceStore sourceCache = sourcePersistenceStoreProvider.getCachePersistenceStore();
final File cacheFolder = createAndCopy(sourceCache, hostName);
this.cacheStore = new FilesystemPersistenceStore(cacheFolder);
final FilesystemPersistenceStore sourceConfiguration = sourcePersistenceStoreProvider.getConfigurationPersistenceStore();
final File configurationFolder = createAndCopy(sourceConfiguration, hostName);
this.configurationStore = new FilesystemPersistenceStore(configurationFolder);
final FilesystemPersistenceStore sourceLog = sourcePersistenceStoreProvider.getLogPersistenceStore();
final File logFolder = createAndCopy(sourceLog, hostName);
this.logStore = new FilesystemPersistenceStore(logFolder);
}
static File createAndCopy(final FilesystemPersistenceStore sourceStore, final String nodeName) {
final File sourceBase = sourceStore.getStoreFile();
final String childName = sourceBase.getName();
final File sourceParent = sourceBase.getParentFile();
final File destinationBase = new File(sourceParent, nodeName);
final File destination = new File(destinationBase, childName);
if (!destination.isDirectory() && sourceBase.isDirectory()) {
try {
FileUtils.copyDirectory(sourceBase, destination);
}
catch (final IOException e) {
throw new Error(e);
}
}
return destination;
}
public FilesystemPersistenceStore getCachePersistenceStore() {
return cacheStore;
}
public FilesystemPersistenceStore getConfigurationPersistenceStore() {
return configurationStore;
}
public FilesystemPersistenceStore getLogPersistenceStore() {
return logStore;
}
public String getHostName() {
return hostName;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ConnectHookEvent.java
================================================
package hudson.plugins.tfs.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import hudson.plugins.tfs.TeamCollectionConfiguration;
import hudson.plugins.tfs.TeamPluginGlobalConfig;
import hudson.plugins.tfs.model.servicehooks.Event;
import net.sf.json.JSONObject;
import java.net.URI;
/**
* This HookEvent is for the TeamEventsEndpoint "Connect" event.
*/
public class ConnectHookEvent extends AbstractHookEvent {
/**
* Factory to create ConnectHookEvent.
*/
public static class Factory implements AbstractHookEvent.Factory {
@Override
public AbstractHookEvent create() {
return new ConnectHookEvent();
}
@Override
public String getSampleRequestPayload() {
return "{\n"
+ " \"eventType\": \"connect\",\n"
+ " \"resource\":\n"
+ " {\n"
+ " \"teamCollectionUrl\": \"https://xplatalm.visualstudio.com\"\n"
+ " \"connectionKey\": \"MyJenkinsServer\"\n"
+ " \"connectionSignature\": \"ABC13ABC123ABC13ABC123ABC13ABC123\"\n"
+ " \"sendJobCompletionEvents\": true\n"
+ " }\n"
+ "}";
}
}
@Override
public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {
final Object resource = serviceHookEvent.getResource();
final ConnectionParameters parameters = mapper.convertValue(resource, ConnectionParameters.class);
//TODO permissions?
// Store the key and the information for the correct collection
final TeamCollectionConfiguration collection = TeamCollectionConfiguration.findCollection(URI.create(parameters.getTeamCollectionUrl()));
if (collection != null) {
// Store key and signature with collection
collection.getConnectionParameters().setConnectionKey(parameters.getConnectionKey());
collection.getConnectionParameters().setConnectionSignature(parameters.getConnectionSignature());
collection.getConnectionParameters().setSendJobCompletionEvents(parameters.isSendJobCompletionEvents());
collection.getConnectionParameters().setTeamCollectionUrl(parameters.getTeamCollectionUrl());
// Save collection info
final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();
config.save();
} else {
throw new IllegalArgumentException("Unable to connect to unknown server: " + parameters.getTeamCollectionUrl());
}
return JSONObject.fromObject(serviceHookEvent);
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ConnectionParameters.java
================================================
package hudson.plugins.tfs.model;
/**
* These parameters are stored and modified from outside Jenkins through the TeamEventsEndpoint "connect" event.
* An instance of this class is owned by every TeamCollectionConfiguration instance.
*/
public class ConnectionParameters {
private String teamCollectionUrl;
private String connectionKey;
private String connectionSignature;
private boolean sendJobCompletionEvents;
/**
* Constructor.
*/
public ConnectionParameters() {
}
public String getConnectionKey() {
return connectionKey;
}
public void setConnectionKey(final String connectionKey) {
this.connectionKey = connectionKey;
}
public String getConnectionSignature() {
return connectionSignature;
}
public void setConnectionSignature(final String connectionSignature) {
this.connectionSignature = connectionSignature;
}
public String getTeamCollectionUrl() {
return teamCollectionUrl;
}
public void setTeamCollectionUrl(final String teamCollectionUrl) {
this.teamCollectionUrl = teamCollectionUrl;
}
public boolean isSendJobCompletionEvents() {
return sendJobCompletionEvents;
}
public void setSendJobCompletionEvents(final boolean sendJobCompletionEvents) {
this.sendJobCompletionEvents = sendJobCompletionEvents;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/CredentialsConfigurer.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import hudson.DescriptorExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Describable;
import jenkins.model.Jenkins;
import java.io.Serializable;
public abstract class CredentialsConfigurer implements ExtensionPoint, Describable, Serializable {
private static final long serialVersionUID = 1L;
public final String getDisplayName() {
return getDescriptor().getDisplayName();
}
public CredentialsConfigurerDescriptor getDescriptor() {
final Jenkins jenkins = Jenkins.getActiveInstance();
return (CredentialsConfigurerDescriptor) jenkins.getDescriptorOrDie(getClass());
}
public abstract StandardUsernamePasswordCredentials getCredentials(final String collectionUri);
public static DescriptorExtensionList all() {
final Jenkins jenkins = Jenkins.getActiveInstance();
return jenkins.getDescriptorList(CredentialsConfigurer.class);
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/CredentialsConfigurerDescriptor.java
================================================
package hudson.plugins.tfs.model;
import hudson.model.Descriptor;
/**
* Descriptor for CredentialsConfigurer.
*/
public abstract class CredentialsConfigurerDescriptor extends Descriptor {
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/DomainUserAccountMapper.java
================================================
package hudson.plugins.tfs.model;
import hudson.Extension;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* Mapper for Domain User accounts.
*/
public class DomainUserAccountMapper extends UserAccountMapper {
private static final long serialVersionUID = 1L;
/**
* Constructor for data binding.
*/
@DataBoundConstructor
public DomainUserAccountMapper() {
}
@Override
public String mapUserAccount(final String input) {
return input;
}
/**
* Class descriptor.
*/
@Extension
public static final class DescriptorImpl extends UserAccountMapperDescriptor {
@Override
public String getDisplayName() {
return "Resolve user using 'DOMAIN\\alias'";
}
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ExtraSettings.java
================================================
package hudson.plugins.tfs.model;
import hudson.model.Computer;
import hudson.plugins.tfs.TeamPluginGlobalConfig;
import jenkins.model.Jenkins;
import java.io.Serializable;
/**
* This class exists to shuttle settings between MASTER to remote nodes,
* who would otherwise be unable to determine said settings because they
* don't have access to the {@link jenkins.model.Jenkins} instance or
* anything that could be obtained from it.
*/
public class ExtraSettings implements Serializable {
private static final long serialVersionUID = 1L;
private boolean configFolderPerNode;
private String nodeComputerName;
public static final ExtraSettings DEFAULT = new ExtraSettings();
@SuppressWarnings("unused" /* Needed by Serializable interface */)
private ExtraSettings() {
}
/**
* Construtor.
* @param teamPluginGlobalConfig
*/
public ExtraSettings(final TeamPluginGlobalConfig teamPluginGlobalConfig) {
if (teamPluginGlobalConfig != null) {
this.configFolderPerNode = teamPluginGlobalConfig.isConfigFolderPerNode();
final Jenkins instance = Jenkins.getInstance();
this.nodeComputerName = "";
if (instance != null) {
final Computer currentComputer = Computer.currentComputer();
if (currentComputer != null) {
this.nodeComputerName = currentComputer.getName();
}
}
} else {
this.configFolderPerNode = false;
this.nodeComputerName = null;
}
}
public boolean isConfigFolderPerNode() {
return configFolderPerNode;
}
public void setConfigFolderPerNode(final boolean configFolderPerNode) {
this.configFolderPerNode = configFolderPerNode;
}
public String getNodeComputerName() {
return nodeComputerName;
}
public void setNodeComputerName(final String nodeComputerName) {
this.nodeComputerName = nodeComputerName;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/GitCodePushedEventArgs.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import org.eclipse.jgit.transport.URIish;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
public class GitCodePushedEventArgs implements Serializable {
private static final long serialVersionUID = 1L;
public URI collectionUri;
public URI repoUri;
public String projectId;
public String repoId;
public String commit;
public String pushedBy;
public String targetBranch;
public URIish getRepoURIish() {
final String repoUriString = repoUri.toString();
try {
return new URIish(repoUriString);
} catch (final URISyntaxException e) {
// shouldn't happen
throw new Error(e);
}
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/GitPullRequestEx.java
================================================
package hudson.plugins.tfs.model;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPullRequest;
import com.microsoft.visualstudio.services.webapi.model.ResourceRef;
import java.util.Arrays;
/**
* Work around some missing fields in the version of vso-httpclient-java
* by extending {@link GitPullRequest}.
*/
public class GitPullRequestEx extends GitPullRequest {
private ResourceRef[] workItemRefs;
/**
* Returns the work item references.
*/
public ResourceRef[] getWorkItemRefs() {
if (workItemRefs != null) {
return Arrays.copyOf(workItemRefs, workItemRefs.length);
}
return null;
}
/**
* Sets the work item references.
*/
public void setWorkItemRefs(final ResourceRef[] workItemRefs) {
this.workItemRefs = (workItemRefs != null) ? Arrays.copyOf(workItemRefs, workItemRefs.length) : null;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/GitPullRequestMergedEvent.java
================================================
package hudson.plugins.tfs.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitCommitRef;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPullRequest;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRepository;
import com.microsoft.visualstudio.services.webapi.model.IdentityRef;
import hudson.model.Action;
import hudson.plugins.git.GitStatus;
import hudson.plugins.tfs.PullRequestParameterAction;
import hudson.plugins.tfs.model.servicehooks.Event;
import hudson.plugins.tfs.util.ResourceHelper;
import hudson.plugins.tfs.TeamPullRequestMergedDetailsAction;
import net.sf.json.JSONObject;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
/**
* A Git push event corresponding to the merge of a pull request on VSTS/TFS.
*/
public class GitPullRequestMergedEvent extends GitPushEvent {
/**
* Factory for creating a GitPullRequestMergedEvent.
*/
public static class Factory implements AbstractHookEvent.Factory {
@Override
public AbstractHookEvent create() {
return new GitPullRequestMergedEvent();
}
@Override
public String getSampleRequestPayload() {
return ResourceHelper.fetchAsString(this.getClass(), "GitPullRequestMergedEvent.json");
}
}
static String determineCreatedBy(final GitPullRequest gitPullRequest) {
final IdentityRef createdBy = gitPullRequest.getCreatedBy();
final String result = createdBy.getDisplayName();
return result;
}
/*
Given the following sample payload fragment:
"lastMergeSourceCommit": {
"commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c",
"url": "https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c"
},
"lastMergeTargetCommit": {
"commitId": "a511f535b1ea495ee0c903badb68fbc83772c882",
"url": "https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882"
},
"lastMergeCommit": {
"commitId": "eef717f69257a6333f221566c1c987dc94cc0d72",
"url": "https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72"
},
"commits": [
{
"commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c",
"url": "https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c"
}
],
...we are assuming the user pushed `53d54a` (lastMergeSourceCommit) and Team Services attempted
to merge it with `a511f5` (the tip of whatever the branch the PR is targeting, lastMergeTargetCommit),
yielding `eef717f`.
*/
static String determineMergeCommit(final GitPullRequest gitPullRequest) {
final GitCommitRef lastMergeCommit = gitPullRequest.getLastMergeCommit();
final String result = lastMergeCommit.getCommitId();
return result;
}
static String determineTargetBranch(final GitPullRequest gitPullRequest) {
// In the form of ref/heads/master
final String targetRefName = gitPullRequest.getTargetRefName();
String[] items = targetRefName.split("/");
return items[items.length - 1];
}
@Override
public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {
final Object resource = serviceHookEvent.getResource();
final GitPullRequestEx gitPullRequest = mapper.convertValue(resource, GitPullRequestEx.class);
final PullRequestMergeCommitCreatedEventArgs args = decodeGitPullRequest(gitPullRequest, serviceHookEvent);
final PullRequestParameterAction parameterAction = new PullRequestParameterAction(args);
final Action teamPullRequestMergedDetailsAction = new TeamPullRequestMergedDetailsAction(gitPullRequest, message, detailedMessage, args.collectionUri.toString());
final ArrayList actions = new ArrayList();
actions.add(parameterAction);
actions.add(teamPullRequestMergedDetailsAction);
final List contributors = pollOrQueueFromEvent(args, actions, true);
final JSONObject response = fromResponseContributors(contributors);
return response;
}
static PullRequestMergeCommitCreatedEventArgs decodeGitPullRequest(final GitPullRequest gitPullRequest, final Event serviceHookEvent) {
final GitRepository repository = gitPullRequest.getRepository();
final URI collectionUri = determineCollectionUri(repository, serviceHookEvent);
final String repoUriString = repository.getRemoteUrl();
final URI repoUri = URI.create(repoUriString);
final String projectId = determineProjectId(repository);
final String repoId = repository.getName();
final String commit = determineMergeCommit(gitPullRequest);
final String pushedBy = determineCreatedBy(gitPullRequest);
final int pullRequestId = gitPullRequest.getPullRequestId();
final String targetBranch = determineTargetBranch(gitPullRequest);
final PullRequestMergeCommitCreatedEventArgs args = new PullRequestMergeCommitCreatedEventArgs();
args.collectionUri = collectionUri;
args.repoUri = repoUri;
args.projectId = projectId;
args.repoId = repoId;
args.commit = commit;
args.pushedBy = pushedBy;
args.pullRequestId = pullRequestId;
args.targetBranch = targetBranch;
return args;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/GitPushEvent.java
================================================
package hudson.plugins.tfs.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.teamfoundation.core.webapi.model.TeamProjectReference;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitCommitRef;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPush;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRepository;
import com.microsoft.visualstudio.services.webapi.model.IdentityRef;
import hudson.model.Action;
import hudson.plugins.git.GitStatus;
import hudson.plugins.tfs.CommitParameterAction;
import hudson.plugins.tfs.model.servicehooks.Event;
import hudson.plugins.tfs.model.servicehooks.ResourceContainer;
import hudson.plugins.tfs.util.ResourceHelper;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* A Git push event corresponding to the push of a set of commits on VSTS/TFS.
*/
public class GitPushEvent extends AbstractHookEvent {
/**
* Factory for creating a GitPushEvent.
*/
public static class Factory implements AbstractHookEvent.Factory {
@Override
public AbstractHookEvent create() {
return new GitPushEvent();
}
@Override
public String getSampleRequestPayload() {
return ResourceHelper.fetchAsString(this.getClass(), "GitPushEvent.json");
}
}
@Override
public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {
final Object resource = serviceHookEvent.getResource();
final GitPush gitPush = mapper.convertValue(resource, GitPush.class);
final GitCodePushedEventArgs args = decodeGitPush(gitPush, serviceHookEvent);
final CommitParameterAction parameterAction = new CommitParameterAction(args);
final ArrayList actions = new ArrayList();
actions.add(parameterAction);
final List contributors = pollOrQueueFromEvent(args, actions, false);
final JSONObject response = fromResponseContributors(contributors);
return response;
}
static URI determineCollectionUri(final URI repoApiUri) {
final String path = repoApiUri.getPath();
final int i = path.indexOf("_apis/");
if (i == -1) {
final String template = "Repository url '%s' did not contain '_apis/'.";
throw new IllegalArgumentException(String.format(template, repoApiUri));
}
final String pathBeforeApis = path.substring(0, i);
final URI uri;
try {
uri = new URI(repoApiUri.getScheme(), repoApiUri.getAuthority(), pathBeforeApis, repoApiUri.getQuery(), repoApiUri.getFragment());
} catch (final URISyntaxException e) {
throw new Error(e);
}
return uri;
}
static URI determineCollectionUri(final GitRepository repository, final Event serviceHookEvent) {
URI result = null;
final Map containers = serviceHookEvent.getResourceContainers();
if (containers != null) {
final String collection = "collection";
if (containers.containsKey(collection)) {
final ResourceContainer collectionContainer = containers.get(collection);
final String baseUrl = collectionContainer.getBaseUrl();
if (StringUtils.isNotEmpty(baseUrl)) {
result = URI.create(baseUrl);
}
}
}
if (result == null) {
final String repoApiUrlString = repository.getUrl();
final URI repoApiUri = URI.create(repoApiUrlString);
result = determineCollectionUri(repoApiUri);
}
return result;
}
static String determineProjectId(final GitRepository repository) {
final TeamProjectReference project = repository.getProject();
final String result = project.getName();
return result;
}
static String determineCommit(final GitPush gitPush) {
final List commits = gitPush.getCommits();
if (commits == null || commits.size() < 1) {
return null;
}
final GitCommitRef commit = commits.get(0);
return commit.getCommitId();
}
static String determinePushedBy(final GitPush gitPush) {
final IdentityRef pushedBy = gitPush.getPushedBy();
final String result = pushedBy.getDisplayName();
return result;
}
static String determineTargetBranch(final GitPush gitPush) {
// In the form of ref/heads/master
final String targetBranch = gitPush.getRefUpdates().get(0).getName();
String[] items = targetBranch.split("/");
return items[items.length - 1];
}
static GitCodePushedEventArgs decodeGitPush(final GitPush gitPush, final Event serviceHookEvent) {
final GitRepository repository = gitPush.getRepository();
final URI collectionUri = determineCollectionUri(repository, serviceHookEvent);
final String repoUriString = repository.getRemoteUrl();
final URI repoUri = URI.create(repoUriString);
final String projectId = determineProjectId(repository);
final String repoId = repository.getName();
final String commit = determineCommit(gitPush);
final String pushedBy = determinePushedBy(gitPush);
final String targetBranch = GitPushEvent.determineTargetBranch(gitPush);
final GitCodePushedEventArgs args = new GitCodePushedEventArgs();
args.collectionUri = collectionUri;
args.repoUri = repoUri;
args.projectId = projectId;
args.repoId = repoId;
args.commit = commit;
args.pushedBy = pushedBy;
args.targetBranch = targetBranch;
return args;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/GitStatusContext.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
public class GitStatusContext {
public String name;
public String genre;
public GitStatusContext() {
}
public GitStatusContext(final String name, final String genre) {
this.name = name;
this.genre = genre;
}
public static GitStatusContext fromJsonString(final String jsonString) {
final JSONObject jsonObject = JSONObject.fromObject(jsonString);
final GitStatusContext result;
final JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setRootClass(GitStatusContext.class);
result = (GitStatusContext) JSONObject.toBean(jsonObject, jsonConfig);
return result;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/GitStatusState.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
public enum GitStatusState {
NotSet(0),
Pending(1),
Succeeded(2),
Failed(3),
Error(4),
;
public static final Map CASE_INSENSITIVE_LOOKUP;
static {
final Map map = new TreeMap(String.CASE_INSENSITIVE_ORDER);
for (final GitStatusState value : GitStatusState.values()) {
map.put(value.name(), value);
}
CASE_INSENSITIVE_LOOKUP = Collections.unmodifiableMap(map);
}
@SuppressWarnings("unused" /* Invoked by Jackson via @JsonCreator */)
@JsonCreator
public static GitStatusState caseInsensitiveValueOf(final String name) {
if (name == null) {
throw new NullPointerException("Name is null");
}
if (!CASE_INSENSITIVE_LOOKUP.containsKey(name)) {
throw new IllegalArgumentException("No enum constant " + name);
}
return CASE_INSENSITIVE_LOOKUP.get(name);
}
private final int value;
GitStatusState(final int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/HttpMethod.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.microsoft.tfs.core.httpclient.methods.GetMethod;
import com.microsoft.tfs.core.httpclient.methods.HeadMethod;
import com.microsoft.tfs.core.httpclient.methods.PostMethod;
import com.microsoft.tfs.core.httpclient.methods.StringRequestEntity;
import hudson.plugins.tfs.util.MediaType;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
public enum HttpMethod {
GET {
@Override
public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {
return new GetMethod(uri);
}
},
POST,
HEAD {
@Override
public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {
return new HeadMethod(uri);
}
},
PATCH {
@Override
public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {
return innerCreateClientMethod(uri, body, MediaType.APPLICATION_JSON_PATCH_JSON);
}
},
OPTIONS,
PUT,
DELETE,
TRACE,
;
public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {
return innerCreateClientMethod(uri, body, MediaType.APPLICATION_JSON);
}
PostMethod innerCreateClientMethod(final String uri, final String body, final String contentType) {
final PostMethod method = new PostMethod(uri);
// https://www.visualstudio.com/en-us/docs/integrate/get-started/rest/basics#http-method-override
method.addRequestHeader("X-HTTP-Method-Override", this.name());
final String charset = MediaType.UTF_8.toString();
final StringRequestEntity requestEntity;
try {
requestEntity = new StringRequestEntity(body, contentType, charset);
}
catch (final UnsupportedEncodingException e) {
// this shouldn't happen
throw new Error(e);
}
method.setRequestEntity(requestEntity);
return method;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/JobCompletionEventArgs.java
================================================
package hudson.plugins.tfs.model;
/**
* This class holds the information needed to send the Job Completion event.
*/
public class JobCompletionEventArgs {
private final String serverKey;
private final String payload;
private final String payloadSignature;
/**
* Construtor.
* @param serverKey
* @param payload
* @param payloadSignature
*/
public JobCompletionEventArgs(final String serverKey, final String payload, final String payloadSignature) {
this.serverKey = serverKey;
this.payload = payload;
this.payloadSignature = payloadSignature;
}
public String getServerKey() {
return serverKey;
}
public String getPayload() {
return payload;
}
public String getPayloadSignature() {
return payloadSignature;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/JsonPatchOperation.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.microsoft.visualstudio.services.webapi.patch.Operation;
/**
* Workaround for broken version in
* com.microsoft.visualstudio.services.webapi.patch.json
* where #getPath() returns this.op
*/
public class JsonPatchOperation {
private Operation op;
private String path;
private Object value;
public Operation getOp() {
return op;
}
public void setOp(Operation op) {
this.op = op;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/LegacyIdentityManagementService.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import org.apache.commons.lang.NotImplementedException;
import com.microsoft.tfs.core.clients.webservices.GroupProperty;
import com.microsoft.tfs.core.clients.webservices.IIdentityManagementService;
import com.microsoft.tfs.core.clients.webservices.IdentityDescriptor;
import com.microsoft.tfs.core.clients.webservices.IdentitySearchFactor;
import com.microsoft.tfs.core.clients.webservices.MembershipQuery;
import com.microsoft.tfs.core.clients.webservices.ReadIdentityOptions;
import com.microsoft.tfs.core.clients.webservices.TeamFoundationIdentity;
import com.microsoft.tfs.util.GUID;
/**
* An {@link IIdentityManagementService} implementation to provide similar
* functionality to that provided by TFS 2010 and up on TFS 2008.
*
* Right now, the {@link TfsUserLookup} is the only consumer of
* {@link IIdentityManagementService} implementations, for the purpose of
* determining a TFS user's display name and e-mail address, given their
* account name.
*/
public class LegacyIdentityManagementService implements IIdentityManagementService {
public TeamFoundationIdentity[] readIdentities(IdentityDescriptor[] paramArrayOfIdentityDescriptor,
MembershipQuery paramMembershipQuery, ReadIdentityOptions paramReadIdentityOptions) {
throw new NotImplementedException();
}
public TeamFoundationIdentity readIdentity(IdentityDescriptor paramIdentityDescriptor, MembershipQuery paramMembershipQuery,
ReadIdentityOptions paramReadIdentityOptions) {
throw new NotImplementedException();
}
public TeamFoundationIdentity[] readIdentities(GUID[] paramArrayOfGUID, MembershipQuery paramMembershipQuery) {
throw new NotImplementedException();
}
public TeamFoundationIdentity[][] readIdentities(IdentitySearchFactor paramIdentitySearchFactor, String[] paramArrayOfString,
MembershipQuery paramMembershipQuery, ReadIdentityOptions paramReadIdentityOptions) {
throw new NotImplementedException();
}
public TeamFoundationIdentity readIdentity(IdentitySearchFactor searchFactor,
String accountName,
MembershipQuery membershipQuery, ReadIdentityOptions readIdentityOptions) {
return new TeamFoundationIdentity(new IdentityDescriptor("identityType", "identifier"), accountName, true, null, null);
}
public IdentityDescriptor createApplicationGroup(String paramString1, String paramString2, String paramString3) {
throw new NotImplementedException();
}
public TeamFoundationIdentity[] listApplicationGroups(String paramString, ReadIdentityOptions paramReadIdentityOptions) {
throw new NotImplementedException();
}
public void updateApplicationGroup(IdentityDescriptor paramIdentityDescriptor, GroupProperty paramGroupProperty,
String paramString) {
throw new NotImplementedException();
}
public void deleteApplicationGroup(IdentityDescriptor paramIdentityDescriptor) {
throw new NotImplementedException();
}
public void addMemberToApplicationGroup(IdentityDescriptor paramIdentityDescriptor1, IdentityDescriptor paramIdentityDescriptor2) {
throw new NotImplementedException();
}
public void removeMemberFromApplicationGroup(IdentityDescriptor paramIdentityDescriptor1,
IdentityDescriptor paramIdentityDescriptor2) {
throw new NotImplementedException();
}
public boolean isMember(IdentityDescriptor paramIdentityDescriptor1, IdentityDescriptor paramIdentityDescriptor2) {
throw new NotImplementedException();
}
public boolean refreshIdentity(IdentityDescriptor paramIdentityDescriptor) {
throw new NotImplementedException();
}
public String getScopeName(String paramString) {
throw new NotImplementedException();
}
public boolean isOwner(IdentityDescriptor paramIdentityDescriptor) {
throw new NotImplementedException();
}
public boolean isOwnedWellKnownGroup(IdentityDescriptor paramIdentityDescriptor) {
throw new NotImplementedException();
}
public String getIdentityDomainScope() {
throw new NotImplementedException();
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/Link.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Workaround for missing Link model class in current version of vso-httpclient-java
*/
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "Used by JsonPathOperation")
public class Link {
public String rel;
public String url;
public Link() {
}
public Link(final String rel, final String url) {
this.rel = rel;
this.url = url;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ListOfGitRepositories.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRepository;
import java.util.List;
public class ListOfGitRepositories {
public int count;
public List value;
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ManualCredentialsConfigurer.java
================================================
package hudson.plugins.tfs.model;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Extension;
import hudson.util.Secret;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* Manual credentials configurer.
*/
@SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Maintain compatibility")
public class ManualCredentialsConfigurer extends CredentialsConfigurer {
private static final long serialVersionUID = 1L;
private final transient String userName;
private final transient Secret password;
/**
* Constructor for data binding.
*/
@DataBoundConstructor
public ManualCredentialsConfigurer(final String userName, final Secret password) {
this.userName = userName;
this.password = password;
}
public String getUserName() {
return userName;
}
public Secret getPassword() {
return password;
}
@Override
public StandardUsernamePasswordCredentials getCredentials(final String collectionUri) {
final StandardUsernamePasswordCredentials credentials = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
null,
null,
this.userName,
this.password.getPlainText()
);
return credentials;
}
/**
* Class descriptor.
*/
@Extension
public static final class DescriptorImpl extends CredentialsConfigurerDescriptor {
@Override
public String getDisplayName() {
return "Manual";
}
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/MockableVersionControlClient.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.microsoft.tfs.core.TFSTeamProjectCollection;
import com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient;
import com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;
import com.microsoft.tfs.core.clients.versioncontrol.WorkspaceLocation;
import com.microsoft.tfs.core.clients.versioncontrol.WorkspaceOptions;
import com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;
import com.microsoft.tfs.core.clients.versioncontrol.Workstation;
import com.microsoft.tfs.core.clients.versioncontrol.events.EventSource;
import com.microsoft.tfs.core.clients.versioncontrol.events.VersionControlEventEngine;
import com.microsoft.tfs.core.clients.versioncontrol.exceptions.ItemNotMappedException;
import com.microsoft.tfs.core.clients.versioncontrol.exceptions.ServerPathFormatException;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.*;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;
import com.microsoft.tfs.core.clients.versioncontrol.specs.LabelItemSpec;
import com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;
import com.microsoft.tfs.core.clients.versioncontrol.workspacecache.WorkspaceInfo;
import com.microsoft.tfs.util.Closable;
import javax.annotation.Nonnull;
/**
* A non-final wrapper over {@link com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient}
*/
public class MockableVersionControlClient implements Closable {
private final VersionControlClient vcc;
private boolean isClosed = false;
public MockableVersionControlClient(final VersionControlClient vcc) {
this.vcc = vcc;
}
public void close() {
if (!isClosed) {
vcc.close();
isClosed = true;
}
}
private void makeSureNotClosed() {
if (isClosed) {
throw new UnsupportedOperationException("Instance has been closed and can no longer be used.");
}
}
/**
* Create or update a label for items in this workspace.
*
* @param label
* the label to create or update (must not be
null)
* @param items
* the items to be included in the label creation or update (not
* null).
* @param options
* options that affect the processing of the label creation or update
* (must not be null or empty).
* @return the label results, null if none were returned. May be empty but
* never null.
*/
public LabelResult[] createLabel(
final VersionControlLabel label,
final LabelItemSpec[] items,
final LabelChildOption options) {
makeSureNotClosed();
return vcc.createLabel(label, items, options);
}
/**
* Create a workspace on the server.
*
*
*
* This method is an core event origination point. The
* {@link EventSource} object that accompanies each event fired by this
* method describes the execution context (current thread, etc.) when and
* where this method was invoked.
*
* @param workingFolders
* the initial working folder mappings for this workspace. May be
* null, which means no working folders mapped.
* @param workspaceName
* the name of the new workspace (must not be null)
* @param owner
* the name of the workspace owner (if null, empty, or
* {@link VersionControlConstants#AUTHENTICATED_USER} the currently
* authorized user's name is used)
* @param ownerDisplayName
* the display name of the workspace owner (if null,
* empty, or {@link VersionControlConstants#AUTHENTICATED_USER} the
* currently authorized user's display name is used)
* @param comment
* an optional comment to be stored with this workspace (may be
* null).
* @param location
* where the workspace data is stored (if null, the
* server's default is used)
* @param options
* options to use on the newly created workspace (if
* null, the default options are used)
* @return the workspace object created by the server.
*/
public Workspace createWorkspace(
final WorkingFolder[] workingFolders,
final String workspaceName,
final String owner,
final String ownerDisplayName,
final String comment,
final WorkspaceLocation location,
final WorkspaceOptions options) {
makeSureNotClosed();
return vcc.createWorkspace(
workingFolders,
workspaceName,
owner,
ownerDisplayName,
comment,
location,
options
);
}
/**
* Delete a workspace on the server.
*
*
*
* This method is an core event origination point. The
* {@link EventSource} object that accompanies each event fired by this
* method describes the execution context (current thread, etc.) when and
* where this method was invoked.
*
* @param workspace
* the workspace to delete.
*/
public void deleteWorkspace(final Workspace workspace) {
makeSureNotClosed();
vcc.deleteWorkspace(workspace);
}
public TFSTeamProjectCollection getConnection() {
makeSureNotClosed();
return vcc.getConnection();
}
/**
* @return a reference to the EventEngine used by this client. Add (and
* remove) listeners to this event engine instance in order to be
* notified of events. All client events are dispatched through this
* event engine.
*/
public VersionControlEventEngine getEventEngine() {
makeSureNotClosed();
return vcc.getEventEngine();
}
/**
* Look up the local workspace for the specified repository, workspaceName
* and workspaceOwner combo. This will only ever return anything if the
* workspaceOwner matches the current user. This returns the actual
* instance, not a copy!
*/
public Workspace getLocalWorkspace(final String workspaceName, final String workspaceOwner) {
makeSureNotClosed();
return vcc.getLocalWorkspace(workspaceName, workspaceOwner);
}
/**
* Gets the latest changeset ID from the server.
*
* @return the changeset ID number of the latest changeset.
*/
public int getLatestChangesetID() {
makeSureNotClosed();
return vcc.getLatestChangesetID();
}
/**
* Retrieve the workspace that is mapped to the provided local path. This
* method searches all known workspaces on the current computer to identify
* a workspace that has explicitly or implicitly mapped the provided local
* path. If no workspace is found, this method throws a
* ItemNotMappedException.
*
* @param localPath
* A local path for which a workspace is desired (must not be
* null)
* @return A reference to the workspace object that has mapped the specified
* local path
* @throws ItemNotMappedException
* if the path is not mapped to any local workspace
*/
public Workspace getWorkspace(final String localPath) throws ItemNotMappedException {
makeSureNotClosed();
return vcc.getWorkspace(localPath);
}
/**
* Queries the server for history about an item. History items are returned
* as an array of changesets.
*
* @param serverOrLocalPath
* the server or local path to the server item being queried for its
* history (must not be null or empty).
* @param version
* the version of the item to query history for (history older than
* this version will be returned) (must not be null)
* @param deletionID
* the deletion ID for the item, if it is a deleted item (pass 0 if
* the item is not deleted).
* @param recursion
* whether to query recursively (must not be null)
* @param user
* only include historical changes made by this user (pass null to
* retrieve changes made by all users).
* @param versionFrom
* the beginning version to query historical changes from (pass null
* to start at the first version).
* @param versionTo
* the ending version to query historical changes to (pass null to
* end at the most recent version).
* @param maxCount
* the maximum number of changes to return (pass Integer.MAX_VALUE
* for all available values). Must be > 0.
* @param includeFileDetails
* true to include individual file change details with the returned
* results, false to return only general changeset information.
* @param slotMode
* if true, all items that have occupied the given serverPath (during
* different times) will have their changes returned. If false, only
* the item that matches that path at the given version will have its
* changes returned.
* @param sortAscending
* when true gets the top maxCount changes in ascending
* order, when false gets them in descending order
* @return the changesets that matched the history query, null if the server
* did not return a changeset array.
*/
public Changeset[] queryHistory(
final String serverOrLocalPath,
final VersionSpec version,
final int deletionID,
final RecursionType recursion,
final String user,
final VersionSpec versionFrom,
final VersionSpec versionTo,
final int maxCount,
final boolean includeFileDetails,
final boolean slotMode,
final boolean includeDownloadInfo,
final boolean sortAscending) throws ServerPathFormatException {
makeSureNotClosed();
return vcc.queryHistory(
serverOrLocalPath,
version,
deletionID,
recursion,
user,
versionFrom,
versionTo,
maxCount,
includeFileDetails,
slotMode,
includeDownloadInfo,
sortAscending
);
}
/**
* Query the collection of labels that match the given specifications.
*
* @param label
* the label name to match (may be null?).
* @param scope
* the scope of the label to match (may be null?).
* @param owner
* the owner of the label to match (may be null?).
* @param includeItemDetails
* if true, details about the labeled items are included in the
* results, otherwise only general label information is included.
* @param filterItem
* if not null, only labels containing this item are
* returned.
* @param filterItemVersion
* if filterItem was supplied, only labels that include this version
* of the filterItem are returned, otherwise may be null.
* @return the label items that matched the query. May be empty but never
* null.
*/
public VersionControlLabel[] queryLabels(
final String label,
final String scope,
final String owner,
final boolean includeItemDetails,
final String filterItem,
final VersionSpec filterItemVersion) {
makeSureNotClosed();
return vcc.queryLabels(
label,
scope,
owner,
includeItemDetails,
filterItem,
filterItemVersion
);
}
/**
* Returns the workspace on the server that matches the given parameters.
* Always queries the server immediately; does not check the local workspace
* cache.
*
* Unlike {@link VersionControlClient#queryWorkspaces(String, String, String)}, this method does
* not update the local workspace cache when workspaces are queried, because
* the workspace's computer is unknown (and the computer must be know to
* update the cache).
*
* @param name
* the workspace name to match, null to match all.
* @param owner
* the owner name to match, null to match all. Use
* {@link VersionControlConstants#AUTHENTICATED_USER} to retrieve
* workspaces owned by the currently logged in user.
* @return the matching workspace or null if no matching workspace was
* found.
*/
public Workspace queryWorkspace(final String name, final String owner) {
makeSureNotClosed();
return vcc.queryWorkspace(name, owner);
}
/**
* Returns all workspaces on the server that match the given parameters.
* Always queries the server immediately; does not check the local workspace
* cache.
*
* @param workspaceName
* the workspace name to match, null to match all.
* @param workspaceOwner
* the owner name to match, null to match all. Use
* {@link VersionControlConstants#AUTHENTICATED_USER} to retrieve
* workspaces owned by the currently logged in user.
* @param computer
* the computer name to match, null to match all. Use
* LocalHost.getShortName() to match workspaces for this computer.
* @param permissionsFilter
* find only workspaces matching the given permissions (must not be
* null) Use
* {@link WorkspacePermissions#NONE_OR_NOT_SUPPORTED} to find all
* workspaces.
* @return an array of matching workspaces. May be empty but never null.
*/
public Workspace[] queryWorkspaces(
final String workspaceName,
final String workspaceOwner,
final String computer,
@Nonnull final WorkspacePermissions permissionsFilter) {
makeSureNotClosed();
return vcc.queryWorkspaces(workspaceName, workspaceOwner, computer, permissionsFilter);
}
/**
* Removes a cached workspace that matches the given name and owner and this
* client's server's GUID from the {@link Workstation}'s cache. The caller
* is responsible for saving the {@link Workstation} cache.
*/
public WorkspaceInfo removeCachedWorkspace(final String workspaceName, String workspaceOwner) {
makeSureNotClosed();
return vcc.removeCachedWorkspace(workspaceName, workspaceOwner);
}
/**
* This is the same as GetWorkspace() except that it returns null rather
* than throwing ItemNotMappedException if the path is not in any known
* local workspace.
*
* @param localPath
* A local path for which a workspace is desired (must not be
* null)
* @return A reference to the workspace object that has mapped the specified
* local path or null if the local path is not in a local workspace
*/
public Workspace tryGetWorkspace(final String localPath) {
makeSureNotClosed();
return vcc.tryGetWorkspace(localPath);
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ModernConnectionAdvisor.java
================================================
package hudson.plugins.tfs.model;
import java.util.Locale;
import java.util.TimeZone;
import com.microsoft.tfs.core.config.ConnectionInstanceData;
import com.microsoft.tfs.core.config.DefaultConnectionAdvisor;
import com.microsoft.tfs.core.config.httpclient.HTTPClientFactory;
import com.microsoft.tfs.core.config.persistence.DefaultPersistenceStoreProvider;
import com.microsoft.tfs.core.config.persistence.PersistenceStoreProvider;
/**
* This connection advisor handles proxies appropriately by setting up a Modern http client factory.
*/
public class ModernConnectionAdvisor extends DefaultConnectionAdvisor {
private final ProxyHostEx proxyHost;
private final PersistenceStoreProvider persistenceStoreProvider;
/**
* Minimal constructor.
* @param proxyHost
*/
public ModernConnectionAdvisor(final ProxyHostEx proxyHost) {
this(proxyHost, null);
}
/**
* Constructor.
* @param proxyHost
* @param persistenceStoreProvider
*/
public ModernConnectionAdvisor(final ProxyHostEx proxyHost, final PersistenceStoreProvider persistenceStoreProvider) {
super(Locale.getDefault(), TimeZone.getDefault());
this.proxyHost = proxyHost;
this.persistenceStoreProvider = persistenceStoreProvider;
}
@Override
public PersistenceStoreProvider getPersistenceStoreProvider(final ConnectionInstanceData instanceData) {
return persistenceStoreProvider != null
? persistenceStoreProvider
: DefaultPersistenceStoreProvider.INSTANCE;
}
@Override
public HTTPClientFactory getHTTPClientFactory(final ConnectionInstanceData connectionInstanceData) {
return new ModernHTTPClientFactory(connectionInstanceData, proxyHost);
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/ModernHTTPClientFactory.java
================================================
package hudson.plugins.tfs.model;
import com.microsoft.tfs.core.config.ConnectionInstanceData;
import com.microsoft.tfs.core.config.httpclient.DefaultHTTPClientFactory;
import com.microsoft.tfs.core.httpclient.DefaultNTCredentials;
import com.microsoft.tfs.core.httpclient.HostConfiguration;
import com.microsoft.tfs.core.httpclient.HttpClient;
import com.microsoft.tfs.core.httpclient.HttpState;
import com.microsoft.tfs.core.httpclient.UsernamePasswordCredentials;
import com.microsoft.tfs.core.httpclient.auth.AuthScope;
import hudson.util.Secret;
/**
* Extends the default Http client factory to properly handle Proxy configurations.
*/
public class ModernHTTPClientFactory extends DefaultHTTPClientFactory {
private final ProxyHostEx proxyHost;
/**
* Constructor.
* @param connectionInstanceData
*/
public ModernHTTPClientFactory(final ConnectionInstanceData connectionInstanceData) {
this(connectionInstanceData, null);
}
/**
* Constructor.
* @param connectionInstanceData
* @param proxyHost
*/
public ModernHTTPClientFactory(final ConnectionInstanceData connectionInstanceData, final ProxyHostEx proxyHost) {
super(connectionInstanceData);
this.proxyHost = proxyHost;
}
@Override
protected String getUserAgentExtraString(final HttpClient httpClient, final ConnectionInstanceData connectionInstanceData) {
// https://stackoverflow.com/a/6773868/
final Class extends ModernHTTPClientFactory> me = this.getClass();
final Package us = me.getPackage();
String version = us.getImplementationVersion();
if (version == null) {
version = "devtest";
}
return "TFS-Jenkins " + version;
}
@Override
public void configureClientProxy(final HttpClient httpClient, final HostConfiguration hostConfiguration, final HttpState httpState, final ConnectionInstanceData connectionInstanceData) {
hostConfiguration.setProxyHost(proxyHost);
if (proxyHost != null) {
final String proxyUser = proxyHost.getProxyUser();
final Secret proxySecret = proxyHost.getProxySecret();
if (proxyUser != null && proxySecret != null) {
httpState.setProxyCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(proxyUser, proxySecret.getPlainText())
);
} else {
httpState.setProxyCredentials(
AuthScope.ANY,
new DefaultNTCredentials()
);
}
}
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/NativeLibraryExtractor.java
================================================
package hudson.plugins.tfs.model;
import java.io.IOException;
/**
* An interface for native library extractors.
*/
public interface NativeLibraryExtractor {
/**
* Method to extract files.
* @param operatingSystem
* @param architecture
* @param fileName
* @throws IOException
*/
void extractFile(String operatingSystem, String architecture, String fileName) throws IOException;
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/NativeLibraryManager.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.microsoft.tfs.core.persistence.FilesystemPersistenceStore;
import com.microsoft.tfs.core.persistence.PersistenceStore;
import com.microsoft.tfs.core.persistence.VersionedVendorFilesystemPersistenceStore;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class NativeLibraryManager implements NativeLibraryExtractor {
private static final String VENDOR_NAME = "Microsoft";
private static final String TFS_SDK = "TFS_SDK";
private static final String VERSION = "14.0.1";
private static final String nativeFolderPropertyName = "com.microsoft.tfs.jni.native.base-directory";
private static final String NATIVE = "native";
private static final Class metaClass = NativeLibraryManager.class;
private static final TreeMap>> NATIVE_LIBRARIES =
new TreeMap>>();
static {
final TreeMap> aix = new TreeMap>();
final List aix_ppc = Arrays.asList(
"libnative_auth.a",
"libnative_console.a",
"libnative_filesystem.a",
"libnative_misc.a",
"libnative_synchronization.a"
);
aix.put("ppc", aix_ppc);
NATIVE_LIBRARIES.put("aix", aix);
final TreeMap> freebsd = new TreeMap>();
final List freebsd_x86 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
freebsd.put("x86", freebsd_x86);
final List freebsd_x86_64 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
freebsd.put("x86_64", freebsd_x86_64);
NATIVE_LIBRARIES.put("freebsd", freebsd);
final TreeMap> hpux = new TreeMap>();
final List hpux_ia64_32 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
hpux.put("ia64_32", hpux_ia64_32);
final List hpux_PA_RISC = Arrays.asList(
"libnative_auth.sl",
"libnative_console.sl",
"libnative_filesystem.sl",
"libnative_misc.sl",
"libnative_synchronization.sl"
);
hpux.put("PA_RISC", hpux_PA_RISC);
NATIVE_LIBRARIES.put("hpux", hpux);
final TreeMap> linux = new TreeMap>();
final List linux_arm = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("arm", linux_arm);
final List linux_ppc = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("ppc", linux_ppc);
final List linux_x86 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("x86", linux_x86);
final List linux_x86_64 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("x86_64", linux_x86_64);
NATIVE_LIBRARIES.put("linux", linux);
final TreeMap> macosx = new TreeMap>(new Comparator() {
@SuppressWarnings("ComparatorMethodParameterNotUsed" /* because of null key */)
public int compare(final String o1, final String o2) {
return 0;
}
});
final List macosx_universal = Arrays.asList(
"libnative_auth.jnilib",
"libnative_console.jnilib",
"libnative_filesystem.jnilib",
"libnative_keychain.jnilib",
"libnative_misc.jnilib",
"libnative_synchronization.jnilib"
);
macosx.put(null, macosx_universal);
NATIVE_LIBRARIES.put("macosx", macosx);
final TreeMap> solaris = new TreeMap>();
final List solaris_sparc = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
solaris.put("sparc", solaris_sparc);
final List solaris_x86 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
solaris.put("x86", solaris_x86);
final List solaris_x86_64 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
solaris.put("x86_64", solaris_x86_64);
NATIVE_LIBRARIES.put("solaris", solaris);
final TreeMap> win32 = new TreeMap>();
final List win32_x86 = Arrays.asList(
"native_auth.dll",
"native_console.dll",
"native_credential.dll",
"native_filesystem.dll",
"native_messagewindow.dll",
"native_misc.dll",
"native_registry.dll",
"native_synchronization.dll"
);
win32.put("x86", win32_x86);
final List win32_x86_64 = Arrays.asList(
"native_auth.dll",
"native_console.dll",
"native_credential.dll",
"native_filesystem.dll",
"native_messagewindow.dll",
"native_misc.dll",
"native_registry.dll",
"native_synchronization.dll"
);
win32.put("x86_64", win32_x86_64);
NATIVE_LIBRARIES.put("win32", win32);
}
private final PersistenceStore store;
public NativeLibraryManager(final PersistenceStore store) {
this.store = store;
}
public void extractFiles() throws IOException {
// TODO: it would be great if we detected the current OS and architecture to extract only the needed files
extractFiles(this);
}
static void extractFiles(final NativeLibraryExtractor extractor) throws IOException {
for (final Map.Entry>> nativeLibrary : NATIVE_LIBRARIES.entrySet()) {
final TreeMap> architecturesToFileNames = nativeLibrary.getValue();
for (final Map.Entry> architectureToFilename : architecturesToFileNames.entrySet()) {
final List fileNames = architectureToFilename.getValue();
for (final String fileName : fileNames) {
extractor.extractFile(nativeLibrary.getKey(), architectureToFilename.getKey(), fileName);
}
}
}
}
public void extractFile(final String operatingSystem, final String architecture, final String fileName) throws IOException {
final String pathToNativeFile = buildPathToNativeFile(operatingSystem, architecture, fileName);
if (!store.containsItem(pathToNativeFile)) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = metaClass.getResourceAsStream(pathToNativeFile);
outputStream = store.getItemOutputStream(pathToNativeFile);
IOUtils.copy(inputStream, outputStream);
}
finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
}
// it is important that this return a string containing forward slashes
static String buildPathToNativeFile(final String operatingSystem, final String architecture, final String fileName) {
final StringBuilder sb = new StringBuilder(NATIVE.length() + 1 + operatingSystem.length() + 1 + 7 /* max architecture length */ + 1 + fileName.length());
sb.append(NATIVE).append('/');
sb.append(operatingSystem).append('/');
if (architecture != null) {
sb.append(architecture).append('/');
}
sb.append(fileName);
final String result = sb.toString();
return result;
}
public static synchronized void initialize() throws IOException {
final String nativeFolder = System.getProperty(nativeFolderPropertyName);
if (nativeFolder == null) {
final File vendor = new File(VENDOR_NAME);
final File vendor_sdk = new File(vendor, TFS_SDK);
final File vendor_sdk_version = new File(vendor_sdk, VERSION);
final FilesystemPersistenceStore store = new UserHomePersistenceStore(vendor_sdk_version);
final NativeLibraryManager manager = new NativeLibraryManager(store);
manager.extractFiles();
final File storeFile = store.getStoreFile();
final File nativeFile = new File(storeFile, NATIVE);
final String absolutePath = nativeFile.getAbsolutePath();
System.setProperty(nativeFolderPropertyName, absolutePath);
}
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/PingCommand.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import hudson.model.BuildableItem;
import hudson.model.Job;
import jenkins.util.TimeDuration;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;
public class PingCommand extends AbstractCommand {
public static class Factory implements AbstractCommand.Factory {
@Override
public AbstractCommand create() {
return new PingCommand();
}
@Override
public String getSampleRequestPayload() {
return "{\n" +
" \"parameter\":\n" +
" [\n" +
" {\"name\":\"id\",\"value\":\"123\"},\n" +
" {\"name\":\"verbosity\",\"value\":\"high\"}\n" +
" ]\n" +
"}\n";
}
}
@Override
public JSONObject perform(final Job project, final BuildableItem buildableItem, final StaplerRequest request,
final JSONObject requestPayload, final ObjectMapper mapper,
final TeamBuildPayload teamBuildPayload, final TimeDuration delay) {
return requestPayload;
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/PingHookEvent.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import hudson.plugins.tfs.model.servicehooks.Event;
import net.sf.json.JSONObject;
public class PingHookEvent extends AbstractHookEvent {
public static class Factory implements AbstractHookEvent.Factory {
@Override
public AbstractHookEvent create() {
return new PingHookEvent();
}
@Override
public String getSampleRequestPayload() {
return "{\n" +
" \"eventType\": \"ping\",\n" +
" \"resource\":\n" +
" {\n" +
" \"message\": \"Hello, world!\"\n" +
" }\n" +
"}";
}
}
@Override
public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {
return JSONObject.fromObject(serviceHookEvent);
}
}
================================================
FILE: tfs/src/main/java/hudson/plugins/tfs/model/Project.java
================================================
//CHECKSTYLE:OFF
package hudson.plugins.tfs.model;
import com.microsoft.tfs.core.clients.versioncontrol.specs.version.LatestVersionSpec;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.model.User;
import hudson.plugins.tfs.TeamPluginGlobalConfig;
import hudson.plugins.tfs.commands.GetFilesToWorkFolderCommand;
import hudson.plugins.tfs.commands.RemoteChangesetVersionCommand;
import hudson.plugins.tfs.model.ChangeSet.Item;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Changeset;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;
import com.microsoft.tfs.core.clients.versioncontrol.specs.LabelSpec;
import com.microsoft.tfs.core.clients.versioncontrol.specs.version.ChangesetVersionSpec;
import com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;
import com.microsoft.tfs.core.clients.versioncontrol.specs.version.LabelVersionSpec;
import com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;
import com.microsoft.tfs.core.clients.webservices.IIdentityManagementService;
public class Project {
private final String projectPath;
private final Server server;
private UserLookup userLookup;
public Project(Server server, String projectPath) {
this.server = server;
this.projectPath = projectPath;
}
public String getProjectPath() {
return projectPath;
}
static hudson.plugins.tfs.model.ChangeSet.Item convertServerChange
(com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change serverChange) {
final String path = serverChange.getItem().getServerItem();
final String action = serverChange.getChangeType().toUIString(true);
final Item result = new Item(path, action);
return result;
}
public static hudson.plugins.tfs.model.ChangeSet convertServerChangeset
(com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Changeset serverChangeset, UserLookup userLookup) {
final String version = Integer.toString(serverChangeset.getChangesetID(), 10);
final Date date = serverChangeset.getDate().getTime();
final String author = serverChangeset.getOwner();
final User authorUser = userLookup.find(author);
final String comment = serverChangeset.getComment();
final ChangeSet result = new ChangeSet(version, date, authorUser, comment);
final Change[] serverChanges = serverChangeset.getChanges();
for (final Change serverChange : serverChanges) {
final Item item = convertServerChange(serverChange);
result.add(item);
}
return result;
}
/**
* Returns a list of changes using TFS Java SDK
* @param fromVersion the version to get the history from
* @param toVersion the version to get the history to
* @param includeFileDetails whether or not to include details of modified items
* @param maxCount the maximum number of changes to return (pass Integer.MAX_VALUE for all available values).
* {@literal Must be > 0.}
* @return a list of change sets
*/
public List getVCCHistory(VersionSpec fromVersion, VersionSpec toVersion, boolean includeFileDetails, int maxCount) {
final UserLookup userLookup = getOrCreateUserLookup();
final MockableVersionControlClient vcc = server.getVersionControlClient();
final Changeset[] serverChangesets = vcc.queryHistory(
projectPath,
fromVersion != null ? fromVersion : toVersion,
0 /* deletionId */,
RecursionType.FULL,
null /* user */,
fromVersion,
toVersion,
maxCount,
includeFileDetails /* includeFileDetails */,
true /* slotMode */,
false /* includeDownloadInfo */,
false /* sortAscending */
);
final List result = new ArrayList();
if (serverChangesets != null) {
for (final Changeset serverChangeset : serverChangesets) {
final ChangeSet changeSet = convertServerChangeset(serverChangeset, userLookup);
result.add(changeSet);
}
}
return result;
}
@SuppressFBWarnings(value = "DC_DOUBLECHECK", justification = "Only synchronize if not null")
public UserLookup getOrCreateUserLookup() {
if (userLookup == null) {
synchronized (this) {
if (userLookup == null) {
final IIdentityManagementService ims = server.createIdentityManagementService();
final TeamPluginGlobalConfig teamPluginGlobalConfig = TeamPluginGlobalConfig.get();
final UserAccountMapper mapper = teamPluginGlobalConfig.getUserAccountMapper();
userLookup = new TfsUserLookup(ims, mapper);
}
}
}
return userLookup;
}
/**
* Returns a list of change sets containing modified items.
* @param fromTimestamp the timestamp to get history from
* @param toTimestamp the timestamp to get history to
* @return a list of change sets
*/
public List getDetailedHistory(Calendar fromTimestamp, Calendar toTimestamp) {
final DateVersionSpec fromVersion = new DateVersionSpec(fromTimestamp);
final DateVersionSpec toVersion = new DateVersionSpec(toTimestamp);
return getVCCHistory(fromVersion, toVersion, true, Integer.MAX_VALUE);
}
public List getDetailedHistory(final String singleVersionSpec) {
final VersionSpec toVersion = VersionSpec.parseSingleVersionFromSpec(singleVersionSpec, null);
return getVCCHistory(toVersion, toVersion, true, 1);
}
/**
* Returns a list of change sets not containing the modified items.
* @param fromTimestamp the timestamp to get history from
* @param toTimestamp the timestamp to get history to
* @return a list of change sets
*/
public List getBriefHistory(Calendar fromTimestamp, Calendar toTimestamp) {
final DateVersionSpec fromVersion = new DateVersionSpec(fromTimestamp);
final DateVersionSpec toVersion = new DateVersionSpec(toTimestamp);
return getVCCHistory(fromVersion, toVersion, false, Integer.MAX_VALUE);
}
/**
* Returns a list of change sets not containing the modified items.
* @param fromChangeset the changeset number to get history from
* @param toTimestamp the timestamp to get history to
* @return a list of change sets
*/
public List getBriefHistory(int fromChangeset, Calendar toTimestamp) {
final ChangesetVersionSpec fromVersion = new ChangesetVersionSpec(fromChangeset);
final VersionSpec toVersion = new DateVersionSpec(toTimestamp);
return getVCCHistory(fromVersion, toVersion, false, Integer.MAX_VALUE);
}
/**
* Returns the latest changeset at the project's path.
* @return the {@link ChangeSet} instance representing the last entry in the history for the path
*/
public ChangeSet getLatestChangeset() {
final List changeSets = getVCCHistory(LatestVersionSpec.INSTANCE, null, false, 1);
final ChangeSet result = changeSets.size() > 0 ? changeSets.get(0) : null;
return result;
}
/**
* Gets the latest changeset that isn't in a cloaked path.
* @param fromChangeset the changeset that was last seen, as a point of reference
* @param cloakedPaths the list of cloaked paths in the project
* @return the {@link ChangeSet} instance representing the last entry in the history for the path
*/
public ChangeSet getLatestUncloakedChangeset(final int fromChangeset, final Collection cloakedPaths) {
final ChangesetVersionSpec fromVersion = new ChangesetVersionSpec(fromChangeset);
final List changeSets = getVCCHistory(fromVersion, LatestVersionSpec.INSTANCE, true, Integer.MAX_VALUE);
final ChangeSet result = findLatestUncloakedChangeset(cloakedPaths, changeSets);
return result;
}
static ChangeSet findLatestUncloakedChangeset(final Collection cloakedPaths, final List changeSets) {
ChangeSet result = null;
// We need to search from latest to earliest, otherwise an incorrect result is produced
int lastChangeSetNumber = Integer.MAX_VALUE;
for (final ChangeSet s : changeSets) {
final String stringVersion = s.getVersion();
final int changeSetNumber = Integer.parseInt(stringVersion, 10);
if (changeSetNumber >= lastChangeSetNumber) {
throw new IllegalArgumentException("The changeset numbers must be strictly decreasing.");
}
lastChangeSetNumber = changeSetNumber;
final Collection changes = s.getAffectedPaths();
final boolean fullyCloaked = isChangesetFullyCloaked(changes, cloakedPaths);
if (!fullyCloaked) {
result = s;
break;
}
}
return result;
}
/**
* Returns a list of changesets without any changesets that are in cloaked paths
* @param fromTimestamp the timestamp to get history from
* @param toTimestamp the timestamp to get history to
* @param cloakedPaths the list of "cloaked" paths that would exclude
* changesets that are fully covered by one or more of these paths
* @return a list of change sets
*/
public List getDetailedHistoryWithoutCloakedPaths(final Calendar fromTimestamp, final Calendar toTimestamp, final Collection cloakedPaths) {
final DateVersionSpec fromVersion = new DateVersionSpec(fromTimestamp);
final DateVersionSpec toVersion = new DateVersionSpec(toTimestamp);
return getDetailedHistoryWithoutCloakedPaths(fromVersion, toVersion, cloakedPaths);
}
public List getDetailedHistoryWithoutCloakedPaths(final VersionSpec fromVersion, final VersionSpec toVersion, final Collection cloakedPaths) {
final List changeSets = getVCCHistory(fromVersion, toVersion, true, Integer.MAX_VALUE);
final ArrayList changeSetNoCloaked = new ArrayList();
for (final ChangeSet changeset : changeSets) {
final Collection affectedPaths = changeset.getAffectedPaths();
final boolean fullyCloaked = isChangesetFullyCloaked(affectedPaths, cloakedPaths);
if (!fullyCloaked) {
changeSetNoCloaked.add(changeset);
}
}
return changeSetNoCloaked;
}
static boolean isChangesetFullyCloaked(final Collection