[
  {
    "path": ".gitignore",
    "content": ".settings\r\n**/target\r\n**/workspaces\r\n**/work\r\n.project\r\n.classpath\r\n/.idea\r\n**/*.iml\r\n"
  },
  {
    "path": "Jenkinsfile",
    "content": "pipeline {\n    agent any\n    stages {\n        stage('Build') {\n            steps {\n                buildPlugin()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "README.md",
    "content": "Azure DevOps and Team Foundation Server plugin for Jenkins\n============================\nCopyright &copy; Erik Ramfelt, Olivier Dagenais, CloudBees, Inc. and others.\nLicensed under [MIT Licence].\n \n## Summary\nThis plugin triggers a release in Azure DevOps, through a post-build step in Jenkins.  It also integrates [Team Foundation Version Control] (also known as TFVC) and Git to Jenkins by connecting to Team Foundation Server (TFS). \n\n## Quick links\n* The legacy [wiki] page on the Jenkins Confluence instance\n* CI build status - [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins/tfs-plugin/master)](https://ci.jenkins.io/job/Plugins/job/tfs-plugin/job/master/)\n* Issues are tracked by the [Jenkins JIRA]\n* Download the latest release [from the Jenkins CDN](http://updates.jenkins-ci.org/latest/tfs.hpi) or [from the GitHub Releases page](https://github.com/jenkinsci/tfs-plugin/releases)\n\n## What can you do with it?\n\nThat depends on which version control system you use in Azure DevOps/TFS:\n\n### Team Foundation Version Control\n\nAllows you to use a TFVC repository as an SCM in a Jenkins jobs. At the moment, this plugin supports:\n* Retrieving read-only copies of files and folders from a TFVC repository.\n* Polling a TFVC repository to automatically start builds when there are changes.\n* Links from the Jenkins change sets to the TFVC repository web interface. _(Also known as a repository browser)_\n* Creating a label in the TFVC repository \n\nThe plugin will automatically create a workspace in TFS/Azure DevOps and map a work folder (in the Jenkins workspace) to it.\n\n\n### Git\n\nThe TFS plug-in for Jenkins adds some features to better integrate with Git repositories hosted in TFS/Azure DevOps:\n* A push trigger, to request builds of specific commits in Git repositories without needing to schedule SCM polling\n    * Instead of adding the **Build when a change is pushed to TFS/Azure DevOps** trigger to every job, you can also check the checkbox next to **Enable Push Trigger for all jobs** in the Jenkins global configuration.  Individual jobs can still opt-out of this global opt-in by enabling the **Poll SCM** trigger and checking its **Ignore post-commit hooks** checkbox.\n* A build step that adds a \"build pending\" status to the associated pull request and/or commit in TFS/Azure DevOps\n    * Instead of adding the **Set build pending status in TFS/Azure DevOps** build step to every job, you can also check the checkbox next to **Enable Team Status for all jobs** in the Jenkins global configuration.\n* A post-build action that add a \"build completed\" status to the associated pull request and/or commit in TFS/Azure DevOps\n    * Instead of adding the **Set build completion status in TFS/Azure DevOps** post-build action to every job, you can also check the checkboxbox next to **Enable Team Status for all jobs** in the Jenkins global configuration.\n* A link to (and summary information about) the associated TFS/Azure DevOps build that triggered the Jenkins build.\n* A link to (and summary information about) the associated TFS/Azure DevOps pull request that triggered the Jenkins build.\n    * Links to associated TFS/Azure DevOps work items.\n    * Associated TFS/Azure DevOps work items link back to the Jenkins build.\n\nThere are two possibilities to trigger a build with SCM Changeset:\n* TFS plugin  \n  Please refer to the [Webhooks with Azure DevOps](https://www.visualstudio.com/en-us/docs/service-hooks/services/webhooks) page for instructions on configuring the integration in TFS. Available endpoints can be found under [http://yourJenkins/team-events](http://yourJenkins/team-events)\n* Git plugin  \n  You have to enable Git SCM polling to receive commit notifications  \n  Please refer to the [Jenkins with Azure DevOps](https://www.visualstudio.com/en-us/docs/service-hooks/services/jenkins) page for instructions on configuring the integration in TFS.\n\n\n# Supported versions\n\nThe following sub-sections list the various versions of software that were tested and are thus supported.  The plugin might work with other versions, they just haven't been tested.\n\n## Team Foundation Server (TFS) / Azure DevOps\n\nThe following table indicates compatibility and support for versions of TFS and Azure DevOps.\n\n> Version | Supported by the TFS plugin? | Mainstream Support End Date\n> ------- | ------ | ---------------------------\n> [Azure DevOps] | :white_check_mark: | n/a\n> Visual Studio Team Foundation Server 2017 | :white_check_mark: | [2022/01/11](https://support.microsoft.com/en-us/lifecycle/search?alpha=Visual%20Studio%20Team%20Foundation%20Server%202017)\n> Visual Studio Team Foundation Server 2015 | :white_check_mark: | [2020/10/13](https://support.microsoft.com/en-us/lifecycle?p1=18576)\n> Microsoft Visual Studio Team Foundation Server 2013 | :white_check_mark: | [2019/04/09](https://support.microsoft.com/en-us/lifecycle?p1=17358)\n> Microsoft Visual Studio Team Foundation Server 2012 | :white_check_mark: | [2018/01/09](https://support.microsoft.com/en-us/lifecycle?p1=16804)\n> Microsoft Visual Studio Team Foundation Server 2010 | :x: | :warning: [2015/07/14](https://support.microsoft.com/en-us/lifecycle?p1=15011)\n> Microsoft Visual Studio Team System 2008 Team Foundation Server | :x: | :warning: [2013/04/09](https://support.microsoft.com/en-us/lifecycle?p1=13083)\n> Microsoft Visual Studio 2005 Team Foundation Server | :x: | :warning: [2011/07/12](https://support.microsoft.com/en-us/lifecycle?p1=10449)\n\nWhereas for **Trigger release in TFS/Azure DevOps** post build action, only following table is supported:\n\n> Version | Supported by the TFS plugin? | Mainstream Support End Date\n> ------- | ------ | ---------------------------\n> [Azure DevOps] | :white_check_mark: | n/a\n> [Team Foundation Server \"15\" RC1] | :white_check_mark: | n/a\n\n## Operating Systems\n\nThe plugin has been tested against the following operating systems and versions, with the latest updates as of 2015/08/27.\n\nName | Version\n---- | -------\nWindows Server | 2012 R2\nMac OS X | Yosemite 10.10.5\nUbuntu Linux | Server 14.04 LTS\n\n## Jenkins\n\nThe plugin is built against Jenkins version **1.580** and that's the version integration tests are run against.\n\n# Configuration\n\n## Requirements\n\n### 4.0.0 and later (New!)\n\nEver since release 4.0.0, a command-line client or tool is no longer necessary as all the interaction with TFS or Azure DevOps is done using the [TFS SDK for Java].  The native libraries needed by the SDK are automatically copied to a sub-directory under the agent user's home folder.\n\n### 3.2.0 and earlier\n\nVersions 3.2.0 and earlier of the plugin required a command line tool to be installed on the build agents to retrieve source code from the TFVC repository.\n\n1. Install either Microsoft Visual Studio or [Microsoft Team Explorer Everywhere] Command-Line Client (CLC) on the build agents\n2. Add `tf.exe` (Visual Studio) OR one of `tf.cmd` or `tf` (TEE CLC) to the `PATH` of the build agents' user(s).\n\n## Global configuration\n\nTo make use of the Git integration with TFS/Azure DevOps and/or to use automatic credentials configuration with the TFVC SCM, it is necessary to first configure your team project collection(s).  Follow these instructions for each team project collection (most organizations will only have one).\n\n1. Add credentials:\n    1. Select **Jenkins** > **Credentials**\n    2. Select **Add domain**\n        1. In the _Domain Name_ field, enter the host's friendly name, such as `fabrikam-fiber-inc`\n        2. In the _Description_ field, you can enter some notes, such as who maintains the server, etc.\n        3. Next to _Specification_, select **Add** > **Hostname**\n            1. In the _Include_ field, enter the Fully-Qualified Domain Name (FQDN), such as `fabrikam-fiber-inc.visualstudio.com`\n        4. Click **OK**\n    3. Select **Add Credentials**\n        1. For the _Kind_ field, select **Username with password**\n        2. For the _Scope_ field, select **Global (Jenkins, nodes, items, all child items, etc)**\n        3. See the _User name and password_ section below for the values of the _Username_ and _Password_; a Personal Access Token (PAT) is strongly recommended.  If the credentials will be used for TFVC, select **All scopes**, otherwise select the following _Authorized Scopes_:\n            1. `Code (read)`\n            2. `Code (status)`\n            3. `Work items (read and write)`\n        4. You can use the _Description_ field to record details about the PAT, such as its intended collection, the selected authorization scopes and expiration date.  For example: `fabrikam-fiber-inc, code read+status, wit read+write, expires 2017-08-05`\n        5. Click **OK**   \n2. Add the collection URL and associate it with the right credentials:\n    1. Select **Jenkins** > **Manage Jenkins** > **Configure System**\n    2. Scroll to **TFS/Azure DevOps** and click **Add**\n        1. If using Azure DevOps, the value of the _Collection URL_ field should omit `/DefaultCollection`.\n        2. Select the associated `Credentials` value created earlier.\n        3. Click **Test Connection**.\n    3. Click **Save**\n\n### Automatic integration\n\nTo avoid having to configure every job to enable integration features, you can check the checkbox next to either or both of:\n\n* Enable Push Trigger for all jobs\n* Enable Team Status for all jobs\n\n![Automatic Integration](images/AutomaticIntegration.png)\n\n### Advanced\n\nIn some environments, the \"home\" directory is mounted over a network and shared between many computers, including Jenkins servers and their associated build nodes, which eventually leads to corruption of the configuration directory used for TFVC workspaces.  If you have such an environment, check the box next to **Store TFVC configuration in computer-specific folders** to use a sub-directory for each computer. :warning: WARNING :warning: Turning this on is equivalent to setting the `TEE_PROFILE_DIRECTORY` environment variable and thus any manual operations performed using the Command-Line Client (CLC) will need to be performed with the `TEE_PROFILE_DIRECTORY` environment variable set accordingly.\n\n## Job configuration\n\n### Team Foundation Version Control\n\nIf your source code is in a TFVC repository, this section is for you.\n\n![SCM configuration](images/tfs-job-config4.png)\n\nField | Description\n----- | -----------\n`Collection URL` | The URL to the [Team Project Collection](https://msdn.microsoft.com/en-us/library/dd236915(v=vs.120).aspx). If you added your team project collection(s) in the global configuration, the field will show you a list to pick from. Examples: `https://tfs02.codeplex.com`, `https://fabrikam-fiber-inc.visualstudio.com`, `http://tfs:8080/tfs/DefaultCollection`\n`Project path` | The Team Project and path to retrieve from the server. The project path must start with `$/`, and contain any sub path that exists in the project repository. Example: `$/Fabrikam-Fiber-TFVC/AuthSample-dev`\n`Credentials` | If you added your team project collection(s) in the global configuration, select **Automatic** and the credentials will be looked up automatically, otherwise you can select **Manual** and configure the `User name` and `User password` fields.\n`Manual` > `User name` | The name of the user that will be connecting to TFS/Azure DevOps to query history, checkout files, etc. See _User name and password_ below for a full description.\n`Manual` > `User password` | The password, alternate password or personal access token associated with the user. See _User name and password_ below for more details.\n`Use update` | If this option is checked, then the workspace will not be deleted and re-created at the start of each build, making the build faster, but this causes the artifacts from the previous build to remain when a new build starts.\n`Local workfolder` | The name of the local work folder. The specified folder will contain the files retrieved from the repository. Default is `.`, ie the files will be downloaded into the Hudson workspace folder.\n`Workspace name` | The name of the workspace that Jenkins should use when creating and deleting workspaces on the server. The workspace name supports three macros; `${JOB_NAME}` is replaced by the job name, `${USER_NAME}` is replaced by the user name Jenkins is running as and `${NODE_NAME}` is replaced by the name of the node. Default workspace name is `Hudson-${JOB_NAME}-${NODE_NAME}`.\n`Cloaked paths` | A collection of server paths to cloak to exclude from the workspace and from the build trigger. Multiple entries must be placed onto separate lines.\n`Repository browser` | Select `Microsoft Team Foundation Server/Azure DevOps` to turn on links inside Jenkins jobs (in the **Changes** page) back to TFS/Azure DevOps, for easier traceability.  If the TFS server is reached by users through a different URL than that provided in `Collection URL`, such as the Fully-Qualified Domain Name (FQDN), provide a value for the `URL` sub-field.\n\n### Git\n\nIf your source code is in a Git repository located on a TFS/Azure DevOps server, this section is for you.\n\n> :warning: Make sure you first followed the instructions in the **Global configuration** section and added your team project collection(s), associated with credentials. :warning:\n\n![Git configuration](images/git-job-config.png)\n\nIf you didn't have the Git plug-in for Jenkins already, installing the TFS plug-in for Jenkins should have brought it on as a dependency.\n\n1. Use the **Git** _Source Code Management_ and add the URL to your Git repository in TFS/Azure DevOps, omitting the `/DefaultCollection` if you are using Azure DevOps.\n2. If you haven't done so already, follow the instructions in the \"User name and password\" section to generate a Personal Access Token, and then add a \"Credentials\" entry as specified in the \"Global configuration\" section.  You should then be able to select it in the _Credentials_ field.\n3. To be able to build the merge commits created for pull requests in TFS/Azure DevOps, click the **Advanced...** button\n    1. In the _Name_ field, enter **origin** (or some unique name if you already have other repositories)\n    2. In the _Refspec_ field, enter `+refs/heads/*:refs/remotes/origin/* +refs/pull/*:refs/remotes/origin-pull/*` (replacing \"origin\" as necessary)\n4. If you haven't already enabled the Push Trigger for all jobs, scroll down to _Build Triggers_ and you can check the **Build when a change is pushed to TFS/Azure DevOps** checkbox.\n5. If you haven't already enabled Team Status for all jobs, scroll down to _Build_, select **Add build step** > **Set build pending status in TFS/Azure DevOps**, moving it _first_ in the list of steps, to notify TFS/Azure DevOps as early as possible that a Jenkins build has been started.\n6. Add other build steps, as necessary. \n7. If you haven't already enabled Team Status for all jobs, scroll down to _Post-build Actions_, select **Add post-build action** > **Set build completion status in TFS/Azure DevOps**.\n8. If you would like to collect results for publication in TFS/Azure DevOps, scroll down to _Post-build Actions_, select **Add post-build action** > **Collect results for TFS/Azure DevOps** and then add one or more results to collect.\n9. If the Jenkins job will be used to validate pull requests in TFS/Azure DevOps and you would like to add links from the associated work items back to the Jenkins build, select **Add post-build action** > **Add link to associated work items in TFS/Azure DevOps**.\n\n### User name and password\n\n#### Team Foundation Server (on-premises)\n\nFor \\[on-premises\\] Team Foundation Server, the _User name_ can be specified in two ways:\n\n1. `EXAMPLE-DOMAIN\\user`\n2. `user@domain.example.com`\n\n#### Azure DevOps (previously known as Visual Studio Team Services or VSTS)\n\nFor Azure DevOps, there are also two options:\n\n1. Personal access tokens (recommended)\n    1. In Azure DevOps, click your name in the top right corner and select **Security**.\n    2. In the _Personal access tokens_ area, select **Add**.\n    3. Describe the token (use something like \"Jenkins server at jenkins.example.com\"), select an expiry timeframe, double-check the Azure DevOps account the token will be valid for and, if the user account will be used for TFVC, select **All scopes** otherwise you can select smaller scopes based on what features you will need.\n    4. Click **\\[Create Token\\]** and copy the generated personal access token to the clipboard.\n    5. Back to Jenkins, enter the e-mail address associated with your Azure DevOps account as the _User name_ and the generated personal access token as the _User password_.\n2.  Alternate credentials\n    1. In Azure DevOps, click your name in the top right corner and select **Security**.\n    2. In the _Alternate credentials_ area, select **Enable alternate authentication credentials**.\n    3. Enter a secondary user name and password, then click **\\[Save\\]**.\n    4. Back to Jenkins, re-enter those credentials in the _User name_ and _User password_ fields.\n\n\n## Checkout by label (New since version 3.2.0)\n\nThe plugin now supports checking out from a specific label or any valid [versionspec](https://www.visualstudio.com/docs/tfvc/use-team-foundation-version-control-commands#use-a-versionspec-argument-to-specify-affected-versions-of-items).  Here's how to configure a job to do that:\n\n> :information_source: Polling the server doesn't make sense when you want to build for a specific label because polling is not \\[currently\\] label-aware and could queue a build **every polling interval**. :information_source:\n\n1. Turn **off** SCM polling by making sure the **Poll SCM** checkbox is _cleared_ (unchecked).\n2. Tick the **This build is parameterised** checkbox\n    1. Add a **String Parameter**\n    2. Set its _Name_ to **VERSION_SPEC**\n    3. Set its _Description_ to the following:\n    ```\n    Enter a valid version spec to use when checking out.\n    Labels are prefixed with \"L\" and changesets are prefixed with \"C\".\n    See the following for a versionspec reference: https://www.visualstudio.com/docs/tfvc/use-team-foundation-version-control-commands#use-a-versionspec-argument-to-specify-affected-versions-of-items\n    Examples: \"LFoo\", \"C42\"\n    ```\n3. **Save** the job.\n\nNow, the next time you want to queue a build, you will need to provide a value for the **VERSION_SPEC** parameter.  The build will then perform a checkout of the source as of the specified **VERSION_SPEC**.\n\n## Proxy server support (New since version 4.1.0)\n\nIn the event Jenkins is deployed on a network with no direct access to other networks (such as the internet), the TFS plugin now supports connecting through proxy servers.\n\n> :information_source: Support for proxy servers requiring authentication was added in version 5.1.0. :information_source:\n\nFollow the instructions at [JenkinsBehindProxy](https://wiki.jenkins-ci.org/display/JENKINS/JenkinsBehindProxy) to configure Jenkins' use of a proxy server, which the TFS plugin also uses.\n\n## Integration with TFS/Azure DevOps (New since version 5.0.0)\n\nThere are some steps to perform in both Jenkins and in TFS/Azure DevOps to activate the integration.  This section assumes you have already configured one or more team project collections, as described in the **Global configuration** section above and then configured the Jenkins jobs as described in the **Git** section above.\n\n### Trigger builds when code is pushed to a Git repository in TFS/Azure DevOps\n\n1. Go to the team project's _Administration_ and then select **Service Hooks**\n2. Select the `+` button\n3. Select **Jenkins** and click **Next**\n4. Select **Code pushed**, configure the **Filters** and click **Next**\n5. You can now configure which action will be performed.  The choices are **Trigger generic build** and **Trigger Git build**.  Once you select the action, its _Settings_ must be configured\n    1. Enter the URL to your Jenkins server. (hint: it's the destination when you click the Jenkins logo in the top left)\n    2. Enter your _User name_\n    3. For the _User API token_, click on your user name in Jenkins (in the top-right corner), then **Configure** and finally click the **Show API Token...*** button.  Copy & paste the token back in TFS/Azure DevOps\n    4. Once valid credentials have been provided, more fields will become available.  If you selected **Trigger generic build**, keep going with these fields\n        1. The _Build_ field should now be configurable as a drop-down list\n        2. Add any additional parameters, if any\n    5. Click **Test**, inspect the results of the test and click **Close**\n    6. If the test was successful, click **Finish**\n\n### Trigger builds when a pull request is created or updated in TFS/Azure DevOps\n\n1. Go to the team project's _Administration_ and then select **Service Hooks**\n2. Select the `+` button\n3. Select **Jenkins** and click **Next**\n4. Select one of **Code pushed** or **Pull request merge commit created**, configure the **Filters** and click **Next**\n5. The only action available is **Trigger generic build**, its _Settings_ must be configured\n    1. Enter the URL to your Jenkins server. (hint: it's the destination when you click the Jenkins logo in the top left)\n    2. Enter your _User name_\n    3. For the _User API token_, click on your user name in Jenkins (in the top-right corner), then **Configure** and finally click the **Show API Token...*** button.  Copy & paste the token back in TFS/Azure DevOps\n    4. Once valid credentials have been provided, more fields will become available\n    5. The _Build_ field should now be configurable as a drop-down list\n    6. Add any additional parameters, if any\n    7. Click **Test**, inspect the results of the test and click **Close**\n    8. If the test was successful, click **Finish**\n\n\n## Build environment variables\n\nThe plugin will set the following environment variables for the build, after a checkout:\n\n* **TFS_WORKSPACE** \\- The name of the workspace.\n* **TFS_WORKFOLDER** \\- The full path to the working folder.\n* **TFS_PROJECTPATH** \\- The TFVC project path that is mapped to the workspace.\n* **TFS_SERVERURL** \\- The URL to the Team Project Collection.\n* **TFS_USERNAME** \\- The user name that is used to connect to TFS/Azure DevOps.\n* **TFS_CHANGESET** \\- The change set number that is checked out in the workspace\n\n# Trigger release in TFS/Azure DevOps\n\n[MSDN documentation](https://blogs.msdn.microsoft.com/visualstudioalm/2016/05/27/continuous-deploymentdelivery-with-jenkins-and-vs-team-services/)\n\n### Overview\nOnce you have configured Continuous Integration (CI) with Jenkins to be able to build with every code checkin/commit, the next step toward automating your DevOps pipeline is to be able to deploy automatically by setting up the Continuous Deployment (CD) pipeline.\n\n[VS Team Service Release Management](https://www.visualstudio.com/features/release-management-vs) service lets you automate your deployments so that you could deliver your apps/services easily and deliver them often. You can setup the CI and CD process all on VS Azure DevOps. However, if you have the CI pipleine already set with Jenkins, VS Team Service has good integration points through its [APIs](https://www.visualstudio.com/integrate/api/overview#Releasepreview) that can let you interact with its release service from any other third-party - Jenkins in this case.\n\nThis plugin makes use these APIs that lets you trigger a release in VS Azure DevOps or TFS, upon completion of a build in Jenkins. The plugin has a post build step - \"VS Azure DevOps Continuous Deployment\".\n\n### Using the plugin\n\nAssuming that you have already [created the Release Definition](https://www.visualstudio.com/en-us/docs/release/author-release-definition/more-release-definition) and [linked the Jenkins as artifact source](https://www.visualstudio.com/en-us/docs/release/author-release-definition/understanding-artifacts#jenkins) in TFS/Azure DevOps - Release Management, you need to follow the following steps at the Jenkins side to trigger releases automatically, upon build creation.\n\n**0. Setup Release Definition with Jenkins as artifact source**\nThis document assumes that you have already set up the RM definition that uses Jenkins artifact to deploy. This means your build/job is configured properly and archives artifacts. If not, see the following video to set up Release Definition with Jenkins build\n\n[![Release Jenkins artifact](images/rmWithJenkins-YT.png)](https://www.youtube.com/watch?v=ZC4hWYqdP_o&index=5&list=PLP3SfFPBD6cTJ2Jp5cHvjQ3flrbwQu-nN)\n\n\n**1. Add the post build action**\nGo to the Job configuration and add the post build action - **Trigger release in TFS/Azure DevOps**.\n![Add post build action](images/addPostBuildAction.png)\n\n**2. Fill in the required fields**\nFill in the details required for this post build action. You need the following details:\n* **Collection URL:** e.g. https://fabfiber.visualstudio.com/**DefaultCollection** <- Note that you need the url till the collection.\n* **Team project:** The VS Azure DevOps Project in which you have defined the release definition.\n* **Release definition:** The Release definition **name** that links this Jenkins job as an artifact source.\n\nYou need to now enter the credentials that lets Jenkins trigger a release with the latest completed build, on your behalf. If you are using VS Azure DevOps, you just need to enter **PAT** with atleast \"Release (read, write and execute)\" scope. (Refer to this [link](https://www.visualstudio.com/en-us/get-started/setup/use-personal-access-tokens-to-authenticate) to understand how to create PAT). In case you are using TFS, you need to enter the **username** and **password**.\n\n![Add post build action](images/fillFieldsForPostBuildAction.JPG)\n\n**3. All set. See CD in action**\nYou have now automated your deployment trigger thereby enabling continuous deployment i.e. a checkin/commit would trigger a build and that will trigger a release.\nGo ahead and test your setup by manually triggering a build in Jenkins or by a code checkin/commit that kicks off Jenkins build which in turn will trigger the release in VS Azure DevOps.\n\n\n# FAQ\n\n### How should I set up the plugin for my CodePlex project?\n\n* Find out the server for your project, which is displayed in the source code page for your project at codeplex.com.\n* The user name must be suffixed with `_cp` and the domain is `snd`. If your user name is redsolo, then enter \"`snd\\redsolo_cp`\" as the user name in the plugin configuration.\n* Note that the user must be a member of the project to be able to create a workspace on the CodePlex server.\n\nThat's all you need to do to start retrieving files from your project at codeplex.com.\n\n### The plugin is having problems parsing the dates that TF outputs, what can I do?\n\n> :information_source: If you can upgrade to version 4 and up, then you can avoid a whole class of TF output parsing difficulties, otherwise, read on. :information_source:\n\nThe TF command line outputs date according to the locale and Microsofts own specification. Sometimes the outputed date can not be parsed by any of the default locale dependent parsers that the JDK includes (_for some more details, see_ _[JENKINS-4184]_ _and_ _[JENKINS-4021]_). This will throw an exception in the change set parsing and fail the build.\n\nTo fix this, do the following:\n* Change the locale by Windows Regional Settings to United States and English on the server and all hudson nodes. After that tf.exe should output dates in english, which can be parsed properly.\n* Start Hudson using the UnitedStates, English locale. Either set it using `-Duser.language=en -Duser.country=US` on the command line or check the documentation for the container that Hudson is running within.\n\n### If I have multiple artifacts linked in my Release Definition, will this plugin trigger a release?\nYes, it is supported from 1.3 version onwards.\n\n# Timeline\n\n## Future\n\nThe best way to get an idea of what will be coming in future releases is to look at the [list of open pull requests](https://github.com/jenkinsci/tfs-plugin/pulls).\n\n## Present\n\nThe next release will be 5.3.0.  See what's been committed [since 5.2.1](https://github.com/jenkinsci/tfs-plugin/compare/tfs-5.2.1...master) and the upcoming [ReleaseNotes.md](ReleaseNotes.md).\n\n## Past\n\nDetails about previous releases can be found on the [Releases page](https://github.com/jenkinsci/tfs-plugin/releases).\n\n[wiki]: http://wiki.jenkins-ci.org/display/JENKINS/Team+Foundation+Server+Plugin\n[MIT Licence]: http://opensource.org/licenses/MIT\n[CloudBees]: https://www.cloudbees.com/\n[Jenkins JIRA]: 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+%27tfs-plugin%27\n[Team Foundation Version Control]: https://msdn.microsoft.com/en-us/library/ms181237.aspx\n[Azure DevOps]: https://www.visualstudio.com/products/visual-studio-team-services-vs\n[TFS SDK for Java]: http://blogs.msdn.com/b/bharry/archive/2011/05/16/announcing-a-java-sdk-for-tfs.aspx\n[Microsoft Team Explorer Everywhere]: http://www.microsoft.com/en-us/download/details.aspx?id=40785\n[JENKINS-4021]: https://issues.jenkins-ci.org/browse/JENKINS-4021\n[JENKINS-4184]: https://issues.jenkins-ci.org/browse/JENKINS-4184\n"
  },
  {
    "path": "ReleaseNotes.md",
    "content": "These notes are for release **(to be determined)**.\nOther releases and their notes can be found at the [tfs-plugin GitHub Releases](https://github.com/jenkinsci/tfs-plugin/releases) page.\n\n* Major:\n    * TODO\n\n* Minor:\n    * TODO\n    \n"
  },
  {
    "path": "Releasing.md",
    "content": "Pre-requisites\r\n==============\r\n\r\n1. Machine: preferably Linux over Windows, to avoid any weirdness between Cygwin and Git for Windows\r\n    1. Oracle JDK 8 (see note in [Installing Jenkins on Red Hat distributions](https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+on+Red+Hat+distributions) about CentOS's default Java)\r\n    1. Maven 3.2 or better\r\n    1. A recent enough Git\r\n    1. Make sure the `COMPUTERNAME` environment variable is defined, as the end-to-end tests rely on its presence.  One can use the [EnvInject plugin](https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin) to set it during the execution of the release job.\r\n1. A GitHub clone you can pull from and push to non-interactively. (Consider configuring GitHub with a public key and use the SSH protocol for everything)\r\n1. A \"Jenkins infrastructure\" account.  They have some sort of LDAP server that provides SSO for JIRA, Confluence and Artifactory.\r\n    1. If you can log in to https://repo.jenkins-ci.org with your account, you're set to punch in those credentials in your `~/.m2/settings.xml` file:\r\n    ```xml\r\n    <?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n    <settings\r\n      xsi:schemaLocation=\"http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd\" \r\n      xmlns=\"http://maven.apache.org/SETTINGS/1.1.0\"\r\n      xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n      <servers>\r\n        <server>\r\n          <id>repo.jenkins-ci.org</id>\r\n          <username>TODO</username>\r\n          <password>TODO</password>\r\n        </server>\r\n      </servers>\r\n    </settings>\r\n    ```\r\n    2. A great test is to try to perform a `mvn deploy`, which should attempt to upload some files to the snapshot repo and will need those credentials.\r\n\t3. If you're worried about putting your \"Jenkins infrastructure\" password  in plain-text in that file, Maven has a password encryption facility that relies on a master password in another file.  Presumably, you secure access to the 2nd file by placing it on a thumbdrive that you carry with you when you're not at your computer, etc.\r\n1. A TFS server or a Azure DevOps account, configured as per `Testing.md`\r\n\r\nRelease\r\n=======\r\n\r\n1. Pre-release.  Perform these manual steps on your workstation:\r\n    1. Run a full build, with all its end-to-end tests; it takes about 5 minutes:\r\n    ```\r\n    mvn clean verify --batch-mode -Dtfs_server_name=&lt;TFS host name or Azure DevOps account host name> -Dtfs_user_name=&lt;user> -Dtfs_user_password=&lt;password>\r\n    ```\r\n    2. Look at the commits since the last release by going to https://github.com/jenkinsci/tfs-plugin/releases and clicking the \"XX commits to master since this release\" link.  It will be easiest to surf the associated pull requests, so hit Ctrl+F, search for \"Merge pull request\" and Ctrl+click every #XXX link to the right of the highlights.\r\n    3. Fill in the categories of the `ReleaseNotes.md` template, usually in one of the following formats:\r\n        1. &lt;Summary>. Thanks to @&lt;GitHub user name> for pull request #&lt;pull request number>.\r\n        2. &lt;Summary>, via pull request #&lt;pull request number>.\r\n    4. Decide on the release version and on the next development version, based on the rules of [Semantic Versioning](http://semver.org/).\r\n    5. Update `ReleaseNotes.md` with the release version and merge/push to `master`.\r\n    6. Merge any \"wiki\" changes to `master`.\r\n2. Automated release.  Create a Jenkins job as follows:\r\n    1. General\r\n        1. Check \"This project is parameterised\"\r\n            1. String parameter **releaseVersion**\r\n            2. String parameter **developmentVersion**\r\n    2. SCM\r\n        1. Git\r\n            1. Repository Url: **git@github.com:jenkinsci/tfs-plugin.git**\r\n            2. Credentials: (select your previously-entered private key file)\r\n            3. Name: **origin**\r\n            4. Refspec: **+refs/heads/master:refs/remotes/origin/master**\r\n\t\t\t5. Branch Specifier: **refs/heads/master**\r\n\t\t\t6. Repository browser: **githubweb**\r\n\t\t\t7. Additional Behaviours:\r\n\t\t\t    1. Clean before checkout\r\n\t\t\t\t2. Check out to specific local branch (to avoid [\"Git fatal: ref HEAD is not a symbolic ref\" while using maven release plugin](https://stackoverflow.com/a/21184154/))\r\n\t\t\t\t\t1. Branch name: **master**\r\n    3. Build Environment\r\n\t\t1. Add timestamps to the Console Output\r\n\t\t2. Inject environment variables to the build process\r\n\t\t    1. **COMPUTERNAME** (the host name of the Jenkins node that will run the job)\r\n            2. **TFS_SERVER_NAME** (the TFS host name or Azure DevOps account host name)\r\n        3. Use secret text(s) or file(s)\r\n\t\t\t1. **TFS_USER_NAME** and **TFS_USER_PASSWORD** are initialized from a credential\r\n    4. Build. Add the following steps:\r\n        1. \"Shell script\" step to check and prepare (filling in the blanks at the `git config` lines near the end)\r\n        ```bash\r\n        set +e\r\n\r\n        # verify releaseVersion and developmentVersion\r\n        if [[ \"$releaseVersion\" != +([0-9])\\.+([0-9])\\.+([0-9]) ]]\r\n        then\r\n            echo \"ERROR: '$releaseVersion' is not a valid releaseVersion\"\r\n            exit 1\r\n        fi\r\n\r\n        if [[ \"$developmentVersion\" != +([0-9])\\.+([0-9])\\.+([0-9])-SNAPSHOT ]]\r\n        then\r\n            echo \"ERROR: '$developmentVersion' is not a valid developmentVersion\"\r\n            exit 1\r\n        fi\r\n\r\n\r\n        # test SSH connection to Git\r\n        ssh -Tv git@github.com\r\n        if [[ $? != \"1\" ]]\r\n        then\r\n            echo \"ERROR: Unable to connect to GitHub via SSH\"\r\n            exit 1\r\n        fi\r\n\r\n        git config --local user.name '<your full name>'\r\n        git config --local user.email '<your e-mail address>'\r\n\r\n        exit 0\r\n        ```\r\n        2. \"Maven\" step as a dry-run, running all tests and performing a SNAPSHOT deploy\r\n        ```\r\n        deploy\r\n        dependency:go-offline\r\n        --batch-mode\r\n        -Dtfs_server_name=${TFS_SERVER_NAME}\r\n        -Dtfs_user_name=${TFS_USER_NAME}\r\n        -Dtfs_user_password=${TFS_USER_PASSWORD}\r\n        ```\r\n        3. \"Maven\" step to actually release\r\n        ```\r\n        clean\r\n        release:prepare\r\n        release:perform\r\n        --batch-mode\r\n        -Dtag=tfs-${releaseVersion}\r\n        -DreleaseVersion=${releaseVersion}\r\n        -DdevelopmentVersion=${developmentVersion}\r\n        ```\r\n        4. \"Shell script\" step for post-release actions (filling in the blanks at the `git config` lines near the beginning)\r\n        ```bash\r\n        cd target/checkout\r\n        git config --local user.name '<your full name>'\r\n        git config --local user.email '<your e-mail address>'\r\n         \r\n        git checkout -b update_documentation_for_$releaseVersion origin/master\r\n         \r\n        cat > ReleaseNotes.md <<EndOfReleaseNotes\r\n        These notes are for release **(to be determined)**.\r\n        Other releases and their notes can be found at the [tfs-plugin GitHub Releases](https://github.com/jenkinsci/tfs-plugin/releases) page.\r\n         \r\n        * Major:\r\n            * TODO\r\n        * Minor:\r\n            * TODO\r\n         \r\n        EndOfReleaseNotes\r\n        git commit -a -m \"Clear out the release notes for the next release\"\r\n         \r\n        git push origin update_documentation_for_$releaseVersion\r\n        ```\r\n        5. Files to archive:\r\n        ```\r\n        tfs/target/tfs.hpi,ReleaseNotes.md,README.md,images/**\r\n        ```\r\n3. Post-release.  Perform these manual steps on your workstation:\r\n    1. Download the artifacts from Jenkins\r\n    2. Create a pull request from the **update_documentation_for_$releaseVersion** branch, then merge it.\r\n    3. Edit the tag on GitHub:\r\n        1. Copy-paste most of `ReleaseNotes.md`.\r\n        2. Upload the artifacts downloaded from Jenkins.\r\n        3. Publish release.\r\n    4. Update `README.md`.\r\n    5. Update affected issues with \"Fixed in\".\r\n    6. Check the update mirror after about a day, to make sure the new version was replicated across the CDN: http://updates.jenkins-ci.org/update-center.json\r\n"
  },
  {
    "path": "Testing.md",
    "content": "Functional Tests\r\n================\r\nThere's only so much testing you can do with test friends such as mocks and network replayers.  To enable more comprehensive and realistic testing, some automated tests were written to talk to live servers.  Some manual, one-time set-up is required to facilitate the process.\r\n\r\nHow to configure your TFS server\r\n--------------------------------\r\nYou'll need to be (or involve) an administrator.  It is assumed your TFS server is installed at the default port (8080) and virtual directory (/tfs).\r\n\r\n1. Launch the **Team Foundation Server Administration Console**\r\n    1. Navigate to root > Application Tier > Team Project Collections\r\n    2. Click **Create Collection**\r\n    3. Set the *Name* to **jenkins-tfs-plugin**\r\n    4. Indicate in the *Description* field that this team project collection was created to isolate the automated tests from normal usage of the server.  A hyperlink to this page would probably be a good idea.\r\n    5. Click **Verify**\r\n    6. Assuming everything was fine, click **Create**\r\n    7. Wait about 1 minute for the process to complete.\r\n    8. Assuming the team project collection was created OK, click **Close**\r\n2. Follow the instructions at [Create a team project](https://msdn.microsoft.com/library/ms181477.aspx) to create a *Team Project*, as specified below:\r\n    1. When prompted for the *Name*, enter **FunctionalTests**\r\n    2. Indicate in the *Description* field that this team project was created for the automated functional tests.  A hyperlink to this page would probably be a good idea.\r\n    3. The choice of process template is not important.\r\n    4. Select **Team Foundation Version Control** as the *version control system*.\r\n4. Follow the instructions at [Add team members](https://msdn.microsoft.com/en-us/library/jj920206.aspx) to add the test user as a member of the **FunctionalTests** team project\r\n5. Ensure the user has access to the team project\r\n    1. Open a web browser in InPrivate/incognito/private mode.  This will make sure you aren't re-using authentication cookies or saved credentials.\r\n    2. Navigate to the **jenkins-tfs-plugin** team project collection on the server.  Example:  `http://tfs.corp.example.com:8080/tfs/jenkins-tfs-plugin`\r\n    3. Log in as the test user.\r\n    4. Confirm you can browse to the **FunctionalTests** team project.\r\n\r\n\r\nHow to configure your Azure DevOps account\r\n-------------------------------------------\r\nTODO: write this\r\n\r\n\r\nHow to configure your development environment\r\n---------------------------------------------\r\nTests that need to connect to a server will only run during the `verify` phase *if* the `tfs_server_name` property was provided to Maven.  The value of this property is the *fully-qualified DNS name (FQDN)* of the server, because a non-qualified host name appears to trigger NTLM authentication attempts.\r\nYou should also provide the following properties:\r\n\r\n1. tfs_server_name - set this to the host name of the server (ex. tfs.corp.example.com)\r\n2. tfs_collection_url - set this to the full url of the collection (ex. http://tfs.corp.example.com:8081/tfs/jenkins-tfs-plugin)\r\n3. tfs_user_name - set this to the test user you gave permissions to above (the default value if not provided is **jenkins-tfs-plugin**)\r\n4. tfs_user_password - set this to the password of the test user (the default value if not provided is **for-test-only**)\r\n5. Set the COMPUTERNAME environment variable as the end-to-end tests rely on its presence\r\n\r\nExample:\r\n\r\n    mvn clean verify -Dtfs_collection_url=\"http://tfs.corp.example.com:8081/tfs/jenkins-tfs-plugin\" -Dtfs_server_name=tfs.corp.example.com -Dtfs_user_name=jenkins-tfs-plugin -Dtfs_user_password=for-test-only\r\n\r\n"
  },
  {
    "path": "contributing.md",
    "content": "Contributing to the Team Foundation Server plugin for Jenkins\n=============================================================\n\n## Building Sources\nThis is a Maven project with Java sources. The mvn package command will produce an HPI file that is the Jenkins Plugin file that will need to be installed on your Jenkins Server.\n- SET JAVA_HOME to the location of the JRE to build with (JRE 1.8 works)\n- Clone the repo from https://github.com/jenkinsci/tfs-plugin.git\n- change dir to the tfs-plugin folder\n- run \"mvn package\"\n    - If you do not have Maven installed yet, here are [instructions](http://www.mkyong.com/maven/how-to-install-maven-in-windows/) on how to install it on Windows.\n    - Initial build will have to download lots of libraries. This could take a few minutes.\n- This produces tfs-plugin\\tfs\\target\\tfs.hpi\n\n## Using IntelliJ IDEA\nTo use Intellij IDEA as the editor for this project simply do the following after getting sources:\n1) Open the tfs-plugin folder (root folder) in IntelliJ (I installed IntelliJ 17 community edition from https://www.jetbrains.com/idea/)\n2) Go to File->Project Structure and click on Project\n3) Specify the Project SDK (Java 1.8 works)\n\nYou should now be able to build from within IntelliJ\n- NOTE to build the hpi file you will have to \n    - bring up the Maven Projects tool window (View->Tool Windows->Maven Projects) and click the \"execute maven goal\" button\n    - Then type \"package\" in the \"Command Line\" text box (of the Execute Maven Goal dialog)\n\n## Debugging the Plugin\nSee https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial for information on how to debug the plugin.\nFrom within IntelliJ:\n1) Create a new Run configuration (Run | Edit Configurations... | + )\n    1) Type = Maven\n    1) Name = run hpi\n    1) Working directory should be the full path to \"../tfs-plugin/tfs\" (NOTE this is NOT the root folder)\n    1) Command Line \n    \n        `\n        hpi:run -Djetty.port=8090 -Dhudson.plugins.tfs.telemetry.isDeveloperMode=true\n        `\n    \n        1) or use whatever port you want\n    1) On the Runner tab\n        1) Environment Variables == MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n\n        1) To set the environment variables, make sure you uncheck 'Use project settings' first. Then use the '...' to set the variable.\n\n1) Run or Debug this configuration using the play and debug icons (top right)\n    1) Set any breakpoints you want in IntelliJ\n    1) Navigate to http://localhost:8090/jenkins\n\nNote: this runs Jenkins on your local OS not in a Docker image. As such, any configurations you make are preserved between runs. You do not need to have Jenkins previously installed locally (IntelliJ will run Jenkins from a local JAR file).\n\n## Installing Jenkins Locally for Manual Testing\nThe easiest method is to run Jenkins in a Docker image.\n1) Install Docker for your OS (https://www.docker.com/community-edition)\n1) Install and run the Jenkins image\n\n    `\n    docker run --name localJenkins -p 9191:9191 -p 50001:50001 --env \"JENKINS_OPTS=--httpPort=9191\" --env JENKINS_SLAVE_AGENT_PORT=50001 --env hudson.plugins.tfs.telemetry.isDeveloperMode=true jenkins\n    `\n    \n    - NOTES: \n        - Note that this command line avoids port 8080 (the default) in case you have VSO deployed as well\n        - Look in the output for the admin password\n        - The output sent to the console is also where you will see any logger output\n        - Note the environment variable \"hudson.plugins.tfs.telemetry.isDeveloperMode\". It is important to set this variable so that AppInsights data is sent to right key\n        - This installs a Linux Jenkins server on Docker (NOT one based on Windows or the host OS)\n1) Setup Jenkins\n    1) Go to http://localhost:9191\n    1) Enter the admin password\n    1) Install default plugins\n    1) Run Jenkins\n1) Install Plugin Manually\n    1) Go to http://localhost:9191/pluginManager/advanced\n    1) Browse to the tfs.hpi file and Upload it\n    1) To update the plugin, repeat steps 1 and 2 and then restart Jenkins by going to http://localhost:9191/restart\n1) To stop Jenkins and start from scratch\n\n    `\n    docker stop localJenkins\n    docker container prune\n    `\n    \n    Then repeat step 2 and 3 above\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.jenkins-ci.plugins</groupId>\n    <artifactId>plugin</artifactId>\n    <version>3.2</version>\n  </parent>\n\n  <artifactId>tfs-parent</artifactId>\n  <packaging>pom</packaging>\n  <name>Team Foundation Server Plug-in parent</name>\n  <version>5.157.1-SNAPSHOT</version>\n  <properties>\n    <!-- Version is required to be compatible with current Pipeline plugin dependencies -->\n    <jenkins.version>1.642.3</jenkins.version>\n    <java.level>7</java.level>\n    <maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>\n    <!--  overriding old version from parent to be consistent with the above in this project -->\n    <maven-surefire-report-plugin.version>${maven-surefire-plugin.version}</maven-surefire-report-plugin.version>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <maven-javadoc-plugin.version>2.8</maven-javadoc-plugin.version>\n  </properties>\n\n  <developers>\n    <developer>\n      <id>dastahel</id>\n      <name>David Staheli</name>\n      <email>dastahel@microsoft.com</email>\n      <timezone>-5</timezone>\n    </developer>\n    <developer>\n      <id>jpricket</id>\n      <name>Jason Prickett</name>\n      <email>jpricket@microsoft.com</email>\n      <timezone>-5</timezone>\n    </developer>\n    <developer>\n      <id>jeffyoung</id>\n      <name>Jeff Young</name>\n      <email>jeyou@microsoft.com</email>\n      <timezone>-5</timezone>\n    </developer>\n    <developer>\n      <id>jenkinssriramb</id>\n      <name>Sriram Balasubramaniyan</name>\n      <email>sriramb@microsoft.com</email>\n      <timezone>+5</timezone>\n    </developer>\n    <developer>\n      <id>kalyan</id>\n      <name>Kalyan</name>\n      <email>kasubram@microsoft.com</email>\n      <timezone>+5</timezone>\n    </developer>\n    <developer>\n      <id>keljos</id>\n      <name>Kellie Jos</name>\n      <email>kej@microsoft.com</email>\n      <timezone>-5</timezone>\n    </developer>\n    <developer>\n      <id>mosabua</id>\n      <name>Manfred Moser</name>\n      <email>manfred@simpligility.com</email>\n      <timezone>-8</timezone>\n    </developer>\n    <developer>\n      <id>leantk</id>\n      <name>Leah Antkiewicz</name>\n      <email>leantk@microsoft.com</email>\n      <timezone>-5</timezone>\n    </developer>\n  </developers>\n  <scm>\n    <connection>scm:git:https://github.com/jenkinsci/tfs-plugin.git</connection>\n    <developerConnection>scm:git:https://github.com/jenkinsci/tfs-plugin.git</developerConnection>\n    <tag>HEAD</tag>\n  </scm>\n\n  <distributionManagement>\n    <snapshotRepository>\n      <id>repo.jenkins-ci.org</id>\n      <url>https://repo.jenkins-ci.org/snapshots/</url>\n    </snapshotRepository>\n    <repository>\n      <id>repo.jenkins-ci.org</id>\n      <url>https://repo.jenkins-ci.org/releases/</url>\n    </repository>\n  </distributionManagement>\n\n  <modules>\n    <module>tfs-sdk</module>\n    <module>tfs</module>\n  </modules>\n\n  <build>\n    <plugins>\n    </plugins>\n  </build>\n\n    <repositories>\n        <repository>\n            <id>repo.jenkins-ci.org</id>\n            <url>https://repo.jenkins-ci.org/public/</url>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>repo.jenkins-ci.org</id>\n            <url>https://repo.jenkins-ci.org/public/</url>\n        </pluginRepository>\n    </pluginRepositories>\n</project>  \n  \n\n"
  },
  {
    "path": "tfs/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n        \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n        \"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd\">\n\n<!--\n\n  Checkstyle configuration that checks the sun coding conventions from:\n\n    - the Java Language Specification at\n      http://java.sun.com/docs/books/jls/second_edition/html/index.html\n\n    - the Sun Code Conventions at http://java.sun.com/docs/codeconv/\n\n    - the Javadoc guidelines at\n      http://java.sun.com/j2se/javadoc/writingdoccomments/index.html\n\n    - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html\n\n    - some best practices\n\n  Checkstyle is very configurable. Be sure to read the documentation at\n  http://checkstyle.sf.net (or in your downloaded distribution).\n\n  Most Checks are configurable, be sure to consult the documentation.\n\n  To completely disable a check, just comment it out or delete it from the file.\n\n  Finally, it is worth reading the documentation.\n\n-->\n\n<module name=\"Checker\">\n    <!--\n        If you set the basedir property below, then all reported file\n        names will be relative to the specified directory. See\n        http://checkstyle.sourceforge.net/5.x/config.html#Checker\n\n        <property name=\"basedir\" value=\"${basedir}\"/>\n    -->\n\n    <property name=\"fileExtensions\" value=\"java, properties, xml\"/>\n\n    <module name=\"SuppressionCommentFilter\"/>\n\n    <!-- Checks that a package-info.java file exists for each package.     -->\n    <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->\n    <!-- module name=\"JavadocPackage\"/ -->\n\n    <!-- Checks whether files end with a new line.                        -->\n    <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->\n    <module name=\"NewlineAtEndOfFile\"/>\n\n    <!-- Checks that property files contain the same keys.         -->\n    <!-- See http://checkstyle.sf.net/config_misc.html#Translation -->\n    <module name=\"Translation\"/>\n\n    <!-- Checks for Size Violations.                    -->\n    <!-- See http://checkstyle.sf.net/config_sizes.html -->\n    <module name=\"FileLength\"/>\n\n    <!-- Checks for whitespace                               -->\n    <!-- See http://checkstyle.sf.net/config_whitespace.html -->\n    <module name=\"FileTabCharacter\"/>\n\n    <!-- Miscellaneous other checks.                   -->\n    <!-- See http://checkstyle.sf.net/config_misc.html -->\n    <module name=\"RegexpSingleline\">\n        <property name=\"format\" value=\"\\s+$\"/>\n        <property name=\"minimum\" value=\"0\"/>\n        <property name=\"maximum\" value=\"0\"/>\n        <property name=\"message\" value=\"Line has trailing spaces.\"/>\n    </module>\n\n    <!-- Checks for Headers                                -->\n    <!-- See http://checkstyle.sf.net/config_header.html   -->\n    <!-- <module name=\"Header\"> -->\n    <!--   <property name=\"headerFile\" value=\"${checkstyle.header.file}\"/> -->\n    <!--   <property name=\"fileExtensions\" value=\"java\"/> -->\n    <!-- </module> -->\n\n    <module name=\"TreeWalker\">\n\n        <!-- Allow the SuppressionCommentFilter to work inside the files -->\n        <module name=\"FileContentsHolder\"/>\n\n        <!-- Checks for Javadoc comments.                     -->\n        <!-- See http://checkstyle.sf.net/config_javadoc.html -->\n        <module name=\"JavadocMethod\">\n            <property name=\"scope\" value=\"public\" />\n            <property name=\"tokens\" value=\"METHOD_DEF, ANNOTATION_FIELD_DEF\" />\n            <property name=\"allowMissingParamTags\" value=\"true\" />\n            <property name=\"allowMissingThrowsTags\" value=\"true\" />\n            <property name=\"allowMissingReturnTag\" value=\"true\" />\n            <property name=\"allowMissingPropertyJavadoc\" value=\"true\" />\n            <property name=\"allowUndeclaredRTE\" value=\"true\" />\n        </module>\n        <module name=\"JavadocType\"/>\n        <!-- module name=\"JavadocVariable\"/ -->\n        <module name=\"JavadocStyle\"/>\n\n        <!-- Checks for Naming Conventions.                  -->\n        <!-- See http://checkstyle.sf.net/config_naming.html -->\n        <module name=\"ConstantName\">\n            <property name=\"format\" value=\"^log(ger)?|[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$\"/>\n        </module>\n        <module name=\"LocalFinalVariableName\"/>\n        <module name=\"LocalVariableName\"/>\n        <module name=\"MemberName\"/>\n        <module name=\"MethodName\"/>\n        <module name=\"PackageName\"/>\n        <module name=\"ParameterName\"/>\n        <module name=\"StaticVariableName\"/>\n        <module name=\"TypeName\"/>\n\n        <!-- Checks for imports                              -->\n        <!-- See http://checkstyle.sf.net/config_import.html -->\n        <module name=\"AvoidStarImport\"/>\n        <module name=\"IllegalImport\"/> <!-- defaults to sun.* packages -->\n        <module name=\"RedundantImport\"/>\n        <module name=\"UnusedImports\">\n            <property name=\"processJavadoc\" value=\"false\"/>\n        </module>\n\n        <!-- Checks for Size Violations.                    -->\n        <!-- See http://checkstyle.sf.net/config_sizes.html\n        <module name=\"LineLength\"/>\n        <module name=\"MethodLength\"/>\n        <module name=\"ParameterNumber\"/>\n        -->\n\n        <!-- Checks for whitespace                               -->\n        <!-- See http://checkstyle.sf.net/config_whitespace.html -->\n        <module name=\"EmptyForIteratorPad\"/>\n        <module name=\"GenericWhitespace\"/>\n        <module name=\"MethodParamPad\"/>\n        <module name=\"NoWhitespaceAfter\"/>\n        <module name=\"NoWhitespaceBefore\"/>\n        <module name=\"OperatorWrap\"/>\n        <module name=\"ParenPad\"/>\n        <module name=\"TypecastParenPad\"/>\n        <module name=\"WhitespaceAfter\"/>\n        <module name=\"WhitespaceAround\"/>\n\n        <!-- Modifier Checks                                    -->\n        <!-- See http://checkstyle.sf.net/config_modifiers.html -->\n        <module name=\"ModifierOrder\"/>\n        <module name=\"RedundantModifier\"/>\n\n        <!-- Checks for blocks. You know, those {}'s         -->\n        <!-- See http://checkstyle.sf.net/config_blocks.html -->\n        <module name=\"AvoidNestedBlocks\"/>\n        <module name=\"EmptyBlock\"/>\n        <module name=\"LeftCurly\"/>\n        <module name=\"NeedBraces\"/>\n        <module name=\"RightCurly\"/>\n\n        <!-- Checks for common coding problems               -->\n        <!-- See http://checkstyle.sf.net/config_coding.html -->\n        <!-- <module name=\"AvoidInlineConditionals\"/> -->\n        <module name=\"EmptyStatement\"/>\n        <module name=\"EqualsHashCode\"/>\n        <module name=\"HiddenField\">\n            <!-- Only warn for variables that hide fields and not parameters -->\n            <property name=\"tokens\" value=\"VARIABLE_DEF\"/>\n        </module>\n        <module name=\"IllegalInstantiation\"/>\n        <module name=\"InnerAssignment\"/>\n        <module name=\"MagicNumber\"/>\n        <module name=\"MissingSwitchDefault\"/>\n        <module name=\"SimplifyBooleanExpression\"/>\n        <module name=\"SimplifyBooleanReturn\"/>\n\n        <!-- Checks for class design                         -->\n        <!-- See http://checkstyle.sf.net/config_design.html -->\n        <!-- <module name=\"DesignForExtension\"/> -->\n        <module name=\"FinalClass\"/>\n        <module name=\"HideUtilityClassConstructor\"/>\n        <module name=\"InterfaceIsType\"/>\n        <module name=\"VisibilityModifier\"/>\n\n        <!-- Miscellaneous other checks.                   -->\n        <!-- See http://checkstyle.sf.net/config_misc.html -->\n        <module name=\"ArrayTypeStyle\"/>\n        <module name=\"FinalParameters\"/>\n        <!-- module name=\"TodoComment\"/> -->\n        <module name=\"UpperEll\"/>\n\n    </module>\n\n</module>"
  },
  {
    "path": "tfs/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.jenkins-ci.plugins</groupId>\n    <artifactId>tfs-parent</artifactId>\n    <version>5.157.1-SNAPSHOT</version>\n  </parent>\n\n  <artifactId>tfs</artifactId>\n  <packaging>hpi</packaging>\n  <name>Team Foundation Server Plug-in</name>\n  <version>5.157.1-SNAPSHOT</version>\n  <url>http://wiki.jenkins-ci.org/display/JENKINS/Team+Foundation+Server+Plugin</url>\n\n  <properties>\n    <!-- TODO: enable once FindBugs issues are fixed -->\n    <findbugs.failOnError>false</findbugs.failOnError>\n  </properties>\n\n  <licenses>\n    <license><name>MIT license</name><comments>All source code is under the MIT license.</comments></license>\n    <license>\n      <name>Microsoft Visual Studio Team Foundation Server 2012 Software Development Kit for Java license terms</name>\n      <url>http://download.microsoft.com/download/5/9/9/5993F89B-AEF0-4381-9CEE-D3D7BA9EA33B/license.html</url>\n    </license>\n    <license>\n      <name>\n        Apache Commons Codec, Apache Commons Logging, Apache HttpClient, Apache Commons Lang, Apache log4j,\n        and Apache ServiceMix are licensed by the Apache Foundation under the Apache License, Version 2.0.\n      </name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0</url>\n    </license>\n    <license>\n      <name>\n        The Apache Foundation's Xerces Java Parser project is licensed by the\n        Apache Foundation under the Apache License, Version 1.1.\n      </name>\n      <url>http://www.apache.org/licenses/LICENSE-1.1</url>\n    </license>\n    <license>\n      <name>\n        The Woodstox XML Processor and the StAX API are licensed by their authors under the Apache License, Version 2.0.\n      </name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0</url></license>\n    <license>\n      <name>This product includes software from the Hypersonic SQL DB http://hsqldb.org/.</name>\n      <url>http://www.hsqldb.org/web/hsqlLicense.html</url>\n    </license>\n    <license>\n      <name>This product includes software from the Cryptix project http://www.cryptix.org/.</name>\n      <url>http://cryptix.org/LICENSE.TXT</url>\n    </license>\n  </licenses>\n\n  <!-- see http://groups.google.com/group/hudson-dev/browse_thread/thread/83e34c639eec470a for the rationale behind this -->\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-jar-plugin</artifactId>\n        <version>2.4</version>\n        <configuration>\n          <archive>\n            <manifest>\n              <!-- https://stackoverflow.com/a/6773868/ -->\n              <addDefaultImplementationEntries>true</addDefaultImplementationEntries>\n            </manifest>\n          </archive>\n        </configuration>\n      </plugin>\n      <plugin>\n        <artifactId>maven-release-plugin</artifactId>\n        <version>2.5.1</version>\n        <configuration>\n          <goals>deploy</goals>\n        </configuration>\n      </plugin>\n      <plugin>\n        <groupId>org.jenkins-ci.tools</groupId>\n        <artifactId>maven-hpi-plugin</artifactId>\n        <extensions>true</extensions>\n        <configuration>\n          <compatibleSinceVersion>3.2.0</compatibleSinceVersion>\n        </configuration>\n      </plugin>\n      <plugin>\n        <artifactId>maven-javadoc-plugin</artifactId>\n        <version>${maven-javadoc-plugin.version}</version>\n        <executions>\n          <execution>\n            <id>verify-javadoc</id>\n            <phase>verify</phase>\n            <goals>\n              <goal>javadoc</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-surefire-plugin</artifactId>\n        <version>${maven-surefire-plugin.version}</version>\n        <dependencies>\n          <dependency>\n            <groupId>org.apache.maven.surefire</groupId>\n            <artifactId>surefire-junit47</artifactId>\n            <version>${maven-surefire-plugin.version}</version>\n          </dependency>\n        </dependencies>\n        <configuration>\n          <excludedGroups>hudson.plugins.tfs.IntegrationTests</excludedGroups>\n        </configuration>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-checkstyle-plugin</artifactId>\n        <version>2.17</version>\n        <executions>\n          <execution>\n            <id>validate</id>\n            <phase>validate</phase>\n            <configuration>\n              <configLocation>checkstyle.xml</configLocation>\n              <encoding>UTF-8</encoding>\n              <consoleOutput>true</consoleOutput>\n              <failsOnError>true</failsOnError>\n            </configuration>\n            <goals>\n              <goal>check</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>integration_test_with_TFS_server</id>\n      <activation>\n        <property>\n          <name>tfs_server_name</name>\n        </property>\n      </activation>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-failsafe-plugin</artifactId>\n            <!-- failsafe and surefire are the same project and release together\n                 this ensures consistent, correctly working behavior\n             -->\n            <version>${maven-surefire-plugin.version}</version>\n            <dependencies>\n              <dependency>\n                <groupId>org.apache.maven.surefire</groupId>\n                <artifactId>surefire-junit47</artifactId>\n                <version>${maven-surefire-plugin.version}</version>\n              </dependency>\n            </dependencies>\n            <executions>\n              <execution>\n                <goals>\n                  <goal>integration-test</goal>\n                  <goal>verify</goal>\n                </goals>\n              </execution>\n            </executions>\n            <configuration>\n              <includes>\n                <include>**/Test*.java</include>\n                <include>**/*Test.java</include>\n                <include>**/*TestCase.java</include>\n              </includes>\n              <groups>hudson.plugins.tfs.IntegrationTests</groups>\n            </configuration>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n\n  <dependencies>\n\n    <dependency>\n      <!-- We need this plugin for the [current] TfsUserLookup implementation -->\n      <groupId>org.jenkins-ci.plugins</groupId>\n      <artifactId>mailer</artifactId>\n      <version>1.16</version>\n    </dependency>\n    <dependency>\n      <!-- Used for configuring collections globally -->\n      <groupId>org.jenkins-ci.plugins</groupId>\n      <artifactId>credentials</artifactId>\n      <version>1.25</version>\n    </dependency>\n    <dependency>\n      <!-- Used for configuring collections globally -->\n      <groupId>org.jenkins-ci.plugins.workflow</groupId>\n      <artifactId>workflow-job</artifactId>\n      <version>2.10</version>\n    </dependency>\n    <dependency>\n      <!-- Used for configuring collections globally -->\n      <groupId>org.jenkins-ci.plugins.workflow</groupId>\n      <artifactId>workflow-cps</artifactId>\n      <version>2.30</version>\n      <exclusions>\n        <exclusion>\n          <!-- Provided by the core -->\n          <groupId>org.jenkins-ci</groupId>\n          <artifactId>annotation-indexer</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <!-- Used for configuring collections globally, resolves upper bound dependency conflicts in other Pipeline plugins -->\n      <groupId>org.jenkins-ci.plugins.workflow</groupId>\n      <artifactId>workflow-support</artifactId>\n      <version>2.14</version>\n    </dependency>\n    <dependency>\n      <!-- Used for augmenting Git-related activities, like commit status -->\n      <groupId>org.jenkins-ci.plugins</groupId>\n      <artifactId>git</artifactId>\n      <version>2.5.2</version>\n    </dependency>\n\n    <dependency>\n      <groupId>com.microsoft.tfs.sdk</groupId>\n      <artifactId>com.microsoft.tfs.sdk</artifactId>\n      <version>14.0.3</version>\n    </dependency>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n        <groupId>xmlunit</groupId>\n        <artifactId>xmlunit</artifactId>\n        <version>1.6</version>\n        <scope>test</scope>\n    </dependency>\n    <dependency>\n        <groupId>org.mockito</groupId>\n        <artifactId>mockito-core</artifactId>\n        <version>1.10.19</version>\n        <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.littleshoot</groupId>\n      <artifactId>littleproxy</artifactId>\n      <version>1.1.0</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.jenkins-ci.plugins</groupId>\n      <artifactId>junit</artifactId>\n      <version>1.6</version>\n      <scope>test</scope>\n    </dependency>\n    \n    <!-- RM dependencies -->\n    <dependency>\n        <groupId>org.apache.httpcomponents</groupId>\n        <artifactId>httpclient</artifactId>\n        <version>4.5</version>\n        <type>jar</type>\n    </dependency>\n    <dependency>\n        <groupId>com.google.code.gson</groupId>\n        <artifactId>gson</artifactId>\n        <version>2.3.1</version>\n    </dependency>\n    <dependency>\n        <groupId>org.json</groupId>\n        <artifactId>json</artifactId>\n        <version>20090211</version>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/ChangeSetReader.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport java.io.File;\r\nimport java.io.FileInputStream;\r\nimport java.io.IOException;\r\nimport java.io.InputStreamReader;\r\nimport java.io.Reader;\r\nimport java.nio.charset.Charset;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport hudson.model.Run;\r\nimport hudson.scm.RepositoryBrowser;\r\nimport org.apache.commons.digester.Digester;\r\nimport org.xml.sax.SAXException;\r\n\r\nimport hudson.plugins.tfs.model.ChangeLogSet;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.scm.ChangeLogParser;\r\nimport hudson.util.Digester2;\r\n\r\n/**\r\n * TeamFoundation change log reader.\r\n *\r\n * @author Erik Ramfelt\r\n */\r\npublic class ChangeSetReader extends ChangeLogParser {\r\n\r\n    @Override\r\n    public ChangeLogSet parse(final Run build, final RepositoryBrowser<?> browser, final File changelogFile) throws IOException, SAXException {\r\n        try (FileInputStream stream = new FileInputStream(changelogFile); Reader reader = new InputStreamReader(stream, Charset.defaultCharset())) {\r\n            return parse(build, browser, reader);\r\n        }\r\n    }\r\n\r\n    /** Performs the actual parsing. */\r\n    public ChangeLogSet parse(final Run build, final RepositoryBrowser<?> browser, final Reader reader) throws IOException, SAXException {\r\n        List<ChangeSet> changesetList = new ArrayList<ChangeSet>();\r\n        Digester digester = new Digester2();\r\n        digester.push(changesetList);\r\n\r\n        digester.addObjectCreate(\"*/changeset\", ChangeSet.class);\r\n        digester.addSetProperties(\"*/changeset\");\r\n        digester.addBeanPropertySetter(\"*/changeset/date\", \"dateStr\");\r\n        digester.addBeanPropertySetter(\"*/changeset/user\");\r\n        digester.addBeanPropertySetter(\"*/changeset/checked_in_by_user\", \"checkedInBy\");\r\n        digester.addBeanPropertySetter(\"*/changeset/comment\");\r\n        digester.addSetNext(\"*/changeset\", \"add\");\r\n\r\n        digester.addObjectCreate(\"*/changeset/items/item\", ChangeSet.Item.class);\r\n        digester.addSetProperties(\"*/changeset/items/item\");\r\n        digester.addBeanPropertySetter(\"*/changeset/items/item\", \"path\");\r\n        digester.addSetNext(\"*/changeset/items/item\", \"add\");\r\n\r\n        digester.parse(reader);\r\n\r\n        return new ChangeLogSet(build, browser, changesetList);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/ChangeSetWriter.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\nimport hudson.Util;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.plugins.tfs.util.DateUtil;\r\n\r\nimport java.io.File;\r\nimport java.io.FileWriter;\r\nimport java.io.IOException;\r\nimport java.io.PrintWriter;\r\nimport java.io.Writer;\r\nimport java.util.List;\r\n\r\nimport org.apache.commons.io.IOUtils;\r\n\r\n/**\r\n * Team Foundation change log writer.\r\n * \r\n * @author Erik Ramfelt\r\n */\r\npublic class ChangeSetWriter {\r\n\r\n    /**\r\n     * Writes the list of change sets to the file\r\n     * @param changeSets list of change sets\r\n     * @param changelogFile file to write change sets to\r\n     *\r\n     * @throws IOException If an I/O error occurs\r\n     */\r\n    @SuppressFBWarnings(value = \"DM_DEFAULT_ENCODING\", justification = \"Better mot modify charset in case it might raise errors\")\r\n    public void write(List<ChangeSet> changeSets, File changelogFile) throws IOException {\r\n        FileWriter writer = new FileWriter(changelogFile);\r\n        try {\r\n            write(changeSets, writer);\r\n        } finally {\r\n            IOUtils.closeQuietly(writer);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Writes the list of change sets to the writer\r\n     * @param changeSets list of change sets\r\n     * @param output output writer\r\n     */    \r\n    public void write(List<ChangeSet> changeSets, Writer output) {\r\n        PrintWriter writer = new PrintWriter(output);\r\n        \r\n        writer.println(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\");\r\n        writer.println(\"<changelog>\");\r\n        \r\n        for (ChangeSet changeSet : changeSets) {\r\n            writer.println(String.format(\"\\t<changeset version=\\\"%s\\\">\", changeSet.getVersion()));\r\n            write(changeSet, writer);\r\n            writer.println(\"\\t</changeset>\");\r\n        }\r\n        \r\n        writer.println(\"</changelog>\");\r\n        writer.flush();\r\n    }\r\n\r\n    private void write(ChangeSet changeSet, PrintWriter writer) {\r\n        writer.println(String.format(\"\\t\\t<date>%s</date>\", DateUtil.TFS_DATETIME_FORMATTER.get().format(changeSet.getDate())));\r\n        if (Util.fixEmpty(changeSet.getDomain()) == null) {\r\n            writer.println(String.format(\"\\t\\t<user>%s</user>\", escapeForXml(changeSet.getUser())));\r\n        } else {\r\n            writer.println(String.format(\"\\t\\t<user>%s\\\\%s</user>\", escapeForXml(changeSet.getDomain()), escapeForXml(changeSet.getUser())));\r\n        }\r\n        if (Util.fixEmpty(changeSet.getCheckedInBy()) != null) {\r\n            writer.println(String.format(\"\\t\\t<checked_in_by_user>%s</checked_in_by_user>\", escapeForXml(changeSet.getCheckedInBy())));\r\n        }\r\n        writer.println(String.format(\"\\t\\t<comment>%s</comment>\", escapeForXml(changeSet.getComment())));\r\n        if (changeSet.getItems().size() > 0) {\r\n            writer.println(\"\\t\\t<items>\");\r\n            for (ChangeSet.Item item : changeSet.getItems()) {\r\n                writer.println(String.format(\"\\t\\t\\t<item action=\\\"%s\\\">%s</item>\", escapeForXml(item.getAction()), escapeForXml(item.getPath())));\r\n            }\r\n            writer.println(\"\\t\\t</items>\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * \r\n     * Converts the input in the way that it can be written to the XML.\r\n     * Special characters are converted to XML understandable way.\r\n     * \r\n     * @param object The object to be escaped.\r\n     * @return Escaped string that can be written to XML.\r\n     */\r\n    private String escapeForXml(Object object)\r\n    {\r\n        if(object == null)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        //Loop through and replace the special chars.\r\n        String string = object.toString();\r\n        int size = string.length();\r\n        char ch;\r\n        StringBuilder escapedString = new StringBuilder(size);\r\n        for(int index = 0;index < size;index ++)\r\n        {\r\n            //Convert special chars.\r\n            ch = string.charAt(index);\r\n            switch(ch)\r\n            {\r\n                case '&'  : escapedString.append(\"&amp;\");  break;\r\n                case '<'  : escapedString.append(\"&lt;\");   break;\r\n                case '>'  : escapedString.append(\"&gt;\");   break;\r\n                case '\\'' : escapedString.append(\"&apos;\"); break;\r\n                case '\\\"' : escapedString.append(\"&quot;\");break;\r\n                default:    escapedString.append(ch);\r\n            }\r\n        }\r\n\r\n        return escapedString.toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/CommitParameterAction.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.plugins.git.RevisionParameterAction;\r\nimport hudson.plugins.tfs.model.GitCodePushedEventArgs;\r\nimport hudson.plugins.tfs.util.UriHelper;\r\nimport org.eclipse.jgit.transport.RemoteConfig;\r\nimport org.eclipse.jgit.transport.URIish;\r\n\r\nimport java.net.URI;\r\n\r\n/**\r\n * Used as a build parameter to record information about the associated project and\r\n * Visual Studio Team Services account or TFS server to facilitate integration.\r\n */\r\npublic class CommitParameterAction extends RevisionParameterAction {\r\n\r\n    private final GitCodePushedEventArgs gitCodePushedEventArgs;\r\n\r\n    /**\r\n     * Saves the repo uri and GitCodePushedEventArgs.\r\n     */\r\n    public CommitParameterAction(final GitCodePushedEventArgs e) {\r\n        super(e.commit, e.getRepoURIish());\r\n\r\n        this.gitCodePushedEventArgs = e;\r\n    }\r\n\r\n    /**\r\n     * Returns the GitCodePushedEventArgs.\r\n     */\r\n    public GitCodePushedEventArgs getGitCodePushedEventArgs() {\r\n        return gitCodePushedEventArgs;\r\n    }\r\n\r\n    /**\r\n     * Returns true if the git repo uri can originate from any of the remotes passed in.\r\n     */\r\n    @Override\r\n    public boolean canOriginateFrom(final Iterable<RemoteConfig> remotes) {\r\n        final URI repoUri = gitCodePushedEventArgs.repoUri;\r\n\r\n        for (final RemoteConfig remote : remotes) {\r\n            for (final URIish remoteURL : remote.getURIs()) {\r\n                final URI remoteUri = URI.create(remoteURL.toString());\r\n                if (UriHelper.areSameGitRepo(remoteUri, repoUri)) {\r\n                    return true;\r\n                }\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/JenkinsEventNotifier.java",
    "content": "package hudson.plugins.tfs;\n\nimport hudson.plugins.tfs.model.ConnectionParameters;\nimport hudson.plugins.tfs.model.JobCompletionEventArgs;\nimport hudson.plugins.tfs.util.TeamRestClient;\nimport jenkins.model.Jenkins;\nimport net.sf.json.JSONObject;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.conn.HttpHostConnectException;\nimport org.apache.http.impl.client.HttpClientBuilder;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.io.UnsupportedEncodingException;\nimport java.net.HttpURLConnection;\nimport java.net.URI;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Formatter;\nimport java.util.List;\nimport java.util.logging.Logger;\n\n/**\n * This class sends Jenkins events to all \"connected\" team collections.\n * Current list of events:\n * - Job Completion event\n */\npublic final class JenkinsEventNotifier {\n    private static final Logger log = Logger.getLogger(JenkinsEventNotifier.class.getName());\n    private static final String ENCODING = \"UTF-8\";\n\n    /**\n     * Hiding the constructor for this Utility class.\n     */\n    private JenkinsEventNotifier() { }\n\n    /**\n     * Send the Job Completion event to connected TFS/VSTS servers.\n     */\n    public static void sendJobCompletionEvent(final JSONObject payload) {\n        final List<TeamCollectionConfiguration> connectedCollections = TeamCollectionConfiguration.getConnectedCollections();\n        for (final TeamCollectionConfiguration c : connectedCollections) {\n            try {\n                // Check to see if there are any collections \"connected\" to this Jenkins server\n                final ConnectionParameters connectionParameters = c.getConnectionParameters();\n                final TeamRestClient client = new TeamRestClient(URI.create(c.getCollectionUrl()));\n                payload.put(\"server\", connectionParameters.getConnectionKey());\n                final String jsonPayload = payload.toString();\n                final JobCompletionEventArgs args = new JobCompletionEventArgs(\n                        connectionParameters.getConnectionKey(),\n                        jsonPayload,\n                        getPayloadSignature(connectionParameters.getConnectionSignature(), jsonPayload));\n                client.sendJobCompletionEvent(args);\n            } catch (final Exception e) {\n                log.warning(\"ERROR: sendJobCompletionEvent: (collection=\" + c.getCollectionUrl() + \") \" + e.getMessage());\n            }\n        }\n    }\n\n    /**\n     * This is a helper method to get the JSON for a Jenkins object.\n     * @param url\n     * @return\n     */\n    public static String getApiJson(final String url) {\n        try {\n            Jenkins jenkins = Jenkins.getInstance();\n            if (jenkins == null) {\n                return \"\";\n            }\n            final String rootUrl = jenkins.getRootUrl();\n            final String fullUrl = urlCombine(rootUrl, url, \"api\", \"json\");\n            final HttpClient client = HttpClientBuilder.create().build();\n            final HttpGet request = new HttpGet(fullUrl);\n\n            // add request header\n            request.addHeader(\"User-Agent\", \"Jenkins-Self\");\n\n            final HttpResponse response = client.execute(request);\n            final int statusCode = response.getStatusLine().getStatusCode();\n\n            if (statusCode <= HttpURLConnection.HTTP_ACCEPTED) {\n                try (BufferedReader reader = new BufferedReader(\n                        new InputStreamReader(response.getEntity().getContent(), ENCODING))) {\n                    final StringBuilder result = new StringBuilder();\n                    String line;\n                    while ((line = reader.readLine()) != null) {\n                        result.append(line);\n                        result.append(\"\\n\");\n                    }\n                    return result.toString();\n                }\n            } else {\n                log.warning(\"ERROR: getApiJson: (url=\" + url + \") failed due to Http error #\" + statusCode);\n                return null;\n            }\n        } catch (final HttpHostConnectException e) {\n            log.warning(\"ERROR: getApiJson: (url=\" + url + \") \" + e.getMessage());\n            return null;\n        } catch (final Exception e) {\n            log.warning(\"ERROR: getApiJson: (url=\" + url + \") \" + e.getMessage());\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Calculates the payload hash.\n     * @param secret\n     * @param payload\n     * @return\n     * @throws NoSuchAlgorithmException\n     * @throws InvalidKeyException\n     * @throws UnsupportedEncodingException\n     */\n    public static String getPayloadSignature(final String secret, final String payload)\n            throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {\n        final SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(ENCODING), \"HmacSHA1\");\n        final Mac mac = Mac.getInstance(\"HmacSHA1\");\n        mac.init(signingKey);\n        return toHexString(mac.doFinal(payload.getBytes(ENCODING)));\n    }\n\n    private static String urlCombine(final String url, final String... parts) {\n        final StringBuilder sb = new StringBuilder();\n        if (url != null) {\n            sb.append(url);\n            for (final String s : parts) {\n                if (StringUtils.isNotBlank(s)) {\n                    if (sb.length() > 0 && sb.charAt(sb.length() - 1) != '/') {\n                        sb.append(\"/\");\n                    }\n                    sb.append(s);\n                }\n            }\n        }\n        return sb.toString();\n    }\n\n    private static String toHexString(final byte[] bytes) {\n        final Formatter formatter = new Formatter();\n        for (final byte b : bytes) {\n            formatter.format(\"%02x\", b);\n        }\n\n        return formatter.toString();\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/PullRequestParameterAction.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.plugins.tfs.model.PullRequestMergeCommitCreatedEventArgs;\r\n\r\n/**\r\n * Action that adds the pull request merge event args to the build information.\r\n */\r\npublic class PullRequestParameterAction extends CommitParameterAction {\r\n\r\n    private final PullRequestMergeCommitCreatedEventArgs args;\r\n\r\n    public PullRequestParameterAction(final PullRequestMergeCommitCreatedEventArgs args) {\r\n        super(args);\r\n        this.args = args;\r\n    }\r\n\r\n    public PullRequestMergeCommitCreatedEventArgs getPullRequestMergeCommitCreatedEventArgs() {\r\n        return args;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/SafeParametersAction.java",
    "content": "package hudson.plugins.tfs;\n\nimport hudson.EnvVars;\nimport hudson.Extension;\nimport hudson.model.EnvironmentContributor;\nimport hudson.model.ParameterValue;\nimport hudson.model.ParametersAction;\nimport hudson.model.Run;\nimport hudson.model.TaskListener;\nimport org.kohsuke.accmod.Restricted;\nimport org.kohsuke.accmod.restrictions.NoExternalUse;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Extension class of ParametersAction to pass in parameters as safe parameters..\n */\n@Restricted(NoExternalUse.class)\npublic class SafeParametersAction extends ParametersAction {\n\n    private List<ParameterValue> parameters;\n\n    public SafeParametersAction(final List<ParameterValue> parameters) {\n        this.parameters = parameters;\n    }\n\n    public SafeParametersAction(final ParameterValue... parameters) {\n        this(Arrays.asList(parameters));\n    }\n\n    @Override\n    public List<ParameterValue> getParameters() {\n        return Collections.unmodifiableList(parameters);\n    }\n\n    @Override\n    public ParameterValue getParameter(final String name) {\n        for (ParameterValue parameter : parameters) {\n            if (parameter != null && parameter.getName().equals(name)) {\n                return parameter;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n    * Environment contributor for SafeParametersAction.\n    */\n    @Extension\n    public static final class SafeParametersActionEnvironmentContributor extends EnvironmentContributor {\n\n        @Override\n        public void buildEnvironmentFor(final Run r, final EnvVars envs, final TaskListener listener) throws IOException, InterruptedException {\n            SafeParametersAction action = r.getAction(SafeParametersAction.class);\n            if (action != null) {\n                for (ParameterValue p : action.getParameters()) {\n                    envs.putIfNotNull(p.getName(), String.valueOf(p.getValue()));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TFSLabeler.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs;\n\nimport hudson.EnvVars;\nimport hudson.Extension;\nimport hudson.FilePath;\nimport hudson.Launcher;\nimport hudson.Util;\nimport hudson.model.*;\nimport hudson.plugins.tfs.commands.LabelCommand;\nimport hudson.plugins.tfs.model.Server;\nimport hudson.plugins.tfs.telemetry.TelemetryHelper;\nimport hudson.plugins.tfs.util.BuildVariableResolver;\nimport hudson.scm.SCM;\nimport hudson.tasks.BuildStepDescriptor;\nimport hudson.tasks.BuildStepMonitor;\nimport hudson.tasks.Notifier;\nimport hudson.tasks.Publisher;\nimport hudson.util.VariableResolver;\nimport hudson.util.VariableResolver.Union;\nimport org.kohsuke.stapler.DataBoundConstructor;\n\nimport java.io.IOException;\nimport java.util.logging.Logger;\n\n/**\n * Used to create a label in TFS after a build is completed.\n * @author Rodrigo Lopes (rodrigolopes)\n */\npublic class TFSLabeler extends Notifier {\n\n    private String whenToLabel;\n    private String labelName;\n\n    private static final Logger logger = Logger.getLogger(TFSLabeler.class.getName());\n\n    @Extension\n    public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {\n        public DescriptorImpl() {\n            super(TFSLabeler.class);\n        }\n\n        @Override\n        public String getDisplayName() {\n            return \"Create a label in TFVC\";\n        }\n\n        @Override\n        public boolean isApplicable(Class<? extends AbstractProject> jobType) {\n            return true;\n        }\n    }\n\n    @DataBoundConstructor\n    public TFSLabeler(String whenToLabel, String labelName) {\n        this.whenToLabel = whenToLabel;\n        this.labelName = labelName;\n    }\n\n    @Override\n    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {\n        SCM scm = build.getRootBuild().getProject().getScm();\n        if (!(scm instanceof TeamFoundationServerScm)) {\n            listener.getLogger().println(\"Labels are only supported for projects using the 'Team Foundation Server' SCM\");\n            return false;\n        }\n\n        TeamFoundationServerScm tfsScm = (TeamFoundationServerScm) scm;\n\n        boolean buildSuccess = Result.SUCCESS.equals(build.getResult());\n\n        String whenCreateLabel = getWhenToLabel();\n        if (\"always\".equals(whenCreateLabel) || (\"success\".equals(whenCreateLabel) && buildSuccess)) {\n\n            final Launcher localLauncher = launcher != null ? launcher : new Launcher.LocalLauncher(listener);\n            Server server = tfsScm.createServer(localLauncher, listener, build.getRootBuild());\n\n            Computer computer = Computer.currentComputer();\n            String normalizedLabelName = computeDynamicValue(build, getLabelName());\n            String tfsWorkspace = tfsScm.getWorkspaceName(build.getRootBuild(), computer);\n            String tfsProjectPath = computeDynamicValue(build, tfsScm.getProjectPath());\n            \n            try {\n                logger.info(String.format(\"Create label '%s' on workspace '%s' with project path '%s' \", normalizedLabelName, tfsWorkspace, tfsProjectPath));\n                LabelCommand labelCommand = new LabelCommand(server, normalizedLabelName, tfsWorkspace, tfsProjectPath);\n                server.execute(labelCommand.getCallable());\n\n                // Send telemetry\n                TelemetryHelper.sendEvent(\"team-label\", new TelemetryHelper.PropertyMapBuilder()\n                        .serverContext(server.getUrl(), server.getUrl())\n                        .build());\n\n            } finally {\n                server.close();\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Replace an expression in the form ${name} in the given String\n     * by the value of the matching environment variable or build parameter.<Br/>\n     */\n    private String computeDynamicValue(AbstractBuild build, String parameterizedValue)\n            throws IllegalStateException, InterruptedException, IOException {\n\n        final EnvVars envVars = build.getEnvironment(TaskListener.NULL);\n        final VariableResolver<String> environmentVariables = new VariableResolver<String>() {\n            public String resolve(String name) {\n                return envVars.get(name);\n            }\n\n        };\n        final BuildVariableResolver buildVariables = new BuildVariableResolver(build.getProject());\n        @SuppressWarnings(\"unchecked\")\n        final Union<String> bothVariables = new VariableResolver.Union<String>(buildVariables, environmentVariables);\n        String value = Util.replaceMacro(parameterizedValue, bothVariables);\n\n        logger.fine(\"oldValue = \" + parameterizedValue + \"; newValue = \" + value);\n        return value;\n    }\n\n    public BuildStepMonitor getRequiredMonitorService() {\n        return BuildStepMonitor.STEP;\n    }\n\n    public String getWhenToLabel() {\n        return whenToLabel;\n    }\n\n    public String getLabelName() {\n        return labelName;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TFSRevisionState.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs;\n\nimport org.kohsuke.stapler.export.Exported;\nimport org.kohsuke.stapler.export.ExportedBean;\n\nimport hudson.scm.SCMRevisionState;\n\n@ExportedBean\npublic class TFSRevisionState extends SCMRevisionState {\n\n    @Exported(visibility=2)\n    public final int changesetVersion;\n    @Exported(visibility=1)\n    public final String projectPath;\n\n    public TFSRevisionState(String changesetVersion, String projectPath) {\n        this.changesetVersion = Integer.parseInt(changesetVersion, 10);\n        this.projectPath = projectPath;\n    }\n    \n    public TFSRevisionState(int changesetVersion, String projectPath) {\n        this.changesetVersion = changesetVersion;\n        this.projectPath = projectPath;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamBuildDetailsAction.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport hudson.model.Action;\r\nimport hudson.plugins.tfs.util.QueryString;\r\nimport hudson.plugins.tfs.util.UriHelper;\r\nimport org.kohsuke.stapler.export.Exported;\r\nimport org.kohsuke.stapler.export.ExportedBean;\r\n\r\nimport java.io.Serializable;\r\nimport java.net.URI;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\n/**\r\n * Captures the details of the TFS/Team Services build which triggered us.\r\n */\r\n@ExportedBean(defaultVisibility = 999)\r\npublic class TeamBuildDetailsAction implements Action, Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public Map<String, String> buildVariables = new HashMap<String, String>();\r\n    public String buildUrl;\r\n\r\n    public TeamBuildDetailsAction() {\r\n\r\n    }\r\n\r\n    public TeamBuildDetailsAction(final Map<String, String> buildVariables) {\r\n        this.buildVariables = new HashMap<String, String>(buildVariables);\r\n        this.buildUrl = determineBuildUrl(buildVariables).toString();\r\n    }\r\n\r\n    static URI determineBuildUrl(final Map<String, String> buildVariables) {\r\n        // TODO: eventually call the build REST API to obtain the proper web URL\r\n        final String collectionUri = buildVariables.get(\"System.TeamFoundationCollectionUri\");\r\n        final String projectName = buildVariables.get(\"System.TeamProject\");\r\n        final String buildId = buildVariables.get(\"Build.BuildId\");\r\n        final QueryString query = new QueryString(\"buildId\", buildId);\r\n        final URI result = UriHelper.join(\r\n                collectionUri,\r\n                projectName,\r\n                \"_build\",\r\n                \"index\",\r\n                query);\r\n        return result;\r\n\r\n    }\r\n\r\n    @Override\r\n    public String getIconFileName() {\r\n        return \"/plugin/tfs/48x48/logo.png\";\r\n    }\r\n\r\n    @Override\r\n    public String getDisplayName() {\r\n        return \"TFS/Team Services build\";\r\n    }\r\n\r\n    @Override\r\n    public String getUrlName() {\r\n        return \"team-build\";\r\n    }\r\n\r\n    // the following methods are called from this/summary.jelly and this/index.jelly\r\n\r\n    @Exported\r\n    public String getBuildNumber() {\r\n        return buildVariables.get(\"Build.BuildNumber\");\r\n    }\r\n\r\n    @Exported\r\n    public String getBuildDefinitionName() {\r\n        return buildVariables.get(\"Build.DefinitionName\");\r\n    }\r\n\r\n    @Exported\r\n    public String getBuildUrl() {\r\n        return buildUrl;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamBuildEndpoint.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport hudson.Extension;\r\nimport hudson.model.BuildAuthorizationToken;\r\nimport hudson.model.BuildableItem;\r\nimport hudson.model.Item;\r\nimport hudson.model.Job;\r\nimport hudson.model.UnprotectedRootAction;\r\nimport hudson.plugins.tfs.model.AbstractCommand;\r\nimport hudson.plugins.tfs.model.BuildCommand;\r\nimport hudson.plugins.tfs.model.BuildWithParametersCommand;\r\nimport hudson.plugins.tfs.model.PingCommand;\r\nimport hudson.plugins.tfs.model.TeamBuildPayload;\r\nimport hudson.plugins.tfs.telemetry.TelemetryHelper;\r\nimport hudson.plugins.tfs.util.EndpointHelper;\r\nimport hudson.plugins.tfs.util.MediaType;\r\nimport jenkins.model.Jenkins;\r\nimport jenkins.model.ParameterizedJobMixIn;\r\nimport jenkins.util.TimeDuration;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.apache.commons.lang3.StringEscapeUtils;\r\nimport org.kohsuke.stapler.ForwardToView;\r\nimport org.kohsuke.stapler.HttpResponse;\r\nimport org.kohsuke.stapler.HttpResponses;\r\nimport org.kohsuke.stapler.QueryParameter;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\nimport org.kohsuke.stapler.StaplerResponse;\r\n\r\nimport javax.servlet.ServletException;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.PrintWriter;\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.net.URLDecoder;\r\nimport java.net.URLEncoder;\r\nimport java.util.Collection;\r\nimport java.util.Collections;\r\nimport java.util.Map;\r\nimport java.util.TreeMap;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\n\r\nimport static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;\r\nimport static javax.servlet.http.HttpServletResponse.SC_CREATED;\r\nimport static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;\r\nimport static javax.servlet.http.HttpServletResponse.SC_OK;\r\n\r\n/**\r\n * The endpoint that TFS/Team Services will PUT to when it wants to schedule a build in Jenkins.\r\n */\r\n@Extension\r\npublic class TeamBuildEndpoint implements UnprotectedRootAction {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(TeamBuildEndpoint.class.getName());\r\n    private static final Map<String, AbstractCommand.Factory> COMMAND_FACTORIES_BY_NAME;\r\n    public static final String URL_NAME = \"team-build\";\r\n    public static final String PARAMETER = \"parameter\";\r\n    public static final String BUILD_SOURCE_BRANCH = \"Build.SourceBranch\";\r\n    public static final String QUEUEJOBTASK_MULTIBRANCH_JOB_BRANCH = \"QueueJobTask.MultibranchPipelineBranch\";\r\n    static final String URL_PREFIX = \"/\" + URL_NAME + \"/\";\r\n\r\n    static {\r\n        final Map<String, AbstractCommand.Factory> map = new TreeMap<String, AbstractCommand.Factory>(String.CASE_INSENSITIVE_ORDER);\r\n        map.put(\"ping\", new PingCommand.Factory());\r\n        map.put(\"build\", new BuildCommand.Factory());\r\n        map.put(\"buildWithParameters\", new BuildWithParametersCommand.Factory());\r\n        COMMAND_FACTORIES_BY_NAME = Collections.unmodifiableMap(map);\r\n    }\r\n\r\n    private String commandName;\r\n    private String jobName;\r\n\r\n    @Override\r\n    public String getIconFileName() {\r\n        return null;\r\n    }\r\n\r\n    @Override\r\n    public String getDisplayName() {\r\n        return null;\r\n    }\r\n\r\n    @Override\r\n    public String getUrlName() {\r\n        return URL_NAME;\r\n    }\r\n\r\n    public String getCommandName() {\r\n        return commandName;\r\n    }\r\n\r\n    public String getJobName() {\r\n        return jobName;\r\n    }\r\n\r\n    boolean decodeCommandAndJobNames(final String pathInfo) {\r\n        if (pathInfo.startsWith(URL_PREFIX)) {\r\n            final String restOfPath = pathInfo.substring(URL_PREFIX.length());\r\n            final int firstSlash = restOfPath.indexOf('/');\r\n            if (firstSlash != -1) {\r\n                commandName = restOfPath.substring(0, firstSlash);\r\n                if (firstSlash < restOfPath.length() - 1) {\r\n                    final String encodedJobName = restOfPath.substring(firstSlash + 1);\r\n                    try {\r\n                        jobName = URLDecoder.decode(encodedJobName, MediaType.UTF_8.name());\r\n                    } catch (final UnsupportedEncodingException e) {\r\n                        throw new Error(e);\r\n                    }\r\n                    return true;\r\n                }\r\n            } else {\r\n                commandName = restOfPath;\r\n            }\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * External endpoint for getting a description of the endpoints in this class.\r\n     */\r\n    public HttpResponse doIndex(final HttpServletRequest request) throws IOException {\r\n        final Class<? extends TeamBuildEndpoint> me = this.getClass();\r\n        final InputStream stream = me.getResourceAsStream(\"TeamBuildEndpoint.html\");\r\n        final Jenkins instance = Jenkins.getActiveInstance();\r\n        final String rootUrl = instance.getRootUrl();\r\n        final String commandRows = describeCommands(COMMAND_FACTORIES_BY_NAME, URL_NAME);\r\n        try {\r\n            final String template = IOUtils.toString(stream, MediaType.UTF_8);\r\n            final String content = String.format(template, URL_NAME, commandRows, rootUrl);\r\n            return HttpResponses.html(content);\r\n        } finally {\r\n            IOUtils.closeQuietly(stream);\r\n        }\r\n    }\r\n\r\n    static String describeCommands(final Map<String, AbstractCommand.Factory> commandMap, final String urlName) {\r\n        final String newLine = System.getProperty(\"line.separator\");\r\n        final StringBuilder sb = new StringBuilder();\r\n        for (final Map.Entry<String, AbstractCommand.Factory> commandPair : commandMap.entrySet()) {\r\n            final String commandName = commandPair.getKey();\r\n            final AbstractCommand.Factory factory = commandPair.getValue();\r\n            sb.append(\"<tr>\").append(newLine);\r\n            sb.append(\"<td valign='top'>\").append(commandName).append(\"</td>\").append(newLine);\r\n            sb.append(\"<td valign='top'>\").append('/').append(urlName).append('/').append(commandName).append('/').append(\"JOB_NAME\").append(\"</td>\").append(newLine);\r\n            final String rawSample = factory.getSampleRequestPayload();\r\n            final String escapedSample = StringEscapeUtils.escapeHtml4(rawSample);\r\n            sb.append(\"<td><pre>\").append(escapedSample).append(\"</pre></td>\").append(newLine);\r\n            sb.append(\"</tr>\").append(newLine);\r\n        }\r\n        return sb.toString();\r\n    }\r\n\r\n    @SuppressWarnings(\"deprecation\" /* We want to do exactly what Jenkins does */)\r\n    void checkPermission(final Job job, final ParameterizedJobMixIn.ParameterizedJob jobMixin,\r\n                         final StaplerRequest req, final StaplerResponse rsp) throws IOException {\r\n\r\n        final BuildAuthorizationToken authToken = jobMixin.getAuthToken();\r\n        hudson.model.BuildAuthorizationToken.checkPermission(job, authToken, req, rsp);\r\n    }\r\n\r\n    void dispatch(final StaplerRequest req, final StaplerResponse rsp, final TimeDuration delay) throws IOException {\r\n        try {\r\n            final JSONObject response = innerDispatch(req, rsp, delay);\r\n\r\n            if (response.containsKey(\"created\")) {\r\n                rsp.setStatus(SC_CREATED);\r\n            } else {\r\n                rsp.setStatus(SC_OK);\r\n            }\r\n            rsp.setContentType(MediaType.APPLICATION_JSON_UTF_8);\r\n            final PrintWriter w = rsp.getWriter();\r\n            final String responseJsonString = response.toString();\r\n            w.print(responseJsonString);\r\n            w.println();\r\n        } catch (final IllegalArgumentException e) {\r\n            LOGGER.log(Level.WARNING, \"IllegalArgumentException\", e);\r\n            EndpointHelper.error(SC_BAD_REQUEST, e);\r\n        } catch (final ForwardToView e) {\r\n            throw e;\r\n        } catch (final Exception e) {\r\n            final String template = \"Error while performing reaction to '%s' command.\";\r\n            final String message = String.format(template, commandName);\r\n            LOGGER.log(Level.SEVERE, message, e);\r\n            EndpointHelper.error(SC_INTERNAL_SERVER_ERROR, e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * If we are calling this method, it means we didn't find any job or project with jobName. Assuming we are building\r\n     * multibranch pipeline projects in this case.\r\n     *\r\n     * We will try to determine the branch name in the following sequence:\r\n     * 1. For JenkinsQueueJob task 1.115.0+, we send the branch in \"QueueJobTask.MultibranchPipelineBranch\".\r\n     * 2. Check if the jobName is composed from ${multibranch_pipeline}/${branch_name}\r\n     * 3. Check if the payload has BuildSource variable defined (for PR builds)\r\n     *\r\n     * If we can't determine the branch name, throw.\r\n     */\r\n    private String getBranch(final String jobName, final StaplerRequest req) {\r\n        final String json = req.getParameter(\"json\");\r\n        final JSONObject formData = JSONObject.fromObject(json);\r\n        final TeamBuildPayload payload = EndpointHelper.MAPPER.convertValue(formData, TeamBuildPayload.class);\r\n\r\n        String sourceBranch = payload.BuildVariables.get(QUEUEJOBTASK_MULTIBRANCH_JOB_BRANCH);\r\n\r\n        if (sourceBranch == null || sourceBranch.trim().isEmpty()) {\r\n            final int idx = jobName.indexOf('/');\r\n            if (idx > 0) {\r\n                sourceBranch = jobName.substring(idx + 1);\r\n            } else {\r\n                sourceBranch = payload.BuildVariables.get(BUILD_SOURCE_BRANCH);\r\n            }\r\n        }\r\n\r\n        if (sourceBranch == null || sourceBranch.trim().isEmpty()) {\r\n            throw new IllegalArgumentException(\"Could not find branch from job name.  If building a multibranch\"\r\n                    + \"pipeline job, the job name should be in the format of '${multibranch pipeline name}/${branch}.'\");\r\n        }\r\n\r\n        try {\r\n            return URLEncoder.encode(sourceBranch.replace(\"refs/heads/\", \"\"), \"UTF-8\");\r\n        } catch (final UnsupportedEncodingException e) {\r\n            throw new RuntimeException(\"Failed to encode branch: \" + sourceBranch, e);\r\n        }\r\n    }\r\n\r\n    private String getJobNameFromNestedFolder(final String jobName) {\r\n        final int idx = jobName.indexOf('/');\r\n        if (idx > 0) {\r\n            return jobName.substring(0, idx);\r\n        }\r\n\r\n        return jobName;\r\n    }\r\n\r\n    private Job getJob(final String jobName, final StaplerRequest req) {\r\n        final Jenkins jenkins = Jenkins.getActiveInstance();\r\n\r\n        Job job = jenkins.getItemByFullName(jobName, Job.class);\r\n\r\n        if (job == null) {\r\n            /* For jobs queued by JenkinsQueueJob task 1.115.0+, the jobname sent over the wire is the real job name\r\n             * without branch name tagged at the end.\r\n             * Try get the job as it was specified first, if there is no such job, fall back to existing logic and\r\n             * assume the jobname is in the format of ${multibranchPipelineJobname}/${branchName].\r\n             */\r\n            final Item mbPipelineJobItem = jenkins.getItemByFullName(jobName);\r\n            final Item item = (mbPipelineJobItem != null)\r\n                    ? mbPipelineJobItem : jenkins.getItemByFullName(getJobNameFromNestedFolder(jobName));\r\n\r\n            if (item != null) {\r\n                final Collection<? extends Job> allJobs = item.getAllJobs();\r\n                final String sourceBranch = getBranch(jobName, req);\r\n\r\n                for (final Job j : allJobs) {\r\n                    if (j.getName().equals(sourceBranch)) {\r\n                        job = j;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        if (job == null) {\r\n            throw new IllegalArgumentException(\"Job: \" + jobName + \" not found\");\r\n        }\r\n\r\n        return job;\r\n    }\r\n\r\n    private JSONObject innerDispatch(final StaplerRequest req, final StaplerResponse rsp, final TimeDuration delay) throws IOException, ServletException {\r\n        commandName = null;\r\n        jobName = null;\r\n        final String pathInfo = req.getPathInfo();\r\n        if (!decodeCommandAndJobNames(pathInfo)) {\r\n            if (commandName == null) {\r\n                throw new IllegalArgumentException(\"Command not provided\");\r\n            }\r\n            if (jobName == null) {\r\n                throw new IllegalArgumentException(\"Job name not provided after command\");\r\n            }\r\n        }\r\n\r\n        if (!COMMAND_FACTORIES_BY_NAME.containsKey(commandName)) {\r\n            throw new IllegalArgumentException(\"Command not implemented\");\r\n        }\r\n\r\n        final Job job = getJob(jobName, req);\r\n\r\n        final ParameterizedJobMixIn.ParameterizedJob jobMixin = (ParameterizedJobMixIn.ParameterizedJob) job;\r\n\r\n        checkPermission(job, jobMixin, req, rsp);\r\n        final TimeDuration actualDelay =\r\n                delay == null ? new TimeDuration(jobMixin.getQuietPeriod()) : delay;\r\n\r\n        final AbstractCommand.Factory factory = COMMAND_FACTORIES_BY_NAME.get(commandName);\r\n        final AbstractCommand command = factory.create();\r\n        final JSONObject response;\r\n        final JSONObject formData = req.getSubmittedForm();\r\n        final ObjectMapper mapper = EndpointHelper.MAPPER;\r\n        final TeamBuildPayload teamBuildPayload = mapper.convertValue(formData, TeamBuildPayload.class);\r\n\r\n        final BuildableItem buildable = (BuildableItem) job;\r\n        response = command.perform(job, buildable, req, formData, mapper, teamBuildPayload, actualDelay);\r\n        return response;\r\n    }\r\n\r\n    /**\r\n     * External endpoint for testing the connection to Jenkins.\r\n     */\r\n    public void doPing(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @QueryParameter final TimeDuration delay\r\n    ) throws IOException {\r\n        dispatch(request, response, delay);\r\n    }\r\n\r\n    /**\r\n     * External endpoint for triggering a build.\r\n     */\r\n    public void doBuild(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @QueryParameter final TimeDuration delay\r\n    ) throws IOException {\r\n        // Send telemetry\r\n        TelemetryHelper.sendEvent(\"team-build\", new TelemetryHelper.PropertyMapBuilder()\r\n                .build());\r\n\r\n        dispatch(request, response, delay);\r\n    }\r\n\r\n    /**\r\n     * External endpoint for triggering a build with paramters.\r\n     */\r\n    public void doBuildWithParameters(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @QueryParameter final TimeDuration delay\r\n    ) throws IOException {\r\n        // Send telemetry\r\n        TelemetryHelper.sendEvent(\"team-build-parameters\", new TelemetryHelper.PropertyMapBuilder()\r\n                .build());\r\n\r\n        dispatch(request, response, delay);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamCollectResultsPostBuildAction.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport hudson.Extension;\r\nimport hudson.FilePath;\r\nimport hudson.Launcher;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Run;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.TeamRequestedResult;\r\nimport hudson.plugins.tfs.model.TeamResultType;\r\nimport hudson.plugins.tfs.telemetry.TelemetryHelper;\r\nimport hudson.tasks.BuildStepDescriptor;\r\nimport hudson.tasks.BuildStepMonitor;\r\nimport hudson.tasks.Publisher;\r\nimport hudson.tasks.Recorder;\r\nimport hudson.util.DirScanner;\r\nimport hudson.util.io.Archiver;\r\nimport hudson.util.io.ArchiverFactory;\r\nimport jenkins.tasks.SimpleBuildStep;\r\nimport org.apache.commons.io.FileUtils;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\nimport org.kohsuke.stapler.DataBoundSetter;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport java.io.File;\r\nimport java.io.FileOutputStream;\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\nimport java.nio.file.Files;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\npublic class TeamCollectResultsPostBuildAction extends Recorder implements SimpleBuildStep {\r\n\r\n    private static final String TEAM_RESULTS = \"team-results\";\r\n    static final String TEAM_RESULTS_ZIP = \"team-results.zip\";\r\n\r\n    private List<TeamRequestedResult> requestedResults = new ArrayList<TeamRequestedResult>();\r\n\r\n    @DataBoundConstructor\r\n    public TeamCollectResultsPostBuildAction() {\r\n\r\n    }\r\n\r\n    public List<TeamRequestedResult> getRequestedResults() {\r\n        return requestedResults;\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setRequestedResults(final List<TeamRequestedResult> requestedResults) {\r\n        this.requestedResults = requestedResults;\r\n    }\r\n\r\n    @Override\r\n    public void perform(\r\n            @Nonnull final Run<?, ?> run,\r\n            @Nonnull final FilePath workspace,\r\n            @Nonnull final Launcher launcher,\r\n            @Nonnull final TaskListener listener) throws InterruptedException, IOException {\r\n        TelemetryHelper.sendEvent(\"team-collect-results\", new TelemetryHelper.PropertyMapBuilder()\r\n                .build());\r\n\r\n        // TODO: do we want to emit an error or warning like the following?\r\n        /*\r\n        if (requestedResults == null || requestedResults.size() == 0) {\r\n            final String template = \"No results were requested.  Aborting the '%s' post-build action.\";\r\n            final String message = String.format(template, displayName);\r\n            listener.error(message);\r\n            return;\r\n        }\r\n        */\r\n\r\n        final PrintStream logger = listener.getLogger();\r\n        logger.print(\"Recording results...\");\r\n        final File rootDir = run.getRootDir();\r\n        final File resultsRoot = new File(rootDir, TEAM_RESULTS);\r\n        for (final TeamRequestedResult requestedResult : requestedResults) {\r\n            final TeamResultType teamResultType = requestedResult.getTeamResultType();\r\n            final String folderName = teamResultType.getFolderName();\r\n            logger.print(\" \" + teamResultType.getDisplayName());\r\n            final File resultFolder = new File(resultsRoot, folderName);\r\n            Files.createDirectories(resultFolder.toPath());\r\n            final String includes = requestedResult.getIncludes();\r\n            final FilePath resultPath = new FilePath(resultFolder);\r\n            final int numCopied = workspace.copyRecursiveTo(includes, resultPath);\r\n            logger.print(\" (\" + numCopied + \" file\" + ((numCopied == 1) ? \"\" : \"s\") + \")\");\r\n        }\r\n        logger.print(\". Compressing...\");\r\n        final ArchiverFactory zip = ArchiverFactory.ZIP;\r\n        final File resultsZipFile = new File(rootDir, TEAM_RESULTS_ZIP);\r\n        final FileOutputStream outputStream = new FileOutputStream(resultsZipFile);\r\n        try {\r\n            final Archiver archiver = zip.create(outputStream);\r\n            try {\r\n                final DirScanner scanner = new DirScanner.Glob(TEAM_RESULTS + \"/**\", null, false);\r\n                scanner.scan(rootDir, archiver);\r\n            }\r\n            finally {\r\n                IOUtils.closeQuietly(archiver);\r\n            }\r\n        }\r\n        finally {\r\n            IOUtils.closeQuietly(outputStream);\r\n        }\r\n        FileUtils.deleteDirectory(resultsRoot);\r\n        TeamResultsAction.addToRun(run);\r\n        logger.println(\" Done.\");\r\n    }\r\n\r\n    @Override\r\n    public DescriptorImpl getDescriptor() {\r\n        return (DescriptorImpl) super.getDescriptor();\r\n    }\r\n\r\n    @Override\r\n    public BuildStepMonitor getRequiredMonitorService() {\r\n        return BuildStepMonitor.NONE;\r\n    }\r\n\r\n    @Extension\r\n    public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {\r\n\r\n        @Override\r\n        public boolean isApplicable(final Class<? extends AbstractProject> jobType) {\r\n            return true;\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Collect results for TFS/Team Services\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamCollectionConfiguration.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport com.cloudbees.plugins.credentials.Credentials;\r\nimport com.cloudbees.plugins.credentials.CredentialsMatcher;\r\nimport com.cloudbees.plugins.credentials.CredentialsMatchers;\r\nimport com.cloudbees.plugins.credentials.CredentialsProvider;\r\nimport com.cloudbees.plugins.credentials.CredentialsScope;\r\nimport com.cloudbees.plugins.credentials.SystemCredentialsProvider;\r\nimport com.cloudbees.plugins.credentials.common.StandardListBoxModel;\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport com.cloudbees.plugins.credentials.domains.Domain;\r\nimport com.cloudbees.plugins.credentials.domains.DomainRequirement;\r\nimport com.cloudbees.plugins.credentials.domains.DomainSpecification;\r\nimport com.cloudbees.plugins.credentials.domains.HostnameRequirement;\r\nimport com.cloudbees.plugins.credentials.domains.HostnameSpecification;\r\nimport com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;\r\nimport com.microsoft.tfs.core.exceptions.TFSUnauthorizedException;\r\nimport hudson.Extension;\r\nimport hudson.model.AbstractDescribableImpl;\r\nimport hudson.model.Descriptor;\r\nimport hudson.model.Item;\r\nimport hudson.model.ItemGroup;\r\nimport hudson.plugins.tfs.model.ConnectionParameters;\r\nimport hudson.plugins.tfs.model.ListOfGitRepositories;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.util.StringHelper;\r\nimport hudson.plugins.tfs.util.TeamRestClient;\r\nimport hudson.plugins.tfs.util.UriHelper;\r\nimport hudson.security.ACL;\r\nimport hudson.util.FormValidation;\r\nimport hudson.util.ListBoxModel;\r\nimport jenkins.model.Jenkins;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\nimport org.kohsuke.stapler.QueryParameter;\r\n\r\nimport java.io.IOException;\r\nimport java.net.URI;\r\nimport java.net.URISyntaxException;\r\nimport java.util.ArrayList;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\nimport java.util.UUID;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\n\r\npublic class TeamCollectionConfiguration extends AbstractDescribableImpl<TeamCollectionConfiguration> {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(TeamCollectionConfiguration.class.getName());\r\n\r\n    private final String collectionUrl;\r\n    private final String credentialsId;\r\n    private ConnectionParameters connectionParameters;\r\n\r\n    @DataBoundConstructor\r\n    public TeamCollectionConfiguration(final String collectionUrl, final String credentialsId) {\r\n        this.collectionUrl = collectionUrl;\r\n        this.credentialsId = credentialsId;\r\n    }\r\n\r\n    public String getCollectionUrl() {\r\n        return collectionUrl;\r\n    }\r\n\r\n    public String getCredentialsId() {\r\n        return credentialsId;\r\n    }\r\n\r\n    public ConnectionParameters getConnectionParameters() {\r\n        if (connectionParameters == null) {\r\n            connectionParameters = new ConnectionParameters();\r\n        }\r\n        return connectionParameters;\r\n    }\r\n\r\n    @Override\r\n    public DescriptorImpl getDescriptor() {\r\n        return (DescriptorImpl) super.getDescriptor();\r\n    }\r\n\r\n    @Extension\r\n    public static class DescriptorImpl extends Descriptor<TeamCollectionConfiguration> {\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Team Project Collection\";\r\n        }\r\n\r\n        @SuppressWarnings(\"unused\")\r\n        public FormValidation doCheckCollectionUrl(\r\n                @QueryParameter final String value) {\r\n\r\n            if (StringUtils.isBlank(value)) {\r\n                return FormValidation.warning(\"Please provide a value\");\r\n            }\r\n\r\n            final URI uri;\r\n            try {\r\n                uri = new URI(value);\r\n            }\r\n            catch (final URISyntaxException e) {\r\n                return FormValidation.error(\"Malformed TFS/Team Services collection URL (%s)\", e.getMessage());\r\n            }\r\n\r\n            final String hostName = uri.getHost();\r\n            if (StringUtils.isBlank(hostName)) {\r\n                return FormValidation.error(\"Please provide a host name\");\r\n            }\r\n            if (isTeamServices(hostName)) {\r\n                return checkTeamServices(uri);\r\n            }\r\n            // TODO: check that it's not a deep URL to a repository, work item, API endpoint, etc.\r\n\r\n            return FormValidation.ok();\r\n        }\r\n\r\n        @SuppressWarnings(\"unused\")\r\n        public FormValidation doTestCredentials(\r\n                @QueryParameter final String collectionUrl,\r\n                @QueryParameter final String credentialsId) {\r\n\r\n            final String errorTemplate = \"Error: %s\";\r\n\r\n            String hostName = null;\r\n            try {\r\n                final URI uri = new URI(collectionUrl);\r\n                hostName = uri.getHost();\r\n            }\r\n            catch (final URISyntaxException e) {\r\n                return FormValidation.error(errorTemplate, e.getMessage());\r\n            }\r\n\r\n            try {\r\n                final StandardUsernamePasswordCredentials credential = findCredentialsById(credentialsId);\r\n                if (isTeamServices(hostName)) {\r\n                    if (credential == null) {\r\n                        return FormValidation.error(errorTemplate, \"Team Services accounts need credentials, preferably a Personal Access Token\");\r\n                    }\r\n                }\r\n                return testConnection(collectionUrl, credential);\r\n            }\r\n            catch (final IOException e) {\r\n                return FormValidation.error(e, errorTemplate, e.getMessage());\r\n            }\r\n        }\r\n\r\n        @SuppressWarnings(\"unused\")\r\n        public ListBoxModel doFillCredentialsIdItems(\r\n            @QueryParameter final String collectionUrl) {\r\n\r\n            final Jenkins jenkins = Jenkins.getInstance();\r\n\r\n            String hostName = null;\r\n            try {\r\n                final URI uri = new URI(collectionUrl);\r\n                hostName = uri.getHost();\r\n            }\r\n            catch (final URISyntaxException ignored) {\r\n            }\r\n\r\n            if (hostName == null || !jenkins.hasPermission(Jenkins.ADMINISTER)) {\r\n                return new ListBoxModel();\r\n            }\r\n\r\n            final List<StandardUsernamePasswordCredentials> matches = findCredentials(hostName);\r\n            return new StandardListBoxModel()\r\n                    .withEmptySelection()\r\n                    .withAll(matches);\r\n        }\r\n    }\r\n\r\n    static FormValidation checkTeamServices(final URI uri) {\r\n        if (UriHelper.hasPath(uri)) {\r\n            return FormValidation.error(\"A Team Services collection URL must have an empty path.\");\r\n        }\r\n        return FormValidation.ok();\r\n    }\r\n\r\n    static boolean areSameCollectionUri(final URI a, final URI b) {\r\n        if (a == null) {\r\n            throw new IllegalArgumentException(\"Parameter 'a' is null\");\r\n        }\r\n        if (b == null) {\r\n            throw new IllegalArgumentException(\"Parameter 'b' is null\");\r\n        }\r\n\r\n        final String aHost = a.getHost();\r\n        final String bHost = b.getHost();\r\n        if (isTeamServices(aHost) && isTeamServices(bHost)) {\r\n            return StringHelper.equalIgnoringCase(aHost, bHost);\r\n        }\r\n\r\n        return UriHelper.areSame(a, b);\r\n    }\r\n\r\n    public static boolean isTeamServices(final String hostName) {\r\n        return StringHelper.endsWithIgnoreCase(hostName, \".visualstudio.com\");\r\n    }\r\n\r\n    static FormValidation testConnection(final String collectionUri, final StandardUsernamePasswordCredentials credentials) throws IOException {\r\n\r\n        final Server server = Server.create(null, null, collectionUri, credentials, null, null);\r\n        try {\r\n            final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n            return FormValidation.ok(\"Success via SOAP API.\");\r\n        }\r\n        catch (final TFSUnauthorizedException e) {\r\n            // performing TFVC requires All Scopes and someone might be setting up for Git only; ignore\r\n        }\r\n        final TeamRestClient client = new TeamRestClient(collectionUri, credentials);\r\n\r\n        try {\r\n            final ListOfGitRepositories repositories = client.getRepositories();\r\n            if (repositories.count < 1) {\r\n                return FormValidation.warning(\"There does not seem to be any Git repositories\");\r\n            }\r\n            return FormValidation.ok(\"Success via REST API.\");\r\n        }\r\n        catch (final IOException e) {\r\n            return FormValidation.error(\"Error: \" + e.getMessage());\r\n        }\r\n    }\r\n\r\n    static StandardUsernamePasswordCredentials findCredential(final String hostName, final String credentialsId) {\r\n        final List<StandardUsernamePasswordCredentials> matches = findCredentials(hostName);\r\n        final CredentialsMatcher matcher = CredentialsMatchers.withId(credentialsId);\r\n        final StandardUsernamePasswordCredentials result = CredentialsMatchers.firstOrNull(matches, matcher);\r\n        return result;\r\n    }\r\n\r\n    public static List<StandardUsernamePasswordCredentials> findCredentials(final String hostName) {\r\n        final Jenkins jenkins = Jenkins.getInstance();\r\n        return findCredentials(hostName, jenkins);\r\n    }\r\n\r\n    public static List<StandardUsernamePasswordCredentials> findCredentials(final String hostName, ItemGroup own) {\r\n        final HostnameRequirement requirement = new HostnameRequirement(hostName);\r\n        final List<StandardUsernamePasswordCredentials> matches =\r\n                CredentialsProvider.lookupCredentials(\r\n                        StandardUsernamePasswordCredentials.class,\r\n                        own,\r\n                        ACL.SYSTEM,\r\n                        requirement\r\n                );\r\n        return matches;\r\n    }\r\n\r\n    public static List<StandardUsernamePasswordCredentials> findCredentials(final String hostName, Item own) {\r\n        final HostnameRequirement requirement = new HostnameRequirement(hostName);\r\n        final List<StandardUsernamePasswordCredentials> matches =\r\n                CredentialsProvider.lookupCredentials(\r\n                        StandardUsernamePasswordCredentials.class,\r\n                        own,\r\n                        ACL.SYSTEM,\r\n                        requirement\r\n                );\r\n        return matches;\r\n    }\r\n\r\n    public static StandardUsernamePasswordCredentials findCredentialsById(final String credentialsId) {\r\n        final Jenkins jenkins = Jenkins.getInstance();\r\n        final List<StandardUsernamePasswordCredentials> matches =\r\n                CredentialsProvider.lookupCredentials(\r\n                        StandardUsernamePasswordCredentials.class,\r\n                        jenkins,\r\n                        ACL.SYSTEM,\r\n                        Collections.<DomainRequirement>emptyList()\r\n                );\r\n        final CredentialsMatcher matcher = CredentialsMatchers.withId(credentialsId);\r\n        final StandardUsernamePasswordCredentials result = CredentialsMatchers.firstOrNull(matches, matcher);\r\n        return result;\r\n    }\r\n\r\n    public static String setCredentials(final String hostName, String username, String password) {\r\n        List<DomainSpecification> domainSpecifications = new ArrayList<>();\r\n        domainSpecifications.add(new HostnameSpecification(hostName, null));\r\n        Domain domain = new Domain(\"Generated for \" + hostName, \"\", domainSpecifications);\r\n\r\n        SystemCredentialsProvider.getInstance().getDomainCredentialsMap().put(domain, new ArrayList<Credentials>());\r\n\r\n        String credentialsId;\r\n        StandardUsernamePasswordCredentials newCredential = new UsernamePasswordCredentialsImpl(\r\n                CredentialsScope.GLOBAL,\r\n                credentialsId = UUID.randomUUID().toString(),\r\n                \"Generated for \" + username,\r\n                username,\r\n                password\r\n        );\r\n        SystemCredentialsProvider.getInstance().getDomainCredentialsMap().get(domain).add(newCredential);\r\n\r\n        try {\r\n            SystemCredentialsProvider.getInstance().save();\r\n        } catch (IOException ex) {\r\n            LOGGER.log(Level.WARNING, \"SystemCredentialsProvider instance save failed: \", ex);\r\n        }\r\n\r\n        return credentialsId;\r\n    }\r\n\r\n    // TODO: we'll probably also want findCredentialsForGitRepo, where we match part of the URL path\r\n    public static StandardUsernamePasswordCredentials findCredentialsForCollection(final URI collectionUri) {\r\n        final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\r\n        // TODO: consider using a different data structure to speed up this look-up\r\n        final List<TeamCollectionConfiguration> pairs = config.getCollectionConfigurations();\r\n        for (final TeamCollectionConfiguration pair : pairs) {\r\n            final String candidateCollectionUrlString = pair.getCollectionUrl();\r\n            final URI candidateCollectionUri = URI.create(candidateCollectionUrlString);\r\n            if (areSameCollectionUri(candidateCollectionUri, collectionUri)) {\r\n                final String credentialsId = pair.credentialsId;\r\n                if (credentialsId != null) {\r\n                    return findCredentialsById(credentialsId);\r\n                }\r\n                return null;\r\n            }\r\n        }\r\n        final String template = \"There is no team project collection configured for the URL '%1$s'.%n\" +\r\n                \"Please go to Jenkins > Manage Jenkins > Configure System and then \" +\r\n                \"add a Team Project Collection with a Collection URL of '%1$s'.\";\r\n        final String message = String.format(template, collectionUri);\r\n        throw new IllegalArgumentException(message);\r\n    }\r\n\r\n    public static TeamCollectionConfiguration findCollection(final URI collectionUri) {\r\n        final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\r\n        // TODO: consider using a different data structure to speed up this look-up\r\n        final List<TeamCollectionConfiguration> pairs = config.getCollectionConfigurations();\r\n        for (final TeamCollectionConfiguration pair : pairs) {\r\n            final String candidateCollectionUrlString = pair.getCollectionUrl();\r\n            final URI candidateCollectionUri = URI.create(candidateCollectionUrlString);\r\n            if (areSameCollectionUri(candidateCollectionUri, collectionUri)) {\r\n                return pair;\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n\r\n    public static List<TeamCollectionConfiguration> getConnectedCollections() {\r\n        final List<TeamCollectionConfiguration> connectedCollections = new ArrayList<>();\r\n        final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\r\n        final List<TeamCollectionConfiguration> collections = config.getCollectionConfigurations();\r\n        for (final TeamCollectionConfiguration c : collections) {\r\n            if (c.getConnectionParameters().isSendJobCompletionEvents() && StringUtils.isNotEmpty(c.getConnectionParameters().getTeamCollectionUrl())) {\r\n                connectedCollections.add(c);\r\n            }\r\n        }\r\n        return connectedCollections;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamCompletedStatusPostBuildAction.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport hudson.Extension;\r\nimport hudson.FilePath;\r\nimport hudson.Launcher;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Descriptor;\r\nimport hudson.model.Run;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.util.TeamStatus;\r\nimport hudson.tasks.BuildStepDescriptor;\r\nimport hudson.tasks.BuildStepMonitor;\r\nimport hudson.tasks.Builder;\r\nimport hudson.tasks.Notifier;\r\nimport hudson.tasks.Publisher;\r\nimport jenkins.tasks.SimpleBuildStep;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport java.io.IOException;\r\n\r\n/**\r\n * A _Post-Build Action_ that reports the completion status of an associated build to TFS/Team Services.\r\n */\r\npublic class TeamCompletedStatusPostBuildAction extends Notifier implements SimpleBuildStep {\r\n\r\n    @DataBoundConstructor\r\n    public TeamCompletedStatusPostBuildAction() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public void perform(\r\n            @Nonnull final Run<?, ?> run,\r\n            @Nonnull final FilePath workspace,\r\n            @Nonnull final Launcher launcher,\r\n            @Nonnull final TaskListener listener\r\n    ) throws InterruptedException, IOException {\r\n        if (!TeamGlobalStatusAction.isApplicable(run)){\r\n            perform(run, listener);\r\n        }\r\n    }\r\n\r\n    public void perform(final @Nonnull Run<?, ?> run, final @Nonnull TaskListener listener) {\r\n        try {\r\n            TeamStatus.createFromRun(run, listener, getDisplayName());\r\n        }\r\n        catch (final IllegalArgumentException e) {\r\n            listener.error(e.getMessage());\r\n        }\r\n        catch (final Exception e) {\r\n            e.printStackTrace(listener.error(\"Error while trying to update completion status in TFS/Team Services\"));\r\n        }\r\n    }\r\n\r\n    String getDisplayName() {\r\n        final Descriptor<Builder> descriptor = getDescriptor();\r\n        return descriptor.getDisplayName();\r\n    }\r\n\r\n    @Override\r\n    public BuildStepMonitor getRequiredMonitorService() {\r\n        // we don't need the outcome of any previous builds for this step\r\n        return BuildStepMonitor.NONE;\r\n    }\r\n\r\n    @Extension\r\n    public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {\r\n\r\n        @Override\r\n        public boolean isApplicable(final Class<? extends AbstractProject> jobType) {\r\n            return true;\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Set build completion status in TFS/Team Services\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamEventsEndpoint.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport hudson.Extension;\r\nimport hudson.model.Item;\r\nimport hudson.model.Job;\r\nimport hudson.model.UnprotectedRootAction;\r\nimport hudson.plugins.git.GitStatus;\r\nimport hudson.plugins.tfs.model.AbstractHookEvent;\r\nimport hudson.plugins.tfs.model.ConnectHookEvent;\r\nimport hudson.plugins.tfs.model.GitPullRequestMergedEvent;\r\nimport hudson.plugins.tfs.model.GitPushEvent;\r\nimport hudson.plugins.tfs.model.PingHookEvent;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport hudson.plugins.tfs.rm.ConnectReleaseWebHookEvent;\r\nimport hudson.plugins.tfs.telemetry.TelemetryHelper;\r\nimport hudson.plugins.tfs.util.EndpointHelper;\r\nimport hudson.plugins.tfs.util.MediaType;\r\nimport hudson.plugins.tfs.util.StringBodyParameter;\r\nimport hudson.triggers.Trigger;\r\nimport jenkins.model.Jenkins;\r\nimport jenkins.model.ParameterizedJobMixIn;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.apache.commons.lang3.StringEscapeUtils;\r\nimport org.kohsuke.stapler.HttpResponse;\r\nimport org.kohsuke.stapler.HttpResponses;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\nimport org.kohsuke.stapler.StaplerResponse;\r\nimport org.kohsuke.stapler.interceptor.RequirePOST;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.PrintWriter;\r\nimport java.util.ArrayList;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.TreeMap;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\n\r\nimport static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;\r\nimport static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;\r\nimport static javax.servlet.http.HttpServletResponse.SC_OK;\r\n\r\n/**\r\n * The endpoint that TFS/Team Services will POST to on Git code push, pull request merge commit creation, etc.\r\n */\r\n@Extension\r\npublic class TeamEventsEndpoint implements UnprotectedRootAction {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(TeamEventsEndpoint.class.getName());\r\n    private static final Map<String, AbstractHookEvent.Factory> HOOK_EVENT_FACTORIES_BY_NAME;\r\n\r\n    static {\r\n        final Map<String, AbstractHookEvent.Factory> eventMap =\r\n                new TreeMap<String, AbstractHookEvent.Factory>(String.CASE_INSENSITIVE_ORDER);\r\n        eventMap.put(\"ping\", new PingHookEvent.Factory());\r\n        eventMap.put(\"gitPullRequestMerged\", new GitPullRequestMergedEvent.Factory());\r\n        eventMap.put(\"gitPush\", new GitPushEvent.Factory());\r\n        eventMap.put(\"connect\", new ConnectHookEvent.Factory());\r\n        eventMap.put(\"rmWebhook\", new ConnectReleaseWebHookEvent.Factory());\r\n        HOOK_EVENT_FACTORIES_BY_NAME = Collections.unmodifiableMap(eventMap);\r\n    }\r\n\r\n    public static final String URL_NAME = \"team-events\";\r\n    static final String URL_PREFIX = \"/\" + URL_NAME + \"/\";\r\n\r\n    @Override\r\n    public String getIconFileName() {\r\n        return null;\r\n    }\r\n\r\n    @Override\r\n    public String getDisplayName() {\r\n        return null;\r\n    }\r\n\r\n    @Override\r\n    public String getUrlName() {\r\n        return URL_NAME;\r\n    }\r\n\r\n    public HttpResponse doIndex(final HttpServletRequest request) throws IOException {\r\n        final Class<? extends TeamEventsEndpoint> me = this.getClass();\r\n        final InputStream stream = me.getResourceAsStream(\"TeamEventsEndpoint.html\");\r\n        final Jenkins instance = Jenkins.getActiveInstance();\r\n        final String rootUrl = instance.getRootUrl();\r\n        final String eventRows = describeEvents(HOOK_EVENT_FACTORIES_BY_NAME, URL_NAME);\r\n        try {\r\n            final String template = IOUtils.toString(stream, MediaType.UTF_8);\r\n            final String content = String.format(template, URL_NAME, eventRows, rootUrl);\r\n            return HttpResponses.html(content);\r\n        }\r\n        finally {\r\n            IOUtils.closeQuietly(stream);\r\n        }\r\n    }\r\n\r\n    static String describeEvents(final Map<String, AbstractHookEvent.Factory> eventMap, final String urlName) {\r\n        final String newLine = System.getProperty(\"line.separator\");\r\n        final StringBuilder sb = new StringBuilder();\r\n        for (final Map.Entry<String, AbstractHookEvent.Factory> eventPair : eventMap.entrySet()) {\r\n            final String eventName = eventPair.getKey();\r\n            final AbstractHookEvent.Factory factory = eventPair.getValue();\r\n            sb.append(\"<tr>\").append(newLine);\r\n            sb.append(\"<td valign='top'>\").append(eventName).append(\"</td>\").append(newLine);\r\n            sb.append(\"<td valign='top'>\").append('/').append(urlName).append('/').append(eventName).append(\"</td>\").append(newLine);\r\n            final String rawSample = factory.getSampleRequestPayload();\r\n            final String escapedSample = StringEscapeUtils.escapeHtml4(rawSample);\r\n            sb.append(\"<td><pre>\").append(escapedSample).append(\"</pre></td>\").append(newLine);\r\n            sb.append(\"</tr>\").append(newLine);\r\n        }\r\n        return sb.toString();\r\n    }\r\n\r\n    static String pathInfoToEventName(final String pathInfo) {\r\n        if (pathInfo.startsWith(URL_PREFIX)) {\r\n            final String restOfPath = pathInfo.substring(URL_PREFIX.length());\r\n            final int firstSlash = restOfPath.indexOf('/');\r\n            final String eventName;\r\n            if (firstSlash != -1) {\r\n                eventName = restOfPath.substring(0, firstSlash);\r\n            }\r\n            else {\r\n                eventName = restOfPath;\r\n            }\r\n            return eventName;\r\n        }\r\n        return null;\r\n    }\r\n\r\n    void dispatch(final StaplerRequest request, final StaplerResponse rsp, final String body) {\r\n        final String pathInfo = request.getPathInfo();\r\n        final String eventName = pathInfoToEventName(pathInfo);\r\n        try {\r\n            final JSONObject response = innerDispatch(body, eventName, HOOK_EVENT_FACTORIES_BY_NAME);\r\n\r\n            rsp.setStatus(SC_OK);\r\n            rsp.setContentType(MediaType.APPLICATION_JSON_UTF_8);\r\n            final PrintWriter w = rsp.getWriter();\r\n            final String responseJsonString = response.toString();\r\n            w.print(responseJsonString);\r\n            w.println();\r\n        }\r\n        catch (final IllegalArgumentException e) {\r\n            LOGGER.log(Level.WARNING, \"IllegalArgumentException\", e);\r\n            EndpointHelper.error(SC_BAD_REQUEST, e);\r\n        }\r\n        catch (final Exception e) {\r\n            final String template = \"Error while performing reaction to '%s' event.\";\r\n            final String message = String.format(template, eventName);\r\n            LOGGER.log(Level.SEVERE, message, e);\r\n            EndpointHelper.error(SC_INTERNAL_SERVER_ERROR, e);\r\n        }\r\n    }\r\n\r\n    static JSONObject innerDispatch(final String body, final String eventName, final Map<String, AbstractHookEvent.Factory> factoriesByName) throws IOException {\r\n        if (StringUtils.isBlank(eventName) || !factoriesByName.containsKey(eventName)) {\r\n            throw new IllegalArgumentException(\"Invalid event\");\r\n        }\r\n        final AbstractHookEvent.Factory factory = factoriesByName.get(eventName);\r\n        final Event serviceHookEvent = deserializeEvent(body);\r\n        final String message = serviceHookEvent.getMessage() != null ? serviceHookEvent.getMessage().getText() : \"\";\r\n        final String detailedMessage = serviceHookEvent.getDetailedMessage() != null ? serviceHookEvent.getDetailedMessage().getText() : \"\";\r\n        final AbstractHookEvent hookEvent = factory.create();\r\n        return hookEvent.perform(EndpointHelper.MAPPER, serviceHookEvent, message, detailedMessage);\r\n    }\r\n\r\n    public static Event deserializeEvent(final String input) throws IOException {\r\n        final Event serviceHookEvent = EndpointHelper.MAPPER.readValue(input, Event.class);\r\n        final String eventType = serviceHookEvent.getEventType();\r\n        if (StringUtils.isEmpty(eventType)) {\r\n            throw new IllegalArgumentException(\"Payload did not contain 'eventType'.\");\r\n        }\r\n        // TODO: assert eventType with what Factory claims to support\r\n        final Object resource = serviceHookEvent.getResource();\r\n        if (resource == null) {\r\n            throw new IllegalArgumentException(\"Payload did not contain 'resource'.\");\r\n        }\r\n        return serviceHookEvent;\r\n    }\r\n\r\n    @RequirePOST\r\n    public void doPing(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @StringBodyParameter @Nonnull final String body) {\r\n        dispatch(request, response, body);\r\n    }\r\n\r\n    @RequirePOST\r\n    public void doGitPullRequestMerged(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @StringBodyParameter @Nonnull final String body) {\r\n        // Send telemetry\r\n        TelemetryHelper.sendEvent(\"team-events-git-pr-merged\", new TelemetryHelper.PropertyMapBuilder()\r\n                .build());\r\n\r\n        dispatch(request, response, body);\r\n    }\r\n\r\n    @RequirePOST\r\n    public void doGitPush(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @StringBodyParameter @Nonnull final String body) {\r\n        // Send telemetry\r\n        TelemetryHelper.sendEvent(\"team-events-git-push\", new TelemetryHelper.PropertyMapBuilder()\r\n                .build());\r\n        dispatch(request, response, body);\r\n    }\r\n\r\n    @RequirePOST\r\n    public void doConnect(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @StringBodyParameter @Nonnull final String body) {\r\n        // Send telemetry\r\n        TelemetryHelper.sendEvent(\"team-events-connect\", new TelemetryHelper.PropertyMapBuilder()\r\n                .build());\r\n        dispatch(request, response, body);\r\n    }\r\n\r\n    @RequirePOST\r\n    public void doRmwebhook(\r\n            final StaplerRequest request,\r\n            final StaplerResponse response,\r\n            @StringBodyParameter @Nonnull final String body) {\r\n        // Send telemetry\r\n        TelemetryHelper.sendEvent(\"team-events-rmwebhook\", new TelemetryHelper.PropertyMapBuilder().build());\r\n        dispatch(request, response, body);\r\n    }\r\n\r\n    public static <T extends Trigger> T findTrigger(final Job<?, ?> job, final Class<T> tClass) {\r\n        if (job instanceof ParameterizedJobMixIn.ParameterizedJob) {\r\n            final ParameterizedJobMixIn.ParameterizedJob pJob = (ParameterizedJobMixIn.ParameterizedJob) job;\r\n            for (final Object trigger : pJob.getTriggers().values()) {\r\n                if (tClass.isInstance(trigger)) {\r\n                    return tClass.cast(trigger);\r\n                }\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n\r\n    // A job may have multiple triggers of the same type. For example, both TeamPRPushTrigger and TeamPushTrigger are TeamPushTrigger type.\r\n    public static <T extends Trigger> List<T> findTriggers(final Job<?, ?> job, final Class<T> tClass) {\r\n        List<T> triggerList = new ArrayList<>();\r\n        if (job instanceof ParameterizedJobMixIn.ParameterizedJob) {\r\n            final ParameterizedJobMixIn.ParameterizedJob pJob = (ParameterizedJobMixIn.ParameterizedJob) job;\r\n            for (final Object trigger : pJob.getTriggers().values()) {\r\n                if (tClass.isInstance(trigger)) {\r\n                    triggerList.add(tClass.cast(trigger));\r\n                }\r\n            }\r\n        }\r\n        return triggerList;\r\n    }\r\n\r\n    /**\r\n     * A response contributor for triggering polling of a project.\r\n     *\r\n     * @since 1.4.1\r\n     */\r\n    public static class PollingScheduledResponseContributor extends GitStatus.ResponseContributor {\r\n        /**\r\n         * The project\r\n         */\r\n        private final Item project;\r\n\r\n        /**\r\n         * Constructor.\r\n         *\r\n         * @param project the project.\r\n         */\r\n        public PollingScheduledResponseContributor(Item project) {\r\n            this.project = project;\r\n        }\r\n\r\n        /**\r\n         * {@inheritDoc}\r\n         */\r\n        @Override\r\n        public void addHeaders(StaplerRequest req, StaplerResponse rsp) {\r\n            rsp.addHeader(\"Triggered\", project.getAbsoluteUrl());\r\n        }\r\n\r\n        /**\r\n         * {@inheritDoc}\r\n         */\r\n        @Override\r\n        public void writeBody(PrintWriter w) {\r\n            w.println(\"Scheduled polling of \" + project.getFullDisplayName());\r\n        }\r\n    }\r\n\r\n    public static class ScheduledResponseContributor extends GitStatus.ResponseContributor {\r\n        /**\r\n         * The project\r\n         */\r\n        private final Item project;\r\n\r\n        /**\r\n         * Constructor.\r\n         *\r\n         * @param project the project.\r\n         */\r\n        public ScheduledResponseContributor(Item project) {\r\n            this.project = project;\r\n        }\r\n\r\n        /**\r\n         * {@inheritDoc}\r\n         */\r\n        @Override\r\n        public void addHeaders(StaplerRequest req, StaplerResponse rsp) {\r\n            rsp.addHeader(\"Triggered\", project.getAbsoluteUrl());\r\n        }\r\n\r\n        /**\r\n         * {@inheritDoc}\r\n         */\r\n        @Override\r\n        public void writeBody(PrintWriter w) {\r\n            w.println(\"Scheduled \" + project.getFullDisplayName());\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamFoundationServerScm.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.ChangesetVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\r\nimport hudson.Extension;\r\nimport hudson.FilePath;\r\nimport hudson.Launcher;\r\nimport hudson.Util;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Job;\r\nimport hudson.model.Computer;\r\nimport hudson.model.Node;\r\nimport hudson.model.ParametersAction;\r\nimport hudson.model.Run;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.actions.CheckoutAction;\r\nimport hudson.plugins.tfs.actions.RemoveWorkspaceAction;\r\nimport hudson.plugins.tfs.browsers.TeamFoundationServerRepositoryBrowser;\r\nimport hudson.plugins.tfs.browsers.TeamSystemWebAccessBrowser;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.plugins.tfs.model.CredentialsConfigurer;\r\nimport hudson.plugins.tfs.model.CredentialsConfigurerDescriptor;\r\nimport hudson.plugins.tfs.model.ManualCredentialsConfigurer;\r\nimport hudson.plugins.tfs.model.Project;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.WorkspaceConfiguration;\r\nimport hudson.plugins.tfs.util.BuildVariableResolver;\r\nimport hudson.plugins.tfs.util.BuildWorkspaceConfigurationRetriever;\r\nimport hudson.plugins.tfs.util.BuildWorkspaceConfigurationRetriever.BuildWorkspaceConfiguration;\r\nimport hudson.scm.ChangeLogParser;\r\nimport hudson.scm.PollingResult;\r\nimport hudson.scm.PollingResult.Change;\r\nimport hudson.scm.RepositoryBrowser;\r\nimport hudson.scm.RepositoryBrowsers;\r\nimport hudson.scm.SCM;\r\nimport hudson.scm.SCMDescriptor;\r\nimport hudson.scm.SCMRevisionState;\r\nimport hudson.util.ComboBoxModel;\r\nimport hudson.util.FormValidation;\r\nimport hudson.util.LogTaskListener;\r\nimport hudson.util.Scrambler;\r\nimport hudson.util.Secret;\r\nimport hudson.util.VariableResolver;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\nimport org.kohsuke.stapler.DataBoundSetter;\r\nimport org.kohsuke.stapler.QueryParameter;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\n\r\nimport javax.annotation.CheckForNull;\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.util.ArrayList;\r\nimport java.util.Calendar;\r\nimport java.util.Collection;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\nimport java.util.regex.Pattern;\r\n\r\nimport static hudson.Util.fixEmpty;\r\n\r\n/**\r\n * SCM for Microsoft Team Foundation Server.\r\n *\r\n * @author Erik Ramfelt\r\n */\r\npublic class TeamFoundationServerScm extends SCM {\r\n\r\n    public static final String WORKSPACE_ENV_STR = \"TFS_WORKSPACE\";\r\n    public static final String WORKFOLDER_ENV_STR = \"TFS_WORKFOLDER\";\r\n    public static final String PROJECTPATH_ENV_STR = \"TFS_PROJECTPATH\";\r\n    public static final String SERVERURL_ENV_STR = \"TFS_SERVERURL\";\r\n    public static final String USERNAME_ENV_STR = \"TFS_USERNAME\";\r\n    public static final String WORKSPACE_CHANGESET_ENV_STR = \"TFS_CHANGESET\";\r\n\r\n    private static final String VERSION_SPEC = \"VERSION_SPEC\";\r\n    private static final int RADIX_10 = 10;\r\n\r\n    private final String serverUrl;\r\n    private final String projectPath;\r\n    private Collection<String> cloakedPaths;\r\n    private String localPath;\r\n    private final String workspaceName;\r\n    @Deprecated private String userPassword;\r\n    private Secret password;\r\n    private String userName;\r\n    private CredentialsConfigurer credentialsConfigurer;\r\n    private boolean useUpdate;\r\n    private boolean useOverwrite;\r\n    private String versionSpec;\r\n\r\n    private TeamFoundationServerRepositoryBrowser repositoryBrowser;\r\n\r\n    private transient String normalizedWorkspaceName;\r\n    private transient String workspaceChangesetVersion;\r\n\r\n    private static final Logger logger = Logger.getLogger(TeamFoundationServerScm.class.getName());\r\n\r\n    /**\r\n     * Constructor used for unit tests.\r\n     *\r\n     * @param serverUrl the URL to the team project collection\r\n     * @param projectPath the path in TFVC to download from\r\n     * @param workspaceName the name (or expression) to use when mapping the workspace\r\n     */\r\n    TeamFoundationServerScm(final String serverUrl, final String projectPath, final String workspaceName) {\r\n        this(serverUrl, projectPath, workspaceName, null, null);\r\n    }\r\n\r\n    /**\r\n     * Constructor used during serialization (and a few tests).\r\n     *\r\n     * WARNING: do NOT add parameters to this constructor when adding fields for new settings.\r\n     * Instead, add a setter annotated with {@link DataBoundSetter} in the \"Bean properties\" section.\r\n     * See {@link #setLocalPath(String)} for an example.\r\n     *\r\n     * @param serverUrl the URL to the team project collection\r\n     * @param projectPath the path in TFVC to download from\r\n     * @param workspaceName the name (or expression) to use when mapping the workspace\r\n     * @param userName the name of the user account to use to talk to TFS/Team Services\r\n     * @param password the password or personal access token to use to talk to TFS/Team Services\r\n     */\r\n    @DataBoundConstructor\r\n    public TeamFoundationServerScm(final String serverUrl, final String projectPath, final String workspaceName, final String userName, final Secret password) {\r\n        this.serverUrl = serverUrl;\r\n        this.projectPath = projectPath;\r\n        this.workspaceName = (Util.fixEmptyAndTrim(workspaceName) == null ? \"Hudson-${JOB_NAME}-${NODE_NAME}\" : workspaceName);\r\n        this.userName = userName;\r\n        this.password = password;\r\n    }\r\n\r\n    @SuppressWarnings(\"unused\" /* Migrate legacy data */)\r\n    private Object readResolve() {\r\n        if (password == null && userPassword != null) {\r\n            password = Secret.fromString(Scrambler.descramble(userPassword));\r\n            userPassword = null;\r\n        }\r\n        if (userName != null && password != null) {\r\n            credentialsConfigurer = new ManualCredentialsConfigurer(userName, password);\r\n        }\r\n        return this;\r\n    }\r\n\r\n    // Bean properties needed for job configuration\r\n    public String getServerUrl() {\r\n        return serverUrl;\r\n    }\r\n\r\n    public String getWorkspaceName() {\r\n        return workspaceName;\r\n    }\r\n\r\n    public String getProjectPath() {\r\n        return projectPath;\r\n    }\r\n\r\n    public String getLocalPath() {\r\n        return (Util.fixEmptyAndTrim(localPath) == null ? \".\" : localPath);\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setLocalPath(final String localPath) {\r\n        this.localPath = localPath;\r\n    }\r\n\r\n    public String getVersionSpec() {\r\n        return versionSpec;\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setVersionSpec(final String versionSpec) {\r\n        this.versionSpec = versionSpec;\r\n    }\r\n\r\n    public boolean isUseUpdate() {\r\n        return useUpdate;\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setUseUpdate(final boolean useUpdate) {\r\n        this.useUpdate = useUpdate;\r\n    }\r\n\r\n    public boolean isUseOverwrite() {\r\n        return useOverwrite;\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setUseOverwrite(final boolean useOverwrite) {\r\n        this.useOverwrite = useOverwrite;\r\n    }\r\n\r\n    public String getUserPassword() {\r\n        return Secret.toString(password);\r\n    }\r\n\r\n    public Secret getPassword() {\r\n        return password;\r\n    }\r\n\r\n    public String getUserName() {\r\n        return userName;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @return a ManualCredentialsConfigurer object with the supplied userName/password\r\n     */\r\n    public CredentialsConfigurer getCredentialsConfigurer() {\r\n        if (credentialsConfigurer == null) {\r\n            credentialsConfigurer = new ManualCredentialsConfigurer(userName, password);\r\n        }\r\n        return credentialsConfigurer;\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setCredentialsConfigurer(final CredentialsConfigurer credentialsConfigurer) {\r\n        this.credentialsConfigurer = credentialsConfigurer;\r\n    }\r\n\r\n    public String getCloakedPaths() {\r\n        return serializeCloakedPathCollectionToString(this.cloakedPaths);\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setCloakedPaths(final String cloakedPaths) {\r\n        this.cloakedPaths = splitCloakedPaths(cloakedPaths);\r\n    }\r\n\r\n    // Bean properties END\r\n\r\n    static String serializeCloakedPathCollectionToString(final Collection<String> cloakedPaths) {\r\n        return cloakedPaths == null ? StringUtils.EMPTY : StringUtils.join(cloakedPaths, \"\\n\");\r\n    }\r\n\r\n    String getWorkspaceName(final Run<?, ?> build, final Computer computer) {\r\n        normalizedWorkspaceName = workspaceName;\r\n        if (build != null) {\r\n            normalizedWorkspaceName = substituteBuildParameter(build, normalizedWorkspaceName);\r\n            normalizedWorkspaceName = Util.replaceMacro(normalizedWorkspaceName, new BuildVariableResolver(build.getParent(), computer));\r\n        }\r\n        normalizedWorkspaceName = normalizedWorkspaceName.replaceAll(\"[\\\"/:<>\\\\|\\\\*\\\\?]+\", \"_\");\r\n        normalizedWorkspaceName = normalizedWorkspaceName.replaceAll(\"[\\\\.\\\\s]+$\", \"_\");\r\n        return normalizedWorkspaceName;\r\n    }\r\n\r\n    /**\r\n     * Returns the URL to the team project collection.\r\n     */\r\n    public String getServerUrl(final Run<?, ?> run) {\r\n        return substituteBuildParameter(run, serverUrl);\r\n    }\r\n\r\n    String getProjectPath(final Run<?, ?> run) {\r\n        return Util.replaceMacro(substituteBuildParameter(run, projectPath), new BuildVariableResolver(run.getParent()));\r\n    }\r\n\r\n    Collection<String> getCloakedPaths(final Run<?, ?> run) {\r\n        final List<String> paths = new ArrayList<String>();\r\n        if (cloakedPaths != null) {\r\n            final BuildVariableResolver resolver = new BuildVariableResolver(run.getParent());\r\n            for (final String cloakedPath : cloakedPaths) {\r\n                final String path = substituteBuildParameter(run, cloakedPath);\r\n                final String enhancedPath = Util.replaceMacro(path, resolver);\r\n                paths.add(enhancedPath);\r\n            }\r\n        }\r\n        return paths;\r\n    }\r\n\r\n    private String substituteBuildParameter(final Run<?, ?> run, final String text) {\r\n        if (run instanceof AbstractBuild<?, ?>) {\r\n            AbstractBuild<?, ?> build = (AbstractBuild<?, ?>) run;\r\n            if (build.getAction(ParametersAction.class) != null) {\r\n                return build.getAction(ParametersAction.class).substitute(build, text);\r\n            }\r\n        }\r\n        return text;\r\n    }\r\n\r\n    static Collection<String> splitCloakedPaths(final String cloakedPaths) {\r\n        final List<String> cloakedPathsList = new ArrayList<String>();\r\n        if (cloakedPaths != null && cloakedPaths.length() > 0) {\r\n            final StringBuilder cloakedPath = new StringBuilder(cloakedPaths.length());\r\n            for (final char character : cloakedPaths.toCharArray()) {\r\n                switch (character) {\r\n                    case '\\n':\r\n                        if (cloakedPath.length() > 0) {\r\n                            cloakedPathsList.add(cloakedPath.toString().trim());\r\n                            cloakedPath.setLength(0);\r\n                        }\r\n                        break;\r\n                    default:\r\n                        cloakedPath.append(character);\r\n                        break;\r\n                }\r\n            }\r\n            if (cloakedPath.length() > 0) {\r\n                cloakedPathsList.add(cloakedPath.toString().trim());\r\n            }\r\n        }\r\n        return cloakedPathsList;\r\n    }\r\n\r\n    @Override\r\n    public void checkout(final Run<?, ?> build, final Launcher launcher, final FilePath workspaceFilePath, final TaskListener listener, final File changelogFile, final SCMRevisionState baseline) throws IOException, InterruptedException {\r\n        Server server = createServer(launcher, listener, build);\r\n        try {\r\n            WorkspaceConfiguration workspaceConfiguration = new WorkspaceConfiguration(server.getUrl(), getWorkspaceName(build, workspaceFilePath.toComputer()), getProjectPath(build), getCloakedPaths(build), getLocalPath());\r\n            final Run<?, ?> previousBuild = build.getPreviousBuild();\r\n            // Check if the configuration has changed\r\n            if (previousBuild != null) {\r\n                Computer computer = workspaceFilePath.toComputer();\r\n                if (computer != null) {\r\n                    BuildWorkspaceConfiguration nodeConfiguration = new BuildWorkspaceConfigurationRetriever().getLatestForNode(computer.getNode(), previousBuild);\r\n                    if ((nodeConfiguration != null)\r\n                            && nodeConfiguration.workspaceExists()\r\n                            && (!workspaceConfiguration.equals(nodeConfiguration))) {\r\n                        listener.getLogger().println(\"Deleting workspace as the configuration has changed since a build was performed on this computer.\");\r\n                        new RemoveWorkspaceAction(workspaceConfiguration.getWorkspaceName()).remove(server);\r\n                        nodeConfiguration.setWorkspaceWasRemoved();\r\n                        nodeConfiguration.save();\r\n                    }\r\n                }\r\n            }\r\n\r\n            build.addAction(workspaceConfiguration);\r\n            String singleVersionSpec = versionSpec;\r\n\r\n            if (build instanceof AbstractBuild) {\r\n                VariableResolver<String> buildVariableResolver = ((AbstractBuild<?, ?>) build).getBuildVariableResolver();\r\n                singleVersionSpec = buildVariableResolver.resolve(VERSION_SPEC);\r\n            }\r\n\r\n            final String projPath = workspaceConfiguration.getProjectPath();\r\n            final Project project = server.getProject(projPath);\r\n            final int changeSet = recordWorkspaceChangesetVersion(build, listener, project, projPath, singleVersionSpec);\r\n\r\n            CheckoutAction action = new CheckoutAction(workspaceConfiguration.getWorkspaceName(), workspaceConfiguration.getProjectPath(), workspaceConfiguration.getCloakedPaths(), workspaceConfiguration.getWorkfolder(), isUseUpdate(), isUseOverwrite());\r\n            List<ChangeSet> list;\r\n            if (StringUtils.isNotEmpty(singleVersionSpec)) {\r\n                list = action.checkoutBySingleVersionSpec(server, workspaceFilePath, singleVersionSpec);\r\n            } else {\r\n                final VersionSpec previousBuildVersionSpec = determineVersionSpecFromBuild(previousBuild, 1, changeSet);\r\n                final ChangesetVersionSpec currentBuildVersionSpec = new ChangesetVersionSpec(changeSet);\r\n                list = action.checkout(server, workspaceFilePath, previousBuildVersionSpec, currentBuildVersionSpec);\r\n            }\r\n\r\n            if (changelogFile != null) {\r\n                ChangeSetWriter writer = new ChangeSetWriter();\r\n                writer.write(list, changelogFile);\r\n            }\r\n        } finally {\r\n            server.close();\r\n        }\r\n    }\r\n\r\n    static VersionSpec determineVersionSpecFromBuild(final Run<?, ?> build, final int offset, final int maximumChangeSetNumber) {\r\n        final VersionSpec result;\r\n        if (build != null) {\r\n            final TFSRevisionState revisionState = build.getAction(TFSRevisionState.class);\r\n            if (revisionState != null) {\r\n                final int changeSetNumber = revisionState.changesetVersion + offset;\r\n                if (changeSetNumber <= maximumChangeSetNumber) {\r\n                    result = new ChangesetVersionSpec(changeSetNumber);\r\n                } else {\r\n                    result = null;\r\n                }\r\n            } else {\r\n                result = null;\r\n            }\r\n        } else {\r\n            result = null;\r\n        }\r\n        return result;\r\n    }\r\n\r\n    int recordWorkspaceChangesetVersion(final Run<?, ?> build, final TaskListener listener, final Project project, final String projectPath, final String singleVersionSpec) throws IOException, InterruptedException {\r\n        final VersionSpec workspaceVersion;\r\n\r\n        if (!StringUtils.isEmpty(singleVersionSpec)) {\r\n            workspaceVersion = VersionSpec.parseSingleVersionFromSpec(singleVersionSpec, null);\r\n        } else {\r\n            workspaceVersion = new DateVersionSpec(build.getTimestamp());\r\n        }\r\n        int buildChangeset;\r\n        setWorkspaceChangesetVersion(null);\r\n        buildChangeset = project.getRemoteChangesetVersion(workspaceVersion);\r\n        setWorkspaceChangesetVersion(Integer.toString(buildChangeset, RADIX_10));\r\n\r\n        // by adding this action, we prevent calcRevisionsFromBuild() from being called\r\n        build.addAction(new TFSRevisionState(buildChangeset, projectPath));\r\n\r\n        return buildChangeset;\r\n    }\r\n\r\n    void setWorkspaceChangesetVersion(final String workspaceChangesetVersion) {\r\n        this.workspaceChangesetVersion = workspaceChangesetVersion;\r\n    }\r\n\r\n    @Override\r\n    public boolean pollChanges(final AbstractProject hudsonProject, final Launcher launcher, final FilePath workspace, final TaskListener listener) throws IOException, InterruptedException {\r\n        Run<?, ?> lastRun = hudsonProject.getLastBuild();\r\n        if (lastRun == null) {\r\n            return true;\r\n        } else {\r\n            Server server = createServer(launcher, listener, lastRun);\r\n            try {\r\n                return (server.getProject(getProjectPath(lastRun)).getDetailedHistoryWithoutCloakedPaths(\r\n                            lastRun.getTimestamp(),\r\n                            Calendar.getInstance(),\r\n                            getCloakedPaths(lastRun)\r\n                        ).size() > 0);\r\n            } finally {\r\n                server.close();\r\n            }\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public boolean processWorkspaceBeforeDeletion(final Job<?, ?> project, final FilePath workspace, final Node node) throws IOException, InterruptedException {\r\n        Node nodeIter = node;\r\n        Run<?, ?> lastRun = project.getLastBuild();\r\n        if (lastRun == null) {\r\n            return true;\r\n        }\r\n\r\n        // Due to an error in Hudson core (pre 1.321), null was sent in for all invocations of this method\r\n        // Therefore we try to work around the problem, and see if its only built on one node or not.\r\n        if (nodeIter == null) {\r\n            while (lastRun != null) {\r\n                if (!(lastRun instanceof AbstractBuild<?, ?>)) {\r\n                    return false;\r\n                }\r\n                AbstractBuild<?, ?> build = (AbstractBuild) lastRun;\r\n                Node buildNode = build.getBuiltOn();\r\n                if (nodeIter == null) {\r\n                    nodeIter = buildNode;\r\n                } else {\r\n                    if (!buildNode.getNodeName().equals(nodeIter.getNodeName())) {\r\n                        logger.warning(\"Could not wipe out workspace as there is no way of telling what Node the request is for. Please upgrade Hudson to a newer version.\");\r\n                        return false;\r\n                    }\r\n                }\r\n                lastRun = lastRun.getPreviousBuild();\r\n            }\r\n            if (nodeIter == null) {\r\n                return true;\r\n            }\r\n            lastRun = project.getLastBuild();\r\n        }\r\n\r\n        BuildWorkspaceConfiguration configuration = new BuildWorkspaceConfigurationRetriever().getLatestForNode(nodeIter, lastRun);\r\n        if ((configuration != null) && configuration.workspaceExists()) {\r\n            LogTaskListener listener = new LogTaskListener(logger, Level.INFO);\r\n            Launcher launcher = nodeIter.createLauncher(listener);\r\n            Server server = createServer(launcher, listener, lastRun);\r\n            try {\r\n                if (new RemoveWorkspaceAction(configuration.getWorkspaceName()).remove(server)) {\r\n                    configuration.setWorkspaceWasRemoved();\r\n                    configuration.save();\r\n                }\r\n            } finally {\r\n                server.close();\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n\r\n    protected Server createServer(final Launcher launcher, final TaskListener taskListener, final Run<?, ?> run) throws IOException {\r\n        final CredentialsConfigurer credentialsConfig = getCredentialsConfigurer();\r\n        final String collectionUri = getServerUrl(run);\r\n        final StandardUsernamePasswordCredentials credentials = credentialsConfig.getCredentials(collectionUri);\r\n        return Server.create(launcher, taskListener, collectionUri, credentials, null, null);\r\n    }\r\n\r\n    @Override\r\n    public boolean requiresWorkspaceForPolling() {\r\n        return false;\r\n    }\r\n\r\n    @Override\r\n    public boolean supportsPolling() {\r\n        return true;\r\n    }\r\n\r\n    @Override\r\n    public ChangeLogParser createChangeLogParser() {\r\n        return new ChangeSetReader();\r\n    }\r\n\r\n    @Override\r\n    public FilePath getModuleRoot(final FilePath workspace) {\r\n        return workspace.child(getLocalPath());\r\n    }\r\n\r\n    @Override\r\n    public TeamFoundationServerRepositoryBrowser getBrowser() {\r\n        return repositoryBrowser;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @return a new TeamSystemWebAccessBrowser even if no repository browser (value in UI is Auto) is\r\n     * configured since its the only implementation that exists anyway\r\n     */\r\n    @Override\r\n    @CheckForNull\r\n    public RepositoryBrowser<?> guessBrowser() {\r\n        return new TeamSystemWebAccessBrowser(serverUrl);\r\n    }\r\n\r\n    // Convenience method for tests.\r\n    public void setRepositoryBrowser(final TeamFoundationServerRepositoryBrowser repositoryBrowser) {\r\n        this.repositoryBrowser = repositoryBrowser;\r\n    }\r\n\r\n\r\n    // TODO: 2.60+ Delete this override.\r\n    @Override\r\n    public void buildEnvVars(final AbstractBuild<?, ?> build, final Map<String, String> env) {\r\n        buildEnvironment(build, env);\r\n    }\r\n\r\n    /**\r\n     * TODO: 2.60+ - add @Override.\r\n     * Sets the environment variables TFS_WORKSPACE, TFS_WORKFOLDER, TFS_PROJECTPATH, TFS_SERVERURL, TFS_USERNAME, TFS_CHANGESET and\r\n     * VERSION_SPEC during the build\r\n     */\r\n    public void buildEnvironment(final Run<?, ?> build, final Map<String, String> env) {\r\n        final TeamBuildDetailsAction buildDetailsAction = build.getAction(TeamBuildDetailsAction.class);\r\n        if (buildDetailsAction != null) {\r\n            //Add the TFS build variables as environment variables in the Jenkins environment\r\n            //https://www.visualstudio.com/en-us/docs/build/define/variables\r\n            for (Map.Entry<String, String> entry : buildDetailsAction.buildVariables.entrySet()) {\r\n                String key = entry.getKey();\r\n                String value = entry.getValue();\r\n                if (value != null) {\r\n                    //Replace . with _ and ensure they're UPPERCASE to match Team Services pattern\r\n                    env.put(key.replace('.', '_').toUpperCase(), value);\r\n                }\r\n            }\r\n        }\r\n\r\n        if (normalizedWorkspaceName != null) {\r\n            env.put(WORKSPACE_ENV_STR, normalizedWorkspaceName);\r\n        }\r\n        if (env.containsKey(\"WORKSPACE\")) {\r\n            env.put(WORKFOLDER_ENV_STR, env.get(\"WORKSPACE\") + File.separator + getLocalPath());\r\n        }\r\n        if (projectPath != null) {\r\n            env.put(PROJECTPATH_ENV_STR, projectPath);\r\n        }\r\n        if (serverUrl != null) {\r\n            env.put(SERVERURL_ENV_STR, serverUrl);\r\n        }\r\n        if (userName != null) {\r\n            env.put(USERNAME_ENV_STR, userName);\r\n        }\r\n        if (workspaceChangesetVersion != null && workspaceChangesetVersion.length() > 0) {\r\n            env.put(WORKSPACE_CHANGESET_ENV_STR, workspaceChangesetVersion);\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public DescriptorImpl getDescriptor() {\r\n        return (DescriptorImpl) super.getDescriptor();\r\n    }\r\n\r\n    /** Descriptor implementation class. Used to create instances of TeamFoundationServerScm. */\r\n    @Extension\r\n    public static class DescriptorImpl extends SCMDescriptor<TeamFoundationServerScm> {\r\n\r\n        public static final Pattern WORKSPACE_NAME_REGEX = Pattern.compile(\"[^\\\"/:<>\\\\|\\\\*\\\\?]+[^\\\\s\\\\.\\\"/:<>\\\\|\\\\*\\\\?]$\", Pattern.CASE_INSENSITIVE);\r\n        public static final Pattern PROJECT_PATH_REGEX = Pattern.compile(\"^\\\\$\\\\/.*\", Pattern.CASE_INSENSITIVE);\r\n        public static final Pattern CLOAKED_PATHS_REGEX = Pattern.compile(\"\\\\s*\\\\$[^\\\\n;]+(\\\\s*[\\\\n]\\\\s*\\\\$[^\\\\n;]+){0,}\\\\s*\", Pattern.CASE_INSENSITIVE);\r\n\r\n        @Override\r\n        public boolean isApplicable(final Job project) {\r\n            return true;\r\n        }\r\n\r\n        public DescriptorImpl() {\r\n            super(TeamFoundationServerScm.class, TeamFoundationServerRepositoryBrowser.class);\r\n            load();\r\n        }\r\n\r\n        @Override\r\n        public SCM newInstance(final StaplerRequest req, final JSONObject formData) throws FormException {\r\n            TeamFoundationServerScm scm = (TeamFoundationServerScm) super.newInstance(req, formData);\r\n            scm.repositoryBrowser = RepositoryBrowsers.createInstance(TeamFoundationServerRepositoryBrowser.class, req, formData,  \"browser\");\r\n            // TODO: is there a more polymorphic way of doing this?\r\n            if (scm.credentialsConfigurer instanceof ManualCredentialsConfigurer) {\r\n                // ManualCredentialsConfigurer has its fields \"transient\"; transfer the values here\r\n                // for backward-compatibility\r\n                final ManualCredentialsConfigurer manualCredentialsConfigurer = (ManualCredentialsConfigurer) scm.credentialsConfigurer;\r\n                scm.userName = manualCredentialsConfigurer.getUserName();\r\n                scm.password = manualCredentialsConfigurer.getPassword();\r\n            }\r\n            return scm;\r\n        }\r\n\r\n        private FormValidation doRegexCheck(final Pattern[] regexArray,\r\n                final String noMatchText, final String nullText, final String value) {\r\n            String val = value;\r\n            val = fixEmpty(val);\r\n            if (val == null) {\r\n                if (nullText == null) {\r\n                    return FormValidation.ok();\r\n                } else {\r\n                    return FormValidation.error(nullText);\r\n                }\r\n            }\r\n            for (Pattern regex : regexArray) {\r\n                if (regex.matcher(val).matches()) {\r\n                    return FormValidation.ok();\r\n                }\r\n            }\r\n            return FormValidation.error(noMatchText);\r\n        }\r\n\r\n        /** Populates comboBox with detected collections URLs. */\r\n        public ComboBoxModel doFillServerUrlItems() {\r\n            final TeamPluginGlobalConfig pluginGlobalConfig = TeamPluginGlobalConfig.get();\r\n            final List<TeamCollectionConfiguration> collectionConfigurations = pluginGlobalConfig.getCollectionConfigurations();\r\n            final ComboBoxModel result = new ComboBoxModel(collectionConfigurations.size());\r\n            for (final TeamCollectionConfiguration collectionConfiguration : collectionConfigurations) {\r\n                result.add(collectionConfiguration.getCollectionUrl());\r\n            }\r\n            return result;\r\n        }\r\n\r\n        /** Validates Project path form field. */\r\n        public FormValidation doProjectPathCheck(@QueryParameter final String value) {\r\n            return doRegexCheck(new Pattern[]{PROJECT_PATH_REGEX},\r\n                    \"Project path must begin with '$/'.\",\r\n                    \"Project path is mandatory.\", value);\r\n        }\r\n\r\n        /** Validates Workspace form field. */\r\n        public FormValidation doWorkspaceNameCheck(@QueryParameter final String value) {\r\n            return doRegexCheck(new Pattern[]{WORKSPACE_NAME_REGEX},\r\n                    \"Workspace name cannot end with a space or period, and cannot contain any of the following characters: \\\"/:<>|*?\",\r\n                    \"Workspace name is mandatory\", value);\r\n        }\r\n\r\n        /** Validates Cloaked Paths form field. */\r\n        public FormValidation doCloakedPathsCheck(@QueryParameter final String value) {\r\n            return doRegexCheck(new Pattern[]{CLOAKED_PATHS_REGEX},\r\n                    \"Each cloaked path must begin with '$/'. Multiple paths must be separated by blank lines.\",\r\n                    null, value);\r\n        }\r\n\r\n        public List<CredentialsConfigurerDescriptor> getCredentialsConfigurerDescriptors() {\r\n            return CredentialsConfigurer.all();\r\n        }\r\n\r\n        @Override\r\n        public boolean configure(final StaplerRequest req, final JSONObject formData) throws FormException {\r\n            save();\r\n            return true;\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Team Foundation Version Control (TFVC)\";\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public SCMRevisionState calcRevisionsFromBuild(final Run<?, ?> build,\r\n            final FilePath workspace,\r\n            final Launcher launcher, final TaskListener listener) throws IOException,\r\n            InterruptedException {\r\n        /*\r\n         * This method does nothing, since the work has already been done in\r\n         * the checkout() method, as per the documentation:\r\n         * \"\"\"\r\n         * As an optimization, SCM implementation can choose to compute SCMRevisionState\r\n         * and add it as an action during check out, in which case this method will not called.\r\n         * \"\"\"\r\n         */\r\n        return SCMRevisionState.NONE;\r\n    }\r\n\r\n    @Override\r\n    public PollingResult compareRemoteRevisionWith(\r\n            final Job<?, ?> project, final Launcher launcher,\r\n            final FilePath workspace, final TaskListener listener, final SCMRevisionState baseline)\r\n            throws IOException, InterruptedException {\r\n\r\n        final Launcher localLauncher = launcher != null ? launcher : new Launcher.LocalLauncher(listener);\r\n        Run<?, ?> build = project.getLastBuild();\r\n        final Server server = createServer(localLauncher, listener, build);\r\n\r\n        if (!(baseline instanceof TFSRevisionState)) {\r\n            // This plugin was just upgraded, we don't yet have a new-style baseline,\r\n            // so we perform an old-school poll\r\n            if (project instanceof AbstractProject) {\r\n                boolean shouldBuild = pollChanges((AbstractProject) project, localLauncher, workspace, listener);\r\n                return shouldBuild ? PollingResult.BUILD_NOW : PollingResult.NO_CHANGES;\r\n            } else {\r\n                // On the pipeline case, we can't call pollChanges. Query the TFS Server directly instead\r\n                if (build == null) {\r\n                    return PollingResult.BUILD_NOW;\r\n                } else {\r\n                    try {\r\n                        return (server.getProject(getProjectPath(build)).getDetailedHistoryWithoutCloakedPaths(\r\n                                build.getTimestamp(),\r\n                                Calendar.getInstance(),\r\n                                getCloakedPaths(build)\r\n                        ).size() > 0) ? PollingResult.BUILD_NOW : PollingResult.NO_CHANGES;\r\n                    } finally {\r\n                        server.close();\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        final TFSRevisionState tfsBaseline = (TFSRevisionState) baseline;\r\n        if (!projectPath.equalsIgnoreCase(tfsBaseline.projectPath)) {\r\n            // There's no PollingResult.INCOMPARABLE, so we use the next closest thing\r\n            return PollingResult.BUILD_NOW;\r\n        }\r\n        final Project tfsProject = server.getProject(projectPath);\r\n        try {\r\n            final ChangeSet latest = tfsProject.getLatestUncloakedChangeset(tfsBaseline.changesetVersion, cloakedPaths);\r\n            final TFSRevisionState tfsRemote =\r\n                    (latest != null)\r\n                    ? new TFSRevisionState(latest.getVersion(), projectPath)\r\n                    : tfsBaseline;\r\n\r\n            // TODO: we could return INSIGNIFICANT if all the changesets\r\n            // contain the string \"***NO_CI***\" at the end of their comment\r\n            final Change change =\r\n                    tfsBaseline.changesetVersion == tfsRemote.changesetVersion\r\n                    ? Change.NONE\r\n                    : Change.SIGNIFICANT;\r\n            return new PollingResult(tfsBaseline, tfsRemote, change);\r\n        } catch (final Exception e) {\r\n            e.printStackTrace(listener.fatalError(e.getMessage()));\r\n            return PollingResult.NO_CHANGES;\r\n        } finally {\r\n            server.close();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamGlobalStatusAction.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.model.Action;\r\nimport hudson.model.InvisibleAction;\r\nimport hudson.model.Run;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.List;\r\n\r\n/**\r\n * Added to the build when triggered by TFS/Team Services AND the \"Enable Team Status for all jobs\"\r\n * option was enabled.\r\n */\r\npublic class TeamGlobalStatusAction extends InvisibleAction implements Serializable {\r\n\r\n    /**\r\n     * Add the passed in actions if EnableTeamStatusForAllJobs is configured.\r\n     */\r\n    public static void addIfApplicable(final List<Action> actions) {\r\n        final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\r\n        if (config.isEnableTeamStatusForAllJobs()) {\r\n            actions.add(new TeamGlobalStatusAction());\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns true if the run already contains a TeamGlobalStatusAction.\r\n     */\r\n    public static boolean isApplicable(final Run<?, ?> run) {\r\n        final TeamGlobalStatusAction action = run.getAction(TeamGlobalStatusAction.class);\r\n        return action != null;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamGlobalStatusPoster.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.Extension;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.TaskListener;\r\nimport hudson.model.listeners.RunListener;\r\n\r\nimport javax.annotation.Nonnull;\r\n\r\n/**\r\n * Posts the status to TFS/Team Services if the {@link TeamGlobalStatusAction} was contributed.\r\n */\r\n@Extension\r\npublic class TeamGlobalStatusPoster extends RunListener<AbstractBuild> {\r\n\r\n    @Override\r\n    public void onStarted(final AbstractBuild build, final TaskListener listener) {\r\n        if (TeamGlobalStatusAction.isApplicable(build)) {\r\n            final TeamPendingStatusBuildStep step = new TeamPendingStatusBuildStep();\r\n            step.perform(build, listener);\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void onCompleted(final AbstractBuild build, @Nonnull final TaskListener listener) {\r\n        if (TeamGlobalStatusAction.isApplicable(build)) {\r\n            final TeamCompletedStatusPostBuildAction step = new TeamCompletedStatusPostBuildAction();\r\n            step.perform(build, listener);\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamHookCause.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.plugins.git.GitStatus;\r\n\r\n/**\r\n * Attached to the build if it was started by a TFS/Team Services commit.\r\n */\r\npublic class TeamHookCause extends GitStatus.CommitHookCause {\r\n\r\n    public TeamHookCause(final String sha1) {\r\n        super(sha1);\r\n    }\r\n\r\n    @Override\r\n    public String getShortDescription() {\r\n        return \"Started by TFS/Team Services web hook for commit \" + sha1;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamPRPushTrigger.java",
    "content": "package hudson.plugins.tfs;\n\nimport hudson.Extension;\nimport hudson.model.Job;\nimport org.kohsuke.stapler.DataBoundConstructor;\nimport org.kohsuke.stapler.DataBoundSetter;\n\n/**\n * Triggers a build when we receive a TFS/Team Services Git code push event in a TFS pull request.\n */\npublic class TeamPRPushTrigger extends TeamPushTrigger {\n\n    private String targetBranches;\n\n    @DataBoundConstructor\n    public TeamPRPushTrigger() {\n    }\n\n    public TeamPRPushTrigger(final Job<?, ?> job, final String targetBranches, final String jobContext) {\n        this.job = job;\n        this.targetBranches = targetBranches;\n\n        setJobContext(jobContext);\n    }\n\n    public String getTargetBranches() {\n        return targetBranches;\n    }\n\n    @DataBoundSetter\n    public void setTargetBranches(final String targetBranches) {\n        this.targetBranches = targetBranches;\n    }\n\n    /**\n     * This class extends trigger descriptor class from TeamPushTrigger, creating a separate check box for TeamPRPushTrigger.\n     */\n    @Extension\n    public static class DescriptorImpl extends TeamPushTrigger.DescriptorImpl {\n\n        @Override\n        public String getDisplayName() {\n            return \"Build when a change is pushed to a TFS pull request\";\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamPendingStatusBuildStep.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport hudson.Extension;\r\nimport hudson.FilePath;\r\nimport hudson.Launcher;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Descriptor;\r\nimport hudson.model.Run;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.util.TeamStatus;\r\nimport hudson.tasks.BuildStepDescriptor;\r\nimport hudson.tasks.Builder;\r\nimport jenkins.tasks.SimpleBuildStep;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport java.io.IOException;\r\n\r\n/**\r\n * A _Build Step_ that reports the status of an associated build as \"Pending\" to TFS/Team Services.\r\n */\r\npublic class TeamPendingStatusBuildStep extends Builder implements SimpleBuildStep {\r\n\r\n    @DataBoundConstructor\r\n    public TeamPendingStatusBuildStep() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public void perform(\r\n            @Nonnull final Run<?, ?> run,\r\n            @Nonnull final FilePath workspace,\r\n            @Nonnull final Launcher launcher,\r\n            @Nonnull final TaskListener listener\r\n    ) throws InterruptedException, IOException {\r\n        if (!TeamGlobalStatusAction.isApplicable(run)){\r\n            perform(run, listener);\r\n        }\r\n    }\r\n\r\n    public void perform(final @Nonnull Run<?, ?> run, final @Nonnull TaskListener listener) {\r\n        try {\r\n            TeamStatus.createFromRun(run, listener, getDisplayName());\r\n        }\r\n        catch (final IllegalArgumentException e) {\r\n            listener.error(e.getMessage());\r\n        }\r\n        catch (final Exception e) {\r\n            e.printStackTrace(listener.error(\"Error while trying to update pending status in TFS/Team Services\"));\r\n        }\r\n    }\r\n\r\n    String getDisplayName() {\r\n        final Descriptor<Builder> descriptor = getDescriptor();\r\n        return descriptor.getDisplayName();\r\n    }\r\n\r\n    @Extension\r\n    public static class DescriptorImpl extends BuildStepDescriptor<Builder> {\r\n\r\n        @Override\r\n        public boolean isApplicable(Class<? extends AbstractProject> jobType) {\r\n            return true;\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Set build pending status in TFS/Team Services\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamPluginGlobalConfig.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport hudson.Extension;\r\nimport hudson.ExtensionList;\r\nimport hudson.plugins.tfs.model.DomainUserAccountMapper;\r\nimport hudson.plugins.tfs.model.UserAccountMapper;\r\nimport hudson.plugins.tfs.model.UserAccountMapperDescriptor;\r\nimport hudson.plugins.tfs.rm.ReleaseWebHook;\r\nimport jenkins.model.GlobalConfiguration;\r\nimport jenkins.model.Jenkins;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.lang3.ObjectUtils;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\n\r\n/**\r\n * All the settings that apply globally.\r\n */\r\n@Extension\r\npublic class TeamPluginGlobalConfig extends GlobalConfiguration {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(TeamPluginGlobalConfig.class.getName());\r\n    public static final TeamPluginGlobalConfig DEFAULT_CONFIG = new TeamPluginGlobalConfig(false);\r\n\r\n    private List<TeamCollectionConfiguration> collectionConfigurations = new ArrayList<TeamCollectionConfiguration>();\r\n    private List<ReleaseWebHook> releaseWebHookConfigurations = new ArrayList<ReleaseWebHook>();\r\n    \r\n    private boolean configFolderPerNode;\r\n    private boolean enableTeamPushTriggerForAllJobs;\r\n    private boolean enableTeamStatusForAllJobs;\r\n    private UserAccountMapper userAccountMapper;\r\n\r\n    public TeamPluginGlobalConfig() {\r\n        this(true);\r\n    }\r\n\r\n    TeamPluginGlobalConfig(final boolean shouldLoadConfig) {\r\n        if (shouldLoadConfig) {\r\n            load();\r\n        }\r\n    }\r\n\r\n    public TeamPluginGlobalConfig(final List<TeamCollectionConfiguration> collectionConfigurations) {\r\n        this.collectionConfigurations = collectionConfigurations;\r\n    }\r\n\r\n    public static TeamPluginGlobalConfig get() {\r\n        TeamPluginGlobalConfig result = DEFAULT_CONFIG;\r\n        if (Jenkins.getInstance() != null) {\r\n            final ExtensionList<GlobalConfiguration> configurationExtensions = all();\r\n            final TeamPluginGlobalConfig config = configurationExtensions.get(TeamPluginGlobalConfig.class);\r\n            result = ObjectUtils.defaultIfNull(config, DEFAULT_CONFIG);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    public List<TeamCollectionConfiguration> getCollectionConfigurations() {\r\n        return collectionConfigurations;\r\n    }\r\n\r\n    public void setCollectionConfigurations(final List<TeamCollectionConfiguration> collectionConfigurations) {\r\n        this.collectionConfigurations = collectionConfigurations;\r\n    }\r\n    \r\n    public List<ReleaseWebHook> getReleaseWebHookConfigurations() {\r\n        return this.releaseWebHookConfigurations;\r\n    }\r\n    \r\n    public void setReleaseWebHookConfigurations(final List<ReleaseWebHook> releaseWebHookConfigurations) {\r\n        this.releaseWebHookConfigurations = releaseWebHookConfigurations;\r\n    }\r\n\r\n    public boolean isConfigFolderPerNode() {\r\n        return configFolderPerNode;\r\n    }\r\n\r\n    public void setConfigFolderPerNode(final boolean configFolderPerNode) {\r\n        this.configFolderPerNode = configFolderPerNode;\r\n    }\r\n\r\n    public boolean isEnableTeamPushTriggerForAllJobs() {\r\n        return enableTeamPushTriggerForAllJobs;\r\n    }\r\n\r\n    public void setEnableTeamPushTriggerForAllJobs(final boolean enableTeamPushTriggerForAllJobs) {\r\n        this.enableTeamPushTriggerForAllJobs = enableTeamPushTriggerForAllJobs;\r\n    }\r\n\r\n    public boolean isEnableTeamStatusForAllJobs() {\r\n        return enableTeamStatusForAllJobs;\r\n    }\r\n\r\n    public void setEnableTeamStatusForAllJobs(final boolean enableTeamStatusForAllJobs) {\r\n        this.enableTeamStatusForAllJobs = enableTeamStatusForAllJobs;\r\n    }\r\n\r\n    public UserAccountMapper getUserAccountMapper() {\r\n        if (userAccountMapper == null) {\r\n            userAccountMapper = new DomainUserAccountMapper();\r\n        }\r\n        return userAccountMapper;\r\n    }\r\n\r\n    public void setUserAccountMapper(UserAccountMapper userAccountMapper) {\r\n        this.userAccountMapper = userAccountMapper;\r\n    }\r\n\r\n    public List<UserAccountMapperDescriptor> getUserAccountMapperDescriptors() {\r\n        return UserAccountMapper.all();\r\n    }\r\n\r\n    @Override\r\n    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {\r\n        try {\r\n            req.bindJSON(this, json);\r\n            \r\n            // stapler oddity, empty lists are not set on bean by  \"req.bindJSON(this, json)\"\r\n            this.releaseWebHookConfigurations = req.bindJSONToList(ReleaseWebHook.class, json.get(\"releaseWebHookConfigurations\"));\r\n        }\r\n        catch (final Exception e) {\r\n            final String message = \"Configuration error: \" + e.getMessage();\r\n            LOGGER.log(Level.WARNING, message, e);\r\n            LOGGER.log(Level.FINE, \"Form data: {}\", json.toString());\r\n            throw new FormException(message, e, \"team-configuration\");\r\n        }\r\n        save();\r\n        return true;\r\n    }\r\n\r\n    @Override\r\n    public String getDisplayName() {\r\n        return \"TFS/Team Services\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamPullRequestMergedDetailsAction.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport com.microsoft.teamfoundation.core.webapi.model.TeamProjectReference;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRepository;\r\nimport com.microsoft.visualstudio.services.webapi.model.ResourceRef;\r\nimport hudson.model.Action;\r\nimport hudson.model.Run;\r\nimport hudson.plugins.tfs.model.GitPullRequestEx;\r\nimport hudson.plugins.tfs.model.GitPushEvent;\r\nimport hudson.plugins.tfs.util.UriHelper;\r\nimport org.kohsuke.stapler.export.Exported;\r\nimport org.kohsuke.stapler.export.ExportedBean;\r\n\r\nimport java.io.Serializable;\r\nimport java.net.URI;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\n/**\r\n * Captures details of the TFS/Team Services pull request event which triggered us.\r\n */\r\n@ExportedBean(defaultVisibility = 999)\r\npublic class TeamPullRequestMergedDetailsAction implements Action, Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n    private static final String URL_NAME = \"team-pullRequestMergedDetails\";\r\n\r\n    public transient GitPullRequestEx gitPullRequest;\r\n    public String message;\r\n    public String detailedMessage;\r\n    public String collectionUri;\r\n\r\n    public TeamPullRequestMergedDetailsAction() {\r\n\r\n    }\r\n\r\n    public TeamPullRequestMergedDetailsAction(final GitPullRequestEx gitPullRequest, final String message, final String detailedMessage, final String collectionUri) {\r\n        this.gitPullRequest = gitPullRequest;\r\n        this.message = message;\r\n        this.detailedMessage = detailedMessage;\r\n        this.collectionUri = collectionUri;\r\n    }\r\n\r\n    public static URI addWorkItemsForRun(final Run<?, ?> run, final List<ResourceRef> destination) {\r\n        final TeamPullRequestMergedDetailsAction action = run.getAction(TeamPullRequestMergedDetailsAction.class);\r\n        if (action != null && action.hasWorkItems()) {\r\n            Collections.addAll(destination, action.getWorkItems());\r\n            final GitPullRequestEx gitPullRequest = action.gitPullRequest;\r\n            final URI collectionUri = URI.create(action.collectionUri);\r\n            return collectionUri;\r\n        }\r\n        return null;\r\n    }\r\n\r\n    @Override\r\n    public String getIconFileName() {\r\n        return \"/plugin/tfs/48x48/logo.png\";\r\n    }\r\n\r\n    @Override\r\n    public String getDisplayName() {\r\n        return \"TFS/Team Services pull request\";\r\n    }\r\n\r\n    @Override\r\n    public String getUrlName() {\r\n        return URL_NAME;\r\n    }\r\n\r\n    // the following methods are called from this/summary.jelly and/or this/index.jelly\r\n\r\n    @Exported\r\n    public String getMessage() {\r\n        return message;\r\n    }\r\n\r\n    @Exported\r\n    public String getDetailedMessage() {\r\n        return detailedMessage;\r\n    }\r\n\r\n    @Exported\r\n    public ResourceRef[] getWorkItems() {\r\n        return gitPullRequest.getWorkItemRefs();\r\n    }\r\n\r\n    @Exported\r\n    public boolean hasWorkItems() {\r\n        final ResourceRef[] workItemRefs = gitPullRequest.getWorkItemRefs();\r\n        return workItemRefs != null && workItemRefs.length > 0;\r\n    }\r\n\r\n    @Exported\r\n    public String getPullRequestUrl() {\r\n        final GitRepository repository = gitPullRequest.getRepository();\r\n        final URI collectionUri = URI.create(this.collectionUri);\r\n        final TeamProjectReference project = repository.getProject();\r\n        final URI pullRequestUrl = UriHelper.join(collectionUri,\r\n                project.getName(),\r\n                \"_git\",\r\n                repository.getName(),\r\n                \"pullrequest\",\r\n                gitPullRequest.getPullRequestId()\r\n        );\r\n        final String result = pullRequestUrl.toString();\r\n        return result;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamPushCause.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.triggers.SCMTrigger.SCMTriggerCause;\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\n\r\n/**\r\n * Indicates that a build was queued because of a TFS/Team Services Git code push event.\r\n */\r\npublic class TeamPushCause extends SCMTriggerCause {\r\n\r\n    private final String pushedBy;\r\n    private final String context;\r\n\r\n    public TeamPushCause(final String pushedBy, final String context) {\r\n        this(\"\", pushedBy, context);\r\n    }\r\n\r\n    public TeamPushCause(final File logFile, final String pushedBy, final String context) throws IOException {\r\n        super(logFile);\r\n        this.pushedBy = pushedBy;\r\n        this.context = context;\r\n    }\r\n\r\n    public TeamPushCause(final String pollingLog, final String pushedBy, final String context) {\r\n        super(pollingLog);\r\n        this.pushedBy = pushedBy;\r\n        this.context = context;\r\n    }\r\n\r\n    @Override\r\n    public String getShortDescription() {\r\n        final String template = \"Started by TFS/Team Services push by %s\";\r\n        final String message = String.format(template, StringUtils.trimToEmpty(pushedBy));\r\n        return message;\r\n    }\r\n\r\n    @Override\r\n    public boolean equals(final Object o) {\r\n        return super.equals(o);\r\n    }\r\n\r\n    @Override\r\n    public int hashCode() {\r\n        return super.hashCode();\r\n    }\r\n\r\n    public String getRunContext() {\r\n        return this.context;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamPushTrigger.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.Extension;\r\nimport hudson.Util;\r\nimport hudson.console.AnnotatedLargeText;\r\nimport hudson.model.Action;\r\nimport hudson.model.CauseAction;\r\nimport hudson.model.Item;\r\nimport hudson.model.Job;\r\nimport hudson.model.queue.QueueTaskFuture;\r\nimport hudson.plugins.tfs.model.GitCodePushedEventArgs;\r\nimport hudson.plugins.tfs.util.ActionHelper;\r\nimport hudson.plugins.tfs.util.MediaType;\r\nimport hudson.triggers.Trigger;\r\nimport hudson.triggers.TriggerDescriptor;\r\nimport hudson.util.StreamTaskListener;\r\nimport jenkins.model.ParameterizedJobMixIn;\r\nimport jenkins.triggers.SCMTriggerItem;\r\nimport org.apache.commons.jelly.XMLOutput;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\nimport java.io.Writer;\r\nimport java.text.DateFormat;\r\nimport java.util.Collection;\r\nimport java.util.Collections;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\nimport org.kohsuke.stapler.DataBoundSetter;\r\n\r\n/**\r\n * Triggers a build when we receive a TFS/Team Services Git code push event.\r\n */\r\npublic class TeamPushTrigger extends Trigger<Job<?, ?>> {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(TeamPushTrigger.class.getName());\r\n    private String jobContext;\r\n\r\n    @DataBoundConstructor\r\n    public TeamPushTrigger() {\r\n    }\r\n\r\n    public TeamPushTrigger(final Job<?, ?> job) {\r\n        this.job = job;\r\n    }\r\n\r\n    public TeamPushTrigger(final Job<?, ?> job, final String jobContext) {\r\n        this.job = job;\r\n        this.jobContext = jobContext;\r\n    }\r\n\r\n    /**\r\n    * Execute function.\r\n    */\r\n    public void execute(final GitCodePushedEventArgs gitCodePushedEventArgs, final List<Action> actions, final boolean bypassPolling) {\r\n        // TODO: Consider executing the poll + queue asynchronously\r\n        final Runner runner = new Runner(gitCodePushedEventArgs, actions, bypassPolling);\r\n        runner.run();\r\n    }\r\n\r\n    public File getLogFile() {\r\n        return new File(job.getRootDir(), \"team-polling.log\");\r\n    }\r\n\r\n    public String getJobContext() {\r\n        return jobContext;\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setJobContext(final String jobContext) {\r\n        this.jobContext = jobContext;\r\n    }\r\n\r\n    /**\r\n     * Runner class for TeamPushTrigger.\r\n     */\r\n    // TODO: This was inspired by SCMTrigger.Runner; it would be worth extracting something for re-use\r\n    public class Runner implements Runnable {\r\n\r\n        private final GitCodePushedEventArgs gitCodePushedEventArgs;\r\n        private final List<Action> actions;\r\n        private final boolean bypassPolling;\r\n\r\n        public Runner(final GitCodePushedEventArgs gitCodePushedEventArgs, final List<Action> actions, final boolean bypassPolling) {\r\n            this.gitCodePushedEventArgs = gitCodePushedEventArgs;\r\n            this.actions = actions;\r\n            this.bypassPolling = bypassPolling;\r\n        }\r\n\r\n        private SCMTriggerItem job() {\r\n            return SCMTriggerItem.SCMTriggerItems.asSCMTriggerItem(job);\r\n        }\r\n\r\n        private boolean runPolling() {\r\n            final String failedToRecord = \"Failed to record SCM polling for \" + job;\r\n            try {\r\n                final StreamTaskListener listener = new StreamTaskListener(getLogFile(), MediaType.UTF_8);\r\n\r\n                try {\r\n                    final PrintStream logger = listener.getLogger();\r\n                    final long startTimeMillis = System.currentTimeMillis();\r\n                    final Date date = new Date(startTimeMillis);\r\n                    logger.println(\"Started on \" + DateFormat.getDateTimeInstance().format(date));\r\n                    final boolean result = job().poll(listener).hasChanges();\r\n                    final long endTimeMillis = System.currentTimeMillis();\r\n                    logger.println(\"Done. Took \" + Util.getTimeSpanString(endTimeMillis - startTimeMillis));\r\n                    if (result) {\r\n                        logger.println(\"Changes found\");\r\n                    } else {\r\n                        logger.println(\"No changes\");\r\n                    }\r\n                    return result;\r\n                } catch (final Error e) {\r\n                    e.printStackTrace(listener.error(failedToRecord));\r\n                    LOGGER.log(Level.SEVERE, failedToRecord, e);\r\n                    throw e;\r\n                } catch (final RuntimeException e) {\r\n                    e.printStackTrace(listener.error(failedToRecord));\r\n                    LOGGER.log(Level.SEVERE, failedToRecord, e);\r\n                    throw e;\r\n                } finally {\r\n                    listener.close();\r\n                }\r\n            } catch (final IOException e) {\r\n                LOGGER.log(Level.SEVERE, failedToRecord, e);\r\n                return false;\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public void run() {\r\n            boolean shouldSchedule = bypassPolling;\r\n            String changesDetected = \"\";\r\n            if (!bypassPolling) {\r\n                // pipeline jobs might have runPolling() returned as false, while still should be scheduled.\r\n                // we should schedule them as long as they are associated with a valid commit.\r\n                if (runPolling() || StringUtils.isNotBlank(gitCodePushedEventArgs.commit)) {\r\n                    changesDetected = \"SCM changes detected in \" + job.getFullDisplayName() + \". \";\r\n                    shouldSchedule = true;\r\n                }\r\n            } else {\r\n                changesDetected = \"Polling bypassed for \" + job.getFullDisplayName() + \". \";\r\n            }\r\n            if (shouldSchedule) {\r\n                final SCMTriggerItem p = job();\r\n                final String name = \"#\" + p.getNextBuildNumber();\r\n                final String pushedBy = gitCodePushedEventArgs.pushedBy;\r\n\r\n                TeamPushCause cause;\r\n                final File logFile = getLogFile();\r\n                if (logFile.isFile()) {\r\n                    try {\r\n                        cause = new TeamPushCause(logFile, pushedBy, getJobContext());\r\n                    } catch (IOException e) {\r\n                        LOGGER.log(Level.WARNING, \"Failed to parse the polling log\", e);\r\n                        cause = new TeamPushCause(pushedBy, getJobContext());\r\n                    }\r\n                } else {\r\n                    cause = new TeamPushCause(pushedBy, getJobContext());\r\n                }\r\n                final int quietPeriod = p.getQuietPeriod();\r\n                final CauseAction causeAction = new CauseAction(cause);\r\n                final Action[] actionArray = ActionHelper.create(actions, causeAction);\r\n                final QueueTaskFuture<?> queueTaskFuture = p.scheduleBuild2(quietPeriod, actionArray);\r\n                if (queueTaskFuture != null) {\r\n                    LOGGER.info(changesDetected + \"Triggering \" + name);\r\n                } else {\r\n                    LOGGER.info(changesDetected + \"Job is already in the queue\");\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public DescriptorImpl getDescriptor() {\r\n        return (DescriptorImpl) super.getDescriptor();\r\n    }\r\n\r\n    /**\r\n     * This class extends trigger descriptor class.\r\n     */\r\n    @Extension\r\n    public static class DescriptorImpl extends TriggerDescriptor {\r\n\r\n        @Override\r\n        public boolean isApplicable(final Item item) {\r\n            return item instanceof Job\r\n                    && SCMTriggerItem.SCMTriggerItems.asSCMTriggerItem(item) != null\r\n                    && item instanceof ParameterizedJobMixIn.ParameterizedJob;\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Build when a change is pushed to TFS/Team Services\";\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public Collection<? extends Action> getProjectActions() {\r\n        if (job == null) {\r\n            return Collections.emptyList();\r\n        }\r\n\r\n        return Collections.singleton(new TeamPollingAction());\r\n    }\r\n\r\n    /**\r\n     * This class defines team polling action.\r\n     */\r\n    public final class TeamPollingAction implements Action {\r\n\r\n        @Override\r\n        public String getIconFileName() {\r\n            return \"/plugin/tfs/48x48/logo.png\";\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"TFS/Team Services hook log\";\r\n        }\r\n\r\n        @Override\r\n        public String getUrlName() {\r\n            return \"TeamPollLog\";\r\n        }\r\n\r\n        // the following methods are called from TeamPushTrigger/TeamPollingAction/index.jelly\r\n\r\n        @SuppressWarnings(\"unused\")\r\n        public Job<?, ?> getOwner() {\r\n            return job;\r\n        }\r\n\r\n        /**\r\n        * Get log.\r\n        */\r\n        @SuppressWarnings(\"unused\")\r\n        public String getLog() throws IOException {\r\n            return Util.loadFile(getLogFile());\r\n        }\r\n\r\n        /**\r\n        * Write log.\r\n        */\r\n        @SuppressWarnings(\"unused\")\r\n        public void writeLogTo(final XMLOutput out) throws IOException {\r\n            final File logFile = getLogFile();\r\n            final AnnotatedLargeText<TeamPollingAction> text =\r\n                    new AnnotatedLargeText<TeamPollingAction>(logFile, MediaType.UTF_8, true, this);\r\n            final Writer writer = out.asWriter();\r\n            text.writeHtmlTo(0, writer);\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamResultsAction.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs;\r\n\r\nimport hudson.model.Run;\r\nimport hudson.plugins.tfs.util.EndpointHelper;\r\nimport hudson.plugins.tfs.util.MediaType;\r\nimport jenkins.model.RunAction2;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.kohsuke.stapler.ForwardToView;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\nimport org.kohsuke.stapler.StaplerResponse;\r\nimport org.kohsuke.stapler.export.ExportedBean;\r\n\r\nimport java.io.File;\r\nimport java.io.FileInputStream;\r\nimport java.io.IOException;\r\nimport java.io.Serializable;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\n\r\nimport static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;\r\nimport static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;\r\n\r\n/**\r\n * Added by {@link TeamCollectResultsPostBuildAction} to enable the download of the ZIP\r\n * file containing the collected results from the build.\r\n */\r\n@ExportedBean(defaultVisibility = 999)\r\npublic class TeamResultsAction implements RunAction2, Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(TeamResultsAction.class.getName());\r\n\r\n    public transient Run<?, ?> run;\r\n\r\n    @Override\r\n    public void onAttached(final Run<?, ?> r) {\r\n        this.run = r;\r\n    }\r\n\r\n    @Override\r\n    public void onLoad(final Run<?, ?> r) {\r\n        this.run = r;\r\n    }\r\n\r\n    @Override\r\n    public String getIconFileName() {\r\n        return null;\r\n    }\r\n\r\n    @Override\r\n    public String getDisplayName() {\r\n        return null;\r\n    }\r\n\r\n    @Override\r\n    public String getUrlName() {\r\n        return \"team-results\";\r\n    }\r\n\r\n    public static void addToRun(final Run<?, ?> run) {\r\n        final TeamResultsAction action = new TeamResultsAction();\r\n        run.addAction(action);\r\n    }\r\n\r\n    @SuppressWarnings(\"unused\" /* API method */)\r\n    public void doZip(final StaplerRequest req, final StaplerResponse rsp) throws IOException {\r\n        try {\r\n            if (run == null) {\r\n                throw new IllegalArgumentException(\"There is no associated Run<?,?>\");\r\n            }\r\n            final File rootDir = run.getRootDir();\r\n            final File resultsZipFile = new File(rootDir, TeamCollectResultsPostBuildAction.TEAM_RESULTS_ZIP);\r\n            if (!resultsZipFile.isFile()) {\r\n                throw new IllegalArgumentException(\"There is no results file in this build\");\r\n            }\r\n            final FileInputStream resultsZipStream = new FileInputStream(resultsZipFile);\r\n            rsp.setContentType(MediaType.APPLICATION_ZIP);\r\n            final long lastModified = resultsZipFile.lastModified();\r\n            final long contentLength = resultsZipFile.length();\r\n            final String fileName = resultsZipFile.getName();\r\n            try {\r\n                rsp.serveFile(req, resultsZipStream, lastModified, contentLength, fileName);\r\n            }\r\n            finally {\r\n                IOUtils.closeQuietly(resultsZipStream);\r\n            }\r\n        }\r\n        catch (final IllegalArgumentException e) {\r\n            LOGGER.log(Level.WARNING, \"IllegalArgumentException\", e);\r\n            EndpointHelper.error(SC_BAD_REQUEST, e);\r\n        }\r\n        catch (final ForwardToView e) {\r\n            throw e;\r\n        }\r\n        catch (final Exception e) {\r\n            LOGGER.log(Level.SEVERE, \"Unknown error\", e);\r\n            EndpointHelper.error(SC_INTERNAL_SERVER_ERROR, e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/TeamUpdateWorkItemPostBuildAction.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport com.microsoft.visualstudio.services.webapi.model.ResourceRef;\r\nimport hudson.Extension;\r\nimport hudson.FilePath;\r\nimport hudson.Launcher;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Run;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.telemetry.TelemetryHelper;\r\nimport hudson.plugins.tfs.util.TeamRestClient;\r\nimport hudson.tasks.BuildStepDescriptor;\r\nimport hudson.tasks.BuildStepMonitor;\r\nimport hudson.tasks.Notifier;\r\nimport hudson.tasks.Publisher;\r\nimport jenkins.tasks.SimpleBuildStep;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport java.io.IOException;\r\nimport java.net.URI;\r\nimport java.util.ArrayList;\r\n\r\n/**\r\n * A _Post-Build Action_ that updates associated work items with a link back\r\n * to the Jenkins build.\r\n */\r\n@SuppressWarnings(\"unused\" /* Jenkins extension */)\r\npublic class TeamUpdateWorkItemPostBuildAction extends Notifier implements SimpleBuildStep {\r\n\r\n    @DataBoundConstructor\r\n    public TeamUpdateWorkItemPostBuildAction() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public void perform(\r\n            @Nonnull final Run<?, ?> run,\r\n            @Nonnull final FilePath workspace,\r\n            @Nonnull final Launcher launcher,\r\n            @Nonnull final TaskListener listener\r\n    ) throws InterruptedException, IOException {\r\n        try {\r\n            final String absoluteUrl = run.getAbsoluteUrl();\r\n            final ArrayList<ResourceRef> workItems = new ArrayList<ResourceRef>();\r\n            final URI collectionUri = TeamPullRequestMergedDetailsAction.addWorkItemsForRun(run, workItems);\r\n            if (collectionUri != null) {\r\n                final TeamRestClient client = new TeamRestClient(collectionUri);\r\n                for (final ResourceRef workItem : workItems) {\r\n                    final String workItemIdString = workItem.getId();\r\n                    final Integer workItemId = Integer.valueOf(workItemIdString, 10);\r\n                    client.addHyperlinkToWorkItem(workItemId, absoluteUrl);\r\n                }\r\n\r\n                // Send telemetry\r\n                TelemetryHelper.sendEvent(\"team-workitem-update\", new TelemetryHelper.PropertyMapBuilder()\r\n                        .serverContext(collectionUri.toString(), collectionUri.toString())\r\n                        .build());\r\n            }\r\n        } catch (final IllegalArgumentException e) {\r\n            listener.error(e.getMessage());\r\n        } catch (final Exception e) {\r\n            e.printStackTrace(listener.error(\"Error while trying to update associated work items in TFS/Team Services\"));\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public BuildStepMonitor getRequiredMonitorService() {\r\n        // we don't need the outcome of any previous builds for this step\r\n        return BuildStepMonitor.NONE;\r\n    }\r\n\r\n    /**\r\n     * Class descriptor.\r\n     */\r\n    @Extension\r\n    public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {\r\n\r\n        @Override\r\n        public boolean isApplicable(final Class<? extends AbstractProject> jobType) {\r\n            return true;\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Add link to associated work items in TFS/Team Services\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/UnsupportedIntegrationAction.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.model.Action;\r\nimport hudson.model.InvisibleAction;\r\nimport hudson.model.Run;\r\nimport hudson.model.TaskListener;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport java.io.Serializable;\r\nimport java.util.List;\r\n\r\n/**\r\n * Contributed to a build whenever the rich TFS/Team Services integration endpoints\r\n * are used with unsupported parameters.\r\n */\r\npublic class UnsupportedIntegrationAction extends InvisibleAction implements Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private final String reason;\r\n\r\n    public UnsupportedIntegrationAction(final String reason) {\r\n        this.reason = reason;\r\n    }\r\n\r\n    /**\r\n     * Returns true if the run does not contain an UnsupportedIntegrationAction.\r\n     */\r\n    public static boolean isSupported(@Nonnull final Run<?, ?> run, @Nonnull final TaskListener listener) {\r\n        final UnsupportedIntegrationAction action = run.getAction(UnsupportedIntegrationAction.class);\r\n        return action == null;\r\n    }\r\n\r\n    /**\r\n     * Adds this action to the build with the given reason.\r\n     */\r\n    public static void addToBuild(final List<Action> actions, final String reason) {\r\n        final UnsupportedIntegrationAction action = new UnsupportedIntegrationAction(reason);\r\n        actions.add(action);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/actions/CheckoutAction.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.actions;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\r\nimport hudson.FilePath;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.commands.RemoteChangesetVersionCommand;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.plugins.tfs.model.Project;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.Workspace;\r\nimport hudson.plugins.tfs.model.Workspaces;\r\n\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\nimport java.text.ParseException;\r\nimport java.util.ArrayList;\r\nimport java.util.Calendar;\r\nimport java.util.Collection;\r\nimport java.util.HashSet;\r\nimport java.util.List;\r\n\r\npublic class CheckoutAction {\r\n\r\n    private final String workspaceName;\r\n    private final String projectPath;\r\n    private final Collection<String> cloakedPaths;\r\n    private final String localFolder;\r\n    private final boolean useUpdate;\r\n    private final boolean useOverwrite;\r\n\r\n    public CheckoutAction(String workspaceName, String projectPath, Collection<String> cloakedPaths, String localFolder, boolean useUpdate, boolean useOverwrite) {\r\n        this.workspaceName = workspaceName;\r\n        this.projectPath = projectPath;\r\n        this.cloakedPaths = cloakedPaths;\r\n        this.localFolder = localFolder;\r\n        this.useUpdate = useUpdate;\r\n        this.useOverwrite = useOverwrite;\r\n    }\r\n\r\n    public List<ChangeSet> checkout(Server server, FilePath workspacePath, Calendar lastBuildTimestamp, Calendar currentBuildTimestamp) throws IOException, InterruptedException, ParseException {\r\n\r\n        final VersionSpec lastBuildVersionSpec;\r\n        if (lastBuildTimestamp != null) {\r\n            lastBuildVersionSpec = new DateVersionSpec(lastBuildTimestamp);\r\n        }\r\n        else{\r\n            lastBuildVersionSpec = null;\r\n        }\r\n\r\n        final VersionSpec currentBuildVersionSpec = new DateVersionSpec(currentBuildTimestamp);\r\n\r\n        return checkout(server, workspacePath, lastBuildVersionSpec, currentBuildVersionSpec);\r\n    }\r\n\r\n    public List<ChangeSet> checkout(final Server server, final FilePath workspacePath, final VersionSpec lastBuildVersionSpec, final VersionSpec currentBuildVersionSpec) throws IOException, InterruptedException {\r\n\r\n        Project project = getProject(server, workspacePath);\r\n\r\n        final String versionSpecString = RemoteChangesetVersionCommand.toString(currentBuildVersionSpec);\r\n        final String normalizedFolder = determineCheckoutPath(workspacePath, localFolder);\r\n        project.getFiles(normalizedFolder, versionSpecString, useOverwrite);\r\n\r\n        if (lastBuildVersionSpec != null) {\r\n            return project.getDetailedHistoryWithoutCloakedPaths(lastBuildVersionSpec, currentBuildVersionSpec, cloakedPaths);\r\n        }\r\n\r\n        return new ArrayList<ChangeSet>();\r\n    }\r\n\r\n    public List<ChangeSet> checkoutBySingleVersionSpec(Server server, FilePath workspacePath, String singleVersionSpec) throws IOException, InterruptedException {\r\n        Project project = getProject(server, workspacePath);\r\n        final String normalizedFolder = determineCheckoutPath(workspacePath, localFolder);\r\n        project.getFiles(normalizedFolder, singleVersionSpec, useOverwrite);\r\n\r\n        return project.getDetailedHistory(singleVersionSpec);\r\n    }\r\n\r\n    static String determineCheckoutPath(final FilePath workspacePath, final String localFolder) {\r\n        final FilePath combinedPath = new FilePath(workspacePath, localFolder);\r\n        final String result = combinedPath.getRemote();\r\n        return result;\r\n    }\r\n\r\n    private Project getProject(final Server server, final FilePath workspacePath)\r\n            throws IOException, InterruptedException {\r\n        final Workspaces workspaces = server.getWorkspaces();\r\n        final Project project = server.getProject(projectPath);\r\n        final FilePath localFolderPath = workspacePath.child(localFolder);\r\n        final String localPath = localFolderPath.getRemote();\r\n        final TaskListener listener = server.getListener();\r\n        final PrintStream logger = listener.getLogger();\r\n\r\n        final HashSet<String> workspaceNamesToDelete = new HashSet<String>();\r\n        final String existingWorkspaceName = workspaces.getWorkspaceMapping(localPath);\r\n        if (workspaces.exists(workspaceName)) {\r\n            if (!useUpdate) {\r\n                workspaceNamesToDelete.add(workspaceName);\r\n            }\r\n            if (existingWorkspaceName == null) {\r\n                logger.println(\"Warning: Although the server thinks the workspace exists, no mapping was found.\");\r\n                workspaceNamesToDelete.add(workspaceName);\r\n            }\r\n            else if (existingWorkspaceName.equalsIgnoreCase(workspaceName)) {\r\n                // workspace exists and \"localPath\" is mapped there: everything is fine.\r\n            }\r\n            else {\r\n                // workspace exists AND \"localPath\" is mapped in another workspace???\r\n                final String template = \"WARNING: Workspace '%s' already exists AND '%s' is also mapped in workspace '%s'.  Is there a configuration error?\";\r\n                final String message = String.format(template, workspaceName, localPath, existingWorkspaceName);\r\n                logger.println(message);\r\n                workspaceNamesToDelete.add(workspaceName);\r\n                workspaceNamesToDelete.add(existingWorkspaceName);\r\n            }\r\n            final boolean localFolderExists = localFolderPath.exists();\r\n            if (!localFolderExists) {\r\n                logger.println(\"Warning: The local folder is missing.\");\r\n                workspaceNamesToDelete.add(workspaceName);\r\n            }\r\n        }\r\n        else {\r\n            // there is (apparently) no workspace called \"workspaceName\"...\r\n            if (existingWorkspaceName != null && !existingWorkspaceName.equalsIgnoreCase(workspaceName)) {\r\n                // \"localPath\" is mapped under another workspace name: delete the old one\r\n                final String template = \"Workspace was apparently renamed, will delete the old one: '%s'.\";\r\n                final String message = String.format(template, existingWorkspaceName);\r\n                logger.println(message);\r\n                workspaceNamesToDelete.add(existingWorkspaceName);\r\n            }\r\n        }\r\n\r\n        for (final String workspaceNameToDelete : workspaceNamesToDelete) {\r\n            final Workspace workspace = workspaces.getWorkspace(workspaceNameToDelete);\r\n            workspaces.deleteWorkspace(workspace);\r\n        }\r\n\r\n        Workspace workspace;\r\n        if (! workspaces.exists(workspaceName)) {\r\n            if ((!useUpdate || workspaceNamesToDelete.size() > 0) && localFolderPath.exists()) {\r\n                localFolderPath.deleteContents();\r\n            }\r\n            final String serverPath = project.getProjectPath();\r\n            workspace = workspaces.newWorkspace(workspaceName, serverPath, cloakedPaths, localPath);\r\n        } else {\r\n            workspace = workspaces.getWorkspace(workspaceName);\r\n        }\r\n        return project;\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/actions/RemoveWorkspaceAction.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.actions;\r\n\r\nimport java.io.IOException;\r\n\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.Workspace;\r\nimport hudson.plugins.tfs.model.Workspaces;\r\n\r\n/**\r\n * Removes a workspace from a TFS server.\r\n * The tf command \"workspace /delete\" removes any mappings also.\r\n * @author Erik Ramfelt\r\n */\r\npublic class RemoveWorkspaceAction {\r\n\r\n    private final String workspaceName;\r\n\r\n    public RemoveWorkspaceAction(String workspaceName) {\r\n        this.workspaceName = workspaceName;\r\n    }\r\n\r\n    public boolean remove(Server server) throws IOException, InterruptedException {\r\n        Workspaces workspaces = server.getWorkspaces(); \r\n        if (workspaces.exists(workspaceName)) {\r\n            Workspace workspace = workspaces.getWorkspace(workspaceName);\r\n            workspaces.deleteWorkspace(workspace);\r\n            return true;\r\n        }\r\n        return false;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/browsers/TeamFoundationServerRepositoryBrowser.java",
    "content": "package hudson.plugins.tfs.browsers;\r\n\r\nimport java.io.IOException;\r\nimport java.net.URL;\r\n\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.scm.RepositoryBrowser;\r\n\r\n/**\r\n * Repository browser for the Team Foundation Server SCM.\r\n *\r\n * @author Erik Ramfelt\r\n */\r\npublic abstract class TeamFoundationServerRepositoryBrowser extends RepositoryBrowser<ChangeSet> {\r\n    /**\r\n     * Determines the link to the diff between the version in\r\n     * the specified revision of {@link ChangeSet.Item} to its previous version.\r\n     *\r\n     * @param item the item for which a link to differences will be generated.\r\n     *\r\n     * @return null if the browser doesn't have any URL for diff.\r\n     *\r\n     * @throws IOException If an I/O error occurs\r\n     */\r\n    public abstract URL getDiffLink(ChangeSet.Item item) throws IOException;\r\n\r\n    /**\r\n     * Determines the link to a single file under TFS.\r\n     *\r\n     * @param item the item for which a link to differences will be generated.\r\n     *\r\n     * @return null if the browser doesn't have any suitable URL.\r\n     *\r\n     * @throws IOException If an I/O error occurs\r\n     */\r\n    public abstract URL getFileLink(ChangeSet.Item item) throws IOException;\r\n\r\n    private static final long serialVersionUID = 1L;\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/browsers/TeamSystemWebAccessBrowser.java",
    "content": "package hudson.plugins.tfs.browsers;\r\n\r\nimport hudson.Extension;\r\nimport hudson.Util;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Descriptor;\r\nimport hudson.plugins.tfs.TeamFoundationServerScm;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.plugins.tfs.util.QueryString;\r\nimport hudson.scm.EditType;\r\nimport hudson.scm.RepositoryBrowser;\r\nimport hudson.scm.SCM;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\nimport java.io.IOException;\r\nimport java.net.MalformedURLException;\r\nimport java.net.URL;\r\n\r\n/**\r\n *  Provides information and links back to the TFS/VSTS repository for the current change set.\r\n */\r\npublic class TeamSystemWebAccessBrowser extends TeamFoundationServerRepositoryBrowser {\r\n\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private final String url;\r\n\r\n    @DataBoundConstructor\r\n    public TeamSystemWebAccessBrowser(final String urlExample) {\r\n        this.url = Util.fixEmpty(urlExample);\r\n    }\r\n\r\n    public String getUrl() {\r\n        return url;\r\n    }\r\n\r\n    private String getServerConfiguration(final ChangeSet changeset) {\r\n        AbstractProject<?, ?> project = changeset.getParent().build.getProject();\r\n        SCM scm = project.getScm();\r\n        if (scm instanceof TeamFoundationServerScm) {\r\n            return ((TeamFoundationServerScm) scm).getServerUrl(changeset.getParent().build);\r\n        } else {\r\n            final DescriptorImpl descriptor = (DescriptorImpl) getDescriptor();\r\n            final String displayName = descriptor.getDisplayName();\r\n            throw new IllegalStateException(\"'\" + displayName + \"' repository browser can only be used with the 'Team Foundation Server' SCM\");\r\n        }\r\n    }\r\n\r\n    private String getBaseUrlString(final ChangeSet changeSet) throws MalformedURLException {\r\n        String baseUrl = url;\r\n        if (baseUrl == null) {\r\n            baseUrl = getServerConfiguration(changeSet);\r\n        }\r\n        baseUrl = normalizeToEndWithSlash(new URL(baseUrl)).toString();\r\n        return baseUrl;\r\n    }\r\n\r\n    /**\r\n     * Gets the link to a specific change set.\r\n     */\r\n    @Override\r\n    public URL getChangeSetLink(final ChangeSet changeSet) throws IOException {\r\n        final String baseUrlString = getBaseUrlString(changeSet);\r\n        final URL baseUrl = new URL(baseUrlString);\r\n        return new URL(baseUrl, \"_versionControl/changeset/\" + changeSet.getVersion());\r\n    }\r\n\r\n    private URL createChangeSetItemLink(final ChangeSet.Item item, final String action) throws IOException {\r\n        final ChangeSet changeSet = item.getParent();\r\n        final URL changeSetUrl = getChangeSetLink(changeSet);\r\n        final QueryString qs = new QueryString();\r\n        qs.put(\"path\", item.getPath());\r\n        qs.put(\"version\", changeSet.getVersion());\r\n        qs.put(\"_a\", action);\r\n        return new URL(changeSetUrl, \"#\" + qs.toString());\r\n    }\r\n\r\n    /**\r\n     * Gets the link for a specific file in a change set.\r\n     */\r\n    public URL getFileLink(final ChangeSet.Item item) throws IOException {\r\n        return createChangeSetItemLink(item, \"contents\");\r\n    }\r\n\r\n    /**\r\n     * Gets the link to compare a specific file in a change set.\r\n     */\r\n    public URL getDiffLink(final ChangeSet.Item item) throws IOException {\r\n        if (item.getEditType() != EditType.EDIT) {\r\n            return null;\r\n        }\r\n        return createChangeSetItemLink(item, \"compare\");\r\n    }\r\n\r\n    /**\r\n     * Gets the descriptor for the repository.\r\n     */\r\n    @Extension\r\n    public static final class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {\r\n\r\n        public DescriptorImpl() {\r\n            super(TeamSystemWebAccessBrowser.class);\r\n        }\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Microsoft Team Foundation Server/Visual Studio Team Services\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/AbstractCallableCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.Workstation;\r\nimport com.microsoft.tfs.core.config.persistence.PersistenceStoreProvider;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.ExtraSettings;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.WebProxySettings;\r\nimport hudson.remoting.Callable;\r\nimport jenkins.security.MasterToSlaveCallable;\r\n\r\nimport java.io.IOException;\r\nimport java.io.Serializable;\r\n\r\npublic abstract class AbstractCallableCommand<V, T extends Throwable> extends MasterToSlaveCallable<V, T> implements Serializable {\r\n\r\n    private final String url;\r\n    private final String userName;\r\n    private final String userPassword;\r\n    private final TaskListener listener;\r\n    private final WebProxySettings webProxySettings;\r\n    private final ExtraSettings extraSettings;\r\n\r\n    protected AbstractCallableCommand(final ServerConfigurationProvider serverConfig) {\r\n        url = serverConfig.getUrl();\r\n        userName = serverConfig.getUserName();\r\n        userPassword = serverConfig.getUserPassword();\r\n        listener = serverConfig.getListener();\r\n        webProxySettings = serverConfig.getWebProxySettings();\r\n        extraSettings = serverConfig.getExtraSettings();\r\n    }\r\n\r\n    protected void updateCache(final TFSTeamProjectCollection connection) {\r\n        final PersistenceStoreProvider persistenceStoreProvider = connection.getPersistenceStoreProvider();\r\n        final Workstation workstation = Workstation.getCurrent(persistenceStoreProvider);\r\n        final VersionControlClient vcc = connection.getVersionControlClient();\r\n        workstation.updateWorkspaceInfoCache(vcc, VersionControlConstants.AUTHENTICATED_USER);\r\n    }\r\n\r\n    public Server createServer() throws IOException {\r\n        final Server server = new Server(null, listener, url, userName, userPassword, webProxySettings, extraSettings);\r\n        return server;\r\n    }\r\n\r\n    public abstract <V, E extends Throwable> Callable<V, E> getCallable();\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/AbstractCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport hudson.Util;\r\nimport hudson.plugins.tfs.util.MaskedArgumentListBuilder;\r\nimport hudson.util.ArgumentListBuilder;\r\n\r\npublic abstract class AbstractCommand implements Command {\r\n\r\n    private final ServerConfigurationProvider config;\r\n    \r\n    public AbstractCommand(ServerConfigurationProvider configurationProvider) {\r\n        this.config = configurationProvider;\r\n    }\r\n\r\n    protected void addServerArgument(ArgumentListBuilder arguments) {\r\n        arguments.add(String.format(\"-server:%s\", config.getUrl()));\r\n    }\r\n    \r\n    protected void addLoginArgument(MaskedArgumentListBuilder arguments) {\r\n        if ((Util.fixEmpty(config.getUserName()) != null) && (config.getUserPassword()!= null)) {\r\n            arguments.addMasked(String.format(\"-login:%s,%s\", \r\n                    config.getUserName(), \r\n                    config.getUserPassword()));\r\n        }\r\n    }\r\n\r\n    public ServerConfigurationProvider getConfig() {\r\n        return config;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/Command.java",
    "content": "package hudson.plugins.tfs.commands;\r\n\r\nimport hudson.plugins.tfs.util.MaskedArgumentListBuilder;\r\n\r\n/**\r\n * Command that issues a tf command line client command.\r\n *\r\n * @author Erik Ramfelt\r\n */\r\npublic interface Command {\r\n\r\n    /**\r\n     * Returns the arguments to be sent to the TF command line client.\r\n     * @return arguments for the TF tool\r\n     */\r\n    MaskedArgumentListBuilder getArguments();\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/DeleteWorkspaceCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.Workstation;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.workspacecache.WorkspaceInfo;\r\nimport com.microsoft.tfs.core.config.persistence.PersistenceStoreProvider;\r\nimport com.microsoft.tfs.jni.helpers.LocalHost;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.remoting.Callable;\r\n\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\n\r\npublic class DeleteWorkspaceCommand extends AbstractCallableCommand<Void, IOException> {\r\n\r\n    private static final String DeletingTemplate = \"Deleting workspaces named '%s' from computer '%s'...\";\r\n    private static final String DeletedTemplate = \"Deleted %d workspace(s) named '%s'.\";\r\n\r\n    private final String workspaceName;\r\n    private final String computerName;\r\n\r\n    public DeleteWorkspaceCommand(final ServerConfigurationProvider server, final String workspaceName) {\r\n        this(server, workspaceName, null);\r\n    }\r\n\r\n    public DeleteWorkspaceCommand(final ServerConfigurationProvider server, final String workspaceName, final String computerName) {\r\n        super(server);\r\n        this.workspaceName = workspaceName;\r\n        this.computerName = computerName;\r\n    }\r\n\r\n    public Callable<Void, IOException> getCallable() {\r\n        return this;\r\n    }\r\n\r\n    public Void call() throws IOException {\r\n        final Server server = createServer();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final TaskListener listener = server.getListener();\r\n        final PrintStream logger = listener.getLogger();\r\n\r\n        final String computerName = (DeleteWorkspaceCommand.this.computerName == null)\r\n                ? LocalHost.getShortName()\r\n                : DeleteWorkspaceCommand.this.computerName;\r\n        final String deletingMessage = String.format(DeletingTemplate, workspaceName, computerName);\r\n        logger.println(deletingMessage);\r\n\r\n        final WorkspacePermissions filter = WorkspacePermissions.NONE_OR_NOT_SUPPORTED;\r\n        final Workspace[] workspaces = vcc.queryWorkspaces(workspaceName, null, computerName, filter);\r\n        int numDeletions = 0;\r\n        for (final Workspace innerWorkspace : workspaces) {\r\n            vcc.deleteWorkspace(innerWorkspace);\r\n\r\n            // work around a defect in the TFS SDK for Java\r\n            // TODO: check if this workaround is still necessary after upgrading\r\n            final WorkspaceInfo workspaceInfo = vcc.removeCachedWorkspace(workspaceName, VersionControlConstants.AUTHENTICATED_USER);\r\n            if (workspaceInfo != null) {\r\n                final TFSTeamProjectCollection tpc = vcc.getConnection();\r\n                final PersistenceStoreProvider provider = tpc.getPersistenceStoreProvider();\r\n                final Workstation currentWorkstation = Workstation.getCurrent(provider);\r\n                currentWorkstation.saveConfigIfDirty();\r\n            }\r\n\r\n            numDeletions++;\r\n        }\r\n\r\n        final String deletedMessage = String.format(DeletedTemplate, numDeletions, workspaceName);\r\n        logger.println(deletedMessage);\r\n\r\n        return null;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/GetFilesToWorkFolderCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport java.io.PrintStream;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.GetOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.events.GetEvent;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.events.GetListener;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.events.VersionControlEventEngine;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.LatestVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.remoting.Callable;\r\n\r\npublic class GetFilesToWorkFolderCommand extends AbstractCallableCommand<Void, Exception> implements GetListener {\r\n\r\n    private static final String GettingTemplate = \"Getting version '%s' to '%s'...\";\r\n    private static final String GotTemplate = \"Finished getting version '%s'. Retrieved %d resources.\";\r\n\r\n    private final String workFolder;\r\n    private final String versionSpec;\r\n    private final boolean useOverwrite;\r\n    private final boolean shouldLogEachGet;\r\n    private PrintStream logger;\r\n    private int getCount = 0;\r\n\r\n    public GetFilesToWorkFolderCommand(final ServerConfigurationProvider server, final String workFolder, final String versionSpec, boolean useOverwrite) {\r\n        this(server, workFolder, versionSpec, useOverwrite, false);\r\n        // using shouldLogEachGet false as default, could be controlled by a config option at a later stage if desired, just adds noise to log though\r\n    }\r\n\r\n    public GetFilesToWorkFolderCommand(final ServerConfigurationProvider server, final String workFolder, final String versionSpec, boolean useOverwrite,\r\n        final boolean shouldLogEachGet) {\r\n        super(server);\r\n        this.workFolder = workFolder;\r\n        this.versionSpec = versionSpec;\r\n        this.useOverwrite = useOverwrite;\r\n        this.shouldLogEachGet = shouldLogEachGet;\r\n    }\r\n\r\n    @Override\r\n    public Callable<Void, Exception> getCallable() {\r\n        return this;\r\n    }\r\n\r\n    void setLogger(final PrintStream logger) {\r\n        this.logger = logger;\r\n    }\r\n\r\n    public Void call() throws Exception {\r\n        final Server server = createServer();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final TaskListener listener = server.getListener();\r\n        logger = listener.getLogger();\r\n\r\n        final VersionSpec getVersionSpec;\r\n        if (versionSpec != null) {\r\n            getVersionSpec = VersionSpec.parseSingleVersionFromSpec(versionSpec, null);\r\n        } else {\r\n            getVersionSpec = LatestVersionSpec.INSTANCE;\r\n        }\r\n        final String versionSpecString = RemoteChangesetVersionCommand.toString(getVersionSpec);\r\n        final String gettingMessage = String.format(GettingTemplate, versionSpecString, workFolder);\r\n        logger.println(gettingMessage);\r\n\r\n        final Workspace workspace = vcc.getWorkspace(workFolder);\r\n        final VersionControlEventEngine eventEngine = vcc.getEventEngine();\r\n        eventEngine.addGetListener(this);\r\n        workspace.get(getVersionSpec, useOverwrite ? GetOptions.OVERWRITE : GetOptions.NONE);\r\n        eventEngine.removeGetListener(this);\r\n\r\n        final String gotMessage = String.format(GotTemplate, versionSpecString, getCount);\r\n        logger.println(gotMessage);\r\n\r\n        return null;\r\n    }\r\n\r\n    public void onGet(final GetEvent getEvent) {\r\n        getCount++;\r\n        if (shouldLogEachGet) {\r\n            logger.println(getEvent.getTargetLocalItem());\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/GetWorkspaceMappingCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.remoting.Callable;\r\n\r\nimport java.io.PrintStream;\r\n\r\npublic class GetWorkspaceMappingCommand extends AbstractCallableCommand<String, Exception> {\r\n\r\n    private static final String CheckingMappingTemplate = \"Checking if there exists a mapping for %s...\";\r\n    private static final String FoundResultTemplate = \"yes, in workspace '%s'.\";\r\n\r\n    private final String localPath;\r\n\r\n    public GetWorkspaceMappingCommand(final ServerConfigurationProvider serverConfig, final String localPath) {\r\n        super(serverConfig);\r\n        this.localPath = localPath;\r\n    }\r\n\r\n    @Override\r\n    public Callable<String, Exception> getCallable() {\r\n        return this;\r\n    }\r\n\r\n    @Override\r\n    public String call() throws Exception {\r\n        final Server server = createServer();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final TFSTeamProjectCollection connection = vcc.getConnection();\r\n        updateCache(connection);\r\n        final TaskListener listener = server.getListener();\r\n        final PrintStream logger = listener.getLogger();\r\n\r\n        final String checkingMessage = String.format(CheckingMappingTemplate, localPath);\r\n        logger.print(checkingMessage);\r\n\r\n        final Workspace workspace = vcc.tryGetWorkspace(localPath);\r\n        final boolean existsMapping = workspace != null;\r\n        final String result = existsMapping ? workspace.getName() : null;\r\n\r\n        final String resultMessage = existsMapping ? String.format(FoundResultTemplate, result) : \"no.\";\r\n        logger.println(resultMessage);\r\n\r\n        return result;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/LabelCommand.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.commands;\n\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.LabelChildOption;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.LabelResult;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.VersionControlLabel;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.ItemSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.LabelItemSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.WorkspaceVersionSpec;\nimport hudson.model.TaskListener;\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\nimport hudson.plugins.tfs.model.Server;\nimport hudson.remoting.Callable;\n\nimport java.io.PrintStream;\n\n/**\n * Command to create a label on TFS.\n * @author Rodrigo Lopes (rodrigolopes)\n */\npublic class LabelCommand extends AbstractCallableCommand<Void, Exception> {\n\n    private static final String CreatingTemplate = \"Creating label '%s' on '%s' as of the current version in workspace '%s'...\";\n    private static final String CreatedTemplate = \"Created label '%s'.\";\n\n    private final String labelName;\n    private final String workspaceName;\n    private final String projectPath;\n\n    public LabelCommand(final ServerConfigurationProvider configurationProvider,\n                        final String labelName,\n                        final String workspaceName,\n                        final String projectPath) {\n        super(configurationProvider);\n        this.labelName = labelName;\n        this.workspaceName = workspaceName;\n        this.projectPath = projectPath;\n    }\n\n    private String getLabelComment() {\n        // TODO 1. Solve issue with quotes and spaces\n        // TODO 2. Include build information in the comment.\n        return \"Automatically_applied_by_Jenkins_TFS_plugin\";\n    }\n\n    @Override\n    public Callable<Void, Exception> getCallable() {\n        return this;\n    }\n\n    public Void call() throws Exception {\n        final Server server = createServer();\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\n        final TaskListener listener = server.getListener();\n        final PrintStream logger = listener.getLogger();\n        final String userName = VersionControlConstants.AUTHENTICATED_USER;\n\n        final String creatingMessage = String.format(CreatingTemplate, labelName, projectPath, workspaceName);\n        logger.println(creatingMessage);\n\n        final VersionControlLabel versionControlLabel = new VersionControlLabel(labelName, userName, userName, null, getLabelComment());\n        final ItemSpec itemSpec = new ItemSpec(projectPath, RecursionType.FULL);\n        final WorkspaceVersionSpec workspaceVersionSpec = new WorkspaceVersionSpec(workspaceName, userName, userName);\n        final LabelItemSpec labelItemSpec = new LabelItemSpec(itemSpec, workspaceVersionSpec, false);\n        final LabelItemSpec[] items = {labelItemSpec};\n        final LabelResult[] labelResults = vcc.createLabel(versionControlLabel, items, LabelChildOption.FAIL);\n\n        if (labelResults == null || labelResults.length == 0) {\n            throw new RuntimeException(\"Label creation failed.\");\n        } else {\n            final String createdMessage = String.format(CreatedTemplate, labelName);\n            logger.println(createdMessage);\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/ListWorkspacesCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;\r\nimport com.microsoft.tfs.jni.helpers.LocalHost;\r\nimport hudson.Util;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.Workspace;\r\nimport hudson.plugins.tfs.util.TextTableParser;\r\nimport hudson.remoting.Callable;\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\nimport java.io.Reader;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\npublic class ListWorkspacesCommand extends AbstractCallableCommand<List<Workspace>, Exception> {\r\n\r\n    private static final String ListingWorkspacesTemplate = \"Downloading list of workspaces from %s...\";\r\n\r\n    private final String computer;\r\n    private final boolean shouldLogWorkspaces;\r\n\r\n    public interface WorkspaceFactory {\r\n        Workspace createWorkspace(String name, String computer, String owner, String comment);\r\n    }\r\n    \r\n    public ListWorkspacesCommand(final ServerConfigurationProvider server) {\r\n        // TODO: shouldLogWorkspaces could be controlled by a property\r\n        this(server, null, false);\r\n    }\r\n\r\n    ListWorkspacesCommand(final ServerConfigurationProvider server, final String computer, final boolean shouldLogWorkspaces) {\r\n        super(server);\r\n        this.computer = computer;\r\n        this.shouldLogWorkspaces = shouldLogWorkspaces;\r\n    }\r\n\r\n    @Override\r\n    public Callable<List<Workspace>, Exception> getCallable() {\r\n        return this;\r\n    }\r\n\r\n    public List<Workspace> call() throws Exception {\r\n        final Server server = createServer();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final TaskListener listener = server.getListener();\r\n        final PrintStream logger = listener.getLogger();\r\n        final String computerName = (computer != null) ? computer : LocalHost.getShortName();\r\n\r\n        final String listWorkspacesMessage = String.format(ListingWorkspacesTemplate, server.getUrl());\r\n        logger.println(listWorkspacesMessage);\r\n\r\n        final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace[] sdkWorkspaces\r\n                = vcc.queryWorkspaces(\r\n                null,\r\n                null,\r\n                computerName,\r\n                WorkspacePermissions.NONE_OR_NOT_SUPPORTED\r\n        );\r\n\r\n        final List<Workspace> result = new ArrayList<Workspace>(sdkWorkspaces.length);\r\n        for (final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace sdkWorkspace : sdkWorkspaces) {\r\n            final String name = sdkWorkspace.getName();\r\n            final String computer = sdkWorkspace.getComputer();\r\n            final String ownerName = sdkWorkspace.getOwnerName();\r\n            final String comment = Util.fixNull(sdkWorkspace.getComment());\r\n\r\n            final Workspace workspace = new Workspace(\r\n                    name,\r\n                    computer,\r\n                    ownerName,\r\n                    comment);\r\n            result.add(workspace);\r\n        }\r\n\r\n        if (shouldLogWorkspaces) {\r\n            log(result, logger);\r\n        }\r\n\r\n        return result;\r\n    }\r\n\r\n    public List<Workspace> parse(Reader consoleReader) throws IOException {\r\n        List<Workspace> list = new ArrayList<Workspace>();\r\n        \r\n        TextTableParser parser = new TextTableParser(consoleReader, 1);\r\n        while (parser.nextRow()) {\r\n            Workspace workspace = new Workspace(\r\n                parser.getColumn(0), \r\n                parser.getColumn(2),\r\n                parser.getColumn(1),\r\n                Util.fixNull(parser.getColumn(3)));\r\n            list.add(workspace);            \r\n        }\r\n        return list;\r\n    }\r\n\r\n    static void log(final List<Workspace> workspaces, final PrintStream logger) {\r\n        int maxName = \"Workspace\".length();\r\n        int maxOwner = \"Owner\".length();\r\n        int maxComputer = \"Computer\".length();\r\n        int maxComment = \"Comment\".length();\r\n        for (final Workspace workspace : workspaces) {\r\n            final String name = workspace.getName();\r\n            maxName = Math.max(maxName, name.length());\r\n            final String ownerName = workspace.getOwner();\r\n            maxOwner = Math.max(maxOwner, ownerName.length());\r\n            final String computer = workspace.getComputer();\r\n            maxComputer = Math.max(maxComputer, computer.length());\r\n            final String comment = workspace.getComment();\r\n            maxComment = Math.max(maxComment, comment.length());\r\n        }\r\n        final String template =\r\n                \"%1$-\" + maxName + \"s %2$-\" + maxOwner + \"s %3$-\" + maxComputer + \"s %4$-\" + maxComment + \"s\";\r\n        final String header = String.format(template, \"Workspace\", \"Owner\", \"Computer\", \"Comment\");\r\n        logger.println(header);\r\n        final String divider = String.format(template,\r\n                StringUtils.repeat(\"-\", maxName),\r\n                StringUtils.repeat(\"-\", maxOwner),\r\n                StringUtils.repeat(\"-\", maxComputer),\r\n                StringUtils.repeat(\"-\", maxComment));\r\n        logger.println(divider);\r\n\r\n        for (final Workspace workspace : workspaces) {\r\n            final String name = workspace.getName();\r\n            final String ownerName = workspace.getOwner();\r\n            final String computer = workspace.getComputer();\r\n            final String comment = workspace.getComment();\r\n            final String line = String.format(template, name, ownerName, computer, comment);\r\n            logger.println(line);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/NewWorkspaceCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceLocation;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.path.LocalPath;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.WorkingFolder;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.WorkingFolderType;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.remoting.Callable;\r\n\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.List;\r\n\r\n\r\npublic class NewWorkspaceCommand extends AbstractCallableCommand<Void, Exception> {\r\n\r\n    private static final WorkingFolder[] EMPTY_WORKING_FOLDER_ARRAY = new WorkingFolder[0];\r\n    private static final String CloakingTemplate = \"Cloaking '%s' in workspace '%s'...\";\r\n    private static final String CreatingTemplate = \"Creating workspace '%s' owned by '%s'...\";\r\n    private static final String CreatedTemplate = \"Created workspace '%s'.\";\r\n    private static final String MappingTemplate = \"Mapping '%s' to local folder '%s' in workspace '%s'...\";\r\n\r\n    private final String workspaceName;\r\n    private final String serverPath;\r\n    private final Collection<String> cloakedPaths;\r\n    private final String localPath;\r\n\r\n    public NewWorkspaceCommand(final ServerConfigurationProvider server, final String workspaceName, final String serverPath, Collection<String> cloakedPaths, final String localPath) {\r\n        super(server);\r\n        this.workspaceName = workspaceName;\r\n        this.serverPath = serverPath;\r\n        this.cloakedPaths = cloakedPaths;\r\n        this.localPath = localPath;\r\n    }\r\n\r\n    public Callable<Void, Exception> getCallable() {\r\n        return this;\r\n    }\r\n\r\n    public Void call() throws IOException {\r\n        final Server server = createServer();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final TFSTeamProjectCollection connection = vcc.getConnection();\r\n        final TaskListener listener = server.getListener();\r\n        final PrintStream logger = listener.getLogger();\r\n        final String userName = server.getUserName();\r\n\r\n        final String creatingMessage = String.format(CreatingTemplate, workspaceName, userName);\r\n        logger.println(creatingMessage);\r\n        \r\n        WorkingFolder[] foldersToMap = null;\r\n        if (serverPath != null && localPath != null) {\r\n            final String mappingMessage = String.format(MappingTemplate, serverPath, localPath, workspaceName);\r\n            logger.println(mappingMessage);\r\n\r\n            final List<WorkingFolder> folderList = new ArrayList<WorkingFolder>();\r\n\r\n            folderList.add(new WorkingFolder(serverPath, LocalPath.canonicalize(localPath), WorkingFolderType.MAP, RecursionType.FULL));\r\n\r\n\r\n            for (final String cloakedPath : cloakedPaths) {\r\n                final String cloakingMessage = String.format(CloakingTemplate, cloakedPath, workspaceName);\r\n                logger.println(cloakingMessage);\r\n\r\n                folderList.add(new WorkingFolder(cloakedPath, null, WorkingFolderType.CLOAK));\r\n            }\r\n            foldersToMap = folderList.toArray(EMPTY_WORKING_FOLDER_ARRAY);\r\n        }\r\n\r\n        updateCache(connection);\r\n        // TODO: we might need to delete a previous workspace that had another name\r\n        vcc.createWorkspace(\r\n                foldersToMap,\r\n                workspaceName,\r\n                VersionControlConstants.AUTHENTICATED_USER,\r\n                VersionControlConstants.AUTHENTICATED_USER,\r\n                null /* TODO: set comment to something nice/useful */,\r\n                WorkspaceLocation.SERVER /* TODO: pull request #33 adds LOCAL support */,\r\n                WorkspaceOptions.NONE\r\n        );\r\n\r\n        final String createdMessage = String.format(CreatedTemplate, workspaceName);\r\n        logger.println(createdMessage);\r\n\r\n        return null;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/RemoteChangesetVersionCommand.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.commands;\n\nimport com.google.common.base.Strings;\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Changeset;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.LabelVersionSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\nimport hudson.model.TaskListener;\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\nimport hudson.plugins.tfs.model.Server;\nimport hudson.plugins.tfs.util.DateUtil;\nimport hudson.plugins.tfs.util.TextTableParser;\nimport hudson.remoting.Callable;\nimport org.apache.commons.lang.StringUtils;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.io.Reader;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.TimeZone;\n\n/**\n * TF command for retrieving the latest remote change set version in effect at the specified time.\n * \n * @author Olivier Dagenais\n *\n */\npublic class RemoteChangesetVersionCommand extends AbstractCallableCommand<Integer, Exception> {\n\n    private static final String QueryingTemplate = \"Querying for remote changeset at '%s' as of '%s'...\";\n    private static final String ResultTemplate = \"Query result is: Changeset #%d by '%s' on '%s'.\";\n    private static final String FailedTemplate = \"Query returned no result!\";\n\n    private final String versionSpecString;\n    private final String path;\n\n    public RemoteChangesetVersionCommand(\n            final ServerConfigurationProvider server, final String remotePath, final VersionSpec versionSpec) {\n        super(server);\n        this.path = remotePath;\n\n        this.versionSpecString = toString(versionSpec);\n    }\n\n    public Callable<Integer, Exception> getCallable() {\n        return this;\n    }\n\n    public Integer call() throws Exception {\n        final Server server = createServer();\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\n        final TaskListener listener = server.getListener();\n        final PrintStream logger = listener.getLogger();\n        final VersionSpec versionSpec = VersionSpec.parseSingleVersionFromSpec(versionSpecString, VersionControlConstants.AUTHENTICATED_USER);\n\n        final String specString = RemoteChangesetVersionCommand.toString(versionSpec);\n        final String queryingMessage = String.format(QueryingTemplate, path, specString);\n        logger.println(queryingMessage);\n\n        final Changeset[] serverChangeSets = vcc.queryHistory(\n                path,\n                versionSpec,\n                0 /* deletionId */,\n                RecursionType.FULL,\n                null /* user */,\n                null,\n                null,\n                1     /* maxCount */,\n                false /* includeFileDetails */,\n                true  /* slotMode */,\n                false /* includeDownloadInfo */,\n                false /* sortAscending */\n        );\n        Integer changeSetNumber = null;\n        final String resultMessage;\n        if (serverChangeSets != null && serverChangeSets.length >= 1) {\n            final Changeset serverChangeset = serverChangeSets[0];\n            changeSetNumber = serverChangeset.getChangesetID();\n            final Date changeSetDate = serverChangeset.getDate().getTime();\n            final String author = serverChangeset.getOwner();\n            final SimpleDateFormat simpleDateFormat = DateUtil.TFS_DATETIME_FORMATTER.get();\n            simpleDateFormat.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n            final String changeSetDateIso8601 = simpleDateFormat.format(changeSetDate);\n            resultMessage = String.format(ResultTemplate, changeSetNumber, author, changeSetDateIso8601);\n        } else {\n            resultMessage = FailedTemplate;\n        }\n        logger.println(resultMessage);\n\n        return changeSetNumber;\n    }\n\n    public static String toString(final VersionSpec versionSpec) {\n        // TODO: just call versionSpec.toString() once DateVersionSpec.toString() uses ISO 8601 format\n        if (versionSpec instanceof DateVersionSpec){\n            final DateVersionSpec dateVersionSpec = (DateVersionSpec) versionSpec;\n            return DateUtil.toString(dateVersionSpec);\n        }\n        else if (versionSpec instanceof LabelVersionSpec) {\n            final LabelVersionSpec labelVersionSpec = (LabelVersionSpec) versionSpec;\n            // TODO: It seems to me LabelVersionSpec.toString() should emit \"Lfoo\" when its scope is null\n            final String label = labelVersionSpec.getLabel();\n            final String scope = labelVersionSpec.getScope();\n            final StringBuilder sb = new StringBuilder(1 + label.length() + Strings.nullToEmpty(scope).length());\n            sb.append('L');\n            sb.append(label);\n            if (!Strings.isNullOrEmpty(scope)) {\n                sb.append('@');\n                sb.append(scope);\n            }\n            return sb.toString();\n        }\n        return versionSpec.toString();\n    }\n\n    public String parse(Reader consoleReader) throws ParseException, IOException {\n        TextTableParser parser = new TextTableParser(new BufferedReader(consoleReader), 1);\n\n        while (parser.nextRow()) {\n            return parser.getColumn(0);\n        }\n\n        return StringUtils.EMPTY;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/commands/ServerConfigurationProvider.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.commands;\r\n\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.ExtraSettings;\r\nimport hudson.plugins.tfs.model.WebProxySettings;\r\n\r\npublic interface ServerConfigurationProvider {\r\n\r\n    public String getUrl();\r\n\r\n    public String getUserName();\r\n\r\n    public String getUserPassword();\r\n\r\n    public TaskListener getListener();\r\n\r\n    public WebProxySettings getWebProxySettings();\r\n\r\n    public ExtraSettings getExtraSettings();\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/listeners/JenkinsRunListener.java",
    "content": "package hudson.plugins.tfs.listeners;\n\nimport hudson.Extension;\nimport hudson.model.Run;\nimport hudson.model.TaskListener;\nimport hudson.model.listeners.RunListener;\n\nimport hudson.plugins.tfs.TeamCompletedStatusPostBuildAction;\nimport hudson.plugins.tfs.TeamPendingStatusBuildStep;\nimport hudson.plugins.tfs.UnsupportedIntegrationAction;\n\nimport javax.annotation.Nonnull;\nimport java.util.logging.Logger;\n\n\n/**\n * This class listens to the events of every Jenkins run instance.\n */\n@Extension\npublic class JenkinsRunListener extends RunListener<Run> {\n    protected static final Logger log = Logger.getLogger(JenkinsRunListener.class.getName());\n\n    public JenkinsRunListener() {\n        log.fine(\"JenkinsRunListener: constructor\");\n    }\n\n    @Override\n    public void onDeleted(final Run run) {\n    }\n\n    @Override\n    public void onStarted(final Run run, final TaskListener listener) {\n        if (UnsupportedIntegrationAction.isSupported(run, listener)) {\n            final TeamPendingStatusBuildStep step = new TeamPendingStatusBuildStep();\n            step.perform(run, listener);\n        }\n    }\n\n    @Override\n    public void onFinalized(final Run run) {\n    }\n\n    @Override\n    public void onCompleted(final Run run, @Nonnull final TaskListener listener) {\n        log.info(\"onCompleted: \" + run.toString());\n        if (UnsupportedIntegrationAction.isSupported(run, listener)) {\n            final TeamCompletedStatusPostBuildAction step = new TeamCompletedStatusPostBuildAction();\n            step.perform(run, listener);\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/AbstractCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport hudson.model.BuildableItem;\r\nimport hudson.model.Job;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport jenkins.util.TimeDuration;\r\nimport net.sf.json.JSONObject;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\n\r\npublic abstract class AbstractCommand {\r\n\r\n    public AbstractCommand() {\r\n    }\r\n\r\n    public interface Factory {\r\n        AbstractCommand create();\r\n        String getSampleRequestPayload();\r\n    }\r\n\r\n    /**\r\n     * Actually do the work of the command, using the supplied {@code requestPayload} and\r\n     * {@code teamBuildPayload}, then returning the output as a {@link JSONObject}.\r\n     *\r\n     * @param job an {@link Job to operate on}\r\n     * @param buildableItem an {@link BuildableItem to operate on}\r\n     * @param request a {@link StaplerRequest} to help build parameter values\r\n     * @param requestPayload a {@link JSONObject} representing the command's input\r\n     * @param mapper an {@link ObjectMapper} instance to use to convert the {@link Event#resource}\r\n     * @param teamBuildPayload a {@link TeamBuildPayload} representing the command's input\r\n     * @param delay how long to wait before the project starts executing\r\n     *\r\n     * @return a {@link JSONObject} representing the hook event's output\r\n     */\r\n    public abstract JSONObject perform(final Job<?, ?> job, final BuildableItem buildableItem, final StaplerRequest request, final JSONObject requestPayload, final ObjectMapper mapper, final TeamBuildPayload teamBuildPayload, final TimeDuration delay);\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/AbstractHookEvent.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Action;\r\nimport hudson.model.Cause;\r\nimport hudson.model.CauseAction;\r\nimport hudson.model.Item;\r\nimport hudson.model.Job;\r\nimport hudson.model.ParameterDefinition;\r\nimport hudson.model.ParameterValue;\r\nimport hudson.model.ParametersDefinitionProperty;\r\nimport hudson.model.StringParameterValue;\r\nimport hudson.plugins.git.BranchSpec;\r\nimport hudson.plugins.git.GitSCM;\r\nimport hudson.plugins.git.GitStatus;\r\nimport hudson.plugins.git.UserRemoteConfig;\r\nimport hudson.plugins.git.extensions.impl.IgnoreNotifyCommit;\r\nimport hudson.plugins.tfs.SafeParametersAction;\r\nimport hudson.plugins.tfs.TeamEventsEndpoint;\r\nimport hudson.plugins.tfs.TeamGlobalStatusAction;\r\nimport hudson.plugins.tfs.TeamHookCause;\r\nimport hudson.plugins.tfs.TeamPRPushTrigger;\r\nimport hudson.plugins.tfs.TeamPluginGlobalConfig;\r\nimport hudson.plugins.tfs.TeamPushTrigger;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport hudson.plugins.tfs.util.ActionHelper;\r\nimport hudson.plugins.tfs.util.TeamStatus;\r\nimport hudson.plugins.tfs.util.UriHelper;\r\nimport hudson.scm.SCM;\r\nimport hudson.security.ACL;\r\nimport hudson.triggers.SCMTrigger;\r\nimport jenkins.model.Jenkins;\r\nimport jenkins.triggers.SCMTriggerItem;\r\nimport net.sf.json.JSONArray;\r\nimport net.sf.json.JSONObject;\r\nimport org.acegisecurity.context.SecurityContext;\r\nimport org.acegisecurity.context.SecurityContextHolder;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.eclipse.jgit.transport.RemoteConfig;\r\nimport org.eclipse.jgit.transport.URIish;\r\nimport org.jenkinsci.plugins.workflow.job.WorkflowJob;\r\nimport org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition;\r\nimport org.jenkinsci.plugins.workflow.flow.FlowDefinition;\r\n\r\nimport java.io.IOException;\r\nimport java.io.PrintWriter;\r\nimport java.io.StringWriter;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.List;\r\nimport java.util.logging.Logger;\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\n/**\r\n * This class abstracts the hook event.\r\n */\r\npublic abstract class AbstractHookEvent {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(AbstractHookEvent.class.getName());\r\n    private static final String TRIGGER_ANY_BRANCH = \"**\";\r\n\r\n    /**\r\n    * Interface of hook event factory.\r\n    */\r\n    public interface Factory {\r\n        /**\r\n        * Create the factory.\r\n        */\r\n        AbstractHookEvent create();\r\n\r\n        /**\r\n        * Get sample request payload.\r\n        */\r\n        String getSampleRequestPayload();\r\n    }\r\n\r\n    /**\r\n     * Actually do the work of the hook event, using the supplied\r\n     * {@code mapper} to convert the event's data from the supplied {@code serviceHookEvent}\r\n     * and returning the output as a {@link JSONObject}.\r\n     *\r\n     * @param mapper an {@link ObjectMapper} instance to use to convert the {@link Event#resource}\r\n     * @param serviceHookEvent an {@link Event} that represents the request payload\r\n     *                         and from which the {@link Event#resource} can be obtained\r\n     * @param message a simple description of the event\r\n     * @param detailedMessage a longer description of the event, with some details\r\n     *\r\n     * @return a {@link JSONObject} representing the hook event's output\r\n     */\r\n    public abstract JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage);\r\n\r\n    static JSONObject fromResponseContributors(final List<GitStatus.ResponseContributor> contributors) {\r\n        final JSONObject result = new JSONObject();\r\n        final JSONArray messages = new JSONArray();\r\n        for (final GitStatus.ResponseContributor contributor : contributors) {\r\n            final StringWriter stringWriter = new StringWriter();\r\n            final PrintWriter printWriter = new PrintWriter(stringWriter);\r\n            try {\r\n                contributor.writeBody(printWriter);\r\n                printWriter.flush();\r\n            } finally {\r\n                IOUtils.closeQuietly(printWriter);\r\n            }\r\n            final String contributorMessage = stringWriter.toString();\r\n            messages.add(contributorMessage);\r\n        }\r\n        result.put(\"messages\", messages);\r\n        return result;\r\n    }\r\n\r\n    GitStatus.ResponseContributor triggerJob(final GitCodePushedEventArgs gitCodePushedEventArgs, final List<Action> actions, final boolean bypassPolling, final Item project, final SCMTriggerItem scmTriggerItem, final Boolean repoMatches, final Boolean branchMatches) {\r\n        if (!(project instanceof AbstractProject && ((AbstractProject) project).isDisabled())) {\r\n            if (project instanceof Job) {\r\n                final Job job = (Job) project;\r\n                final int quietPeriod = scmTriggerItem.getQuietPeriod();\r\n                final String targetUrl = job.getAbsoluteUrl() + job.getNextBuildNumber();\r\n\r\n                final ArrayList<ParameterValue> values = getDefaultParameters(job);\r\n                final String vstsRefspec = getVstsRefspec(gitCodePushedEventArgs);\r\n                values.add(new StringParameterValue(\"vstsRefspec\", vstsRefspec));\r\n                values.add(new StringParameterValue(\"vstsBranchOrCommit\", gitCodePushedEventArgs.commit));\r\n                SafeParametersAction paraAction = new SafeParametersAction(values);\r\n                final Action[] actionsNew = ActionHelper.create(actions, paraAction);\r\n                final List<Action> actionsWithSafeParams = new ArrayList<Action>(Arrays.asList(actionsNew));\r\n\r\n                final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\r\n                final SCMTrigger scmTrigger = TeamEventsEndpoint.findTrigger(job, SCMTrigger.class);\r\n                if (config.isEnableTeamPushTriggerForAllJobs()) {\r\n                    if (scmTrigger == null || !scmTrigger.isIgnorePostCommitHooks()) {\r\n                        // trigger is null OR job does NOT have explicitly opted out of hooks\r\n                        final TeamPushTrigger trigger = new TeamPushTrigger(job);\r\n                        trigger.execute(gitCodePushedEventArgs, actionsWithSafeParams, bypassPolling);\r\n                        if (bypassPolling) {\r\n                            return new TeamEventsEndpoint.ScheduledResponseContributor(project);\r\n                        } else {\r\n                            return new TeamEventsEndpoint.PollingScheduledResponseContributor(project);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                if (scmTrigger != null && !scmTrigger.isIgnorePostCommitHooks()) {\r\n                    // queue build without first polling\r\n                    final Cause cause = new TeamHookCause(gitCodePushedEventArgs.commit);\r\n                    final CauseAction causeAction = new CauseAction(cause);\r\n                    final Action[] actionArray = ActionHelper.create(actionsWithSafeParams, causeAction);\r\n                    scmTriggerItem.scheduleBuild2(quietPeriod, actionArray);\r\n                    if (gitCodePushedEventArgs instanceof PullRequestMergeCommitCreatedEventArgs) {\r\n                        try {\r\n                            TeamStatus.createFromJob((PullRequestMergeCommitCreatedEventArgs) gitCodePushedEventArgs, job);\r\n                        } catch (IOException ex) {\r\n                            LOGGER.warning(\"Could not create TeamStatus: \" + ex.toString());\r\n                        }\r\n                    }\r\n\r\n                    return new TeamEventsEndpoint.ScheduledResponseContributor(project);\r\n                }\r\n\r\n                if ((repoMatches || repoMatches(gitCodePushedEventArgs, job)) && (branchMatches || branchMatches(gitCodePushedEventArgs, job))) {\r\n                    TeamPushTrigger pushTrigger = null;\r\n                    if (gitCodePushedEventArgs instanceof PullRequestMergeCommitCreatedEventArgs) {\r\n                        pushTrigger = TeamEventsEndpoint.findTrigger(job, TeamPRPushTrigger.class);\r\n                    } else { // Check whether current job has an EXACT TeamPushTrigger instead of a TeamPRPushTrigger whose type is also TeamPushTrigger.\r\n                        final List<TeamPushTrigger> listTriggers = TeamEventsEndpoint.findTriggers(job, TeamPushTrigger.class);\r\n                        if (!listTriggers.isEmpty()) {\r\n                            for (TeamPushTrigger trigger : listTriggers) {\r\n                                if (!(trigger instanceof TeamPRPushTrigger)) {\r\n                                    pushTrigger = trigger;\r\n                                    break;\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                    if (pushTrigger != null) {\r\n                        pushTrigger.execute(gitCodePushedEventArgs, actionsWithSafeParams, bypassPolling);\r\n                        if (bypassPolling) {\r\n                            return new TeamEventsEndpoint.ScheduledResponseContributor(project);\r\n                        } else {\r\n                            return  new TeamEventsEndpoint.PollingScheduledResponseContributor(project);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    private Boolean repoMatches(final GitCodePushedEventArgs gitCodePushedEventArgs, final Job job) {\r\n        if (job instanceof WorkflowJob) {\r\n            final FlowDefinition jobDef = ((WorkflowJob) job).getDefinition();\r\n            if (jobDef instanceof CpsScmFlowDefinition) {\r\n                final SCM jobSCM = ((CpsScmFlowDefinition) jobDef).getScm();\r\n                if (jobSCM instanceof GitSCM) {\r\n                    final GitSCM gitJobSCM = (GitSCM) jobSCM;\r\n                    final URIish uri = gitCodePushedEventArgs.getRepoURIish();\r\n\r\n                    for (final UserRemoteConfig remoteConfig : gitJobSCM.getUserRemoteConfigs()) {\r\n                        final String jobRepoUrl = remoteConfig.getUrl();\r\n\r\n                        if (StringUtils.equalsIgnoreCase(jobRepoUrl, uri.toString())) {\r\n                            return true;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    private Boolean branchMatches(final GitCodePushedEventArgs gitCodePushedEventArgs, final Job job) {\r\n        // Jobs triggered by PR merge need to check whether its target branch matches the one specified in the parameter of PR trigger UI\r\n        if (gitCodePushedEventArgs instanceof PullRequestMergeCommitCreatedEventArgs) {\r\n            TeamPRPushTrigger pushTrigger = TeamEventsEndpoint.findTrigger(job, TeamPRPushTrigger.class);\r\n            if (pushTrigger != null) {\r\n                final String targetBranches = pushTrigger.getTargetBranches();\r\n                if (targetBranches != null) {\r\n                    String[] branches = targetBranches.split(\" \");\r\n                    if (branches != null) {\r\n                        for (String branchFullName : branches) {\r\n                            // branchFullName could be in the format of */pr_status\r\n                            String[] items = branchFullName.split(\"/\");\r\n                            if (StringUtils.equalsIgnoreCase(items[items.length - 1], gitCodePushedEventArgs.targetBranch)) {\r\n                                return true;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        } else { // Pipeline jobs triggered by code push need to check whether its target branch matches the one in its Git parameter\r\n            if (job instanceof WorkflowJob) {\r\n                final FlowDefinition jobDef = ((WorkflowJob) job).getDefinition();\r\n                if (jobDef instanceof CpsScmFlowDefinition) {\r\n                    final SCM jobSCM = ((CpsScmFlowDefinition) jobDef).getScm();\r\n                    if (jobSCM instanceof GitSCM) {\r\n                        final GitSCM gitJobSCM = (GitSCM) jobSCM;\r\n                        for (final BranchSpec branchFullName : gitJobSCM.getBranches()) {\r\n                            // branchFullName could be in the format of */pr_status\r\n                            String[] items = branchFullName.getName().split(\"/\");\r\n                            if (StringUtils.equalsIgnoreCase(items[items.length - 1], gitCodePushedEventArgs.targetBranch)) {\r\n                                return true;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    // TODO: it would be easiest if pollOrQueueFromEvent built a JSONObject directly\r\n    List<GitStatus.ResponseContributor> pollOrQueueFromEvent(final GitCodePushedEventArgs gitCodePushedEventArgs, final List<Action> actions, final boolean bypassPolling) {\r\n        List<GitStatus.ResponseContributor> result = new ArrayList<GitStatus.ResponseContributor>();\r\n        final String commit = gitCodePushedEventArgs.commit;\r\n        if (commit == null) {\r\n            result.add(new GitStatus.MessageResponseContributor(\"No commits were pushed, skipping further event processing.\"));\r\n            return result;\r\n        }\r\n        final URIish uri = gitCodePushedEventArgs.getRepoURIish();\r\n\r\n        TeamGlobalStatusAction.addIfApplicable(actions);\r\n\r\n        // run in high privilege to see all the projects anonymous users don't see.\r\n        // this is safe because when we actually schedule a build, it's a build that can\r\n        // happen at some random time anyway.\r\n        SecurityContext old = ACL.impersonate(ACL.SYSTEM);\r\n        try {\r\n\r\n            boolean scmFound = false;\r\n            final Jenkins jenkins = Jenkins.getInstance();\r\n            if (jenkins == null) {\r\n                LOGGER.severe(\"Jenkins.getInstance() is null\");\r\n                return result;\r\n            }\r\n            int totalBranchMatches = 0;\r\n            for (final Item project : Jenkins.getActiveInstance().getAllItems()) {\r\n                final SCMTriggerItem scmTriggerItem = SCMTriggerItem.SCMTriggerItems.asSCMTriggerItem(project);\r\n\r\n                if (scmTriggerItem == null || scmTriggerItem.getSCMs() == null) {\r\n                    continue;\r\n                }\r\n\r\n                // Pipeline job\r\n                if (scmTriggerItem.getSCMs().isEmpty()) {\r\n                    GitStatus.ResponseContributor triggerResult = triggerJob(gitCodePushedEventArgs, actions, bypassPolling, project, scmTriggerItem, false, false);\r\n                    if (triggerResult != null) {\r\n                        result.add(triggerResult);\r\n                    }\r\n                    continue;\r\n                }\r\n\r\n                for (final SCM scm : scmTriggerItem.getSCMs()) {\r\n                    if (!(scm instanceof GitSCM)) {\r\n                        continue;\r\n                    }\r\n                    final GitSCM git = (GitSCM) scm;\r\n                    scmFound = true;\r\n\r\n                    for (final RemoteConfig repository : git.getRepositories()) {\r\n                        boolean repositoryMatches = false;\r\n                        for (final URIish remoteURL : repository.getURIs()) {\r\n                            if (UriHelper.areSameGitRepo(uri, remoteURL)) {\r\n                                repositoryMatches = true;\r\n                                break;\r\n                            }\r\n                        }\r\n\r\n                        // Jobs triggered by PR merge need to check whether its target branch matches the one specified in the parameter of PR trigger UI\r\n                        if (repositoryMatches && gitCodePushedEventArgs instanceof PullRequestMergeCommitCreatedEventArgs) {\r\n                            GitStatus.ResponseContributor triggerResult = triggerJob(gitCodePushedEventArgs, actions, bypassPolling, project, scmTriggerItem, true, false);\r\n                            if (triggerResult != null) {\r\n                                result.add(triggerResult);\r\n                            }\r\n                            break;\r\n                        }\r\n\r\n                        boolean branchMatches = false;\r\n                        // Jobs triggered by code push need to check whether its target branch matches the one in its Git parameter\r\n                        for (final BranchSpec branch : git.getBranches()) {\r\n                            final String branchString = branch.toString();\r\n                            // Might be in the form of */master\r\n                            final String[] items = branchString.split(\"/\");\r\n                            final String branchName = items[items.length - 1];\r\n                            if (branchName.equalsIgnoreCase(TRIGGER_ANY_BRANCH) || branchName.equalsIgnoreCase(gitCodePushedEventArgs.targetBranch)) {\r\n                                branchMatches = true;\r\n                                totalBranchMatches++;\r\n                                break;\r\n                            }\r\n                        }\r\n\r\n                        if (!repositoryMatches || !branchMatches || git.getExtensions().get(IgnoreNotifyCommit.class) != null) {\r\n                            continue;\r\n                        }\r\n\r\n                        GitStatus.ResponseContributor triggerResult = triggerJob(gitCodePushedEventArgs, actions, bypassPolling, project, scmTriggerItem, true, true);\r\n                        if (triggerResult != null) {\r\n                            result.add(triggerResult);\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            if (!scmFound) {\r\n                result.add(new GitStatus.MessageResponseContributor(\"No Git jobs found\"));\r\n            } else if (totalBranchMatches == 0) {\r\n                final String template = \"No Git jobs matched the remote URL '%s' requested by an event.\";\r\n                final String message = String.format(template, uri);\r\n                LOGGER.warning(message);\r\n            }\r\n\r\n            return result;\r\n        } finally {\r\n            SecurityContextHolder.setContext(old);\r\n        }\r\n    }\r\n\r\n    private ArrayList<ParameterValue> getDefaultParameters(final Job<?, ?> job) {\r\n        ArrayList<ParameterValue> values = new ArrayList<ParameterValue>();\r\n        ParametersDefinitionProperty pdp = job.getProperty(ParametersDefinitionProperty.class);\r\n        if (pdp != null) {\r\n            for (ParameterDefinition pd : pdp.getParameterDefinitions()) {\r\n                if (pd.getName().equals(\"sha1\")) {\r\n                    continue;\r\n                }\r\n                values.add(pd.getDefaultParameterValue());\r\n            }\r\n        }\r\n        return values;\r\n    }\r\n\r\n    private String getVstsRefspec(final GitCodePushedEventArgs gitCodePushedEventArgs) {\r\n        if (gitCodePushedEventArgs instanceof PullRequestMergeCommitCreatedEventArgs) {\r\n            int prId = ((PullRequestMergeCommitCreatedEventArgs) gitCodePushedEventArgs).pullRequestId;\r\n            return String.format(\"+refs/pull/%d/merge:refs/remotes/pull/%d/merge\", prId, prId);\r\n        } else {\r\n            return \"+refs/heads/*:refs/remotes/origin/*\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/AliasOnlyUserAccountMapper.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.Extension;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\n/**\r\n * Maps user accounts without using the DOMAIN.\r\n */\r\npublic class AliasOnlyUserAccountMapper extends UserAccountMapper {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * Constructor.\r\n     */\r\n    @DataBoundConstructor\r\n    public AliasOnlyUserAccountMapper() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public String mapUserAccount(final String input) {\r\n        final String[] split = input.split(\"\\\\\\\\\");\r\n        final String result;\r\n        if (split.length == 2) {\r\n            result = split[1];\r\n        } else {\r\n            result = input;\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * A descriptor for the class.\r\n     */\r\n    @Extension\r\n    public static final class DescriptorImpl extends UserAccountMapperDescriptor {\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Resolve user using 'alias' only, removing 'DOMAIN\\\\'\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/AutomaticCredentialsConfigurer.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport hudson.Extension;\r\nimport hudson.plugins.tfs.TeamCollectionConfiguration;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\nimport java.net.URI;\r\n\r\n/**\r\n * Finds credentials in the TeamCollectionConfiguration.\r\n */\r\npublic class AutomaticCredentialsConfigurer extends CredentialsConfigurer {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * Constructor for use with data binding.\r\n     */\r\n    @DataBoundConstructor\r\n    public AutomaticCredentialsConfigurer() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public StandardUsernamePasswordCredentials getCredentials(final String collectionUriString) {\r\n        final URI collectionUri = URI.create(collectionUriString);\r\n        return TeamCollectionConfiguration.findCredentialsForCollection(collectionUri);\r\n    }\r\n\r\n    /**\r\n     * Class descriptor.\r\n     */\r\n    @Extension\r\n    public static final class DescriptorImpl extends CredentialsConfigurerDescriptor {\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Automatic\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/BuildCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPush;\r\nimport hudson.model.Action;\r\nimport hudson.model.BuildableItem;\r\nimport hudson.model.Cause;\r\nimport hudson.model.CauseAction;\r\nimport hudson.model.Executor;\r\nimport hudson.model.Job;\r\nimport hudson.model.ParameterDefinition;\r\nimport hudson.model.ParameterValue;\r\nimport hudson.model.ParametersAction;\r\nimport hudson.model.ParametersDefinitionProperty;\r\nimport hudson.model.Queue;\r\nimport hudson.model.Run;\r\nimport hudson.model.SimpleParameterDefinition;\r\nimport hudson.model.queue.ScheduleResult;\r\nimport hudson.plugins.tfs.CommitParameterAction;\r\nimport hudson.plugins.tfs.PullRequestParameterAction;\r\nimport hudson.plugins.tfs.TeamBuildDetailsAction;\r\nimport hudson.plugins.tfs.TeamBuildEndpoint;\r\nimport hudson.plugins.tfs.TeamGlobalStatusAction;\r\nimport hudson.plugins.tfs.TeamPullRequestMergedDetailsAction;\r\nimport hudson.plugins.tfs.UnsupportedIntegrationAction;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport hudson.plugins.tfs.util.ActionHelper;\r\nimport hudson.plugins.tfs.util.MediaType;\r\nimport hudson.util.RunList;\r\nimport jenkins.model.Jenkins;\r\nimport jenkins.util.TimeDuration;\r\nimport net.sf.json.JSONArray;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.net.URI;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.logging.Logger;\r\n\r\npublic class BuildCommand extends AbstractCommand {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(BuildCommand.class.getName());\r\n\r\n    private static final String BUILD_REPOSITORY_PROVIDER = \"Build.Repository.Provider\";\r\n    private static final String BUILD_REPOSITORY_URI = \"Build.Repository.Uri\";\r\n    private static final String BUILD_REPOSITORY_NAME = \"Build.Repository.Name\";\r\n    private static final String SYSTEM_TEAM_PROJECT = \"System.TeamProject\";\r\n    private static final String BUILD_SOURCE_VERSION = \"Build.SourceVersion\";\r\n    private static final String BUILD_REQUESTED_FOR = \"Build.RequestedFor\";\r\n    private static final String SYSTEM_TEAM_FOUNDATION_COLLECTION_URI = \"System.TeamFoundationCollectionUri\";\r\n    private static final String COMMIT_ID = \"commitId\";\r\n    private static final String PULL_REQUEST_ID = \"pullRequestId\";\r\n    private static final String UNSUPPORTED_TEMPLATE =\r\n            \"The rich integration with TFS/Team Services is not supported. Reason: %s\";\r\n\r\n    public static String formatUnsupportedReason(final String reason) {\r\n        return String.format(UNSUPPORTED_TEMPLATE, reason);\r\n    }\r\n\r\n    public static class Factory implements AbstractCommand.Factory {\r\n        @Override\r\n        public AbstractCommand create() {\r\n            return new BuildCommand();\r\n        }\r\n\r\n        @Override\r\n        public String getSampleRequestPayload() {\r\n            final Class<? extends Factory> me = this.getClass();\r\n            final InputStream stream = me.getResourceAsStream(\"BuildCommand.json\");\r\n            try {\r\n                return IOUtils.toString(stream, MediaType.UTF_8);\r\n            }\r\n            catch (final IOException e) {\r\n                throw new Error(e);\r\n            }\r\n            finally {\r\n                IOUtils.closeQuietly(stream);\r\n            }\r\n        }\r\n    }\r\n\r\n    protected JSONObject innerPerform(final Job job, final BuildableItem buildableItem, final TimeDuration delay, final List<Action> extraActions) {\r\n        final JSONObject result = new JSONObject();\r\n\r\n        final Jenkins jenkins = Jenkins.getActiveInstance();\r\n        final Queue queue = jenkins.getQueue();\r\n        final Cause cause = new Cause.UserIdCause();\r\n        final CauseAction causeAction = new CauseAction(cause);\r\n        final Action[] actionArray = ActionHelper.create(extraActions, causeAction);\r\n        for (Action a : extraActions) {\r\n            if (a instanceof TeamPullRequestMergedDetailsAction) {\r\n                cancelPreviousPullRequestBuilds(job, (TeamPullRequestMergedDetailsAction) a, queue);\r\n            }\r\n        }\r\n        final ScheduleResult scheduleResult = queue.schedule2(buildableItem, delay.getTime(), actionArray);\r\n        final Queue.Item item = scheduleResult.getItem();\r\n        if (item != null) {\r\n            result.put(\"created\", jenkins.getRootUrl() + item.getUrl());\r\n        }\r\n        return result;\r\n    }\r\n\r\n    @Override\r\n    public JSONObject perform(final Job<?, ?> job, final BuildableItem buildableItem, final StaplerRequest req,\r\n                              final JSONObject requestPayload, final ObjectMapper mapper,\r\n                              final TeamBuildPayload teamBuildPayload, final TimeDuration delay) {\r\n\r\n        // These values are for optional parameters of the same name, for the git.pullrequest.merged event\r\n        String commitId = null;\r\n        String pullRequestId = null;\r\n\r\n        final List<Action> actions = new ArrayList<Action>();\r\n\r\n        if (teamBuildPayload.BuildVariables != null) {\r\n            contributeTeamBuildParameterActions(teamBuildPayload.BuildVariables, actions);\r\n        }\r\n        else if (teamBuildPayload.ServiceHookEvent != null) {\r\n            final Event event = teamBuildPayload.ServiceHookEvent;\r\n            final String eventType = event.getEventType();\r\n            final Object resource = event.getResource();\r\n            if (\"git.push\".equals(eventType)) {\r\n                final GitPush gitPush = mapper.convertValue(resource, GitPush.class);\r\n                final GitCodePushedEventArgs args = GitPushEvent.decodeGitPush(gitPush, event);\r\n                final Action action = new CommitParameterAction(args);\r\n                actions.add(action);\r\n                TeamGlobalStatusAction.addIfApplicable(actions);\r\n            }\r\n            else if (\"git.pullrequest.merged\".equals(eventType)) {\r\n                final GitPullRequestEx gitPullRequest = mapper.convertValue(resource, GitPullRequestEx.class);\r\n                final PullRequestMergeCommitCreatedEventArgs args = GitPullRequestMergedEvent.decodeGitPullRequest(gitPullRequest, event);\r\n                // record the values for the special optional parameters\r\n                commitId = args.commit;\r\n                pullRequestId = Integer.toString(args.pullRequestId, 10);\r\n                final Action action = new PullRequestParameterAction(args);\r\n                actions.add(action);\r\n                final String message = event.getMessage().getText();\r\n                final String detailedMessage = event.getDetailedMessage().getText();\r\n                final Action teamPullRequestMergedDetailsAction = new TeamPullRequestMergedDetailsAction(gitPullRequest, message, detailedMessage, args.collectionUri.toString());\r\n                actions.add(teamPullRequestMergedDetailsAction);\r\n                TeamGlobalStatusAction.addIfApplicable(actions);\r\n            }\r\n        }\r\n\r\n        final ParametersDefinitionProperty pp = job.getProperty(ParametersDefinitionProperty.class);\r\n        if (pp != null && requestPayload.containsKey(TeamBuildEndpoint.PARAMETER)) {\r\n            final List<ParameterValue> values = new ArrayList<ParameterValue>();\r\n            final JSONArray a = requestPayload.getJSONArray(TeamBuildEndpoint.PARAMETER);\r\n            final List<String> parameterNames = new ArrayList<>();\r\n\r\n            for (final Object o : a) {\r\n                final JSONObject jo = (JSONObject) o;\r\n                final String name = jo.getString(\"name\");\r\n                parameterNames.add(name);\r\n\r\n                final ParameterDefinition d = pp.getParameterDefinition(name);\r\n                if (d == null)\r\n                    throw new IllegalArgumentException(\"No such parameter definition: \" + name);\r\n                final ParameterValue parameterValue;\r\n                // commitId and pullRequestId are special and override any user-provided value\r\n                // when the team-event's eventType was \"git.pullrequest.merged\"\r\n                if (name.equals(COMMIT_ID) && commitId != null && d instanceof SimpleParameterDefinition) {\r\n                    final SimpleParameterDefinition spd = (SimpleParameterDefinition) d;\r\n                    parameterValue = spd.createValue(commitId);\r\n                    // erase value to avoid adding it a second time\r\n                    commitId = null;\r\n                }\r\n                else if (name.equals(PULL_REQUEST_ID) && pullRequestId != null && d instanceof SimpleParameterDefinition) {\r\n                    final SimpleParameterDefinition spd = (SimpleParameterDefinition) d;\r\n                    parameterValue = spd.createValue(pullRequestId);\r\n                    // erase value to avoid adding it a second time\r\n                    pullRequestId = null;\r\n                }\r\n                else {\r\n                    parameterValue = d.createValue(req, jo);\r\n                }\r\n                if (parameterValue != null) {\r\n                    values.add(parameterValue);\r\n                }\r\n                else {\r\n                    throw new IllegalArgumentException(\"Cannot retrieve the parameter value: \" + name);\r\n                }\r\n            }\r\n\r\n            //Pick up default build parameters that have not been overridden\r\n            for(final ParameterDefinition paramDef : pp.getParameterDefinitions()) {\r\n                if(!parameterNames.contains(paramDef.getName()) && paramDef instanceof SimpleParameterDefinition){\r\n                    values.add(paramDef.getDefaultParameterValue());\r\n                }\r\n            }\r\n\r\n            // typical case: set optional \"git.pullrequest.merged\" parameters\r\n            if (commitId != null) {\r\n                final ParameterDefinition d = pp.getParameterDefinition(COMMIT_ID);\r\n                if (d != null && d instanceof SimpleParameterDefinition) {\r\n                    final SimpleParameterDefinition spd = (SimpleParameterDefinition) d;\r\n                    final ParameterValue parameterValue = spd.createValue(commitId);\r\n                    values.add(parameterValue);\r\n                }\r\n            }\r\n            if (pullRequestId != null) {\r\n                final ParameterDefinition d = pp.getParameterDefinition(PULL_REQUEST_ID);\r\n                if (d != null && d instanceof SimpleParameterDefinition) {\r\n                    final SimpleParameterDefinition spd = (SimpleParameterDefinition) d;\r\n                    final ParameterValue parameterValue = spd.createValue(pullRequestId);\r\n                    values.add(parameterValue);\r\n                }\r\n            }\r\n\r\n            final ParametersAction action = new ParametersAction(values);\r\n            actions.add(action);\r\n        }\r\n\r\n        return innerPerform(job, buildableItem, delay, actions);\r\n    }\r\n\r\n    private void cancelPreviousPullRequestBuilds(Job job, TeamPullRequestMergedDetailsAction pullReqeuestMergedDetails, Queue queue) {\r\n        RunList<?> allBuilds = job.getBuilds();\r\n\r\n        for (Run run : allBuilds) {\r\n            TeamPullRequestMergedDetailsAction cause = run.getAction(TeamPullRequestMergedDetailsAction.class);\r\n            if (cause != null && run.isBuilding()) {\r\n                if (cause instanceof TeamPullRequestMergedDetailsAction &&\r\n                        cause.gitPullRequest.getPullRequestId() == pullReqeuestMergedDetails.gitPullRequest.getPullRequestId()) {\r\n                    LOGGER.info(\"Canceling previously triggered Job: \" + run.getFullDisplayName());\r\n\r\n                    Executor executor = run.getExecutor();\r\n                    if (executor != null)\r\n                        executor.doStop();\r\n\r\n                    Queue.Item item = queue.getItem(run.getQueueId());\r\n                    if (item != null)\r\n                        queue.cancel(item);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    static void contributeTeamBuildParameterActions(final Map<String, String> teamBuildParameters, final List<Action> actions) {\r\n        final Action teamBuildDetails = new TeamBuildDetailsAction(teamBuildParameters);\r\n        actions.add(teamBuildDetails);\r\n        if (teamBuildParameters.containsKey(BUILD_REPOSITORY_PROVIDER)) {\r\n            final String provider = teamBuildParameters.get(BUILD_REPOSITORY_PROVIDER);\r\n            final boolean isTeamGit = \"TfGit\".equalsIgnoreCase(provider)\r\n                    || \"TfsGit\".equalsIgnoreCase(provider);\r\n            if (isTeamGit) {\r\n            \t// \"Build.Repository.Uri\" is null/whitespace/empty when the 'Jenkins Queue Job' task runs in TFS Release Management.\r\n            \t// In this case, do not reference a CommitParameterAction in the actions reported as unsupported.\r\n                final String repoUriString = teamBuildParameters.get(BUILD_REPOSITORY_URI);\r\n                if (StringUtils.isNotBlank(repoUriString)) {\r\n                    final URI repoUri = URI.create(repoUriString);\r\n                    final String collectionUriString = teamBuildParameters.get(SYSTEM_TEAM_FOUNDATION_COLLECTION_URI);\r\n                    final URI collectionUri = URI.create(collectionUriString);\r\n                    final String projectId = teamBuildParameters.get(SYSTEM_TEAM_PROJECT);\r\n                    final String repoId = teamBuildParameters.get(BUILD_REPOSITORY_NAME);\r\n                    final String commit = teamBuildParameters.get(BUILD_SOURCE_VERSION);\r\n                    final String pushedBy = teamBuildParameters.get(BUILD_REQUESTED_FOR);\r\n                    final GitCodePushedEventArgs args = new GitCodePushedEventArgs();\r\n                    args.collectionUri = collectionUri;\r\n                    args.repoUri = repoUri;\r\n                    args.projectId = projectId;\r\n                    args.repoId = repoId;\r\n                    args.commit = commit;\r\n                    args.pushedBy = pushedBy;\r\n                    final CommitParameterAction action = new CommitParameterAction(args);\r\n                    actions.add(action);\r\n                }\r\n\r\n                UnsupportedIntegrationAction.addToBuild(actions, \"Posting build status is not supported for builds triggered by the 'Jenkins Queue Job' task.\");\r\n            }\r\n            else {\r\n                final String reason = String.format(\r\n                        \"The '%s' build variable has a value of '%s', which is not supported.\", BUILD_REPOSITORY_PROVIDER, provider);\r\n                UnsupportedIntegrationAction.addToBuild(actions, reason);\r\n                LOGGER.warning(formatUnsupportedReason(reason));\r\n            }\r\n        }\r\n        else {\r\n            final String reason = String.format(\r\n                    \"There was no value provided for the '%s' build variable.\",\r\n                    BUILD_REPOSITORY_PROVIDER);\r\n            UnsupportedIntegrationAction.addToBuild(actions, reason);\r\n            LOGGER.warning(formatUnsupportedReason(reason));\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/BuildParameter.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\n\r\n/**\r\n * Used by TFS Build payload.\r\n */\r\n@SuppressFBWarnings(value = \"UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD\", justification = \"Used by TeamBuildPayload\")\r\npublic class BuildParameter {\r\n\r\n    // Turn off checkstyle for the public fields in this class.\r\n    //CHECKSTYLE:OFF\r\n\r\n    public String name;\r\n\r\n    public String value;\r\n\r\n    //CHECKSTYLE:ON\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/BuildWithParametersCommand.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.plugins.tfs.util.MediaType;\r\nimport org.apache.commons.io.IOUtils;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\n\r\n/**\r\n * Used for builds with parameters.\r\n */\r\npublic class BuildWithParametersCommand extends BuildCommand {\r\n\r\n    /**\r\n     * Factory for creating BuildWithParametersCommand instances.\r\n     */\r\n    public static class Factory implements AbstractCommand.Factory {\r\n\r\n        @Override\r\n        public AbstractCommand create() {\r\n            return new BuildWithParametersCommand();\r\n        }\r\n\r\n        @Override\r\n        public String getSampleRequestPayload() {\r\n            final Class<? extends Factory> me = this.getClass();\r\n            final InputStream stream = me.getResourceAsStream(\"BuildWithParametersCommand.json\");\r\n            try {\r\n                return IOUtils.toString(stream, MediaType.UTF_8);\r\n            } catch (final IOException e) {\r\n                throw new Error(e);\r\n            } finally {\r\n                IOUtils.closeQuietly(stream);\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ChangeLogSet.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.Run;\r\nimport hudson.scm.RepositoryBrowser;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Iterator;\r\nimport java.util.List;\r\n\r\n/**\r\n * ChangeLogSet for the Team Foundation Server SCM\r\n * The log set will set the parent of the log entries in the constructor.\r\n *\r\n * @author Erik Ramfelt\r\n */\r\n@SuppressFBWarnings(value = \"NM_SAME_SIMPLE_NAME_AS_SUPERCLASS\", justification = \"Public so shouldn't be changed\")\r\npublic class ChangeLogSet extends hudson.scm.ChangeLogSet<ChangeSet> {\r\n\r\n    private final List<ChangeSet> changesets;\r\n\r\n    public ChangeLogSet(final Run<?, ?> build, final RepositoryBrowser<?> browser, final List<ChangeSet> changesets) {\r\n        super(build, browser);\r\n        this.changesets = changesets;\r\n        for (ChangeSet changeset : changesets) {\r\n            changeset.setParent(this);\r\n        }\r\n    }\r\n\r\n    @Deprecated\r\n    /* TODO: Used by TeamSystemWebAccessBrowserTest, should update to use non-deprecated method instead */\r\n    public ChangeLogSet(final AbstractBuild build, final ChangeSet[] changesetArray) {\r\n        this(build, build.getProject().getScm().getEffectiveBrowser(), changesetArray);\r\n    }\r\n\r\n    public ChangeLogSet(final Run<?, ?> build, final RepositoryBrowser<?> browser, final ChangeSet[] changesetArray) {\r\n        super(build, browser);\r\n        changesets = new ArrayList<ChangeSet>();\r\n        for (ChangeSet changeset : changesetArray) {\r\n            changeset.setParent(this);\r\n            changesets.add(changeset);\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public boolean isEmptySet() {\r\n        return changesets.isEmpty();\r\n    }\r\n\r\n    /** Returns a ChangeSet iterator. */\r\n    public Iterator<ChangeSet> iterator() {\r\n        return changesets.iterator();\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ChangeSet.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport java.text.ParseException;\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.Date;\r\nimport java.util.List;\r\n\r\nimport org.kohsuke.stapler.export.Exported;\r\nimport org.kohsuke.stapler.export.ExportedBean;\r\n\r\nimport hudson.model.User;\r\nimport hudson.plugins.tfs.util.DateUtil;\r\nimport hudson.scm.EditType;\r\n\r\n@ExportedBean(defaultVisibility=999)\r\npublic class ChangeSet extends hudson.scm.ChangeLogSet.Entry {\r\n\r\n    private User authorUser;\r\n    private User checkedInByUser;\r\n    private String version;\r\n    private String userString;\r\n    private String domain;\r\n    private Date date;\r\n    private String comment;\r\n    private List<Item> items;\r\n    private String checkedInByUserString;\r\n    \r\n    public ChangeSet() {\r\n        this(\"\", null, \"\", \"\");\r\n    }\r\n    \r\n    public ChangeSet(String version, Date date, String userString, String comment) {\r\n        this.version = version;\r\n        this.date = (date != null) ? new Date(date.getTime()) : null;\r\n        this.comment = comment;\r\n        items = new ArrayList<>();\r\n        setUser(userString);\r\n    }\r\n    \r\n    public ChangeSet(String version, Date date, User author, String comment) {\r\n        this.version = version;\r\n        this.date = (date != null) ? new Date(date.getTime()) : null;\r\n        this.authorUser = author;\r\n        this.userString = author.getId();\r\n        this.comment = comment;\r\n        items = new ArrayList<>();\r\n    }\r\n    \r\n    @Override\r\n    public Collection<String> getAffectedPaths() {\r\n        Collection<String> paths = new ArrayList<String>(items.size());\r\n        for (Item item : items) {\r\n            paths.add(item.getPath());\r\n        }\r\n        return paths;\r\n    }\r\n\r\n    @Override\r\n    public Collection<? extends hudson.scm.ChangeLogSet.AffectedFile> getAffectedFiles() {\r\n        return items;\r\n    }\r\n\r\n    @Override\r\n    public ChangeLogSet getParent() {\r\n        return (ChangeLogSet)super.getParent();\r\n    }\r\n\r\n    @Override\r\n    public User getAuthor() {\r\n        if(authorUser == null) {\r\n            authorUser = User.get(userString);\r\n        }\r\n        return authorUser;\r\n    }\r\n\r\n    @Override\r\n    public String getMsg() {\r\n        return comment;\r\n    }\r\n    \r\n    @Exported\r\n    public String getVersion() {\r\n        return version;\r\n    }\r\n\r\n    public void setVersion(String version) {\r\n        this.version = version;\r\n    }\r\n\r\n    /**\r\n     * Returns a human readable display name of the changeset number.\r\n     *\r\n     * <p>\r\n     * This method is primarily intended for visualization of the data.\r\n     */\r\n    @Exported\r\n    public String getCommitId() {\r\n        return version;\r\n    }\r\n\r\n    @Exported\r\n    public String getDomain() {\r\n        return domain;\r\n    }\r\n\r\n    @Exported\r\n    public String getUser() {\r\n        return userString;\r\n    }\r\n    \r\n    public void setUser(String user) {        \r\n        String[] split = user.split(\"\\\\\\\\\");\r\n        if (split.length == 2) {\r\n            this.domain = split[0];\r\n            this.userString = split[1];\r\n        } else {\r\n            this.userString = user;\r\n            this.domain = null;\r\n        }\r\n    }\r\n\r\n    @Exported\r\n    public Date getDate() {\r\n        if (date != null) {\r\n            return new Date(date.getTime());\r\n        }\r\n        return null;\r\n    }\r\n    \r\n    public void setDateStr(String dateStr) throws ParseException {\r\n        date = DateUtil.TFS_DATETIME_FORMATTER.get().parse(dateStr);\r\n    }\r\n\r\n    @Exported\r\n    public String getComment() {\r\n        return comment;\r\n    }\r\n    \r\n    public void setComment(String comment) {\r\n        this.comment = comment;\r\n    }\r\n\r\n    public void setCheckedInBy(String checkedInByUserString) {\r\n        if (checkedInByUserString != null) {\r\n            String[] split = checkedInByUserString.split(\"\\\\\\\\\");\r\n            if (split.length == 2) {\r\n                this.checkedInByUserString = split[1];\r\n            } else {\r\n                this.checkedInByUserString = checkedInByUserString;\r\n            }\r\n        }\r\n    }\r\n\r\n    public String getCheckedInBy() {\r\n        return checkedInByUserString;\r\n    }\r\n\r\n    public User getCheckedInByUser() {\r\n        if (checkedInByUser == null) {\r\n           checkedInByUser = User.get(checkedInByUserString);  \r\n        }\r\n        return checkedInByUser;\r\n    }\r\n\r\n    public void setCheckedInByUser(User checkedInBy) {\r\n        this.checkedInByUser = checkedInBy;\r\n    }\r\n\r\n    @Exported\r\n    public List<Item> getItems() {\r\n        return items;\r\n    }\r\n    \r\n    public void add(ChangeSet.Item item) {\r\n        items.add(item);\r\n        item.setParent(this);\r\n    }\r\n\r\n    @Override\r\n    protected void setParent(hudson.scm.ChangeLogSet parent) {\r\n        super.setParent(parent);\r\n    }\r\n    \r\n    @ExportedBean(defaultVisibility=999)\r\n    public static class Item implements hudson.scm.ChangeLogSet.AffectedFile {\r\n        private String path;\r\n        private String action;\r\n        private ChangeSet parent;\r\n\r\n        public Item() {\r\n            this(\"\",\"\");\r\n        }\r\n        \r\n        public Item(String path, String action) {\r\n            this.path = path;\r\n            this.action = action;\r\n        }\r\n\r\n        public ChangeSet getParent() {\r\n            return parent;\r\n        }\r\n\r\n        void setParent(ChangeSet parent) {\r\n            this.parent = parent;\r\n        }\r\n\r\n        @Exported\r\n        public String getPath() {\r\n            return path;\r\n        }\r\n\r\n        public void setPath(String path) {\r\n            this.path = path;\r\n        }\r\n\r\n        @Exported   \r\n        public String getAction() {\r\n            return action;\r\n        }\r\n\r\n        public void setAction(String action) {\r\n            this.action = action;\r\n        }\r\n\r\n        @Exported\r\n        public EditType getEditType() {\r\n            if (action.equalsIgnoreCase(\"delete\")) {\r\n                return EditType.DELETE;\r\n            }\r\n            if (action.equalsIgnoreCase(\"add\")) {\r\n                return EditType.ADD;\r\n            }\r\n            return EditType.EDIT;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ClonePersistenceStoreProvider.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.config.persistence.PersistenceStoreProvider;\r\nimport com.microsoft.tfs.core.persistence.FilesystemPersistenceStore;\r\nimport org.apache.commons.io.FileUtils;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\n\r\npublic class ClonePersistenceStoreProvider implements PersistenceStoreProvider {\r\n\r\n    private final FilesystemPersistenceStore cacheStore;\r\n    private final FilesystemPersistenceStore configurationStore;\r\n    private final FilesystemPersistenceStore logStore;\r\n    private final String hostName;\r\n\r\n    public ClonePersistenceStoreProvider(final PersistenceStoreProvider sourcePersistenceStoreProvider, final String hostName) {\r\n\r\n        this.hostName = hostName;\r\n        final FilesystemPersistenceStore sourceCache = sourcePersistenceStoreProvider.getCachePersistenceStore();\r\n        final File cacheFolder = createAndCopy(sourceCache, hostName);\r\n        this.cacheStore = new FilesystemPersistenceStore(cacheFolder);\r\n\r\n        final FilesystemPersistenceStore sourceConfiguration = sourcePersistenceStoreProvider.getConfigurationPersistenceStore();\r\n        final File configurationFolder = createAndCopy(sourceConfiguration, hostName);\r\n        this.configurationStore = new FilesystemPersistenceStore(configurationFolder);\r\n\r\n        final FilesystemPersistenceStore sourceLog = sourcePersistenceStoreProvider.getLogPersistenceStore();\r\n        final File logFolder = createAndCopy(sourceLog, hostName);\r\n        this.logStore = new FilesystemPersistenceStore(logFolder);\r\n    }\r\n\r\n    static File createAndCopy(final FilesystemPersistenceStore sourceStore, final String nodeName) {\r\n        final File sourceBase = sourceStore.getStoreFile();\r\n        final String childName = sourceBase.getName();\r\n        final File sourceParent = sourceBase.getParentFile();\r\n        final File destinationBase = new File(sourceParent, nodeName);\r\n        final File destination = new File(destinationBase, childName);\r\n        if (!destination.isDirectory() && sourceBase.isDirectory()) {\r\n            try {\r\n                FileUtils.copyDirectory(sourceBase, destination);\r\n            }\r\n            catch (final IOException e) {\r\n                throw new Error(e);\r\n            }\r\n        }\r\n        return destination;\r\n    }\r\n\r\n    public FilesystemPersistenceStore getCachePersistenceStore() {\r\n        return cacheStore;\r\n    }\r\n\r\n    public FilesystemPersistenceStore getConfigurationPersistenceStore() {\r\n        return configurationStore;\r\n    }\r\n\r\n    public FilesystemPersistenceStore getLogPersistenceStore() {\r\n        return logStore;\r\n    }\r\n\r\n    public String getHostName() {\r\n        return hostName;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ConnectHookEvent.java",
    "content": "package hudson.plugins.tfs.model;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport hudson.plugins.tfs.TeamCollectionConfiguration;\nimport hudson.plugins.tfs.TeamPluginGlobalConfig;\nimport hudson.plugins.tfs.model.servicehooks.Event;\nimport net.sf.json.JSONObject;\n\nimport java.net.URI;\n\n/**\n * This HookEvent is for the TeamEventsEndpoint \"Connect\" event.\n */\npublic class ConnectHookEvent extends AbstractHookEvent {\n\n    /**\n     * Factory to create ConnectHookEvent.\n     */\n    public static class Factory implements AbstractHookEvent.Factory {\n        @Override\n        public AbstractHookEvent create() {\n            return new ConnectHookEvent();\n        }\n\n        @Override\n        public String getSampleRequestPayload() {\n            return \"{\\n\"\n                 + \"    \\\"eventType\\\": \\\"connect\\\",\\n\"\n                 + \"    \\\"resource\\\":\\n\"\n                 + \"    {\\n\"\n                 + \"        \\\"teamCollectionUrl\\\": \\\"https://xplatalm.visualstudio.com\\\"\\n\"\n                 + \"        \\\"connectionKey\\\": \\\"MyJenkinsServer\\\"\\n\"\n                 + \"        \\\"connectionSignature\\\": \\\"ABC13ABC123ABC13ABC123ABC13ABC123\\\"\\n\"\n                 + \"        \\\"sendJobCompletionEvents\\\": true\\n\"\n                 + \"    }\\n\"\n                 + \"}\";\n        }\n    }\n\n    @Override\n    public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {\n        final Object resource = serviceHookEvent.getResource();\n        final ConnectionParameters parameters = mapper.convertValue(resource, ConnectionParameters.class);\n\n        //TODO permissions?\n\n        // Store the key and the information for the correct collection\n        final TeamCollectionConfiguration collection = TeamCollectionConfiguration.findCollection(URI.create(parameters.getTeamCollectionUrl()));\n        if (collection != null) {\n            // Store key and signature with collection\n            collection.getConnectionParameters().setConnectionKey(parameters.getConnectionKey());\n            collection.getConnectionParameters().setConnectionSignature(parameters.getConnectionSignature());\n            collection.getConnectionParameters().setSendJobCompletionEvents(parameters.isSendJobCompletionEvents());\n            collection.getConnectionParameters().setTeamCollectionUrl(parameters.getTeamCollectionUrl());\n\n            // Save collection info\n            final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\n            config.save();\n        } else {\n            throw new IllegalArgumentException(\"Unable to connect to unknown server: \" + parameters.getTeamCollectionUrl());\n        }\n        return JSONObject.fromObject(serviceHookEvent);\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ConnectionParameters.java",
    "content": "package hudson.plugins.tfs.model;\n\n/**\n * These parameters are stored and modified from outside Jenkins through the TeamEventsEndpoint \"connect\" event.\n * An instance of this class is owned by every TeamCollectionConfiguration instance.\n */\npublic class ConnectionParameters {\n    private String teamCollectionUrl;\n    private String connectionKey;\n    private String connectionSignature;\n    private boolean sendJobCompletionEvents;\n\n    /**\n     * Constructor.\n     */\n    public ConnectionParameters() {\n    }\n\n    public String getConnectionKey() {\n        return connectionKey;\n    }\n\n    public void setConnectionKey(final String connectionKey) {\n        this.connectionKey = connectionKey;\n    }\n\n    public String getConnectionSignature() {\n        return connectionSignature;\n    }\n\n    public void setConnectionSignature(final String connectionSignature) {\n        this.connectionSignature = connectionSignature;\n    }\n\n    public String getTeamCollectionUrl() {\n        return teamCollectionUrl;\n    }\n\n    public void setTeamCollectionUrl(final String teamCollectionUrl) {\n        this.teamCollectionUrl = teamCollectionUrl;\n    }\n\n    public boolean isSendJobCompletionEvents() {\n        return sendJobCompletionEvents;\n    }\n\n    public void setSendJobCompletionEvents(final boolean sendJobCompletionEvents) {\n        this.sendJobCompletionEvents = sendJobCompletionEvents;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/CredentialsConfigurer.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport hudson.DescriptorExtensionList;\r\nimport hudson.ExtensionPoint;\r\nimport hudson.model.Describable;\r\nimport jenkins.model.Jenkins;\r\n\r\nimport java.io.Serializable;\r\n\r\npublic abstract class CredentialsConfigurer implements ExtensionPoint, Describable<CredentialsConfigurer>, Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public final String getDisplayName() {\r\n        return getDescriptor().getDisplayName();\r\n    }\r\n\r\n    public CredentialsConfigurerDescriptor getDescriptor() {\r\n        final Jenkins jenkins = Jenkins.getActiveInstance();\r\n        return (CredentialsConfigurerDescriptor) jenkins.getDescriptorOrDie(getClass());\r\n    }\r\n\r\n    public abstract StandardUsernamePasswordCredentials getCredentials(final String collectionUri);\r\n\r\n    public static DescriptorExtensionList<CredentialsConfigurer, CredentialsConfigurerDescriptor> all() {\r\n        final Jenkins jenkins = Jenkins.getActiveInstance();\r\n        return jenkins.getDescriptorList(CredentialsConfigurer.class);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/CredentialsConfigurerDescriptor.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.model.Descriptor;\r\n\r\n/**\r\n * Descriptor for CredentialsConfigurer.\r\n */\r\npublic abstract class CredentialsConfigurerDescriptor extends Descriptor<CredentialsConfigurer> {\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/DomainUserAccountMapper.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.Extension;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\n/**\r\n * Mapper for Domain User accounts.\r\n */\r\npublic class DomainUserAccountMapper extends UserAccountMapper {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * Constructor for data binding.\r\n     */\r\n    @DataBoundConstructor\r\n    public DomainUserAccountMapper() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public String mapUserAccount(final String input) {\r\n        return input;\r\n    }\r\n\r\n    /**\r\n     * Class descriptor.\r\n     */\r\n    @Extension\r\n    public static final class DescriptorImpl extends UserAccountMapperDescriptor {\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Resolve user using 'DOMAIN\\\\alias'\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ExtraSettings.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.model.Computer;\r\nimport hudson.plugins.tfs.TeamPluginGlobalConfig;\r\nimport jenkins.model.Jenkins;\r\n\r\nimport java.io.Serializable;\r\n\r\n/**\r\n * This class exists to shuttle settings between MASTER to remote nodes,\r\n * who would otherwise be unable to determine said settings because they\r\n * don't have access to the {@link jenkins.model.Jenkins} instance or\r\n * anything that could be obtained from it.\r\n */\r\npublic class ExtraSettings implements Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private boolean configFolderPerNode;\r\n    private String nodeComputerName;\r\n\r\n    public static final ExtraSettings DEFAULT = new ExtraSettings();\r\n\r\n    @SuppressWarnings(\"unused\" /* Needed by Serializable interface */)\r\n    private ExtraSettings() {\r\n    }\r\n\r\n    /**\r\n     * Construtor.\r\n     * @param teamPluginGlobalConfig\r\n     */\r\n    public ExtraSettings(final TeamPluginGlobalConfig teamPluginGlobalConfig) {\r\n        if (teamPluginGlobalConfig != null) {\r\n            this.configFolderPerNode = teamPluginGlobalConfig.isConfigFolderPerNode();\r\n            final Jenkins instance = Jenkins.getInstance();\r\n            this.nodeComputerName = \"\";\r\n            if (instance != null) {\r\n                final Computer currentComputer = Computer.currentComputer();\r\n                if (currentComputer != null) {\r\n                    this.nodeComputerName = currentComputer.getName();\r\n                }\r\n            }\r\n        } else {\r\n            this.configFolderPerNode = false;\r\n            this.nodeComputerName = null;\r\n        }\r\n    }\r\n\r\n    public boolean isConfigFolderPerNode() {\r\n        return configFolderPerNode;\r\n    }\r\n\r\n    public void setConfigFolderPerNode(final boolean configFolderPerNode) {\r\n        this.configFolderPerNode = configFolderPerNode;\r\n    }\r\n\r\n    public String getNodeComputerName() {\r\n        return nodeComputerName;\r\n    }\r\n\r\n    public void setNodeComputerName(final String nodeComputerName) {\r\n        this.nodeComputerName = nodeComputerName;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/GitCodePushedEventArgs.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport org.eclipse.jgit.transport.URIish;\r\n\r\nimport java.io.Serializable;\r\nimport java.net.URI;\r\nimport java.net.URISyntaxException;\r\n\r\npublic class GitCodePushedEventArgs implements Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public URI collectionUri;\r\n    public URI repoUri;\r\n    public String projectId;\r\n    public String repoId;\r\n    public String commit;\r\n    public String pushedBy;\r\n    public String targetBranch;\r\n\r\n    public URIish getRepoURIish() {\r\n        final String repoUriString = repoUri.toString();\r\n        try {\r\n            return new URIish(repoUriString);\r\n        } catch (final URISyntaxException e) {\r\n            // shouldn't happen\r\n            throw new Error(e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/GitPullRequestEx.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPullRequest;\r\nimport com.microsoft.visualstudio.services.webapi.model.ResourceRef;\r\n\r\nimport java.util.Arrays;\r\n\r\n/**\r\n * Work around some missing fields in the version of vso-httpclient-java\r\n * by extending {@link GitPullRequest}.\r\n */\r\npublic class GitPullRequestEx extends GitPullRequest {\r\n    private ResourceRef[] workItemRefs;\r\n\r\n    /**\r\n     * Returns the work item references.\r\n     */\r\n    public ResourceRef[] getWorkItemRefs() {\r\n        if (workItemRefs != null) {\r\n            return Arrays.copyOf(workItemRefs, workItemRefs.length);\r\n        }\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Sets the work item references.\r\n     */\r\n    public void setWorkItemRefs(final ResourceRef[] workItemRefs) {\r\n        this.workItemRefs = (workItemRefs != null) ? Arrays.copyOf(workItemRefs, workItemRefs.length) : null;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/GitPullRequestMergedEvent.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitCommitRef;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPullRequest;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRepository;\r\nimport com.microsoft.visualstudio.services.webapi.model.IdentityRef;\r\nimport hudson.model.Action;\r\nimport hudson.plugins.git.GitStatus;\r\nimport hudson.plugins.tfs.PullRequestParameterAction;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport hudson.plugins.tfs.util.ResourceHelper;\r\nimport hudson.plugins.tfs.TeamPullRequestMergedDetailsAction;\r\nimport net.sf.json.JSONObject;\r\n\r\nimport java.net.URI;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\n/**\r\n * A Git push event corresponding to the merge of a pull request on VSTS/TFS.\r\n */\r\npublic class GitPullRequestMergedEvent extends GitPushEvent {\r\n\r\n    /**\r\n     * Factory for creating a GitPullRequestMergedEvent.\r\n     */\r\n    public static class Factory implements AbstractHookEvent.Factory {\r\n\r\n        @Override\r\n        public AbstractHookEvent create() {\r\n            return new GitPullRequestMergedEvent();\r\n        }\r\n\r\n        @Override\r\n        public String getSampleRequestPayload() {\r\n            return ResourceHelper.fetchAsString(this.getClass(), \"GitPullRequestMergedEvent.json\");\r\n        }\r\n    }\r\n\r\n    static String determineCreatedBy(final GitPullRequest gitPullRequest) {\r\n        final IdentityRef createdBy = gitPullRequest.getCreatedBy();\r\n        final String result = createdBy.getDisplayName();\r\n        return result;\r\n    }\r\n\r\n    /*\r\n    Given the following sample payload fragment:\r\n\r\n    \"lastMergeSourceCommit\": {\r\n      \"commitId\": \"53d54ac915144006c2c9e90d2c7d3880920db49c\",\r\n      \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c\"\r\n    },\r\n    \"lastMergeTargetCommit\": {\r\n      \"commitId\": \"a511f535b1ea495ee0c903badb68fbc83772c882\",\r\n      \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882\"\r\n    },\r\n    \"lastMergeCommit\": {\r\n      \"commitId\": \"eef717f69257a6333f221566c1c987dc94cc0d72\",\r\n      \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72\"\r\n    },\r\n    \"commits\": [\r\n      {\r\n        \"commitId\": \"53d54ac915144006c2c9e90d2c7d3880920db49c\",\r\n        \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c\"\r\n      }\r\n    ],\r\n\r\n    ...we are assuming the user pushed `53d54a` (lastMergeSourceCommit) and Team Services attempted\r\n    to merge it with `a511f5` (the tip of whatever the branch the PR is targeting, lastMergeTargetCommit),\r\n    yielding `eef717f`.\r\n     */\r\n    static String determineMergeCommit(final GitPullRequest gitPullRequest) {\r\n        final GitCommitRef lastMergeCommit = gitPullRequest.getLastMergeCommit();\r\n        final String result = lastMergeCommit.getCommitId();\r\n        return result;\r\n    }\r\n\r\n    static String determineTargetBranch(final GitPullRequest gitPullRequest) {\r\n        // In the form of ref/heads/master\r\n        final String targetRefName = gitPullRequest.getTargetRefName();\r\n        String[] items = targetRefName.split(\"/\");\r\n        return items[items.length - 1];\r\n    }\r\n\r\n    @Override\r\n    public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {\r\n        final Object resource = serviceHookEvent.getResource();\r\n        final GitPullRequestEx gitPullRequest = mapper.convertValue(resource, GitPullRequestEx.class);\r\n\r\n        final PullRequestMergeCommitCreatedEventArgs args = decodeGitPullRequest(gitPullRequest, serviceHookEvent);\r\n        final PullRequestParameterAction parameterAction = new PullRequestParameterAction(args);\r\n        final Action teamPullRequestMergedDetailsAction = new TeamPullRequestMergedDetailsAction(gitPullRequest, message, detailedMessage, args.collectionUri.toString());\r\n        final ArrayList<Action> actions = new ArrayList<Action>();\r\n        actions.add(parameterAction);\r\n        actions.add(teamPullRequestMergedDetailsAction);\r\n        final List<GitStatus.ResponseContributor> contributors = pollOrQueueFromEvent(args, actions, true);\r\n        final JSONObject response = fromResponseContributors(contributors);\r\n        return response;\r\n    }\r\n\r\n    static PullRequestMergeCommitCreatedEventArgs decodeGitPullRequest(final GitPullRequest gitPullRequest, final Event serviceHookEvent) {\r\n        final GitRepository repository = gitPullRequest.getRepository();\r\n        final URI collectionUri = determineCollectionUri(repository, serviceHookEvent);\r\n        final String repoUriString = repository.getRemoteUrl();\r\n        final URI repoUri = URI.create(repoUriString);\r\n        final String projectId = determineProjectId(repository);\r\n        final String repoId = repository.getName();\r\n        final String commit = determineMergeCommit(gitPullRequest);\r\n        final String pushedBy = determineCreatedBy(gitPullRequest);\r\n        final int pullRequestId = gitPullRequest.getPullRequestId();\r\n        final String targetBranch = determineTargetBranch(gitPullRequest);\r\n\r\n        final PullRequestMergeCommitCreatedEventArgs args = new PullRequestMergeCommitCreatedEventArgs();\r\n        args.collectionUri = collectionUri;\r\n        args.repoUri = repoUri;\r\n        args.projectId = projectId;\r\n        args.repoId = repoId;\r\n        args.commit = commit;\r\n        args.pushedBy = pushedBy;\r\n        args.pullRequestId = pullRequestId;\r\n        args.targetBranch = targetBranch;\r\n        return args;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/GitPushEvent.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport com.microsoft.teamfoundation.core.webapi.model.TeamProjectReference;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitCommitRef;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPush;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRepository;\r\nimport com.microsoft.visualstudio.services.webapi.model.IdentityRef;\r\nimport hudson.model.Action;\r\nimport hudson.plugins.git.GitStatus;\r\nimport hudson.plugins.tfs.CommitParameterAction;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport hudson.plugins.tfs.model.servicehooks.ResourceContainer;\r\nimport hudson.plugins.tfs.util.ResourceHelper;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\nimport java.net.URI;\r\nimport java.net.URISyntaxException;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\n/**\r\n * A Git push event corresponding to the push of a set of commits on VSTS/TFS.\r\n */\r\npublic class GitPushEvent extends AbstractHookEvent {\r\n\r\n    /**\r\n     * Factory for creating a GitPushEvent.\r\n     */\r\n    public static class Factory implements AbstractHookEvent.Factory {\r\n\r\n        @Override\r\n        public AbstractHookEvent create() {\r\n            return new GitPushEvent();\r\n        }\r\n\r\n        @Override\r\n        public String getSampleRequestPayload() {\r\n            return ResourceHelper.fetchAsString(this.getClass(), \"GitPushEvent.json\");\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {\r\n        final Object resource = serviceHookEvent.getResource();\r\n        final GitPush gitPush = mapper.convertValue(resource, GitPush.class);\r\n\r\n        final GitCodePushedEventArgs args = decodeGitPush(gitPush, serviceHookEvent);\r\n        final CommitParameterAction parameterAction = new CommitParameterAction(args);\r\n        final ArrayList<Action> actions = new ArrayList<Action>();\r\n        actions.add(parameterAction);\r\n        final List<GitStatus.ResponseContributor> contributors = pollOrQueueFromEvent(args, actions, false);\r\n        final JSONObject response = fromResponseContributors(contributors);\r\n        return response;\r\n    }\r\n\r\n    static URI determineCollectionUri(final URI repoApiUri) {\r\n        final String path = repoApiUri.getPath();\r\n        final int i = path.indexOf(\"_apis/\");\r\n        if (i == -1) {\r\n            final String template = \"Repository url '%s' did not contain '_apis/'.\";\r\n            throw new IllegalArgumentException(String.format(template, repoApiUri));\r\n        }\r\n        final String pathBeforeApis = path.substring(0, i);\r\n        final URI uri;\r\n        try {\r\n            uri = new URI(repoApiUri.getScheme(), repoApiUri.getAuthority(), pathBeforeApis, repoApiUri.getQuery(), repoApiUri.getFragment());\r\n        } catch (final URISyntaxException e) {\r\n            throw new Error(e);\r\n        }\r\n        return uri;\r\n    }\r\n\r\n    static URI determineCollectionUri(final GitRepository repository, final Event serviceHookEvent) {\r\n        URI result = null;\r\n        final Map<String, ResourceContainer> containers = serviceHookEvent.getResourceContainers();\r\n        if (containers != null) {\r\n            final String collection = \"collection\";\r\n            if (containers.containsKey(collection)) {\r\n                final ResourceContainer collectionContainer = containers.get(collection);\r\n                final String baseUrl = collectionContainer.getBaseUrl();\r\n                if (StringUtils.isNotEmpty(baseUrl)) {\r\n                    result = URI.create(baseUrl);\r\n                }\r\n            }\r\n        }\r\n        if (result == null) {\r\n            final String repoApiUrlString = repository.getUrl();\r\n            final URI repoApiUri = URI.create(repoApiUrlString);\r\n            result = determineCollectionUri(repoApiUri);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    static String determineProjectId(final GitRepository repository) {\r\n        final TeamProjectReference project = repository.getProject();\r\n        final String result = project.getName();\r\n        return result;\r\n    }\r\n\r\n    static String determineCommit(final GitPush gitPush) {\r\n        final List<GitCommitRef> commits = gitPush.getCommits();\r\n        if (commits == null || commits.size() < 1) {\r\n            return null;\r\n        }\r\n        final GitCommitRef commit = commits.get(0);\r\n        return commit.getCommitId();\r\n    }\r\n\r\n    static String determinePushedBy(final GitPush gitPush) {\r\n        final IdentityRef pushedBy = gitPush.getPushedBy();\r\n        final String result = pushedBy.getDisplayName();\r\n        return result;\r\n    }\r\n\r\n    static String determineTargetBranch(final GitPush gitPush) {\r\n        // In the form of ref/heads/master\r\n        final String targetBranch = gitPush.getRefUpdates().get(0).getName();\r\n        String[] items = targetBranch.split(\"/\");\r\n        return items[items.length - 1];\r\n    }\r\n\r\n    static GitCodePushedEventArgs decodeGitPush(final GitPush gitPush, final Event serviceHookEvent) {\r\n        final GitRepository repository = gitPush.getRepository();\r\n        final URI collectionUri = determineCollectionUri(repository, serviceHookEvent);\r\n        final String repoUriString = repository.getRemoteUrl();\r\n        final URI repoUri = URI.create(repoUriString);\r\n        final String projectId = determineProjectId(repository);\r\n        final String repoId = repository.getName();\r\n        final String commit = determineCommit(gitPush);\r\n        final String pushedBy = determinePushedBy(gitPush);\r\n        final String targetBranch = GitPushEvent.determineTargetBranch(gitPush);\r\n\r\n        final GitCodePushedEventArgs args = new GitCodePushedEventArgs();\r\n        args.collectionUri = collectionUri;\r\n        args.repoUri = repoUri;\r\n        args.projectId = projectId;\r\n        args.repoId = repoId;\r\n        args.commit = commit;\r\n        args.pushedBy = pushedBy;\r\n        args.targetBranch = targetBranch;\r\n        return args;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/GitStatusContext.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport net.sf.json.JSONObject;\r\nimport net.sf.json.JsonConfig;\r\n\r\npublic class GitStatusContext {\r\n    public String name;\r\n    public String genre;\r\n\r\n    public GitStatusContext() {\r\n    }\r\n\r\n    public GitStatusContext(final String name, final String genre) {\r\n        this.name = name;\r\n        this.genre = genre;\r\n    }\r\n\r\n    public static GitStatusContext fromJsonString(final String jsonString) {\r\n        final JSONObject jsonObject = JSONObject.fromObject(jsonString);\r\n        final GitStatusContext result;\r\n\r\n        final JsonConfig jsonConfig = new JsonConfig();\r\n        jsonConfig.setRootClass(GitStatusContext.class);\r\n\r\n        result = (GitStatusContext) JSONObject.toBean(jsonObject, jsonConfig);\r\n\r\n        return result;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/GitStatusState.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.annotation.JsonCreator;\r\n\r\nimport java.util.Collections;\r\nimport java.util.Map;\r\nimport java.util.TreeMap;\r\n\r\npublic enum GitStatusState {\r\n\r\n    NotSet(0),\r\n    Pending(1),\r\n    Succeeded(2),\r\n    Failed(3),\r\n    Error(4),\r\n    ;\r\n\r\n    public static final Map<String, GitStatusState> CASE_INSENSITIVE_LOOKUP;\r\n\r\n    static {\r\n        final Map<String, GitStatusState> map = new TreeMap<String, GitStatusState>(String.CASE_INSENSITIVE_ORDER);\r\n        for (final GitStatusState value : GitStatusState.values()) {\r\n            map.put(value.name(), value);\r\n        }\r\n        CASE_INSENSITIVE_LOOKUP = Collections.unmodifiableMap(map);\r\n    }\r\n\r\n    @SuppressWarnings(\"unused\" /* Invoked by Jackson via @JsonCreator */)\r\n    @JsonCreator\r\n    public static GitStatusState caseInsensitiveValueOf(final String name) {\r\n        if (name == null) {\r\n            throw new NullPointerException(\"Name is null\");\r\n        }\r\n        if (!CASE_INSENSITIVE_LOOKUP.containsKey(name)) {\r\n            throw new IllegalArgumentException(\"No enum constant \" + name);\r\n        }\r\n        return CASE_INSENSITIVE_LOOKUP.get(name);\r\n    }\r\n\r\n    private final int value;\r\n\r\n    GitStatusState(final int value) {\r\n        this.value = value;\r\n    }\r\n\r\n    public int getValue() {\r\n        return value;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/HttpMethod.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.httpclient.methods.GetMethod;\r\nimport com.microsoft.tfs.core.httpclient.methods.HeadMethod;\r\nimport com.microsoft.tfs.core.httpclient.methods.PostMethod;\r\nimport com.microsoft.tfs.core.httpclient.methods.StringRequestEntity;\r\nimport hudson.plugins.tfs.util.MediaType;\r\nimport org.apache.commons.io.IOUtils;\r\n\r\nimport java.io.IOException;\r\nimport java.io.OutputStream;\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.net.HttpURLConnection;\r\nimport java.net.ProtocolException;\r\n\r\npublic enum HttpMethod {\r\n    GET {\r\n        @Override\r\n        public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {\r\n            return new GetMethod(uri);\r\n        }\r\n\r\n    },\r\n    POST,\r\n    HEAD {\r\n        @Override\r\n        public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {\r\n            return new HeadMethod(uri);\r\n        }\r\n\r\n    },\r\n    PATCH {\r\n        @Override\r\n        public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {\r\n            return innerCreateClientMethod(uri, body, MediaType.APPLICATION_JSON_PATCH_JSON);\r\n        }\r\n\r\n    },\r\n    OPTIONS,\r\n    PUT,\r\n    DELETE,\r\n    TRACE,\r\n    ;\r\n\r\n    public com.microsoft.tfs.core.httpclient.HttpMethod createClientMethod(final String uri, final String body) {\r\n        return innerCreateClientMethod(uri, body, MediaType.APPLICATION_JSON);\r\n    }\r\n\r\n    PostMethod innerCreateClientMethod(final String uri, final String body, final String contentType) {\r\n        final PostMethod method = new PostMethod(uri);\r\n        // https://www.visualstudio.com/en-us/docs/integrate/get-started/rest/basics#http-method-override\r\n        method.addRequestHeader(\"X-HTTP-Method-Override\", this.name());\r\n        final String charset = MediaType.UTF_8.toString();\r\n        final StringRequestEntity requestEntity;\r\n        try {\r\n            requestEntity = new StringRequestEntity(body, contentType, charset);\r\n        }\r\n        catch (final UnsupportedEncodingException e) {\r\n            // this shouldn't happen\r\n            throw new Error(e);\r\n        }\r\n        method.setRequestEntity(requestEntity);\r\n        return method;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/JobCompletionEventArgs.java",
    "content": "package hudson.plugins.tfs.model;\n\n/**\n * This class holds the information needed to send the Job Completion event.\n */\npublic class JobCompletionEventArgs {\n    private final String serverKey;\n    private final String payload;\n    private final String payloadSignature;\n\n    /**\n     * Construtor.\n     * @param serverKey\n     * @param payload\n     * @param payloadSignature\n     */\n    public JobCompletionEventArgs(final String serverKey, final String payload, final String payloadSignature) {\n        this.serverKey = serverKey;\n        this.payload = payload;\n        this.payloadSignature = payloadSignature;\n    }\n\n    public String getServerKey() {\n        return serverKey;\n    }\n\n    public String getPayload() {\n        return payload;\n    }\n\n    public String getPayloadSignature() {\n        return payloadSignature;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/JsonPatchOperation.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.visualstudio.services.webapi.patch.Operation;\r\n\r\n/**\r\n * Workaround for broken version in\r\n * com.microsoft.visualstudio.services.webapi.patch.json\r\n * where #getPath() returns this.op\r\n */\r\npublic class JsonPatchOperation {\r\n\r\n    private Operation op;\r\n    private String path;\r\n    private Object value;\r\n\r\n    public Operation getOp() {\r\n        return op;\r\n    }\r\n\r\n    public void setOp(Operation op) {\r\n        this.op = op;\r\n    }\r\n\r\n    public String getPath() {\r\n        return path;\r\n    }\r\n\r\n    public void setPath(String path) {\r\n        this.path = path;\r\n    }\r\n\r\n    public Object getValue() {\r\n        return value;\r\n    }\r\n\r\n    public void setValue(Object value) {\r\n        this.value = value;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/LegacyIdentityManagementService.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport org.apache.commons.lang.NotImplementedException;\r\n\r\nimport com.microsoft.tfs.core.clients.webservices.GroupProperty;\r\nimport com.microsoft.tfs.core.clients.webservices.IIdentityManagementService;\r\nimport com.microsoft.tfs.core.clients.webservices.IdentityDescriptor;\r\nimport com.microsoft.tfs.core.clients.webservices.IdentitySearchFactor;\r\nimport com.microsoft.tfs.core.clients.webservices.MembershipQuery;\r\nimport com.microsoft.tfs.core.clients.webservices.ReadIdentityOptions;\r\nimport com.microsoft.tfs.core.clients.webservices.TeamFoundationIdentity;\r\nimport com.microsoft.tfs.util.GUID;\r\n\r\n/**\r\n * An {@link IIdentityManagementService} implementation to provide similar\r\n * functionality to that provided by TFS 2010 and up on TFS 2008.  \r\n *\r\n * Right now, the {@link TfsUserLookup} is the only consumer of\r\n * {@link IIdentityManagementService} implementations, for the purpose of\r\n * determining a TFS user's display name and e-mail address, given their\r\n * account name.\r\n */\r\npublic class LegacyIdentityManagementService implements IIdentityManagementService {\r\n\r\n    public TeamFoundationIdentity[] readIdentities(IdentityDescriptor[] paramArrayOfIdentityDescriptor,\r\n            MembershipQuery paramMembershipQuery, ReadIdentityOptions paramReadIdentityOptions) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public TeamFoundationIdentity readIdentity(IdentityDescriptor paramIdentityDescriptor, MembershipQuery paramMembershipQuery,\r\n            ReadIdentityOptions paramReadIdentityOptions) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public TeamFoundationIdentity[] readIdentities(GUID[] paramArrayOfGUID, MembershipQuery paramMembershipQuery) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public TeamFoundationIdentity[][] readIdentities(IdentitySearchFactor paramIdentitySearchFactor, String[] paramArrayOfString,\r\n            MembershipQuery paramMembershipQuery, ReadIdentityOptions paramReadIdentityOptions) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public TeamFoundationIdentity readIdentity(IdentitySearchFactor searchFactor,\r\n            String accountName,\r\n            MembershipQuery membershipQuery, ReadIdentityOptions readIdentityOptions) {\r\n        return new TeamFoundationIdentity(new IdentityDescriptor(\"identityType\", \"identifier\"), accountName, true, null, null);\r\n    }\r\n\r\n    public IdentityDescriptor createApplicationGroup(String paramString1, String paramString2, String paramString3) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public TeamFoundationIdentity[] listApplicationGroups(String paramString, ReadIdentityOptions paramReadIdentityOptions) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public void updateApplicationGroup(IdentityDescriptor paramIdentityDescriptor, GroupProperty paramGroupProperty,\r\n            String paramString) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public void deleteApplicationGroup(IdentityDescriptor paramIdentityDescriptor) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public void addMemberToApplicationGroup(IdentityDescriptor paramIdentityDescriptor1, IdentityDescriptor paramIdentityDescriptor2) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public void removeMemberFromApplicationGroup(IdentityDescriptor paramIdentityDescriptor1,\r\n            IdentityDescriptor paramIdentityDescriptor2) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public boolean isMember(IdentityDescriptor paramIdentityDescriptor1, IdentityDescriptor paramIdentityDescriptor2) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public boolean refreshIdentity(IdentityDescriptor paramIdentityDescriptor) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public String getScopeName(String paramString) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public boolean isOwner(IdentityDescriptor paramIdentityDescriptor) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public boolean isOwnedWellKnownGroup(IdentityDescriptor paramIdentityDescriptor) {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public String getIdentityDomainScope() {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/Link.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\n\r\n/**\r\n * Workaround for missing Link model class in current version of vso-httpclient-java\r\n */\r\n@SuppressFBWarnings(value = \"URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD\", justification = \"Used by JsonPathOperation\")\r\npublic class Link {\r\n    public String rel;\r\n    public String url;\r\n\r\n    public Link() {\r\n\r\n    }\r\n\r\n    public Link(final String rel, final String url) {\r\n        this.rel = rel;\r\n        this.url = url;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ListOfGitRepositories.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRepository;\r\n\r\nimport java.util.List;\r\n\r\npublic class ListOfGitRepositories {\r\n    public int count;\r\n    public List<GitRepository> value;\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ManualCredentialsConfigurer.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.cloudbees.plugins.credentials.CredentialsScope;\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\nimport hudson.Extension;\r\nimport hudson.util.Secret;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\n\r\n/**\r\n * Manual credentials configurer.\r\n */\r\n@SuppressFBWarnings(value = \"SE_TRANSIENT_FIELD_NOT_RESTORED\", justification = \"Maintain compatibility\")\r\npublic class ManualCredentialsConfigurer extends CredentialsConfigurer {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private final transient String userName;\r\n    private final transient Secret password;\r\n\r\n    /**\r\n     * Constructor for data binding.\r\n     */\r\n    @DataBoundConstructor\r\n    public ManualCredentialsConfigurer(final String userName, final Secret password) {\r\n        this.userName = userName;\r\n        this.password = password;\r\n    }\r\n\r\n    public String getUserName() {\r\n        return userName;\r\n    }\r\n\r\n    public Secret getPassword() {\r\n        return password;\r\n    }\r\n\r\n    @Override\r\n    public StandardUsernamePasswordCredentials getCredentials(final String collectionUri) {\r\n        final StandardUsernamePasswordCredentials credentials = new UsernamePasswordCredentialsImpl(\r\n                CredentialsScope.GLOBAL,\r\n                null,\r\n                null,\r\n                this.userName,\r\n                this.password.getPlainText()\r\n        );\r\n        return credentials;\r\n    }\r\n\r\n    /**\r\n     * Class descriptor.\r\n     */\r\n    @Extension\r\n    public static final class DescriptorImpl extends CredentialsConfigurerDescriptor {\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Manual\";\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/MockableVersionControlClient.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceLocation;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.Workstation;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.events.EventSource;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.events.VersionControlEventEngine;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.exceptions.ItemNotMappedException;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.exceptions.ServerPathFormatException;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.*;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.LabelItemSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.workspacecache.WorkspaceInfo;\r\nimport com.microsoft.tfs.util.Closable;\r\n\r\nimport javax.annotation.Nonnull;\r\n\r\n/**\r\n * A non-final wrapper over {@link com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient}\r\n */\r\npublic class MockableVersionControlClient implements Closable {\r\n\r\n    private final VersionControlClient vcc;\r\n    private boolean isClosed = false;\r\n\r\n    public MockableVersionControlClient(final VersionControlClient vcc) {\r\n        this.vcc = vcc;\r\n    }\r\n\r\n    public void close() {\r\n        if (!isClosed) {\r\n            vcc.close();\r\n            isClosed = true;\r\n        }\r\n    }\r\n\r\n    private void makeSureNotClosed() {\r\n        if (isClosed) {\r\n            throw new UnsupportedOperationException(\"Instance has been closed and can no longer be used.\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Create or update a label for items in this workspace.\r\n     *\r\n     * @param label\r\n     *        the label to create or update (must not be <code>null</code>)\r\n     * @param items\r\n     *        the items to be included in the label creation or update (not\r\n     *        null).\r\n     * @param options\r\n     *        options that affect the processing of the label creation or update\r\n     *        (must not be <code>null</code> or empty).\r\n     * @return the label results, null if none were returned. May be empty but\r\n     *         never null.\r\n     */\r\n    public LabelResult[] createLabel(\r\n            final VersionControlLabel label,\r\n            final LabelItemSpec[] items,\r\n            final LabelChildOption options) {\r\n        makeSureNotClosed();\r\n        return vcc.createLabel(label, items, options);\r\n    }\r\n\r\n    /**\r\n     * Create a workspace on the server.\r\n     * <p>\r\n     * <!-- Event Origination Info -->\r\n     * <p>\r\n     * This method is an <b>core event origination point</b>. The\r\n     * {@link EventSource} object that accompanies each event fired by this\r\n     * method describes the execution context (current thread, etc.) when and\r\n     * where this method was invoked.\r\n     *\r\n     * @param workingFolders\r\n     *        the initial working folder mappings for this workspace. May be\r\n     *        null, which means no working folders mapped.\r\n     * @param workspaceName\r\n     *        the name of the new workspace (must not be <code>null</code>)\r\n     * @param owner\r\n     *        the name of the workspace owner (if <code>null</code>, empty, or\r\n     *        {@link VersionControlConstants#AUTHENTICATED_USER} the currently\r\n     *        authorized user's name is used)\r\n     * @param ownerDisplayName\r\n     *        the display name of the workspace owner (if <code>null</code>,\r\n     *        empty, or {@link VersionControlConstants#AUTHENTICATED_USER} the\r\n     *        currently authorized user's display name is used)\r\n     * @param comment\r\n     *        an optional comment to be stored with this workspace (may be\r\n     *        null).\r\n     * @param location\r\n     *        where the workspace data is stored (if <code>null</code>, the\r\n     *        server's default is used)\r\n     * @param options\r\n     *        options to use on the newly created workspace (if\r\n     *        <code>null</code>, the default options are used)\r\n     * @return the workspace object created by the server.\r\n     */\r\n    public Workspace createWorkspace(\r\n            final WorkingFolder[] workingFolders,\r\n            final String workspaceName,\r\n            final String owner,\r\n            final String ownerDisplayName,\r\n            final String comment,\r\n            final WorkspaceLocation location,\r\n            final WorkspaceOptions options) {\r\n        makeSureNotClosed();\r\n        return vcc.createWorkspace(\r\n                workingFolders,\r\n                workspaceName,\r\n                owner,\r\n                ownerDisplayName,\r\n                comment,\r\n                location,\r\n                options\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Delete a workspace on the server.\r\n     * <p>\r\n     * <!-- Event Origination Info -->\r\n     * <p>\r\n     * This method is an <b>core event origination point</b>. The\r\n     * {@link EventSource} object that accompanies each event fired by this\r\n     * method describes the execution context (current thread, etc.) when and\r\n     * where this method was invoked.\r\n     *\r\n     * @param workspace\r\n     *        the workspace to delete.\r\n     */\r\n    public void deleteWorkspace(final Workspace workspace) {\r\n        makeSureNotClosed();\r\n        vcc.deleteWorkspace(workspace);\r\n    }\r\n\r\n    public TFSTeamProjectCollection getConnection() {\r\n        makeSureNotClosed();\r\n        return vcc.getConnection();\r\n    }\r\n\r\n    /**\r\n     * @return a reference to the EventEngine used by this client. Add (and\r\n     *         remove) listeners to this event engine instance in order to be\r\n     *         notified of events. All client events are dispatched through this\r\n     *         event engine.\r\n     */\r\n    public VersionControlEventEngine getEventEngine() {\r\n        makeSureNotClosed();\r\n        return vcc.getEventEngine();\r\n    }\r\n\r\n    /**\r\n     * Look up the local workspace for the specified repository, workspaceName\r\n     * and workspaceOwner combo. This will only ever return anything if the\r\n     * workspaceOwner matches the current user. This returns the actual\r\n     * instance, not a copy!\r\n     */\r\n    public Workspace getLocalWorkspace(final String workspaceName, final String workspaceOwner) {\r\n        makeSureNotClosed();\r\n        return vcc.getLocalWorkspace(workspaceName, workspaceOwner);\r\n    }\r\n\r\n    /**\r\n     * Gets the latest changeset ID from the server.\r\n     *\r\n     * @return the changeset ID number of the latest changeset.\r\n     */\r\n    public int getLatestChangesetID() {\r\n        makeSureNotClosed();\r\n        return vcc.getLatestChangesetID();\r\n    }\r\n\r\n    /**\r\n     * Retrieve the workspace that is mapped to the provided local path. This\r\n     * method searches all known workspaces on the current computer to identify\r\n     * a workspace that has explicitly or implicitly mapped the provided local\r\n     * path. If no workspace is found, this method throws a\r\n     * ItemNotMappedException.\r\n     *\r\n     * @param localPath\r\n     *        A local path for which a workspace is desired (must not be\r\n     *        <code>null</code>)\r\n     * @return A reference to the workspace object that has mapped the specified\r\n     *         local path\r\n     * @throws ItemNotMappedException\r\n     *         if the path is not mapped to any local workspace\r\n     */\r\n    public Workspace getWorkspace(final String localPath) throws ItemNotMappedException {\r\n        makeSureNotClosed();\r\n        return vcc.getWorkspace(localPath);\r\n    }\r\n\r\n    /**\r\n     * Queries the server for history about an item. History items are returned\r\n     * as an array of changesets.\r\n     *\r\n     * @param serverOrLocalPath\r\n     *        the server or local path to the server item being queried for its\r\n     *        history (must not be <code>null</code> or empty).\r\n     * @param version\r\n     *        the version of the item to query history for (history older than\r\n     *        this version will be returned) (must not be <code>null</code>)\r\n     * @param deletionID\r\n     *        the deletion ID for the item, if it is a deleted item (pass 0 if\r\n     *        the item is not deleted).\r\n     * @param recursion\r\n     *        whether to query recursively (must not be <code>null</code>)\r\n     * @param user\r\n     *        only include historical changes made by this user (pass null to\r\n     *        retrieve changes made by all users).\r\n     * @param versionFrom\r\n     *        the beginning version to query historical changes from (pass null\r\n     *        to start at the first version).\r\n     * @param versionTo\r\n     *        the ending version to query historical changes to (pass null to\r\n     *        end at the most recent version).\r\n     * @param maxCount\r\n     *        the maximum number of changes to return (pass Integer.MAX_VALUE\r\n     *        for all available values). Must be &gt; 0.\r\n     * @param includeFileDetails\r\n     *        true to include individual file change details with the returned\r\n     *        results, false to return only general changeset information.\r\n     * @param slotMode\r\n     *        if true, all items that have occupied the given serverPath (during\r\n     *        different times) will have their changes returned. If false, only\r\n     *        the item that matches that path at the given version will have its\r\n     *        changes returned.\r\n     * @param sortAscending\r\n     *        when <code>true</code> gets the top maxCount changes in ascending\r\n     *        order, when <code>false</code> gets them in descending order\r\n     * @return the changesets that matched the history query, null if the server\r\n     *         did not return a changeset array.\r\n     */\r\n    public Changeset[] queryHistory(\r\n            final String serverOrLocalPath,\r\n            final VersionSpec version,\r\n            final int deletionID,\r\n            final RecursionType recursion,\r\n            final String user,\r\n            final VersionSpec versionFrom,\r\n            final VersionSpec versionTo,\r\n            final int maxCount,\r\n            final boolean includeFileDetails,\r\n            final boolean slotMode,\r\n            final boolean includeDownloadInfo,\r\n            final boolean sortAscending) throws ServerPathFormatException {\r\n        makeSureNotClosed();\r\n        return vcc.queryHistory(\r\n                serverOrLocalPath,\r\n                version,\r\n                deletionID,\r\n                recursion,\r\n                user,\r\n                versionFrom,\r\n                versionTo,\r\n                maxCount,\r\n                includeFileDetails,\r\n                slotMode,\r\n                includeDownloadInfo,\r\n                sortAscending\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Query the collection of labels that match the given specifications.\r\n     *\r\n     * @param label\r\n     *        the label name to match (may be null?).\r\n     * @param scope\r\n     *        the scope of the label to match (may be null?).\r\n     * @param owner\r\n     *        the owner of the label to match (may be null?).\r\n     * @param includeItemDetails\r\n     *        if true, details about the labeled items are included in the\r\n     *        results, otherwise only general label information is included.\r\n     * @param filterItem\r\n     *        if not <code>null</code>, only labels containing this item are\r\n     *        returned.\r\n     * @param filterItemVersion\r\n     *        if filterItem was supplied, only labels that include this version\r\n     *        of the filterItem are returned, otherwise may be null.\r\n     * @return the label items that matched the query. May be empty but never\r\n     *         null.\r\n     */\r\n    public VersionControlLabel[] queryLabels(\r\n            final String label,\r\n            final String scope,\r\n            final String owner,\r\n            final boolean includeItemDetails,\r\n            final String filterItem,\r\n            final VersionSpec filterItemVersion) {\r\n        makeSureNotClosed();\r\n        return vcc.queryLabels(\r\n                label,\r\n                scope,\r\n                owner,\r\n                includeItemDetails,\r\n                filterItem,\r\n                filterItemVersion\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Returns the workspace on the server that matches the given parameters.\r\n     * Always queries the server immediately; does not check the local workspace\r\n     * cache.\r\n     * <p>\r\n     * Unlike {@link VersionControlClient#queryWorkspaces(String, String, String)}, this method does\r\n     * not update the local workspace cache when workspaces are queried, because\r\n     * the workspace's computer is unknown (and the computer must be know to\r\n     * update the cache).\r\n     *\r\n     * @param name\r\n     *        the workspace name to match, null to match all.\r\n     * @param owner\r\n     *        the owner name to match, null to match all. Use\r\n     *        {@link VersionControlConstants#AUTHENTICATED_USER} to retrieve\r\n     *        workspaces owned by the currently logged in user.\r\n     * @return the matching workspace or null if no matching workspace was\r\n     *         found.\r\n     */\r\n    public Workspace queryWorkspace(final String name, final String owner) {\r\n        makeSureNotClosed();\r\n        return vcc.queryWorkspace(name, owner);\r\n    }\r\n\r\n    /**\r\n     * Returns all workspaces on the server that match the given parameters.\r\n     * Always queries the server immediately; does not check the local workspace\r\n     * cache.\r\n     *\r\n     * @param workspaceName\r\n     *        the workspace name to match, null to match all.\r\n     * @param workspaceOwner\r\n     *        the owner name to match, null to match all. Use\r\n     *        {@link VersionControlConstants#AUTHENTICATED_USER} to retrieve\r\n     *        workspaces owned by the currently logged in user.\r\n     * @param computer\r\n     *        the computer name to match, null to match all. Use\r\n     *        LocalHost.getShortName() to match workspaces for this computer.\r\n     * @param permissionsFilter\r\n     *        find only workspaces matching the given permissions (must not be\r\n     *        <code>null</code>) Use\r\n     *        {@link WorkspacePermissions#NONE_OR_NOT_SUPPORTED} to find all\r\n     *        workspaces.\r\n     * @return an array of matching workspaces. May be empty but never null.\r\n     */\r\n    public Workspace[] queryWorkspaces(\r\n            final String workspaceName,\r\n            final String workspaceOwner,\r\n            final String computer,\r\n            @Nonnull final WorkspacePermissions permissionsFilter) {\r\n        makeSureNotClosed();\r\n        return vcc.queryWorkspaces(workspaceName, workspaceOwner, computer, permissionsFilter);\r\n    }\r\n\r\n    /**\r\n     * Removes a cached workspace that matches the given name and owner and this\r\n     * client's server's GUID from the {@link Workstation}'s cache. The caller\r\n     * is responsible for saving the {@link Workstation} cache.\r\n     */\r\n    public WorkspaceInfo removeCachedWorkspace(final String workspaceName, String workspaceOwner) {\r\n        makeSureNotClosed();\r\n        return vcc.removeCachedWorkspace(workspaceName, workspaceOwner);\r\n    }\r\n\r\n    /**\r\n     * This is the same as GetWorkspace() except that it returns null rather\r\n     * than throwing ItemNotMappedException if the path is not in any known\r\n     * local workspace.\r\n     *\r\n     * @param localPath\r\n     *        A local path for which a workspace is desired (must not be\r\n     *        <code>null</code>)\r\n     * @return A reference to the workspace object that has mapped the specified\r\n     *         local path or null if the local path is not in a local workspace\r\n     */\r\n    public Workspace tryGetWorkspace(final String localPath) {\r\n        makeSureNotClosed();\r\n        return vcc.tryGetWorkspace(localPath);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ModernConnectionAdvisor.java",
    "content": "package hudson.plugins.tfs.model;\n\nimport java.util.Locale;\nimport java.util.TimeZone;\n\nimport com.microsoft.tfs.core.config.ConnectionInstanceData;\nimport com.microsoft.tfs.core.config.DefaultConnectionAdvisor;\nimport com.microsoft.tfs.core.config.httpclient.HTTPClientFactory;\nimport com.microsoft.tfs.core.config.persistence.DefaultPersistenceStoreProvider;\nimport com.microsoft.tfs.core.config.persistence.PersistenceStoreProvider;\n\n/**\n * This connection advisor handles proxies appropriately by setting up a Modern http client factory.\n */\npublic class ModernConnectionAdvisor extends DefaultConnectionAdvisor {\n\n    private final ProxyHostEx proxyHost;\n    private final PersistenceStoreProvider persistenceStoreProvider;\n\n    /**\n     * Minimal constructor.\n     * @param proxyHost\n     */\n    public ModernConnectionAdvisor(final ProxyHostEx proxyHost) {\n        this(proxyHost, null);\n    }\n\n    /**\n     * Constructor.\n     * @param proxyHost\n     * @param persistenceStoreProvider\n     */\n    public ModernConnectionAdvisor(final ProxyHostEx proxyHost, final PersistenceStoreProvider persistenceStoreProvider) {\n        super(Locale.getDefault(), TimeZone.getDefault());\n        this.proxyHost = proxyHost;\n        this.persistenceStoreProvider = persistenceStoreProvider;\n    }\n\n    @Override\n    public PersistenceStoreProvider getPersistenceStoreProvider(final ConnectionInstanceData instanceData) {\n        return persistenceStoreProvider != null\n                ? persistenceStoreProvider\n                : DefaultPersistenceStoreProvider.INSTANCE;\n    }\n\n    @Override\n    public HTTPClientFactory getHTTPClientFactory(final ConnectionInstanceData connectionInstanceData) {\n        return new ModernHTTPClientFactory(connectionInstanceData, proxyHost);\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ModernHTTPClientFactory.java",
    "content": "package hudson.plugins.tfs.model;\n\nimport com.microsoft.tfs.core.config.ConnectionInstanceData;\nimport com.microsoft.tfs.core.config.httpclient.DefaultHTTPClientFactory;\nimport com.microsoft.tfs.core.httpclient.DefaultNTCredentials;\nimport com.microsoft.tfs.core.httpclient.HostConfiguration;\nimport com.microsoft.tfs.core.httpclient.HttpClient;\nimport com.microsoft.tfs.core.httpclient.HttpState;\nimport com.microsoft.tfs.core.httpclient.UsernamePasswordCredentials;\nimport com.microsoft.tfs.core.httpclient.auth.AuthScope;\nimport hudson.util.Secret;\n\n/**\n * Extends the default Http client factory to properly handle Proxy configurations.\n */\npublic class ModernHTTPClientFactory extends DefaultHTTPClientFactory {\n\n    private final ProxyHostEx proxyHost;\n\n    /**\n     * Constructor.\n     * @param connectionInstanceData\n     */\n    public ModernHTTPClientFactory(final ConnectionInstanceData connectionInstanceData) {\n        this(connectionInstanceData,  null);\n    }\n\n    /**\n     * Constructor.\n     * @param connectionInstanceData\n     * @param proxyHost\n     */\n    public ModernHTTPClientFactory(final ConnectionInstanceData connectionInstanceData, final ProxyHostEx proxyHost) {\n        super(connectionInstanceData);\n        this.proxyHost = proxyHost;\n    }\n\n    @Override\n    protected String getUserAgentExtraString(final HttpClient httpClient, final ConnectionInstanceData connectionInstanceData) {\n        // https://stackoverflow.com/a/6773868/\n        final Class<? extends ModernHTTPClientFactory> me = this.getClass();\n        final Package us = me.getPackage();\n        String version = us.getImplementationVersion();\n        if (version == null) {\n            version = \"devtest\";\n        }\n        return \"TFS-Jenkins \" + version;\n    }\n\n    @Override\n    public void configureClientProxy(final HttpClient httpClient, final HostConfiguration hostConfiguration, final HttpState httpState, final ConnectionInstanceData connectionInstanceData) {\n        hostConfiguration.setProxyHost(proxyHost);\n\n        if (proxyHost != null) {\n            final String proxyUser = proxyHost.getProxyUser();\n            final Secret proxySecret = proxyHost.getProxySecret();\n            if (proxyUser != null && proxySecret != null) {\n                httpState.setProxyCredentials(\n                        AuthScope.ANY,\n                        new UsernamePasswordCredentials(proxyUser, proxySecret.getPlainText())\n                );\n            } else {\n                httpState.setProxyCredentials(\n                        AuthScope.ANY,\n                        new DefaultNTCredentials()\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/NativeLibraryExtractor.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * An interface for native library extractors.\r\n */\r\npublic interface NativeLibraryExtractor {\r\n\r\n    /**\r\n     * Method to extract files.\r\n     * @param operatingSystem\r\n     * @param architecture\r\n     * @param fileName\r\n     * @throws IOException\r\n     */\r\n    void extractFile(String operatingSystem, String architecture, String fileName) throws IOException;\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/NativeLibraryManager.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.persistence.FilesystemPersistenceStore;\r\nimport com.microsoft.tfs.core.persistence.PersistenceStore;\r\nimport com.microsoft.tfs.core.persistence.VersionedVendorFilesystemPersistenceStore;\r\nimport org.apache.commons.io.IOUtils;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\nimport java.util.Arrays;\r\nimport java.util.Comparator;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.TreeMap;\r\n\r\npublic class NativeLibraryManager implements NativeLibraryExtractor {\r\n    private static final String VENDOR_NAME = \"Microsoft\";\r\n    private static final String TFS_SDK = \"TFS_SDK\";\r\n    private static final String VERSION = \"14.0.1\";\r\n    private static final String nativeFolderPropertyName = \"com.microsoft.tfs.jni.native.base-directory\";\r\n    private static final String NATIVE = \"native\";\r\n    private static final Class<NativeLibraryManager> metaClass = NativeLibraryManager.class;\r\n    private static final TreeMap<String, TreeMap<String, List<String>>> NATIVE_LIBRARIES =\r\n            new TreeMap<String, TreeMap<String, List<String>>>();\r\n    static {\r\n        final TreeMap<String, List<String>> aix = new TreeMap<String, List<String>>();\r\n        final List<String> aix_ppc = Arrays.asList(\r\n                \"libnative_auth.a\",\r\n                \"libnative_console.a\",\r\n                \"libnative_filesystem.a\",\r\n                \"libnative_misc.a\",\r\n                \"libnative_synchronization.a\"\r\n        );\r\n        aix.put(\"ppc\", aix_ppc);\r\n        NATIVE_LIBRARIES.put(\"aix\", aix);\r\n\r\n        final TreeMap<String, List<String>> freebsd = new TreeMap<String, List<String>>();\r\n        final List<String> freebsd_x86 = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        freebsd.put(\"x86\", freebsd_x86);\r\n        final List<String> freebsd_x86_64 = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        freebsd.put(\"x86_64\", freebsd_x86_64);\r\n        NATIVE_LIBRARIES.put(\"freebsd\", freebsd);\r\n\r\n        final TreeMap<String, List<String>> hpux = new TreeMap<String, List<String>>();\r\n        final List<String> hpux_ia64_32 = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        hpux.put(\"ia64_32\", hpux_ia64_32);\r\n        final List<String> hpux_PA_RISC = Arrays.asList(\r\n                \"libnative_auth.sl\",\r\n                \"libnative_console.sl\",\r\n                \"libnative_filesystem.sl\",\r\n                \"libnative_misc.sl\",\r\n                \"libnative_synchronization.sl\"\r\n        );\r\n        hpux.put(\"PA_RISC\", hpux_PA_RISC);\r\n        NATIVE_LIBRARIES.put(\"hpux\", hpux);\r\n\r\n        final TreeMap<String, List<String>> linux = new TreeMap<String, List<String>>();\r\n        final List<String> linux_arm = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        linux.put(\"arm\", linux_arm);\r\n        final List<String> linux_ppc = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        linux.put(\"ppc\", linux_ppc);\r\n        final List<String> linux_x86 = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        linux.put(\"x86\", linux_x86);\r\n        final List<String> linux_x86_64 = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        linux.put(\"x86_64\", linux_x86_64);\r\n        NATIVE_LIBRARIES.put(\"linux\", linux);\r\n\r\n        final TreeMap<String, List<String>> macosx = new TreeMap<String, List<String>>(new Comparator<String>() {\r\n            @SuppressWarnings(\"ComparatorMethodParameterNotUsed\" /* because of null key */)\r\n            public int compare(final String o1, final String o2) {\r\n                return 0;\r\n            }\r\n        });\r\n        final List<String> macosx_universal = Arrays.asList(\r\n                \"libnative_auth.jnilib\",\r\n                \"libnative_console.jnilib\",\r\n                \"libnative_filesystem.jnilib\",\r\n                \"libnative_keychain.jnilib\",\r\n                \"libnative_misc.jnilib\",\r\n                \"libnative_synchronization.jnilib\"\r\n        );\r\n        macosx.put(null, macosx_universal);\r\n        NATIVE_LIBRARIES.put(\"macosx\", macosx);\r\n\r\n        final TreeMap<String, List<String>> solaris = new TreeMap<String, List<String>>();\r\n        final List<String> solaris_sparc = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        solaris.put(\"sparc\", solaris_sparc);\r\n        final List<String> solaris_x86 = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        solaris.put(\"x86\", solaris_x86);\r\n        final List<String> solaris_x86_64 = Arrays.asList(\r\n                \"libnative_auth.so\",\r\n                \"libnative_console.so\",\r\n                \"libnative_filesystem.so\",\r\n                \"libnative_misc.so\",\r\n                \"libnative_synchronization.so\"\r\n        );\r\n        solaris.put(\"x86_64\", solaris_x86_64);\r\n        NATIVE_LIBRARIES.put(\"solaris\", solaris);\r\n\r\n        final TreeMap<String, List<String>> win32 = new TreeMap<String, List<String>>();\r\n        final List<String> win32_x86 = Arrays.asList(\r\n                \"native_auth.dll\",\r\n                \"native_console.dll\",\r\n                \"native_credential.dll\",\r\n                \"native_filesystem.dll\",\r\n                \"native_messagewindow.dll\",\r\n                \"native_misc.dll\",\r\n                \"native_registry.dll\",\r\n                \"native_synchronization.dll\"\r\n        );\r\n        win32.put(\"x86\", win32_x86);\r\n        final List<String> win32_x86_64 = Arrays.asList(\r\n                \"native_auth.dll\",\r\n                \"native_console.dll\",\r\n                \"native_credential.dll\",\r\n                \"native_filesystem.dll\",\r\n                \"native_messagewindow.dll\",\r\n                \"native_misc.dll\",\r\n                \"native_registry.dll\",\r\n                \"native_synchronization.dll\"\r\n        );\r\n        win32.put(\"x86_64\", win32_x86_64);\r\n        NATIVE_LIBRARIES.put(\"win32\", win32);\r\n    }\r\n\r\n    private final PersistenceStore store;\r\n\r\n    public NativeLibraryManager(final PersistenceStore store) {\r\n        this.store = store;\r\n    }\r\n\r\n    public void extractFiles() throws IOException {\r\n        // TODO: it would be great if we detected the current OS and architecture to extract only the needed files\r\n        extractFiles(this);\r\n    }\r\n\r\n    static void extractFiles(final NativeLibraryExtractor extractor) throws IOException {\r\n        for (final Map.Entry<String, TreeMap<String, List<String>>> nativeLibrary : NATIVE_LIBRARIES.entrySet()) {\r\n            final TreeMap<String, List<String>> architecturesToFileNames = nativeLibrary.getValue();\r\n            for (final Map.Entry<String, List<String>> architectureToFilename : architecturesToFileNames.entrySet()) {\r\n                final List<String> fileNames = architectureToFilename.getValue();\r\n                for (final String fileName : fileNames) {\r\n                    extractor.extractFile(nativeLibrary.getKey(), architectureToFilename.getKey(), fileName);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    public void extractFile(final String operatingSystem, final String architecture, final String fileName) throws IOException {\r\n        final String pathToNativeFile = buildPathToNativeFile(operatingSystem, architecture, fileName);\r\n        if (!store.containsItem(pathToNativeFile)) {\r\n            InputStream inputStream = null;\r\n            OutputStream outputStream = null;\r\n            try {\r\n                inputStream = metaClass.getResourceAsStream(pathToNativeFile);\r\n                outputStream = store.getItemOutputStream(pathToNativeFile);\r\n                IOUtils.copy(inputStream, outputStream);\r\n            }\r\n            finally {\r\n                IOUtils.closeQuietly(inputStream);\r\n                IOUtils.closeQuietly(outputStream);\r\n            }\r\n        }\r\n    }\r\n\r\n    // it is important that this return a string containing forward slashes\r\n    static String buildPathToNativeFile(final String operatingSystem, final String architecture, final String fileName) {\r\n        final StringBuilder sb = new StringBuilder(NATIVE.length() + 1 + operatingSystem.length() + 1 + 7 /* max architecture length */ + 1 + fileName.length());\r\n        sb.append(NATIVE).append('/');\r\n        sb.append(operatingSystem).append('/');\r\n        if (architecture != null) {\r\n            sb.append(architecture).append('/');\r\n        }\r\n        sb.append(fileName);\r\n        final String result = sb.toString();\r\n        return result;\r\n    }\r\n\r\n    public static synchronized void initialize() throws IOException {\r\n        final String nativeFolder = System.getProperty(nativeFolderPropertyName);\r\n        if (nativeFolder == null) {\r\n            final File vendor = new File(VENDOR_NAME);\r\n            final File vendor_sdk = new File(vendor, TFS_SDK);\r\n            final File vendor_sdk_version = new File(vendor_sdk, VERSION);\r\n            final FilesystemPersistenceStore store = new UserHomePersistenceStore(vendor_sdk_version);\r\n            final NativeLibraryManager manager = new NativeLibraryManager(store);\r\n            manager.extractFiles();\r\n\r\n            final File storeFile = store.getStoreFile();\r\n            final File nativeFile = new File(storeFile, NATIVE);\r\n            final String absolutePath = nativeFile.getAbsolutePath();\r\n            System.setProperty(nativeFolderPropertyName, absolutePath);\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/PingCommand.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport hudson.model.BuildableItem;\r\nimport hudson.model.Job;\r\nimport jenkins.util.TimeDuration;\r\nimport net.sf.json.JSONObject;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\n\r\npublic class PingCommand extends AbstractCommand {\r\n\r\n    public static class Factory implements AbstractCommand.Factory {\r\n        @Override\r\n        public AbstractCommand create() {\r\n            return new PingCommand();\r\n        }\r\n\r\n        @Override\r\n        public String getSampleRequestPayload() {\r\n            return \"{\\n\" +\r\n                    \"    \\\"parameter\\\":\\n\" +\r\n                    \"    [\\n\" +\r\n                    \"        {\\\"name\\\":\\\"id\\\",\\\"value\\\":\\\"123\\\"},\\n\" +\r\n                    \"        {\\\"name\\\":\\\"verbosity\\\",\\\"value\\\":\\\"high\\\"}\\n\" +\r\n                    \"    ]\\n\" +\r\n                    \"}\\n\";\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public JSONObject perform(final Job project, final BuildableItem buildableItem, final StaplerRequest request,\r\n                              final JSONObject requestPayload, final ObjectMapper mapper,\r\n                              final TeamBuildPayload teamBuildPayload, final TimeDuration delay) {\r\n        return requestPayload;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/PingHookEvent.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport net.sf.json.JSONObject;\r\n\r\npublic class PingHookEvent extends AbstractHookEvent {\r\n\r\n    public static class Factory implements AbstractHookEvent.Factory {\r\n        @Override\r\n        public AbstractHookEvent create() {\r\n            return new PingHookEvent();\r\n        }\r\n\r\n        @Override\r\n        public String getSampleRequestPayload() {\r\n            return \"{\\n\" +\r\n                    \"    \\\"eventType\\\": \\\"ping\\\",\\n\" +\r\n                    \"    \\\"resource\\\":\\n\" +\r\n                    \"    {\\n\" +\r\n                    \"        \\\"message\\\": \\\"Hello, world!\\\"\\n\" +\r\n                    \"    }\\n\" +\r\n                    \"}\";\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {\r\n        return JSONObject.fromObject(serviceHookEvent);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/Project.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.LatestVersionSpec;\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\nimport hudson.model.User;\r\nimport hudson.plugins.tfs.TeamPluginGlobalConfig;\r\nimport hudson.plugins.tfs.commands.GetFilesToWorkFolderCommand;\r\nimport hudson.plugins.tfs.commands.RemoteChangesetVersionCommand;\r\nimport hudson.plugins.tfs.model.ChangeSet.Item;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Calendar;\r\nimport java.util.Collection;\r\nimport java.util.Date;\r\nimport java.util.List;\r\n\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.apache.commons.lang.builder.EqualsBuilder;\r\nimport org.apache.commons.lang.builder.HashCodeBuilder;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Changeset;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.LabelSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.ChangesetVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.LabelVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\r\nimport com.microsoft.tfs.core.clients.webservices.IIdentityManagementService;\r\n\r\npublic class Project {\r\n\r\n    private final String projectPath;\r\n    private final Server server;\r\n    private UserLookup userLookup;\r\n\r\n    public Project(Server server, String projectPath) {\r\n        this.server = server;\r\n        this.projectPath = projectPath;\r\n    }\r\n\r\n    public String getProjectPath() {\r\n        return projectPath;\r\n    }\r\n\r\n    static hudson.plugins.tfs.model.ChangeSet.Item convertServerChange\r\n        (com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change serverChange) {\r\n        final String path = serverChange.getItem().getServerItem();\r\n        final String action = serverChange.getChangeType().toUIString(true);\r\n        final Item result = new Item(path, action);\r\n        return result;\r\n    }\r\n\r\n    public static hudson.plugins.tfs.model.ChangeSet convertServerChangeset\r\n        (com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Changeset serverChangeset, UserLookup userLookup) {\r\n        final String version = Integer.toString(serverChangeset.getChangesetID(), 10);\r\n        final Date date = serverChangeset.getDate().getTime();\r\n        final String author = serverChangeset.getOwner();\r\n        final User authorUser = userLookup.find(author);\r\n        final String comment = serverChangeset.getComment();\r\n\r\n        final ChangeSet result = new ChangeSet(version, date, authorUser, comment);\r\n        final Change[] serverChanges = serverChangeset.getChanges();\r\n        for (final Change serverChange : serverChanges) {\r\n            final Item item = convertServerChange(serverChange);\r\n            result.add(item);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Returns a list of changes using TFS Java SDK\r\n     * @param fromVersion the version to get the history from\r\n     * @param toVersion the version to get the history to\r\n     * @param includeFileDetails whether or not to include details of modified items\r\n     * @param maxCount the maximum number of changes to return (pass Integer.MAX_VALUE for all available values).\r\n     *                 {@literal Must be > 0.}\r\n     * @return a list of change sets\r\n     */\r\n    public List<ChangeSet> getVCCHistory(VersionSpec fromVersion, VersionSpec toVersion, boolean includeFileDetails, int maxCount) {\r\n        final UserLookup userLookup = getOrCreateUserLookup();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final Changeset[] serverChangesets = vcc.queryHistory(\r\n                projectPath,\r\n                fromVersion != null ? fromVersion : toVersion,\r\n                0 /* deletionId */,\r\n                RecursionType.FULL,\r\n                null /* user */,\r\n                fromVersion,\r\n                toVersion,\r\n                maxCount,\r\n                includeFileDetails /* includeFileDetails */,\r\n                true /* slotMode */,\r\n                false /* includeDownloadInfo */,\r\n                false /* sortAscending */\r\n        );\r\n        final List<ChangeSet> result = new ArrayList<ChangeSet>();\r\n        if (serverChangesets != null) {\r\n            for (final Changeset serverChangeset : serverChangesets) {\r\n                final ChangeSet changeSet = convertServerChangeset(serverChangeset, userLookup);\r\n                result.add(changeSet);\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n\r\n    @SuppressFBWarnings(value = \"DC_DOUBLECHECK\", justification = \"Only synchronize if not null\")\r\n    public UserLookup getOrCreateUserLookup() {\r\n        if (userLookup == null) {\r\n            synchronized (this) {\r\n                if (userLookup == null) {\r\n                    final IIdentityManagementService ims = server.createIdentityManagementService();\r\n                    final TeamPluginGlobalConfig teamPluginGlobalConfig = TeamPluginGlobalConfig.get();\r\n                    final UserAccountMapper mapper = teamPluginGlobalConfig.getUserAccountMapper();\r\n                    userLookup = new TfsUserLookup(ims, mapper);\r\n                }\r\n            }\r\n        }\r\n        return userLookup;\r\n    }\r\n\r\n    /**\r\n     * Returns a list of change sets containing modified items.\r\n     * @param fromTimestamp the timestamp to get history from\r\n     * @param toTimestamp the timestamp to get history to\r\n     * @return a list of change sets\r\n     */\r\n    public List<ChangeSet> getDetailedHistory(Calendar fromTimestamp, Calendar toTimestamp) {\r\n        final DateVersionSpec fromVersion = new DateVersionSpec(fromTimestamp);\r\n        final DateVersionSpec toVersion = new DateVersionSpec(toTimestamp);\r\n        return getVCCHistory(fromVersion, toVersion, true, Integer.MAX_VALUE);\r\n    }\r\n    \r\n    public List<ChangeSet> getDetailedHistory(final String singleVersionSpec) {\r\n        final VersionSpec toVersion = VersionSpec.parseSingleVersionFromSpec(singleVersionSpec, null);\r\n        return getVCCHistory(toVersion, toVersion, true, 1);\r\n    }\r\n\r\n    /**\r\n     * Returns a list of change sets not containing the modified items.\r\n     * @param fromTimestamp the timestamp to get history from\r\n     * @param toTimestamp the timestamp to get history to\r\n     * @return a list of change sets\r\n     */\r\n    public List<ChangeSet> getBriefHistory(Calendar fromTimestamp, Calendar toTimestamp) {\r\n        final DateVersionSpec fromVersion = new DateVersionSpec(fromTimestamp);\r\n        final DateVersionSpec toVersion = new DateVersionSpec(toTimestamp);\r\n        return getVCCHistory(fromVersion, toVersion, false, Integer.MAX_VALUE);\r\n    }\r\n\r\n    /**\r\n     * Returns a list of change sets not containing the modified items.\r\n     * @param fromChangeset the changeset number to get history from\r\n     * @param toTimestamp the timestamp to get history to\r\n     * @return a list of change sets\r\n     */\r\n    public List<ChangeSet> getBriefHistory(int fromChangeset, Calendar toTimestamp) {\r\n        final ChangesetVersionSpec fromVersion = new ChangesetVersionSpec(fromChangeset);\r\n        final VersionSpec toVersion = new DateVersionSpec(toTimestamp);\r\n        return getVCCHistory(fromVersion, toVersion, false, Integer.MAX_VALUE);\r\n    }\r\n\r\n    /**\r\n     * Returns the latest changeset at the project's path.\r\n     * @return the {@link ChangeSet} instance representing the last entry in the history for the path\r\n     */\r\n    public ChangeSet getLatestChangeset() {\r\n        final List<ChangeSet> changeSets = getVCCHistory(LatestVersionSpec.INSTANCE, null, false, 1);\r\n        final ChangeSet result = changeSets.size() > 0 ? changeSets.get(0) : null;\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Gets the latest changeset that isn't in a cloaked path.\r\n     * @param fromChangeset the changeset that was last seen, as a point of reference\r\n     * @param cloakedPaths the list of cloaked paths in the project\r\n     * @return the {@link ChangeSet} instance representing the last entry in the history for the path\r\n     */\r\n    public ChangeSet getLatestUncloakedChangeset(final int fromChangeset, final Collection<String> cloakedPaths) {\r\n        final ChangesetVersionSpec fromVersion = new ChangesetVersionSpec(fromChangeset);\r\n        final List<ChangeSet> changeSets = getVCCHistory(fromVersion, LatestVersionSpec.INSTANCE, true, Integer.MAX_VALUE);\r\n        final ChangeSet result = findLatestUncloakedChangeset(cloakedPaths, changeSets);\r\n        return result;\r\n    }\r\n\r\n    static ChangeSet findLatestUncloakedChangeset(final Collection<String> cloakedPaths, final List<ChangeSet> changeSets) {\r\n        ChangeSet result = null;\r\n\r\n        // We need to search from latest to earliest, otherwise an incorrect result is produced\r\n        int lastChangeSetNumber = Integer.MAX_VALUE;\r\n        for (final ChangeSet s : changeSets) {\r\n            final String stringVersion = s.getVersion();\r\n            final int changeSetNumber = Integer.parseInt(stringVersion, 10);\r\n            if (changeSetNumber >= lastChangeSetNumber) {\r\n                throw new IllegalArgumentException(\"The changeset numbers must be strictly decreasing.\");\r\n            }\r\n            lastChangeSetNumber = changeSetNumber;\r\n            final Collection<String> changes = s.getAffectedPaths();\r\n\r\n            final boolean fullyCloaked = isChangesetFullyCloaked(changes, cloakedPaths);\r\n            if (!fullyCloaked) {\r\n                result = s;\r\n                break;\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Returns a list of changesets without any changesets that are in cloaked paths\r\n     * @param fromTimestamp the timestamp to get history from\r\n     * @param toTimestamp the timestamp to get history to\r\n     * @param cloakedPaths the list of \"cloaked\" paths that would exclude\r\n     *                     changesets that are fully covered by one or more of these paths\r\n     * @return a list of change sets\r\n     */\r\n    public List<ChangeSet> getDetailedHistoryWithoutCloakedPaths(final Calendar fromTimestamp, final Calendar toTimestamp, final Collection<String> cloakedPaths) {\r\n        final DateVersionSpec fromVersion = new DateVersionSpec(fromTimestamp);\r\n        final DateVersionSpec toVersion = new DateVersionSpec(toTimestamp);\r\n        return getDetailedHistoryWithoutCloakedPaths(fromVersion, toVersion, cloakedPaths);\r\n    }\r\n\r\n    public List<ChangeSet> getDetailedHistoryWithoutCloakedPaths(final VersionSpec fromVersion, final VersionSpec toVersion, final Collection<String> cloakedPaths) {\r\n        final List<ChangeSet> changeSets = getVCCHistory(fromVersion, toVersion, true, Integer.MAX_VALUE);\r\n        final ArrayList<ChangeSet> changeSetNoCloaked = new ArrayList<ChangeSet>();\r\n        for (final ChangeSet changeset : changeSets) {\r\n            final Collection<String> affectedPaths = changeset.getAffectedPaths();\r\n            final boolean fullyCloaked = isChangesetFullyCloaked(affectedPaths, cloakedPaths);\r\n            if (!fullyCloaked) {\r\n                changeSetNoCloaked.add(changeset);\r\n            }\r\n        }\r\n        return changeSetNoCloaked;\r\n    }\r\n\r\n    static boolean isChangesetFullyCloaked(final Collection<String> changesetPaths, final Collection<String> cloakedPaths) {\r\n        if (cloakedPaths == null) {\r\n            return false;\r\n        }\r\n        for (final String tfsPath : changesetPaths) {\r\n            boolean isPathCloaked = false;\r\n            for (final String cloakedPath : cloakedPaths) {\r\n                if (tfsPath.regionMatches(true, 0, cloakedPath, 0, cloakedPath.length())) {\r\n                    isPathCloaked = true;\r\n                    break;\r\n                }\r\n            }\r\n            if (!isPathCloaked) {\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Gets all files from server.\r\n     * @param localPath the local path to get all files into\r\n     * @param versionSpec the version spec to use when getting the files\r\n     * @param useOverwrite if should overwrite changes\r\n     */\r\n    public void getFiles(String localPath, String versionSpec, boolean useOverwrite) {\r\n        GetFilesToWorkFolderCommand command = new GetFilesToWorkFolderCommand(server, localPath, versionSpec, useOverwrite);\r\n        server.execute(command.getCallable());\r\n    }\r\n\r\n    /**\r\n     * Gets remote changeset version for specified remote path, as of versionSpec.\r\n     *\r\n     * @param remotePath for which to get latest changeset version\r\n     * @param versionSpec a version specification to convert to a changeset number\r\n     * @return changeset version for specified remote path\r\n     */\r\n    public int getRemoteChangesetVersion(final String remotePath, final VersionSpec versionSpec) {\r\n        RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(server, remotePath, versionSpec);\r\n        return extractChangesetNumber(command);\r\n    }\r\n\r\n    int extractChangesetNumber(final RemoteChangesetVersionCommand command) {\r\n        final Integer changeSet = server.execute(command.getCallable());\r\n        final int result = changeSet;\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Gets remote changeset version for the project's remote path, as of versionSpec.\r\n     *\r\n     * @param versionSpec a version specification to convert to a changeset number\r\n     * @return changeset version for the project's remote path\r\n     */\r\n    public int getRemoteChangesetVersion(final VersionSpec versionSpec) {\r\n        return getRemoteChangesetVersion(projectPath, versionSpec);\r\n    }\r\n\r\n    @Override\r\n    public int hashCode() {\r\n        return new HashCodeBuilder(13, 27).append(projectPath).toHashCode();\r\n    }\r\n\r\n    @Override\r\n    public boolean equals(Object obj) {\r\n        if (this == obj)\r\n            return true;\r\n        if ((obj == null) || (getClass() != obj.getClass()))\r\n            return false;\r\n        final Project other = (Project) obj;\r\n        EqualsBuilder builder = new EqualsBuilder();\r\n        builder.append(this.projectPath, other.projectPath);\r\n        return builder.isEquals();\r\n    }\r\n\r\n    protected UserLookup getUserLookup() {\r\n        return userLookup;\r\n    }\r\n\r\n    protected void setUserLookup(final UserLookup userLookup) {\r\n        this.userLookup = userLookup;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/ProxyHostEx.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport hudson.util.Secret;\r\n\r\npublic class ProxyHostEx extends com.microsoft.tfs.core.httpclient.ProxyHost {\r\n\r\n    private final String proxyUser;\r\n    private final Secret proxySecret;\r\n\r\n    public ProxyHostEx(final String hostname, final int port, final String proxyUser, final Secret proxySecret) {\r\n        super(hostname, port);\r\n        this.proxyUser = proxyUser;\r\n        this.proxySecret = proxySecret;\r\n    }\r\n\r\n    public String getProxyUser() {\r\n        return proxyUser;\r\n    }\r\n\r\n    public Secret getProxySecret() {\r\n        return proxySecret;\r\n    }\r\n\r\n    @Override\r\n    public boolean equals(Object o) {\r\n        return super.equals(o);\r\n    }\r\n\r\n    @Override\r\n    public int hashCode() {\r\n        return super.hashCode();\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/PullRequestMergeCommitCreatedEventArgs.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\npublic class PullRequestMergeCommitCreatedEventArgs extends GitCodePushedEventArgs {\r\n\r\n    public int pullRequestId;\r\n    public int iterationId = -1;\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/Server.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient;\r\nimport com.microsoft.tfs.core.clients.webservices.IIdentityManagementService;\r\nimport com.microsoft.tfs.core.clients.webservices.IdentityManagementException;\r\nimport com.microsoft.tfs.core.clients.webservices.IdentityManagementService;\r\nimport com.microsoft.tfs.core.config.persistence.DefaultPersistenceStoreProvider;\r\nimport com.microsoft.tfs.core.config.persistence.PersistenceStoreProvider;\r\nimport com.microsoft.tfs.core.httpclient.Credentials;\r\nimport com.microsoft.tfs.core.httpclient.DefaultNTCredentials;\r\nimport com.microsoft.tfs.core.httpclient.HttpClient;\r\nimport com.microsoft.tfs.core.httpclient.UsernamePasswordCredentials;\r\nimport com.microsoft.tfs.core.util.CredentialsUtils;\r\nimport com.microsoft.tfs.core.util.URIUtils;\r\nimport com.microsoft.tfs.jni.helpers.LocalHost;\r\nimport com.microsoft.tfs.util.Closable;\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\nimport hudson.Launcher;\r\nimport hudson.ProxyConfiguration;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.TeamPluginGlobalConfig;\r\nimport hudson.plugins.tfs.commands.ServerConfigurationProvider;\r\nimport hudson.remoting.Callable;\r\nimport hudson.remoting.VirtualChannel;\r\nimport hudson.util.Secret;\r\nimport jenkins.model.Jenkins;\r\nimport jenkins.security.MasterToSlaveCallable;\r\n\r\nimport java.io.IOException;\r\nimport java.net.URI;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\nimport java.util.logging.Logger;\r\n\r\npublic class Server implements ServerConfigurationProvider, Closable {\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(Server.class.getName());\r\n    private final String url;\r\n    private final String userName;\r\n    private final String userPassword;\r\n    private Workspaces workspaces;\r\n    private Map<String, Project> projects = new HashMap<String, Project>();\r\n    private final Launcher launcher;\r\n    private final TaskListener taskListener;\r\n    private final TFSTeamProjectCollection tpc;\r\n    private final WebProxySettings webProxySettings;\r\n    private final ExtraSettings extraSettings;\r\n    private MockableVersionControlClient mockableVcc;\r\n    private static HashMap<String, PersistenceStoreProvider> persistenceStoreProviderCache = new HashMap<String, PersistenceStoreProvider>();\r\n\r\n\r\n    /**\r\n     * This constructor overload assumes a Jenkins instance is present.\r\n     */\r\n    public Server(final Launcher launcher, final TaskListener taskListener, final String url, final String username, final String password) throws IOException {\r\n        this(launcher, taskListener, url, username, password, null, null);\r\n    }\r\n\r\n    public static Server create(final Launcher launcher, final TaskListener taskListener, final String url, final StandardUsernamePasswordCredentials credentials, final WebProxySettings webProxySettings, final ExtraSettings extraSettings) throws IOException {\r\n\r\n        final String username;\r\n        final String userPassword;\r\n        if (credentials == null) {\r\n            username = null;\r\n            userPassword = null;\r\n        }\r\n        else {\r\n            username = credentials.getUsername();\r\n            final Secret password = credentials.getPassword();\r\n            userPassword = password.getPlainText();\r\n        }\r\n        return new Server(launcher, taskListener, url, username, userPassword, webProxySettings, extraSettings);\r\n    }\r\n\r\n    public Server(final Launcher launcher, final TaskListener taskListener, final String url, final String username, final String password, final WebProxySettings webProxySettings, final ExtraSettings extraSettings) throws IOException {\r\n        this.launcher = launcher;\r\n        this.taskListener = taskListener;\r\n        this.url = url;\r\n        this.userName = username;\r\n        this.userPassword = password;\r\n        final URI uri = URIUtils.newURI(url);\r\n\r\n        NativeLibraryManager.initialize();\r\n\r\n        Credentials credentials = null;\r\n        // In case no user name is provided and the current platform supports\r\n        // default credentials, use default credentials\r\n        if ((username == null || username.length() == 0) && CredentialsUtils.supportsDefaultCredentials()) {\r\n            credentials = new DefaultNTCredentials();\r\n        }\r\n        else if (username != null && password != null) {\r\n            credentials = new UsernamePasswordCredentials(username, password);\r\n        }\r\n\r\n        if (credentials != null) {\r\n            final VirtualChannel channel = launcher != null ? launcher.getChannel() : null;\r\n            if (webProxySettings != null) {\r\n                this.webProxySettings = webProxySettings;\r\n            }\r\n            else {\r\n                final ProxyConfiguration proxyConfiguration = determineProxyConfiguration(channel);\r\n                this.webProxySettings = new WebProxySettings(proxyConfiguration);\r\n            }\r\n            final String host = uri.getHost();\r\n            final ProxyHostEx proxyHost = this.webProxySettings.toProxyHost(host);\r\n\r\n            if (extraSettings != null) {\r\n                this.extraSettings = extraSettings;\r\n            }\r\n            else {\r\n                final TeamPluginGlobalConfig globalConfig = determineGlobalConfig(channel);\r\n                this.extraSettings = new ExtraSettings(globalConfig);\r\n            }\r\n            final PersistenceStoreProvider defaultProvider = DefaultPersistenceStoreProvider.INSTANCE;\r\n            final PersistenceStoreProvider provider;\r\n            if (this.extraSettings.isConfigFolderPerNode()) {\r\n                final String hostName = LocalHost.getShortName();\r\n                if(persistenceStoreProviderCache.containsKey(hostName)) {\r\n                \tprovider =  persistenceStoreProviderCache.get(hostName);\r\n                } else {\r\n                \tprovider = new ClonePersistenceStoreProvider(defaultProvider, hostName);\r\n                \tpersistenceStoreProviderCache.put(hostName, provider);\r\n                }\r\n            }\r\n            else {\r\n                provider = defaultProvider;\r\n            }\r\n            final ModernConnectionAdvisor advisor = new ModernConnectionAdvisor(proxyHost, provider);\r\n            this.tpc = new TFSTeamProjectCollection(uri, credentials, advisor);\r\n        }\r\n        else {\r\n            this.webProxySettings = null;\r\n            this.extraSettings = null;\r\n            this.tpc = null;\r\n        }\r\n    }\r\n\r\n    static TeamPluginGlobalConfig determineGlobalConfig(final VirtualChannel channel) {\r\n        final Jenkins jenkins = Jenkins.getInstance();\r\n        final TeamPluginGlobalConfig result;\r\n        if (jenkins == null) {\r\n            if (channel != null) {\r\n                try {\r\n                    result = channel.call(new MasterToSlaveCallable<TeamPluginGlobalConfig, Throwable>() {\r\n                        @Override\r\n                        public TeamPluginGlobalConfig call() throws Throwable {\r\n                            final Jenkins jenkins = Jenkins.getInstance();\r\n                            final TeamPluginGlobalConfig result = jenkins != null ? TeamPluginGlobalConfig.get() : null;\r\n                            return result;\r\n                        }\r\n                    });\r\n                }\r\n                catch (final Throwable throwable) {\r\n                    throw new Error(throwable);\r\n                }\r\n            }\r\n            else {\r\n                result = TeamPluginGlobalConfig.DEFAULT_CONFIG;\r\n            }\r\n        }\r\n        else {\r\n            result = TeamPluginGlobalConfig.get();\r\n        }\r\n        return result;\r\n    }\r\n\r\n    static ProxyConfiguration determineProxyConfiguration(final VirtualChannel channel) {\r\n        final Jenkins jenkins = Jenkins.getInstance();\r\n        final ProxyConfiguration proxyConfiguration;\r\n        if (jenkins == null) {\r\n            if (channel != null) {\r\n                try {\r\n                    proxyConfiguration = channel.call(new MasterToSlaveCallable<ProxyConfiguration, Throwable>() {\r\n                        public ProxyConfiguration call() throws Throwable {\r\n                            final Jenkins jenkins = Jenkins.getInstance();\r\n                            final ProxyConfiguration result = jenkins != null ? jenkins.proxy : null;\r\n                            return result;\r\n                        }\r\n                    });\r\n                } catch (final Throwable throwable) {\r\n                    throw new Error(throwable);\r\n                }\r\n            }\r\n            else {\r\n                proxyConfiguration = null;\r\n            }\r\n        }\r\n        else {\r\n            proxyConfiguration = jenkins.proxy;\r\n        }\r\n        return proxyConfiguration;\r\n    }\r\n\r\n    public Project getProject(String projectPath) {\r\n        if (! projects.containsKey(projectPath)) {\r\n            projects.put(projectPath, new Project(this, projectPath));\r\n        }\r\n        return projects.get(projectPath);\r\n    }\r\n\r\n    public Workspaces getWorkspaces() {\r\n        if (workspaces == null) {\r\n            workspaces = new Workspaces(this);\r\n        }\r\n        return workspaces;\r\n    }\r\n\r\n    @SuppressFBWarnings(value = { \"DC_DOUBLECHECK\", \"IS2_INCONSISTENT_SYNC\"}, justification = \"Only synchronize if not null\")\r\n    public MockableVersionControlClient getVersionControlClient() {\r\n        if (mockableVcc == null) {\r\n            synchronized (this) {\r\n                if (mockableVcc == null) {\r\n                    final VersionControlClient vcc = tpc.getVersionControlClient();\r\n                    mockableVcc = new MockableVersionControlClient(vcc);\r\n                }\r\n            }\r\n        }\r\n        return mockableVcc;\r\n    }\r\n\r\n    public HttpClient getHttpClient() {\r\n        return tpc.getHTTPClient();\r\n    }\r\n\r\n    public <T, E extends Exception> T execute(final Callable<T, E> callable) {\r\n        try {\r\n            final VirtualChannel channel = launcher.getChannel();\r\n            final T result = channel.call(callable);\r\n            return result;\r\n        } catch (final Exception e) {\r\n            // convert from checked to unchecked exception\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    public String getUrl() {\r\n        return url;\r\n    }\r\n\r\n    public String getUserName() {\r\n        return userName;\r\n    }\r\n\r\n    public String getUserPassword() {\r\n        return userPassword;\r\n    }\r\n\r\n    public Launcher getLauncher() {\r\n        return launcher;\r\n    }\r\n\r\n    public WebProxySettings getWebProxySettings() {\r\n        return webProxySettings;\r\n    }\r\n\r\n    public ExtraSettings getExtraSettings() {\r\n        return extraSettings;\r\n    }\r\n\r\n    public TaskListener getListener() {\r\n        return taskListener;\r\n    }\r\n\r\n    public synchronized void close() {\r\n        if (this.mockableVcc != null) {\r\n            this.mockableVcc.close();\r\n        }\r\n        if (this.tpc != null) {\r\n            if(this.tpc.getConfigurationServer() != null) {\r\n                this.tpc.getConfigurationServer().close();\r\n            }\r\n            this.tpc.close();\r\n        }\r\n    }\r\n\r\n    public IIdentityManagementService createIdentityManagementService() {\r\n        IIdentityManagementService ims;\r\n        try {\r\n            ims = new IdentityManagementService(tpc);\r\n        } catch (IdentityManagementException e) {\r\n            ims = new LegacyIdentityManagementService();\r\n        }\r\n        return ims;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/TeamBuildPayload.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.annotation.JsonProperty;\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\n\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\n@SuppressFBWarnings(value = \"NM_FIELD_NAMING_CONVENTION\", justification = \"Public so shouldn't be changed\")\r\npublic class TeamBuildPayload {\r\n\r\n    @JsonProperty(\"parameter\")\r\n    public List<BuildParameter> BuildParameters;\r\n\r\n    @JsonProperty(\"team-build\")\r\n    public Map<String, String> BuildVariables;\r\n\r\n    @JsonProperty(\"team-event\")\r\n    public Event ServiceHookEvent;\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/TeamGitStatus.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport hudson.model.Job;\r\nimport hudson.model.Result;\r\nimport hudson.model.Run;\r\nimport jenkins.model.Jenkins;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport java.util.Collections;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\npublic class TeamGitStatus {\r\n\r\n    private static final Map<Result, GitStatusState> RESULT_TO_STATE;\r\n\r\n    static {\r\n        final Map<Result, GitStatusState> resultToStatus = new HashMap<Result, GitStatusState>();\r\n        resultToStatus.put(Result.SUCCESS, GitStatusState.Succeeded);\r\n        resultToStatus.put(Result.UNSTABLE, GitStatusState.Failed);\r\n        resultToStatus.put(Result.FAILURE, GitStatusState.Failed);\r\n        resultToStatus.put(Result.NOT_BUILT, GitStatusState.Error);\r\n        resultToStatus.put(Result.ABORTED, GitStatusState.Error);\r\n        RESULT_TO_STATE = Collections.unmodifiableMap(resultToStatus);\r\n    }\r\n\r\n    public GitStatusState state;\r\n    public String description;\r\n    public String targetUrl;\r\n    public GitStatusContext context;\r\n\r\n    public static TeamGitStatus fromRun(@Nonnull final Run<?, ?> run) {\r\n        final TeamGitStatus status = new TeamGitStatus();\r\n        final Result result = run.getResult();\r\n        if (result == null) {\r\n            status.state = GitStatusState.Pending;\r\n            status.description = status.state.toString();\r\n        } else {\r\n            status.state = RESULT_TO_STATE.get(result);\r\n            status.description = result.toString();\r\n        }\r\n        final Job<?, ?> job = run.getParent();\r\n        status.description = job.getDisplayName() + run.getDisplayName() + \": \" + status.description;\r\n        status.targetUrl = run.getAbsoluteUrl();\r\n        status.context = getStatusContext(job);\r\n        return status;\r\n    }\r\n\r\n    public static TeamGitStatus fromJob(@Nonnull final Job job) {\r\n        final TeamGitStatus status = new TeamGitStatus();\r\n        status.state = GitStatusState.Pending;\r\n        status.description = \"Jenkins Job \" + job.getDisplayName() + \" queued\";\r\n        status.targetUrl = job.getAbsoluteUrl();\r\n        status.context = getStatusContext(job);\r\n        return status;\r\n    }\r\n\r\n    private static GitStatusContext getStatusContext(@Nonnull final Job job) {\r\n        final String instanceUrl = StringUtils.stripEnd(Jenkins.getInstance().getRootUrl(), \"/\");\r\n        final String projectDisplayName = job.getParent().getFullName() + \"/\" + job.getDisplayName();\r\n        return new GitStatusContext(projectDisplayName, instanceUrl);\r\n    }\r\n\r\n    public String toJson() {\r\n        final JSONObject jsonObject = JSONObject.fromObject(this);\r\n        final String result = jsonObject.toString();\r\n        return result;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/TeamRequestedResult.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport hudson.Extension;\r\nimport hudson.FilePath;\r\nimport hudson.model.AbstractDescribableImpl;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Descriptor;\r\nimport hudson.util.FormValidation;\r\nimport hudson.util.ListBoxModel;\r\nimport org.kohsuke.stapler.AncestorInPath;\r\nimport org.kohsuke.stapler.DataBoundConstructor;\r\nimport org.kohsuke.stapler.DataBoundSetter;\r\nimport org.kohsuke.stapler.QueryParameter;\r\n\r\nimport java.io.IOException;\r\nimport java.util.Arrays;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\npublic class TeamRequestedResult extends AbstractDescribableImpl<TeamRequestedResult> {\r\n    private final TeamResultType teamResultType;\r\n    private String includes;\r\n\r\n    @DataBoundConstructor\r\n    public TeamRequestedResult(final TeamResultType teamResultType) {\r\n\r\n        this.teamResultType = teamResultType;\r\n    }\r\n\r\n    public TeamResultType getTeamResultType() {\r\n        return teamResultType;\r\n    }\r\n\r\n    public String getIncludes() {\r\n        return includes;\r\n    }\r\n\r\n    @DataBoundSetter\r\n    public void setIncludes(final String includes) {\r\n        this.includes = includes;\r\n    }\r\n\r\n    @Extension\r\n    public static class DescriptorImpl extends Descriptor<TeamRequestedResult> {\r\n\r\n        @Override\r\n        public String getDisplayName() {\r\n            return \"Requested build result\";\r\n        }\r\n\r\n        @SuppressWarnings(\"unused\")\r\n        public ListBoxModel doFillTeamResultTypeItems() {\r\n            final TeamResultType[] values = TeamResultType.values();\r\n            final ListBoxModel result = new ListBoxModel(values.length);\r\n\r\n            for (final TeamResultType value : values) {\r\n                result.add(value.getDisplayName(), value.name());\r\n            }\r\n            return result;\r\n        }\r\n\r\n        public FormValidation doCheckIncludes(\r\n                @AncestorInPath final AbstractProject project,\r\n                @QueryParameter final String value) throws IOException {\r\n            if (project == null) {\r\n                return FormValidation.ok();\r\n            }\r\n            return FilePath.validateFileMask(project.getSomeWorkspace(), value);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/TeamResultType.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\n/**\r\n * Enum to represent the type of build result (junit tests, cobertura report, etc.).\r\n */\r\npublic enum TeamResultType {\r\n    JUNIT(\"junit\", \"JUnit\"),\r\n    NUNIT(\"nunit\", \"NUnit\"),\r\n    VS_TEST(\"vstest\", \"VSTest\"),\r\n    XUNIT(\"xunit\", \"XUnit\"),\r\n    COBERTURA(\"cobertura\", \"Cobertura\"),\r\n    JACOCO(\"jacoco\", \"JaCoCo\");\r\n\r\n    private final String folderName;\r\n    private final String displayName;\r\n\r\n    TeamResultType(final String folderName, final String displayName) {\r\n        this.folderName = folderName;\r\n        this.displayName = displayName;\r\n    }\r\n\r\n    public String getFolderName() {\r\n        return folderName;\r\n    }\r\n\r\n    public String getDisplayName() {\r\n        return displayName;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/TfsUserLookup.java",
    "content": "package hudson.plugins.tfs.model;\n\nimport java.io.IOException;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport com.microsoft.tfs.core.clients.webservices.IIdentityManagementService;\nimport com.microsoft.tfs.core.clients.webservices.IdentitySearchFactor;\nimport com.microsoft.tfs.core.clients.webservices.MembershipQuery;\nimport com.microsoft.tfs.core.clients.webservices.ReadIdentityOptions;\nimport com.microsoft.tfs.core.clients.webservices.TeamFoundationIdentity;\n\nimport hudson.model.User;\nimport hudson.tasks.Mailer;\n\n/**\n * Finds user information via the UserAccountMappers that it knows about.\n */\npublic class TfsUserLookup implements UserLookup {\n\n    private static final Logger logger = Logger.getLogger(TfsUserLookup.class.getName());\n\n    private final IIdentityManagementService ims;\n    private final UserAccountMapper userAccountMapper;\n\n    public TfsUserLookup(final IIdentityManagementService ims, final UserAccountMapper userAccountMapper) {\n        this.ims = ims;\n        this.userAccountMapper = userAccountMapper;\n    }\n\n    /**\n     * Finds the User instance for the account name provided.\n     * @param accountName Windows NT account name: domain\\alias.\n     */\n    public User find(final String accountName) {\n        final String mappedAccountName = userAccountMapper.mapUserAccount(accountName);\n        logger.log(Level.FINE, String.format(\"Looking up Jenkins user for account '%s'.\", mappedAccountName));\n        final User jenkinsUser = User.get(mappedAccountName);\n        Mailer.UserProperty mailerProperty = jenkinsUser.getProperty(Mailer.UserProperty.class);\n        if (mailerProperty == null || mailerProperty.getAddress() == null || mailerProperty.getAddress().length() == 0) {\n            logger.log(Level.FINE, String.format(\"No Mailer.UserProperty defined for '%s', looking in TFS\", mappedAccountName));\n            final TeamFoundationIdentity tfsUser = ims.readIdentity(\n                IdentitySearchFactor.ACCOUNT_NAME,\n                accountName,\n                MembershipQuery.NONE,\n                ReadIdentityOptions.NONE\n            );\n            if (tfsUser != null) {\n                final String displayName = tfsUser.getDisplayName();\n                jenkinsUser.setFullName(displayName);\n                final String emailAddress = (String) tfsUser.getProperty(\"Mail\");\n                if (emailAddress != null) {\n                    mailerProperty = new Mailer.UserProperty(emailAddress);\n                    try {\n                        jenkinsUser.addProperty(mailerProperty);\n                    } catch (IOException e) {\n                        logger.warning(String.format(\"Unable to save Jenkins account for  user '%s'.\", accountName));\n                    }\n                } else {\n                    logger.info(String.format(\"User '%s' did not have an e-mail address configured.\", accountName));\n                }\n            } else {\n                logger.warning(String.format(\"Unable to find user '%s'.\", accountName));\n            }\n        }\n        return jenkinsUser;\n    }\n\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/UserAccountMapper.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.DescriptorExtensionList;\r\nimport hudson.ExtensionPoint;\r\nimport hudson.model.Describable;\r\nimport jenkins.model.Jenkins;\r\n\r\nimport java.io.Serializable;\r\n\r\n/**\r\n * Extends Jenkins to add our own UserAccountMapper.\r\n */\r\npublic abstract class UserAccountMapper implements ExtensionPoint, Describable<UserAccountMapper>, Serializable {\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * Returns the display name for this class.\r\n     */\r\n    public final String getDisplayName() {\r\n        return getDescriptor().getDisplayName();\r\n    }\r\n\r\n    /**\r\n     * Returns the class descriptor.\r\n     */\r\n    public UserAccountMapperDescriptor getDescriptor() {\r\n        final Jenkins jenkins = Jenkins.getActiveInstance();\r\n        return (UserAccountMapperDescriptor) jenkins.getDescriptorOrDie(getClass());\r\n    }\r\n\r\n    /**\r\n     * Abstract method to map an account from user input.\r\n     */\r\n    public abstract String mapUserAccount(final String input);\r\n\r\n    /**\r\n     * Gets all user account descriptors.\r\n     */\r\n    public static DescriptorExtensionList<UserAccountMapper, UserAccountMapperDescriptor> all() {\r\n        final Jenkins jenkins = Jenkins.getActiveInstance();\r\n        return jenkins.getDescriptorList(UserAccountMapper.class);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/UserAccountMapperDescriptor.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.model.Descriptor;\r\n\r\n/**\r\n * Class descriptor for UserAccountMapper.\r\n */\r\npublic abstract class UserAccountMapperDescriptor extends Descriptor<UserAccountMapper> {\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/UserHomePersistenceStore.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.persistence.FilesystemPersistenceStore;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.OutputStream;\r\n\r\n/**\r\n * Inspired by http://stackoverflow.com/a/20885974.\r\n */\r\npublic class UserHomePersistenceStore extends FilesystemPersistenceStore {\r\n    public UserHomePersistenceStore(final File subDirectory) {\r\n        super(new File(System.getProperty(\"user.home\"), subDirectory.getPath()));\r\n    }\r\n\r\n    @Override\r\n    public OutputStream getItemOutputStream(final String itemName) throws IOException {\r\n        final File itemFile = this.getItemFile(itemName);\r\n        final File folder = itemFile.getParentFile();\r\n        if (!folder.exists()) {\r\n            final boolean fullyCreated = folder.mkdirs();\r\n            if (!fullyCreated) {\r\n                throw new IOException(\"Unable to create folder structure for \" + folder.getAbsolutePath());\r\n            }\r\n        }\r\n        return super.getItemOutputStream(itemName);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/UserLookup.java",
    "content": "package hudson.plugins.tfs.model;\n\nimport hudson.model.User;\n\n/**\n * An interface to define the UserLookup contract.\n */\npublic interface UserLookup {\n    /**\n     * @param accountName Windows NT account name: domain\\alias.\n     *\n     * @return the Jenkins {@link User} object associated with the account name\n     */\n    User find(String accountName);\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/WebProxySettings.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.ProxyConfiguration;\r\nimport hudson.util.Secret;\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\nimport java.io.Serializable;\r\nimport java.net.Authenticator;\r\nimport java.net.InetSocketAddress;\r\nimport java.net.PasswordAuthentication;\r\nimport java.net.Proxy;\r\nimport java.util.ArrayList;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\nimport java.util.regex.Pattern;\r\n\r\n/**\r\n * A {@link Serializable} adapter between {@link ProxyConfiguration} and {@link ProxyHostEx}.\r\n */\r\npublic class WebProxySettings implements Serializable {\r\n    private static final long serialVersionUID = 401L;\r\n\r\n    private final String hostName;\r\n    private final int port;\r\n    private final String proxyUser;\r\n    private final Secret proxySecret;\r\n    private final List<Pattern> noProxyHostPatterns;\r\n\r\n    @SuppressWarnings(\"unused\" /* Needed by Serializable interface */)\r\n    private WebProxySettings() {\r\n        this(null, -1, null, null, null);\r\n    }\r\n\r\n    /**\r\n     * Convenience constructor, mostly for tests.\r\n     *\r\n     * @param hostName            the name (or address) of the proxy server.\r\n     *                            May be {@code null}, meaning there is no proxy server configured.\r\n     * @param port                the port that the proxy server is listening on\r\n     * @param noProxyHostPatterns a list of {@link Pattern} representing hosts that should not be proxied.\r\n     *                            May be {@code null}, meaning all hosts will be proxied.\r\n     * @param proxyUser           the name of the user with which to authenticate to the proxy server.\r\n     *                            May be {@code null}, meaning the proxy server doesn't need authentication.\r\n     * @param proxySecret         the password of the user with which to authenticate to the proxy server.\r\n     *                            May be {@code null}, meaning the proxy server doesn't need authentication.\r\n     */\r\n    public WebProxySettings(final String hostName, final int port, final List<Pattern> noProxyHostPatterns, final String proxyUser, final Secret proxySecret) {\r\n        this.hostName = hostName;\r\n        this.port = port;\r\n        this.noProxyHostPatterns = copyNoProxyHostPatterns(noProxyHostPatterns);\r\n        this.proxyUser = proxyUser;\r\n        this.proxySecret = proxySecret;\r\n    }\r\n\r\n    /**\r\n     * Initialize a {@link WebProxySettings} from a Jenkins {@link ProxyConfiguration}.\r\n     *\r\n     * @param proxyConfiguration the proxy settings as obtained from Jenkins.\r\n     *                           May be {@code null}, meaning there is no proxy configured.\r\n     */\r\n    public WebProxySettings(final ProxyConfiguration proxyConfiguration) {\r\n        if (proxyConfiguration != null) {\r\n            this.hostName = proxyConfiguration.name;\r\n            this.port = proxyConfiguration.port;\r\n            this.proxyUser = proxyConfiguration.getUserName();\r\n            this.noProxyHostPatterns = copyNoProxyHostPatterns(proxyConfiguration.getNoProxyHostPatterns());\r\n            this.proxySecret = Secret.fromString(proxyConfiguration.getEncryptedPassword());\r\n        } else {\r\n            this.hostName = null;\r\n            this.port = -1;\r\n            this.proxyUser = null;\r\n            this.proxySecret = null;\r\n            this.noProxyHostPatterns = copyNoProxyHostPatterns(null);\r\n        }\r\n    }\r\n\r\n    private static ArrayList<Pattern> copyNoProxyHostPatterns(final List<Pattern> noProxyHostPatterns) {\r\n        return new ArrayList<Pattern>(\r\n                noProxyHostPatterns == null\r\n                        ? Collections.<Pattern>emptyList()\r\n                        : noProxyHostPatterns\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Initialize a {@link ProxyHostEx} from this {@link WebProxySettings} for the provided hostToProxy.\r\n     * May return null, which either means there is no proxy server configured or it does not apply\r\n     * to the provided hostToProxy.\r\n     *\r\n     * @param hostToProxy the name of the host for which proxying is considered.\r\n     * @return an instance of {@link ProxyHostEx} or {@code null} if no proxy is to be used.\r\n     */\r\n    public ProxyHostEx toProxyHost(final String hostToProxy) {\r\n        final ProxyHostEx proxyHost;\r\n        if (this.hostName != null) {\r\n            final boolean shouldProxy = shouldProxy(hostToProxy, noProxyHostPatterns);\r\n            if (shouldProxy) {\r\n                proxyHost = new ProxyHostEx(hostName, port, proxyUser, proxySecret);\r\n            } else {\r\n                proxyHost = null;\r\n            }\r\n        } else {\r\n            proxyHost = null;\r\n        }\r\n        return proxyHost;\r\n    }\r\n\r\n    /**\r\n     * Convert the host to the proxy information.\r\n     */\r\n    public Proxy toProxy(final String hostToProxy) {\r\n        final Proxy proxy;\r\n        if (this.hostName != null) {\r\n            final boolean shouldProxy = shouldProxy(hostToProxy, noProxyHostPatterns);\r\n            if (shouldProxy) {\r\n                final InetSocketAddress proxyAddress = new InetSocketAddress(hostName, port);\r\n                proxy = new Proxy(Proxy.Type.HTTP, proxyAddress);\r\n                if (proxyUser != null && proxySecret != null) {\r\n                    final Authenticator authenticator = new Authenticator() {\r\n                        @Override\r\n                        protected PasswordAuthentication getPasswordAuthentication() {\r\n                            if (StringUtils.equalsIgnoreCase(hostName, this.getRequestingHost())) {\r\n                                return new PasswordAuthentication(proxyUser, proxySecret.getPlainText().toCharArray());\r\n                            }\r\n                            return null;\r\n                        }\r\n                    };\r\n                    Authenticator.setDefault(authenticator);\r\n                }\r\n            } else {\r\n                proxy = Proxy.NO_PROXY;\r\n            }\r\n        } else {\r\n            proxy = Proxy.NO_PROXY;\r\n        }\r\n        return proxy;\r\n    }\r\n\r\n    static boolean shouldProxy(final String host, final List<Pattern> noProxyHostPatterns) {\r\n        // inspired by https://github.com/jenkinsci/git-client-plugin/commit/2fefeae06db79d09d6604994001f8f2bd21549e1\r\n        boolean shouldProxy = true;\r\n        for (final Pattern p : noProxyHostPatterns) {\r\n            if (p.matcher(host).matches()) {\r\n                shouldProxy = false;\r\n                break;\r\n            }\r\n        }\r\n        return shouldProxy;\r\n    }\r\n\r\n    public String getHostName() {\r\n        return hostName;\r\n    }\r\n\r\n    public int getPort() {\r\n        return port;\r\n    }\r\n\r\n    public String getProxyUser() {\r\n        return proxyUser;\r\n    }\r\n\r\n    public Secret getProxySecret() {\r\n        return proxySecret;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/WorkItem.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.clients.workitem.internal.query.WorkItemRelation;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\n\r\n/**\r\n * Workaround for missing classes in vso-httpclient-java.\r\n */\r\npublic class WorkItem\r\n    extends WorkItemTrackingResource {\r\n\r\n    private HashMap<String, Object> fields;\r\n    private int id;\r\n    private ArrayList<WorkItemRelation> relations;\r\n    private int rev;\r\n\r\n    public HashMap<String, Object> getFields() {\r\n        return fields;\r\n    }\r\n\r\n    public void setFields(final HashMap<String, Object> fields) {\r\n        this.fields = fields;\r\n    }\r\n\r\n    public int getId() {\r\n        return id;\r\n    }\r\n\r\n    public void setId(final int id) {\r\n        this.id = id;\r\n    }\r\n\r\n    public ArrayList<WorkItemRelation> getRelations() {\r\n        return relations;\r\n    }\r\n\r\n    public void setRelations(final ArrayList<WorkItemRelation> relations) {\r\n        this.relations = relations;\r\n    }\r\n\r\n    public int getRev() {\r\n        return rev;\r\n    }\r\n\r\n    public void setRev(final int rev) {\r\n        this.rev = rev;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/WorkItemTrackingResource.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.annotation.JsonProperty;\r\nimport com.microsoft.visualstudio.services.webapi.model.ReferenceLinks;\r\n\r\n/**\r\n * Workaround for missing classes in vso-httpclient-java.\r\n */\r\npublic class WorkItemTrackingResource\r\n    extends WorkItemTrackingResourceReference {\r\n\r\n    private ReferenceLinks _links;\r\n\r\n    @JsonProperty(\"_links\")\r\n    public ReferenceLinks getLinks() {\r\n        return _links;\r\n    }\r\n\r\n    @JsonProperty(\"_links\")\r\n    public void setLinks(final ReferenceLinks _links) {\r\n        this._links = _links;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/WorkItemTrackingResourceReference.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\n/**\r\n * Workaround for missing classes in vso-httpclient-java.\r\n */\r\npublic class WorkItemTrackingResourceReference {\r\n\r\n    private String url;\r\n\r\n    public String getUrl() {\r\n        return url;\r\n    }\r\n\r\n    public void setUrl(final String url) {\r\n        this.url = url;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/Workspace.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport org.apache.commons.lang.builder.EqualsBuilder;\r\nimport org.apache.commons.lang.builder.HashCodeBuilder;\r\n\r\nimport java.io.Serializable;\r\n\r\npublic class Workspace implements Serializable{\r\n\r\n    private final String name;\r\n    private final String computer;\r\n    private final String owner;\r\n    private final String comment;\r\n\r\n    public Workspace(String name, String computer, String owner, String comment) {\r\n        this.name = name;\r\n        this.computer = computer;\r\n        this.owner = owner;\r\n        this.comment = comment;\r\n    }\r\n    \r\n    public Workspace(String name) {\r\n        this(name, \"\", \"\", \"\");\r\n    }\r\n\r\n    public String getName() {\r\n        return name;\r\n    }\r\n\r\n    public String getComputer() {\r\n        return computer;\r\n    }\r\n\r\n    public String getOwner() {\r\n        return owner;\r\n    }\r\n\r\n    public String getComment() {\r\n        return comment;\r\n    }\r\n\r\n    @Override\r\n    public int hashCode() {\r\n        return new HashCodeBuilder(13, 27).append(name).append(owner).append(computer).toHashCode();\r\n    }\r\n\r\n    @Override\r\n    public boolean equals(Object obj) {\r\n        if (this == obj)\r\n            return true;\r\n        if ((obj == null) || (getClass() != obj.getClass()))\r\n            return false;\r\n        final Workspace other = (Workspace) obj;\r\n        EqualsBuilder builder = new EqualsBuilder();\r\n        builder.append(this.name, other.name);\r\n        builder.append(this.owner, other.owner);\r\n        builder.append(this.computer, other.computer);\r\n        return builder.isEquals();\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/WorkspaceConfiguration.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.Collection;\r\n\r\nimport hudson.model.InvisibleAction;\r\n\r\n/**\r\n * An action for storing TFS configuration data in a build \r\n * \r\n * @author Erik Ramfelt, redsolo\r\n */\r\npublic class WorkspaceConfiguration extends InvisibleAction implements Serializable {\r\n\r\n    private static final long serialVersionUID = 1L;\r\n    \r\n    private final String workspaceName;\r\n    private final String workfolder;\r\n    private final String projectPath;\r\n    private final String serverUrl;\r\n    private boolean workspaceExists;\r\n    private Collection<String> cloakedPaths;\r\n\r\n    public WorkspaceConfiguration(String serverUrl, String workspaceName, String projectPath, Collection<String> cloakedPaths, String workfolder) {\r\n        this.workspaceName = workspaceName;\r\n        this.workfolder = workfolder;\r\n        this.projectPath = projectPath;\r\n        this.serverUrl = serverUrl;\r\n        this.workspaceExists = true;\r\n        this.cloakedPaths = cloakedPaths;\r\n    }\r\n\r\n    public WorkspaceConfiguration(WorkspaceConfiguration configuration) {\r\n        this.workspaceName = configuration.workspaceName;\r\n        this.workfolder = configuration.workfolder;\r\n        this.projectPath = configuration.projectPath;\r\n        this.serverUrl = configuration.serverUrl;\r\n        this.workspaceExists = configuration.workspaceExists;\r\n        this.cloakedPaths = configuration.cloakedPaths;\r\n    }\r\n\r\n    public String getWorkspaceName() {\r\n        return workspaceName;\r\n    }\r\n\r\n    public String getWorkfolder() {\r\n        return workfolder;\r\n    }\r\n\r\n    public String getProjectPath() {\r\n        return projectPath;\r\n    }\r\n\r\n    public String getServerUrl() {\r\n        return serverUrl;\r\n    }\r\n    \r\n    public boolean workspaceExists() {\r\n        return workspaceExists;\r\n    }\r\n    \r\n    public void setWorkspaceWasRemoved() {\r\n        this.workspaceExists = false;\r\n    }\r\n\r\n    public Collection<String> getCloakedPaths() {\r\n        return cloakedPaths;\r\n    }\r\n\r\n    @Override\r\n    public int hashCode() {\r\n        final int prime = 31;\r\n        int result = 1;\r\n        result = prime * result + ((projectPath == null) ? 0 : projectPath.hashCode());\r\n        result = prime * result + ((serverUrl == null) ? 0 : serverUrl.hashCode());\r\n        result = prime * result + ((workfolder == null) ? 0 : workfolder.hashCode());\r\n        result = prime * result + (workspaceExists ? 1231 : 1237);\r\n        result = prime * result + ((workspaceName == null) ? 0 : workspaceName.hashCode());\r\n        result = prime * result + ((cloakedPaths == null) ? 0 : cloakedPaths.hashCode());\r\n        return result;\r\n    }\r\n\r\n    @Override\r\n    public boolean equals(Object obj) {\r\n        if (this == obj)\r\n            return true;\r\n        if (obj == null)\r\n            return false;\r\n        if (!(obj instanceof WorkspaceConfiguration))\r\n            return false;\r\n        WorkspaceConfiguration other = (WorkspaceConfiguration) obj;\r\n        if (projectPath == null) {\r\n            if (other.projectPath != null)\r\n                return false;\r\n        } else if (!projectPath.equals(other.projectPath))\r\n            return false;\r\n        if (serverUrl == null) {\r\n            if (other.serverUrl != null)\r\n                return false;\r\n        } else if (!serverUrl.equals(other.serverUrl))\r\n            return false;\r\n        if (workfolder == null) {\r\n            if (other.workfolder != null)\r\n                return false;\r\n        } else if (!workfolder.equals(other.workfolder))\r\n            return false;\r\n        if (workspaceExists != other.workspaceExists)\r\n            return false;\r\n        if (workspaceName == null) {\r\n            if (other.workspaceName != null)\r\n                return false;\r\n        } else if (!workspaceName.equals(other.workspaceName))\r\n            return false;\r\n        if (cloakedPaths == null) {\r\n            if (other.cloakedPaths != null)\r\n                return false;\r\n        } else if (other.cloakedPaths == null)\r\n            return false;\r\n        else if (cloakedPaths.size() != other.cloakedPaths.size())\r\n            return false;\r\n        else if (!cloakedPaths.containsAll(other.cloakedPaths))\r\n            return false;\r\n        return true;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return String.format(\"WorkspaceConfiguration [projectPath=%s, serverUrl=%s, workfolder=%s, workspaceExists=%s, workspaceName=%s]\", \r\n                projectPath, serverUrl, workfolder, workspaceExists, workspaceName);\r\n    }    \r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/WorkspaceMapping.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\n/**\r\n * Mapping between a working folder and a project path that exists in a workspace.\r\n */\r\npublic class WorkspaceMapping {\r\n\r\n    private final String projectPath;\r\n    private final String localPath;\r\n\r\n    public WorkspaceMapping(final String projectPath, final String localPath) {\r\n        this.projectPath = projectPath;\r\n        this.localPath = localPath;\r\n    }\r\n\r\n    public String getProjectPath() {\r\n        return projectPath;\r\n    }\r\n\r\n    public String getLocalPath() {\r\n        return localPath;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/Workspaces.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.model;\r\n\r\nimport hudson.plugins.tfs.commands.DeleteWorkspaceCommand;\r\nimport hudson.plugins.tfs.commands.GetWorkspaceMappingCommand;\r\nimport hudson.plugins.tfs.commands.ListWorkspacesCommand;\r\nimport hudson.plugins.tfs.commands.NewWorkspaceCommand;\r\n\r\nimport java.util.Collection;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\n/**\r\n * Class that creates, deletes and gets workspaces from a TeamFoundationServer.\r\n * \r\n * @author Erik Ramfelt\r\n */\r\npublic class Workspaces implements ListWorkspacesCommand.WorkspaceFactory {\r\n\r\n    private Map<String,Workspace> workspaces = new HashMap<String,Workspace>();\r\n    private Server server;\r\n    private boolean mapIsPopulatedFromServer;\r\n\r\n    public Workspaces(Server server) {\r\n        this.server = server;\r\n    }\r\n\r\n    /**\r\n     * Get the list of workspaces from the server\r\n     * @return the list of workspaces at the server\r\n     */\r\n    private List<Workspace> getListFromServer() {\r\n        // the 2nd arg must NOT be provided, to force computerName resolution on the agent & not the master\r\n        ListWorkspacesCommand command = new ListWorkspacesCommand(server);\r\n        final List<Workspace> result = server.execute(command.getCallable());\r\n        return result;\r\n    }\r\n    \r\n    /**\r\n     * Populate the map field with workspaces from the server once.\r\n     */\r\n    private void populateMapFromServer() {\r\n        if (!mapIsPopulatedFromServer) {\r\n            for (Workspace workspace : getListFromServer()) {\r\n                workspaces.put(workspace.getName(), workspace);\r\n            }\r\n            mapIsPopulatedFromServer = true;\r\n        }\r\n    }\r\n    \r\n    /**\r\n     * Returns the workspace with the specified name\r\n     * @param workspaceName the name of the workspace name\r\n     * @return the workspace with the specified name; null if it wasnt found\r\n     */\r\n    public Workspace getWorkspace(String workspaceName) {\r\n        if (!workspaces.containsKey(workspaceName)) {\r\n            populateMapFromServer();\r\n        }\r\n        return workspaces.get(workspaceName);\r\n    }\r\n\r\n    /**\r\n     * Returns the if the workspace with the specified name exists on the server\r\n     * @param workspaceName the name of the workspace \r\n     * @return true if the workspace exists on server; false otherwise\r\n     */\r\n    public boolean exists(String workspaceName) {\r\n        if (!workspaces.containsKey(workspaceName)) {\r\n            populateMapFromServer();\r\n        }\r\n        return workspaces.containsKey(workspaceName);\r\n    }\r\n\r\n    /**\r\n     * Returns the if the workspace exists on the server\r\n     * @param workspace the workspace \r\n     * @return true if the workspace exists on server; false otherwise\r\n     */\r\n    public boolean exists(Workspace workspace) {\r\n        return exists(workspace.getName());\r\n    }\r\n\r\n    /**\r\n     * Returns the name of the workspace that mapped at the given localPath,\r\n     * if applicable.\r\n     *\r\n     * @param localPath the path where TFVC files would be downloaded\r\n     * @return the workspace name if there exists a mapping;\r\n     *          {@code null} otherwise.\r\n     */\r\n    public String getWorkspaceMapping(final String localPath) {\r\n        final GetWorkspaceMappingCommand command = new GetWorkspaceMappingCommand(server, localPath);\r\n        final String result = server.execute(command.getCallable());\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Create workspace on server, map it and return a workspace object with the specified name\r\n     * @param workspaceName the name of the new workspace\r\n     * @param serverPath the path in TFVC to map\r\n     * @param cloakedPaths the paths in TFVC to exclude from mapping\r\n     * @param localPath the path in the local filesystem to map\r\n     * @return a workspace\r\n     */\r\n    public Workspace newWorkspace(final String workspaceName, final String serverPath, Collection<String> cloakedPaths, final String localPath) {\r\n        NewWorkspaceCommand command = new NewWorkspaceCommand(server, workspaceName, serverPath, cloakedPaths, localPath);\r\n        server.execute(command.getCallable());\r\n        Workspace workspace = new Workspace(workspaceName);\r\n        workspaces.put(workspaceName, workspace);\r\n        return workspace;\r\n    }\r\n\r\n    /**\r\n     * Deletes the workspace from the server\r\n     * @param workspace the workspace to delete\r\n     */\r\n    public void deleteWorkspace(Workspace workspace) {\r\n        DeleteWorkspaceCommand command = new DeleteWorkspaceCommand(server, workspace.getName());\r\n        workspaces.remove(workspace.getName());\r\n        server.execute(command.getCallable());\r\n    }\r\n\r\n    public Workspace createWorkspace(String name, String computer, String owner, String comment) {\r\n        return new Workspace(name, computer, owner, comment);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/servicehooks/Event.java",
    "content": "package hudson.plugins.tfs.model.servicehooks;\r\n\r\nimport java.util.Map;\r\nimport java.util.UUID;\r\n\r\n/**\r\n * Encapsulates the properties of an event.\r\n */\r\npublic class Event {\r\n    private UUID id;\r\n    private String eventType;\r\n    private String publisherId;\r\n    private EventScope scope;\r\n    private FormattedEventMessage message;\r\n    private FormattedEventMessage detailedMessage;\r\n    private Object resource;\r\n    private String resourceVersion;\r\n    private Map<String, ResourceContainer> resourceContainers;\r\n\r\n    public Event() {\r\n\r\n    }\r\n\r\n    public UUID getId() {\r\n        return id;\r\n    }\r\n\r\n    public void setId(final UUID id) {\r\n        this.id = id;\r\n    }\r\n\r\n    public String getEventType() {\r\n        return eventType;\r\n    }\r\n\r\n    public void setEventType(final String eventType) {\r\n        this.eventType = eventType;\r\n    }\r\n\r\n    public String getPublisherId() {\r\n        return publisherId;\r\n    }\r\n\r\n    public void setPublisherId(final String publisherId) {\r\n        this.publisherId = publisherId;\r\n    }\r\n\r\n    public EventScope getScope() {\r\n        return scope;\r\n    }\r\n\r\n    public void setScope(final EventScope scope) {\r\n        this.scope = scope;\r\n    }\r\n\r\n    public FormattedEventMessage getMessage() {\r\n        return message;\r\n    }\r\n\r\n    public void setMessage(final FormattedEventMessage message) {\r\n        this.message = message;\r\n    }\r\n\r\n    public FormattedEventMessage getDetailedMessage() {\r\n        return detailedMessage;\r\n    }\r\n\r\n    public void setDetailedMessage(final FormattedEventMessage detailedMessage) {\r\n        this.detailedMessage = detailedMessage;\r\n    }\r\n\r\n    public Object getResource() {\r\n        return resource;\r\n    }\r\n\r\n    public void setResource(final Object resource) {\r\n        this.resource = resource;\r\n    }\r\n\r\n    public String getResourceVersion() {\r\n        return resourceVersion;\r\n    }\r\n\r\n    public void setResourceVersion(final String resourceVersion) {\r\n        this.resourceVersion = resourceVersion;\r\n    }\r\n\r\n    public Map<String, ResourceContainer> getResourceContainers() {\r\n        return resourceContainers;\r\n    }\r\n\r\n    public void setResourceContainers(final Map<String, ResourceContainer> resourceContainers) {\r\n        this.resourceContainers = resourceContainers;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/servicehooks/EventScope.java",
    "content": "package hudson.plugins.tfs.model.servicehooks;\r\n\r\nimport com.fasterxml.jackson.annotation.JsonCreator;\r\n\r\nimport java.util.Collections;\r\nimport java.util.Map;\r\nimport java.util.TreeMap;\r\n\r\n/**\r\n * Enum used to specify the scope of the incoming event from TFS/VSTS.\r\n */\r\npublic enum EventScope {\r\n    /**\r\n     * No input scope specified.\r\n     */\r\n    All,\r\n\r\n    /**\r\n     * Team Project scope.\r\n     */\r\n    Project,\r\n\r\n    /**\r\n     * Team scope.\r\n     */\r\n    Team,\r\n\r\n    /**\r\n     * Collection scope.\r\n     */\r\n    Collection,\r\n\r\n    /**\r\n     * Account scope.\r\n     */\r\n    Account,\r\n\r\n    /**\r\n     * Deployment scope.\r\n     */\r\n    Deployment;\r\n\r\n    private static final Map<String, EventScope> CASE_INSENSITIVE_LOOKUP;\r\n\r\n    static {\r\n        final Map<String, EventScope> map = new TreeMap<String, EventScope>(String.CASE_INSENSITIVE_ORDER);\r\n        for (final EventScope value : EventScope.values()) {\r\n            map.put(value.name(), value);\r\n        }\r\n        CASE_INSENSITIVE_LOOKUP = Collections.unmodifiableMap(map);\r\n    }\r\n\r\n    /**\r\n     * Use to compare event scopes to a string representation of the scope.\r\n     */\r\n    @SuppressWarnings(\"unused\" /* Invoked by Jackson via @JsonCreator */)\r\n    @JsonCreator\r\n    public static EventScope caseInsensitiveValueOf(final String name) {\r\n        if (name == null) {\r\n            throw new NullPointerException(\"Name is null\");\r\n        }\r\n        if (!CASE_INSENSITIVE_LOOKUP.containsKey(name)) {\r\n            throw new IllegalArgumentException(\"No enum constant \" + name);\r\n        }\r\n        return CASE_INSENSITIVE_LOOKUP.get(name);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/servicehooks/FormattedEventMessage.java",
    "content": "package hudson.plugins.tfs.model.servicehooks;\r\n\r\n/**\r\n * Provides different formats of an event message.\r\n */\r\npublic class FormattedEventMessage {\r\n    private String text;\r\n    private String html;\r\n    private String markdown;\r\n\r\n    public String getText() {\r\n        return text;\r\n    }\r\n\r\n    public void setText(final String text) {\r\n        this.text = text;\r\n    }\r\n\r\n    public String getHtml() {\r\n        return html;\r\n    }\r\n\r\n    public void setHtml(final String html) {\r\n        this.html = html;\r\n    }\r\n\r\n    public String getMarkdown() {\r\n        return markdown;\r\n    }\r\n\r\n    public void setMarkdown(final String markdown) {\r\n        this.markdown = markdown;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/model/servicehooks/ResourceContainer.java",
    "content": "package hudson.plugins.tfs.model.servicehooks;\r\n\r\nimport java.util.UUID;\r\n\r\n/**\r\n * The base class for all resource containers, i.e. Account, Collection, Project\r\n */\r\npublic class ResourceContainer {\r\n    private UUID id;\r\n    private String baseUrl;\r\n    private String url;\r\n    private String name;\r\n\r\n    public ResourceContainer() {\r\n\r\n    }\r\n\r\n    public UUID getId() {\r\n        return id;\r\n    }\r\n\r\n    public void setId(final UUID id) {\r\n        this.id = id;\r\n    }\r\n\r\n    public String getBaseUrl() {\r\n        return baseUrl;\r\n    }\r\n\r\n    public void setBaseUrl(final String baseUrl) {\r\n        this.baseUrl = baseUrl;\r\n    }\r\n\r\n    public String getUrl() {\r\n        return url;\r\n    }\r\n\r\n    public void setUrl(final String url) {\r\n        this.url = url;\r\n    }\r\n\r\n    public String getName() {\r\n        return name;\r\n    }\r\n\r\n    public void setName(final String name) {\r\n        this.name = name;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/Artifact.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class Artifact\n{\n\n    private Integer id;\n    private String type;\n    private String alias;\n    private DefinitionReference definitionReference;\n    private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n    * \n    * @return\n    * The id\n    */\n    public Integer getId()\n    {\n        return id;\n    }\n\n    /**\n    * \n    * @param id\n    * The id\n    */\n    public void setId(Integer id)\n    {\n        this.id = id;\n    }\n\n    /**\n    * \n    * @return\n    * The type\n    */\n    public String getType()\n    {\n        return type;\n    }\n\n    /**\n    * \n    * @param type\n    * The type\n    */\n    public void setType(String type)\n    {\n        this.type = type;\n    }\n\n    /**\n    * \n    * @return\n    * The alias\n    */\n    public String getAlias()\n    {\n        return alias;\n    }\n\n    /**\n    * \n    * @param alias\n    * The alias\n    */\n    public void setAlias(String alias)\n    {\n        this.alias = alias;\n    }\n\n    /**\n    * \n    * @return\n    * The definitionReference\n    */\n    public DefinitionReference getDefinitionReference()\n    {\n        return definitionReference;\n    }\n\n    /**\n    * \n    * @param definitionReference\n    * The definitionReference\n    */\n    public void setDefinitionReference(DefinitionReference definitionReference)\n    {\n        this.definitionReference = definitionReference;\n    }\n\n    public Map<String, Object> getAdditionalProperties()\n    {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value)\n    {\n        this.additionalProperties.put(name, value);\n    }\n\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ArtifactVersion.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n *\n * @author angoya\n */\npublic class ArtifactVersion \n{\n    private Object sourceId;\n    private String alias;\n    private List<Version> versions = new ArrayList<Version>();\n    private Object errorMessage;\n\n    /**\n    * \n    * @return\n    * The sourceId\n    */\n    public Object getSourceId()\n    {\n        return sourceId;\n    }\n\n    /**\n    * \n    * @param sourceId\n    * The sourceId\n    */\n    public void setSourceId(Object sourceId)\n    {\n        this.sourceId = sourceId;\n    }\n\n    /**\n    * \n    * @return\n    * The alias\n    */\n    public String getAlias()\n    {\n        return alias;\n    }\n\n    /**\n    * \n    * @param alias\n    * The alias\n    */\n    public void setAlias(String alias)\n    {\n        this.alias = alias;\n    }\n\n    /**\n    * \n    * @return\n    * The versions\n    */\n    public List<Version> getVersions()\n    {\n        return versions;\n    }\n\n    /**\n    * \n    * @param versions\n    * The versions\n    */\n    public void setVersions(List<Version> versions)\n    {\n        this.versions = versions;\n    }\n\n    /**\n    * \n    * @return\n    * The errorMessage\n    */\n    public Object getErrorMessage()\n    {\n        return errorMessage;\n    }\n\n    /**\n    * \n    * @param errorMessage\n    * The errorMessage\n    */\n    public void setErrorMessage(Object errorMessage)\n    {\n        this.errorMessage = errorMessage;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ConnectReleaseWebHookEvent.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport hudson.model.AbstractProject;\nimport hudson.model.Descriptor;\nimport hudson.model.Item;\nimport hudson.plugins.tfs.TeamPluginGlobalConfig;\nimport hudson.plugins.tfs.model.AbstractHookEvent;\nimport hudson.plugins.tfs.model.servicehooks.Event;\nimport hudson.tasks.Publisher;\nimport hudson.util.DescribableList;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.security.InvalidParameterException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.logging.Logger;\nimport jenkins.model.Jenkins;\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\nimport org.apache.commons.lang.StringUtils;\n\n/**\n * This HookEvent is for to create/delete Release Webhook.\n*/\npublic class ConnectReleaseWebHookEvent extends AbstractHookEvent {\n\n    private static final Logger logger = Logger.getLogger(ReleaseWebHookAction.class.getName());\n    private static final String CREATE_WEBHOOK_EVENTNAME = \"rmwebhook-create\";\n    private static final String REMOVE_WEBHOOK_ENENTNAME = \"rmwebhook-remove\";\n    private static final String LIST_WEBHOOK_EVENTNAME = \"rmwebhook-list\";\n    private static final String LINK_WEBHOOK_EVENTNAME = \"rmwebhook-link\";\n    private static final String UNLINK_WEBHOOK_EVENTNAME = \"rmwebhook-unlink\";\n\n    /**\n     * Factory to create ConnectReleaseWebHookEvent.\n     */\n    public static class Factory implements AbstractHookEvent.Factory {\n        @Override\n        public ConnectReleaseWebHookEvent create() {\n            return new ConnectReleaseWebHookEvent();\n        }\n\n        @Override\n        public String getSampleRequestPayload() {\n            return \"{\\n\"\n                 + \"    \\\"eventType\\\": rmwebhook-create\\n\"\n                 + \"    \\\"resource\\\": {\"\n                 + \"       \\\"webhookName\\\": \\\"webhook name\\\"\\n\"\n                 + \"       \\\"payloadUrl\\\": \\\"https://xplatalm.visualstudio.com/_apis/Release/receiveExternalEvent/wenhookId\\\"\\n\"\n                 + \"       \\\"secret\\\": \\\"secret\\\"\\n\"\n                 + \"     }\"\n                 + \"}\";\n        }\n    }\n\n    @Override\n    public JSONObject perform(final ObjectMapper mapper, final Event event, final String message, final String detailedMessage) {\n        final Object resource = event.getResource();\n        final ReleaseWebHookResource parameters = mapper.convertValue(resource, ReleaseWebHookResource.class);\n\n        if (event.getEventType().equalsIgnoreCase(CREATE_WEBHOOK_EVENTNAME)) {\n            createReleaseWebHook(parameters);\n        } else if (event.getEventType().equalsIgnoreCase(REMOVE_WEBHOOK_ENENTNAME)) {\n            deleteReleaseWebHook(parameters);\n        } else if (event.getEventType().equalsIgnoreCase(LIST_WEBHOOK_EVENTNAME)) {\n            return listReleaseWebHook();\n        } else if (event.getEventType().equalsIgnoreCase(LINK_WEBHOOK_EVENTNAME)) {\n            linkWebHook(parameters);\n        } else if (event.getEventType().equalsIgnoreCase(UNLINK_WEBHOOK_EVENTNAME)) {\n            unlinkWebHook(parameters);\n        } else {\n            throw new UnsupportedOperationException(\"Webhook operation \" + parameters.getOperationType() + \" is not supported\");\n        }\n\n        return JSONObject.fromObject(event);\n    }\n\n    private String validateAndGetPayloadUrl(final ReleaseWebHookResource parameters) {\n        String payloadUrl = parameters.getPayloadUrl();\n\n        if (StringUtils.isBlank(payloadUrl)) {\n            throw new InvalidParameterException(\"PayloadUrl is empty\");\n        }\n\n        final URI uri;\n        try {\n            uri = new URI(payloadUrl);\n        } catch (final URISyntaxException e) {\n            throw new InvalidParameterException(\"Malformed Payload URL \" + e.getMessage());\n        }\n\n        final String hostName = uri.getHost();\n        if (StringUtils.isBlank(hostName)) {\n            throw new InvalidParameterException(\"Payload URL is empty\");\n        }\n\n        return StringUtils.stripEnd(StringUtils.trim(payloadUrl), \"/\");\n    }\n\n    private AbstractProject validateAndGetJenkinsProject(final ReleaseWebHookResource resource) {\n        String projectName = resource.getProjectName();\n\n        if (StringUtils.isBlank(projectName)) {\n            throw new InvalidParameterException(\"Project name is empty\");\n        }\n\n        for (final Item project : Jenkins.getActiveInstance().getAllItems()) {\n            if (project instanceof AbstractProject && project.getFullName().equalsIgnoreCase(projectName)) {\n                return (AbstractProject) project;\n            }\n        }\n\n        throw new InvalidParameterException(\"Cannot find Jenkins Project with the name \" + resource.getProjectName());\n    }\n\n    private ReleaseWebHook validateAndGetReleaseWebHookByName(final String webHookName) {\n        ReleaseWebHook webHook = null;\n        for (ReleaseWebHook webHookItem : ReleaseWebHookHelper.getReleaseWebHookConfigurations()) {\n            if (webHookItem.getWebHookName().equalsIgnoreCase(webHookName)) {\n                webHook = webHookItem;\n                logger.fine(String.format(\"WebHook found for webhook name %s\", webHookName));\n                break;\n            }\n        }\n\n        if (webHook == null) {\n            throw new InvalidParameterException(String.format(\"Cannot find webhook with the name %s\", webHookName));\n        }\n\n        return webHook;\n    }\n\n    private void createReleaseWebHook(final ReleaseWebHookResource resource) {\n        if (resource == null) {\n            throw new InvalidParameterException(\"resource is null\");\n        }\n\n        String payloadUrl = validateAndGetPayloadUrl(resource);\n        String secret = resource.getSecret();\n        String webHookName = resource.getWebHookName();\n\n        if (StringUtils.isBlank(webHookName)) {\n            throw new InvalidParameterException(\"webhook name is empty\");\n        }\n\n        List<ReleaseWebHook> releaseWebHooks = ReleaseWebHookHelper.getReleaseWebHookConfigurations();\n        for (ReleaseWebHook webHook : releaseWebHooks) {\n            if (webHook.getWebHookName().equalsIgnoreCase(webHookName)) {\n                if (webHook.getPayloadUrl().equalsIgnoreCase(payloadUrl)) {\n                    logger.fine(String.format(\"WebHook with the name %s and payloadUrl %s already exists\", webHookName, payloadUrl));\n                    return;\n                } else {\n                    throw new InvalidParameterException(String.format(\"WebHook with the name %s already exists. Provide a unique name for the ReleaseWebHook\", webHookName));\n                }\n            }\n        }\n\n        ReleaseWebHook webHook = new ReleaseWebHook(webHookName, payloadUrl, secret);\n        releaseWebHooks.add(webHook);\n        ReleaseWebHookHelper.saveReleaseWebHookConfigurations(releaseWebHooks);\n    }\n\n    private void deleteReleaseWebHook(final ReleaseWebHookResource resource) {\n        if (resource == null) {\n            throw new InvalidParameterException(\"resource is null\");\n        }\n\n        final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\n        if (config == null) {\n            throw new InternalError(\"Cannot load TFS global configuration\");\n        }\n\n        String webHookNameToDelete = resource.getWebHookName();\n        ReleaseWebHook webHook = validateAndGetReleaseWebHookByName(webHookNameToDelete);\n\n        for (final Item projectItem : Jenkins.getActiveInstance().getAllItems()) {\n            if (projectItem instanceof AbstractProject) {\n                AbstractProject project = (AbstractProject) projectItem;\n\n                ReleaseWebHookAction action = getReleaseWebHookActionFromProject(project);\n                if (action != null) {\n                    for (ReleaseWebHookReference webHookReference : action.getWebHookReferences()) {\n                        if (webHookReference.getWebHookName().equalsIgnoreCase(webHookNameToDelete)) {\n                            throw new UnsupportedOperationException(String.format(\"WebHook %s is referenced in project %s. Cannot delete until all the references are removed.\", webHookNameToDelete, project.getName()));\n                        }\n                    }\n                }\n            }\n        }\n\n        List<ReleaseWebHook> releaseWebHooks = ReleaseWebHookHelper.getReleaseWebHookConfigurations();\n        releaseWebHooks.remove(webHook);\n        ReleaseWebHookHelper.saveReleaseWebHookConfigurations(releaseWebHooks);\n    }\n\n    private JSONObject listReleaseWebHook() {\n        JSONArray webHooks = new JSONArray();\n\n        for (ReleaseWebHook webHookConfig : ReleaseWebHookHelper.getReleaseWebHookConfigurations()) {\n            JSONObject webHook = new JSONObject();\n            webHook.put(\"WebHookName\", webHookConfig.getWebHookName());\n            webHook.put(\"PayloadUrl\", webHookConfig.getPayloadUrl());\n\n            webHooks.add(webHook);\n        }\n\n        JSONObject result = new JSONObject();\n        result.put(\"ReleaseWebHooks\", webHooks);\n\n        return result;\n    }\n\n    private void linkWebHook(final ReleaseWebHookResource resource) {\n        if (resource == null) {\n            throw new InvalidParameterException(\"resource is null\");\n        }\n\n        AbstractProject project = validateAndGetJenkinsProject(resource);\n        String webHookNameToLink = resource.getWebHookName();\n\n        // validate the webhook exists in the server config\n        ReleaseWebHook webHook = validateAndGetReleaseWebHookByName(webHookNameToLink);\n\n        ReleaseWebHookAction action = getReleaseWebHookActionFromProject(project);\n\n        if (action != null && action.getWebHookReferences() != null) {\n            for (ReleaseWebHookReference webHookReference : action.getWebHookReferences()) {\n                if (webHookReference.getWebHookName().equalsIgnoreCase(webHookNameToLink)) {\n                    logger.fine(String.format(\"WebHook %s already added in the project %s\", webHookNameToLink, project.getName()));\n                    return;\n                }\n            }\n        }\n\n        ReleaseWebHookReference webHookReference = new ReleaseWebHookReference(webHookNameToLink);\n\n        if (action == null) {\n            List<ReleaseWebHookReference> webHookReferences = new ArrayList<ReleaseWebHookReference>();\n            webHookReferences.add(webHookReference);\n\n            action = new ReleaseWebHookAction(webHookReferences);\n            DescribableList<Publisher, Descriptor<Publisher>> publishersList = project.getPublishersList();\n            publishersList.add(action);\n        } else {\n            List<ReleaseWebHookReference> webHookReferences = action.getWebHookReferences();\n            if (webHookReferences == null) {\n                webHookReferences = new ArrayList<ReleaseWebHookReference>();\n            }\n\n            webHookReferences.add(webHookReference);\n            action.setWebHookReferences(webHookReferences);\n\n            logger.fine(String.format(\"WebHook %s is linked to project %s\", webHookReference, project));\n        }\n\n        saveProject(project);\n    }\n\n    private void unlinkWebHook(final ReleaseWebHookResource resource) {\n        if (resource == null) {\n            throw new InvalidParameterException(\"resource is null\");\n        }\n\n        AbstractProject project = validateAndGetJenkinsProject(resource);\n        String webHookNameToUnlink = resource.getWebHookName();\n\n        if (StringUtils.isBlank(webHookNameToUnlink)) {\n            throw new InvalidParameterException(\"webhook name is empty\");\n        }\n\n        ReleaseWebHookAction action = getReleaseWebHookActionFromProject(project);\n\n        if (action == null) {\n            logger.fine(String.format(\"Cannot find ReleaseWebHook post build action\"));\n            return;\n        }\n\n        List<ReleaseWebHookReference> webHookReferences = action.getWebHookReferences();\n        for (ReleaseWebHookReference webHookReference : webHookReferences) {\n            if (webHookReference.getWebHookName().equalsIgnoreCase(webHookNameToUnlink)) {\n                logger.fine(String.format(\"Found webhook %s in project %s. Removing it\", webHookNameToUnlink, project.getName()));\n\n                webHookReferences.remove(webHookReference);\n                if (webHookReferences.isEmpty()) {\n                    // no webhook exists, removing the post build action itself\n                    logger.fine(String.format(\"ReleaseWebHook post build action is empty, removing the post build action from project\"));\n                    DescribableList<Publisher, Descriptor<Publisher>> publishersList = project.getPublishersList();\n                    publishersList.remove(action);\n                }\n\n                saveProject(project);\n                return;\n            }\n        }\n\n        logger.fine(String.format(\"Cannnot find webhook with the name %s in project %s\", webHookNameToUnlink, project.getName()));\n    }\n\n    private ReleaseWebHookAction getReleaseWebHookActionFromProject(final AbstractProject project) {\n        if (project == null) {\n            return null;\n        }\n\n        ReleaseWebHookAction action = null;\n        DescribableList<Publisher, Descriptor<Publisher>> publishersList = project.getPublishersList();\n\n        for (Publisher publisher : publishersList) {\n            if (publisher instanceof ReleaseWebHookAction) {\n                action = (ReleaseWebHookAction) publisher;\n            }\n        }\n\n        return action;\n    }\n\n    private void saveProject(final AbstractProject project) {\n        if (project != null) {\n            try {\n                project.save();\n            } catch (IOException ex) {\n                throw new InternalError(String.format(\"Updating project %s failed with an error %s\", project.getName(), ex.getMessage()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/CreatedBy.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class CreatedBy\n{\n\n    private String id;\n    private String displayName;\n    private String uniqueName;\n    private String url;\n    private String imageUrl;\n    private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n    * \n    * @return\n    * The id\n    */\n    public String getId()\n    {\n        return id;\n    }\n\n    /**\n    * \n    * @param id\n    * The id\n    */\n    public void setId(String id)\n    {\n        this.id = id;\n    }\n\n    /**\n    * \n    * @return\n    * The displayName\n    */\n    public String getDisplayName()\n    {\n        return displayName;\n    }\n\n    /**\n    * \n    * @param displayName\n    * The displayName\n    */\n    public void setDisplayName(String displayName)\n    {\n        this.displayName = displayName;\n    }\n\n    /**\n    * \n    * @return\n    * The uniqueName\n    */\n    public String getUniqueName()\n    {\n        return uniqueName;\n    }\n\n    /**\n    * \n    * @param uniqueName\n    * The uniqueName\n    */\n    public void setUniqueName(String uniqueName)\n    {\n        this.uniqueName = uniqueName;\n    }\n\n    /**\n    * \n    * @return\n    * The url\n    */\n    public String getUrl()\n    {\n        return url;\n    }\n\n    /**\n    * \n    * @param url\n    * The url\n    */\n    public void setUrl(String url)\n    {\n        this.url = url;\n    }\n\n    /**\n    * \n    * @return\n    * The imageUrl\n    */\n    public String getImageUrl()\n    {\n        return imageUrl;\n    }\n\n    /**\n    * \n    * @param imageUrl\n    * The imageUrl\n    */\n    public void setImageUrl(String imageUrl)\n    {\n        this.imageUrl = imageUrl;\n    }\n\n    public Map<String, Object> getAdditionalProperties()\n    {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value)\n    {\n        this.additionalProperties.put(name, value);\n    }\n\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/Definition.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class Definition\n{\n\n    private String id;\n    private String name;\n    private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n    * \n    * @return\n    * The id\n    */\n    public String getId()\n    {\n        return id;\n    }\n\n    /**\n    * \n    * @param id\n    * The id\n    */\n    public void setId(String id)\n    {\n        this.id = id;\n    }\n\n    /**\n    * \n    * @return\n    * The name\n    */\n    public String getName()\n    {\n        return name;\n    }\n\n    /**\n    * \n    * @param name\n    * The name\n    */\n    public void setName(String name)\n    {\n        this.name = name;\n    }\n\n    public Map<String, Object> getAdditionalProperties()\n    {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value)\n    {\n        this.additionalProperties.put(name, value);\n    }\n\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/DefinitionReference.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class DefinitionReference\n{\n\n    private Definition definition;\n    private Project project;\n    private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n    * \n    * @return\n    * The definition\n    */\n    public Definition getDefinition()\n    {\n        return definition;\n    }\n\n    /**\n    * \n    * @param definition\n    * The definition\n    */\n    public void setDefinition(Definition definition)\n    {\n        this.definition = definition;\n    }\n\n    /**\n    * \n    * @return\n    * The project\n    */\n    public Project getProject()\n    {\n        return project;\n    }\n\n    /**\n    * \n    * @param project\n    * The project\n    */\n    public void setProject(Project project)\n    {\n        this.project = project;\n    }\n\n    public Map<String, Object> getAdditionalProperties()\n    {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value)\n    {\n        this.additionalProperties.put(name, value);\n    }\n\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/InstanceReference.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport com.google.gson.annotations.SerializedName;\n\n/**\n *\n * @author angoya\n */\npublic class InstanceReference \n{\n    @SerializedName(\"name\")\n    private String name;\n    @SerializedName(\"id\")\n    private String id;\n    @SerializedName(\"sourceBranch\")\n    private String sourceBranch;\n\n    /**\n    * \n    * @return\n    * The name\n    */\n    public String getName()\n    {\n        return name;\n    }\n\n    /**\n    * \n    * @param name\n    * The name\n    */\n    public void setName(String name)\n    {\n        this.name = name;\n    }\n\n    /**\n    * \n    * @return\n    * The id\n    */\n    public String getId()\n    {\n        return id;\n    }\n\n    /**\n    * \n    * @param id\n    * The id\n    */\n    public void setId(String id)\n    {\n        this.id = id;\n    }\n\n    /**\n    * \n    * @return\n    * The sourceBranch\n    */\n    public String getSourceBranch()\n    {\n        return sourceBranch;\n    }\n\n    /**\n    * \n    * @param sourceBranch\n    * The sourceBranch\n    */\n    public void setSourceBranch(String sourceBranch)\n    {\n        this.sourceBranch = sourceBranch;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ModifiedBy.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\npublic class ModifiedBy {\n\n    private String id;\n    private String displayName;\n    private String uniqueName;\n    private String url;\n    private String imageUrl;\n    private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n     *\n     * @return The id\n     */\n    public String getId() {\n        return id;\n    }\n\n    /**\n     *\n     * @param id The id\n     */\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    /**\n     *\n     * @return The displayName\n     */\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    /**\n     *\n     * @param displayName The displayName\n     */\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    /**\n     *\n     * @return The uniqueName\n     */\n    public String getUniqueName() {\n        return uniqueName;\n    }\n\n    /**\n     *\n     * @param uniqueName The uniqueName\n     */\n    public void setUniqueName(String uniqueName) {\n        this.uniqueName = uniqueName;\n    }\n\n    /**\n     *\n     * @return The url\n     */\n    public String getUrl() {\n        return url;\n    }\n\n    /**\n     *\n     * @param url The url\n     */\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    /**\n     *\n     * @return The imageUrl\n     */\n    public String getImageUrl() {\n        return imageUrl;\n    }\n\n    /**\n     *\n     * @param imageUrl The imageUrl\n     */\n    public void setImageUrl(String imageUrl) {\n        this.imageUrl = imageUrl;\n    }\n\n    public Map<String, Object> getAdditionalProperties() {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value) {\n        this.additionalProperties.put(name, value);\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/Project.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class Project \n{\n\n    private String id;\n    private String name;\n    private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n    * \n    * @return\n    * The id\n    */\n    public String getId()\n    {\n        return id;\n    }\n\n    /**\n    * \n    * @param id\n    * The id\n    */\n    public void setId(String id)\n    {\n        this.id = id;\n    }\n\n    /**\n    * \n    * @return\n    * The name\n    */\n    public String getName()\n    {\n        return name;\n    }\n\n    /**\n    * \n    * @param name\n    * The name\n    */\n    public void setName(String name)\n    {\n        this.name = name;\n    }\n\n    public Map<String, Object> getAdditionalProperties()\n    {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value)\n    {\n        this.additionalProperties.put(name, value);\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseArtifact.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport com.google.gson.annotations.SerializedName;\n\n/**\n *\n * @author angoya\n */\npublic class ReleaseArtifact \n{\n\n    @SerializedName(\"alias\")\n    private String alias;\n    @SerializedName(\"instanceReference\")\n    private InstanceReference instanceReference;\n\n    /**\n    * \n    * @return\n    * The alias\n    */\n    public String getAlias()\n    {\n        return alias;\n    }\n\n    /**\n    * \n    * @param alias\n    * The alias\n    */\n    public void setAlias(String alias)\n    {\n        this.alias = alias;\n    }\n\n    /**\n    * \n    * @return\n    * The instanceReference\n    */\n    public InstanceReference getInstanceReference()\n    {\n        return instanceReference;\n    }\n\n    /**\n    * \n    * @param instanceReference\n    * The instanceReference\n    */\n    public void setInstanceReference(InstanceReference instanceReference)\n    {\n        this.instanceReference = instanceReference;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseArtifactVersionsResponse.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n *\n * @author angoya\n */\npublic class ReleaseArtifactVersionsResponse \n{\n    private List<ArtifactVersion> artifactVersions = new ArrayList<ArtifactVersion>();\n\n    /**\n    * \n    * @return\n    * The artifactVersions\n    */\n    public List<ArtifactVersion> getArtifactVersions()\n    {\n        return artifactVersions;\n    }\n\n    /**\n    * \n    * @param artifactVersions\n    * The artifactVersions\n    */\n    public void setArtifactVersions(List<ArtifactVersion> artifactVersions)\n    {\n        this.artifactVersions = artifactVersions;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseBody.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport com.google.gson.annotations.SerializedName;\n\n/**\n *\n * @author angoya\n */\npublic class ReleaseBody\n{\n    \n    @SerializedName(\"definitionId\")\n    private Integer definitionId;\n    @SerializedName(\"description\")\n    private String description;\n    @SerializedName(\"artifacts\")\n    private List<ReleaseArtifact> artifacts = new ArrayList<ReleaseArtifact>();\n    @SerializedName(\"isDraft\")\n    private Boolean isDraft;\n    @SerializedName(\"manualEnvironments\")\n    private List<Object> manualEnvironments = new ArrayList<Object>();\n\n    /**\n    * \n    * @return\n    * The definitionId\n    */\n    public Integer getDefinitionId()\n    {\n        return definitionId;\n    }\n\n    /**\n    * \n    * @param definitionId\n    * The definitionId\n    */\n    public void setDefinitionId(Integer definitionId)\n    {\n        this.definitionId = definitionId;\n    }\n\n    /**\n    * \n    * @return\n    * The description\n    */\n    public String getDescription()\n    {\n        return description;\n    }\n\n    /**\n    * \n    * @param description\n    * The description\n    */\n    public void setDescription(String description)\n    {\n        this.description = description;\n    }\n\n    /**\n    * \n    * @return\n    * The artifacts\n    */\n    public List<ReleaseArtifact> getArtifacts()\n    {\n        return artifacts;\n    }\n\n    /**\n    * \n    * @param artifacts\n    * The artifacts\n    */\n    public void setArtifacts(List<ReleaseArtifact> artifacts)\n    {\n        this.artifacts = artifacts;\n    }\n\n    /**\n    * \n    * @return\n    * The isDraft\n    */\n    public Boolean getIsDraft()\n    {\n        return isDraft;\n    }\n\n    /**\n    * \n    * @param isDraft\n    * The isDraft\n    */\n    public void setIsDraft(Boolean isDraft)\n    {\n        this.isDraft = isDraft;\n    }\n\n    /**\n    * \n    * @return\n    * The manualEnvironments\n    */\n    public List<Object> getManualEnvironments()\n    {\n        return manualEnvironments;\n    }\n\n    /**\n    * \n    * @param manualEnvironments\n    * The manualEnvironments\n    */\n    public void setManualEnvironments(List<Object> manualEnvironments)\n    {\n        this.manualEnvironments = manualEnvironments;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseDefinition.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class ReleaseDefinition\n{\n    private Integer id;\n    private Integer revision;\n    private String name;\n    private CreatedBy createdBy;\n    private String createdOn;\n    private ModifiedBy modifiedBy;\n    private String modifiedOn;\n    private List<Artifact> artifacts = new ArrayList<Artifact>();\n    private String releaseNameFormat;\n    private RetentionPolicy retentionPolicy;\n    private String url;\n    private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n    * \n    * @return\n    * The id\n    */\n    public Integer getId()\n    {\n        return id;\n    }\n\n    /**\n    * \n    * @param id\n    * The id\n    */\n    public void setId(Integer id)\n    {\n        this.id = id;\n    }\n\n    /**\n    * \n    * @return\n    * The revision\n    */\n    public Integer getRevision()\n    {\n        return revision;\n    }\n\n    /**\n    * \n    * @param revision\n    * The revision\n    */\n    public void setRevision(Integer revision)\n    {\n        this.revision = revision;\n    }\n\n    /**\n    * \n    * @return\n    * The name\n    */\n    public String getName()\n    {\n        return name;\n    }\n\n    /**\n    * \n    * @param name\n    * The name\n    */\n    public void setName(String name)\n    {\n        this.name = name;\n    }\n\n    /**\n    * \n    * @return\n    * The createdBy\n    */\n    public CreatedBy getCreatedBy()\n    {\n        return createdBy;\n    }\n\n    /**\n    * \n    * @param createdBy\n    * The createdBy\n    */\n    public void setCreatedBy(CreatedBy createdBy)\n    {\n        this.createdBy = createdBy;\n    }\n\n    /**\n    * \n    * @return\n    * The createdOn\n    */\n    public String getCreatedOn()\n    {\n        return createdOn;\n    }\n\n    /**\n    * \n    * @param createdOn\n    * The createdOn\n    */\n    public void setCreatedOn(String createdOn)\n    {\n        this.createdOn = createdOn;\n    }\n\n    /**\n    * \n    * @return\n    * The modifiedBy\n    */\n    public ModifiedBy getModifiedBy()\n    {\n        return modifiedBy;\n    }\n\n    /**\n    * \n    * @param modifiedBy\n    * The modifiedBy\n    */\n    public void setModifiedBy(ModifiedBy modifiedBy)\n    {\n        this.modifiedBy = modifiedBy;\n    }\n\n    /**\n    * \n    * @return\n    * The modifiedOn\n    */\n    public String getModifiedOn() \n    {\n        return modifiedOn;\n    }\n\n    /**\n    * \n    * @param modifiedOn\n    * The modifiedOn\n    */\n    public void setModifiedOn(String modifiedOn)\n    {\n        this.modifiedOn = modifiedOn;\n    }\n\n    /**\n    * \n    * @return\n    * The artifacts\n    */\n    public List<Artifact> getArtifacts()\n    {\n        return artifacts;\n    }\n\n    /**\n    * \n    * @param artifacts\n    * The artifacts\n    */\n    public void setArtifacts(List<Artifact> artifacts)\n    {\n        this.artifacts = artifacts;\n    }\n\n    /**\n    * \n    * @return\n    * The releaseNameFormat\n    */\n    public String getReleaseNameFormat()\n    {\n        return releaseNameFormat;\n    }\n\n    /**\n    * \n    * @param releaseNameFormat\n    * The releaseNameFormat\n    */\n    public void setReleaseNameFormat(String releaseNameFormat)\n    {\n        this.releaseNameFormat = releaseNameFormat;\n    }\n\n    /**\n    * \n    * @return\n    * The retentionPolicy\n    */\n    public RetentionPolicy getRetentionPolicy()\n    {\n        return retentionPolicy;\n    }\n\n    /**\n    * \n    * @param retentionPolicy\n    * The retentionPolicy\n    */\n    public void setRetentionPolicy(RetentionPolicy retentionPolicy)\n    {\n        this.retentionPolicy = retentionPolicy;\n    }\n\n    public String getUrl()\n    {\n        return url;\n    }\n\n\n    public void setUrl(String url)\n    {\n        this.url = url;\n    }\n\n    public Map<String, Object> getAdditionalProperties()\n    {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value)\n    {\n        this.additionalProperties.put(name, value);\n    }\n\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseManagementCI.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport com.cloudbees.plugins.credentials.common.StandardListBoxModel;\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\nimport com.google.gson.Gson;\nimport hudson.Launcher;\nimport hudson.Extension;\nimport hudson.model.AbstractBuild;\nimport hudson.model.AbstractProject;\nimport hudson.model.BuildListener;\nimport hudson.model.Item;\nimport hudson.model.Result;\nimport hudson.plugins.tfs.TeamCollectionConfiguration;\nimport hudson.tasks.BuildStepDescriptor;\nimport hudson.tasks.BuildStepMonitor;\nimport hudson.tasks.Notifier;\nimport hudson.tasks.Publisher;\nimport hudson.util.ListBoxModel;\nimport hudson.util.Secret;\nimport org.apache.commons.lang.StringUtils;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.kohsuke.stapler.AncestorInPath;\nimport org.kohsuke.stapler.DataBoundConstructor;\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.kohsuke.stapler.QueryParameter;\n\n/**\n * @author Ankit Goyal\n */\npublic class ReleaseManagementCI extends Notifier implements Serializable {\n\n    private static final long serialVersionUID = -760016860995557L;\n    private static final Logger logger = Logger.getLogger(ReleaseManagementCI.class.getName());\n\n\n    public final String collectionUrl;\n    public final String projectName;\n    public final String releaseDefinitionName;\n    public transient String username;\n    public transient Secret password;\n    public String credentialsId;\n\n\n    public ReleaseManagementCI(String collectionUrl, String projectName, String releaseDefinitionName, String username, Secret password)\n    {\n        if (collectionUrl.endsWith(\"/\"))\n        {\n            this.collectionUrl = collectionUrl;\n        }\n        else\n        {\n            this.collectionUrl = collectionUrl + \"/\";\n        }\n        \n        //this.collectionUrl = this.collectionUrl.toLowerCase().replaceFirst(\".visualstudio.com\", \".vsrm.visualstudio.com\");\n        this.projectName = projectName;\n        this.releaseDefinitionName = releaseDefinitionName;\n        this.username = username;\n        this.password = password;\n    }\n\n    // Fields in config.jelly must match the parameter names in the \"DataBoundConstructor\"\n    @DataBoundConstructor\n    public ReleaseManagementCI(String collectionUrl,\n                               String projectName,\n                               String releaseDefinitionName,\n                               String credentialsId) {\n        if (collectionUrl.endsWith(\"/\"))\n        {\n            this.collectionUrl = collectionUrl;\n        }\n        else\n        {\n            this.collectionUrl = collectionUrl + \"/\";\n        }\n\n        this.projectName = projectName;\n        this.releaseDefinitionName = releaseDefinitionName;\n        StandardUsernamePasswordCredentials credential = TeamCollectionConfiguration.findCredentialsById(credentialsId);\n        this.username = credential == null ? \"\" : credential.getUsername();\n        this.password = credential == null ? Secret.fromString(\"\") : credential.getPassword();\n        this.credentialsId = credentialsId;\n    }\n\n    protected Object readResolve() {\n        if (StringUtils.isNotBlank(collectionUrl)\n                && password != null\n                && StringUtils.isNotBlank(password.getPlainText())) {\n            try {\n                final URI uri = new URI(collectionUrl);\n                String hostName = uri.getHost();\n                List<StandardUsernamePasswordCredentials> credentials = TeamCollectionConfiguration.findCredentials(hostName);\n                for (StandardUsernamePasswordCredentials credential : credentials) {\n                    if ((StringUtils.isBlank(username) || credential.getUsername().equals(username))\n                            && credential.getPassword().getPlainText().equals(password.getPlainText())) {\n                        this.credentialsId = credential.getId();\n                        return this;\n                    }\n                }\n                this.credentialsId\n                        = TeamCollectionConfiguration.setCredentials(hostName, username, password.getPlainText());\n            } catch (Exception ex) {\n                logger.log(Level.WARNING,\n                        String.format(\"Get or generate credentials for collection url: %s and username: %s failed.\", collectionUrl, username),\n                        ex);\n            }\n        }\n        return this;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see hudson.tasks.BuildStep#getRequiredMonitorService()\n     */\n    @Override\n    public BuildStepMonitor getRequiredMonitorService() {\n        return BuildStepMonitor.NONE;\n    }\n\n        /*\n     * (non-Javadoc)\n     *\n     * @see\n     * hudson.tasks.BuildStepCompatibilityLayer#perform(hudson.model.AbstractBuild\n     * , hudson.Launcher, hudson.model.BuildListener)\n     */\n    @Override\n    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException\n    {\n        StandardUsernamePasswordCredentials credential = TeamCollectionConfiguration.findCredentialsById(credentialsId);\n        this.username = credential == null ? \"\" : credential.getUsername();\n        this.password = credential == null ? Secret.fromString(\"\") : credential.getPassword();\n\n        String jobName = build.getProject().getName();\n        int buildId = build.number;\n        String buildNumber = build.getDisplayName();\n        if (build.getResult() == Result.SUCCESS)\n        {\n            ReleaseManagementHttpClient releaseManagementHttpClient = \n                    new ReleaseManagementHttpClient(\n                            this.collectionUrl.toLowerCase().replaceFirst(\".visualstudio.com\", \".vsrm.visualstudio.com\"),\n                            this.username,\n                            this.password);\n            \n            try \n            {\n                ReleaseDefinition releaseDefinition = null;\n                List<ReleaseDefinition> releaseDefinitions = releaseManagementHttpClient.GetReleaseDefinitions(this.projectName);\n                for(final ReleaseDefinition rd : releaseDefinitions)\n                {\n                    if(rd.getName().equalsIgnoreCase(this.releaseDefinitionName))\n                    {\n                        releaseDefinition = rd;\n                        break;\n                    }\n                }\n\n                if(releaseDefinition == null)\n                {\n                    listener.getLogger().printf(\"No release definition found with name: %s%n\", this.releaseDefinitionName);\n                    listener.getLogger().println(\"Release will not be triggered.\");\n                }\n                else\n                {\n                    CreateRelease(releaseManagementHttpClient, releaseDefinition, jobName, buildNumber, buildId, listener, build, launcher);\n                }\n            }\n            catch (ReleaseManagementException ex)\n            {\n                ex.printStackTrace(listener.error(\"Failed to trigger release.%n\"));\n            }\n            catch (JSONException ex)\n            {\n                ex.printStackTrace(listener.error(\"Failed to trigger release.%n\"));\n            }\n        }\n        \n        return true;\n    }\n    \n    void CreateRelease(\n            ReleaseManagementHttpClient releaseManagementHttpClient,\n            ReleaseDefinition releaseDefinition,\n            String jobName,\n            String buildNumber,\n            int buildId,\n            BuildListener listener,\n            AbstractBuild<?, ?> build,\n            Launcher launcher) throws ReleaseManagementException, JSONException\n    {\n        Artifact jenkinsArtifact = null;\n        for(final Artifact artifact : releaseDefinition.getArtifacts())\n        {\n            if(artifact.getType().equalsIgnoreCase(\"jenkins\") && artifact.getDefinitionReference().getDefinition().getName().equalsIgnoreCase(jobName))\n            {\n                jenkinsArtifact = artifact;\n                break;\n            }\n        }\n        \n        if(jenkinsArtifact == null)\n        {\n            listener.getLogger().printf(\"No jenkins artifact found with name: %s%n\", jobName);\n        }\n        else\n        {\n            List<ReleaseArtifact> releaseArtifacts = PrepareReleaseArtifacts(\n                    releaseDefinition,\n                    jenkinsArtifact,\n                    buildNumber,\n                    buildId,\n                    listener,\n                    releaseManagementHttpClient);            \n            String description = \"Triggered by \" + buildNumber;\n            ReleaseBody releaseBody = new ReleaseBody();\n            releaseBody.setDescription(description);\n            releaseBody.setDefinitionId(releaseDefinition.getId());\n            releaseBody.setArtifacts(releaseArtifacts);\n            releaseBody.setIsDraft(false);\n            String body  = new Gson().toJson(releaseBody);\n\n            listener.getLogger().printf(\"Triggering release...%n\");\n            String response = releaseManagementHttpClient.CreateRelease(this.projectName, body);\n            listener.getLogger().printf(\"Successfully triggered release.%n\");\n            JSONObject object = new JSONObject(response);\n            listener.getLogger().printf(\"Release Name: %s%n\", object.getString(\"name\"));\n            listener.getLogger().printf(\"Release id: %s%n\", object.getString(\"id\"));\n            build.addAction(new ReleaseSummaryAction(jobName, buildId,\n                    object.getJSONObject(\"_links\").getJSONObject(\"web\").getString(\"href\")));\n        }\n    }\n\n    private List<ReleaseArtifact> PrepareReleaseArtifacts(ReleaseDefinition releaseDefinition, Artifact jenkinsArtifact, String buildNumber, int buildId, BuildListener listener, ReleaseManagementHttpClient releaseManagementHttpClient) throws ReleaseManagementException {\n        List<ReleaseArtifact> releaseArtifacts = new ArrayList<ReleaseArtifact>();\n        for(final Artifact artifact : releaseDefinition.getArtifacts())\n        {\n            ReleaseArtifact releaseArtifact = new ReleaseArtifact();\n            InstanceReference instanceReference = new InstanceReference();\n            if(artifact == jenkinsArtifact)\n            {\n                instanceReference.setName(buildNumber);\n                instanceReference.setId(Integer.toString(buildId));\n            }\n            else\n            {\n                listener.getLogger().printf(\"Fetching latest version for artifact: %s%n\", artifact.getAlias());\n                ReleaseArtifactVersionsResponse response = releaseManagementHttpClient.GetVersions(this.projectName, new ArrayList<Artifact>(Arrays.asList(artifact)));\n                if(response.getArtifactVersions().isEmpty())\n                {\n                    throw new ReleaseManagementException(\"Could not fetch versions for the linked artifact sources\");\n                }\n                if(response.getArtifactVersions().get(0).getVersions().isEmpty())\n                {\n                    throw new ReleaseManagementException(\"Could not fetch versions for the linked artifact: \" + artifact.getAlias());\n                }\n                \n                instanceReference.setName(response.getArtifactVersions().get(0).getVersions().get(0).getName());\n                instanceReference.setId(response.getArtifactVersions().get(0).getVersions().get(0).getId());\n            }\n            \n            releaseArtifact.setAlias(artifact.getAlias());\n            releaseArtifact.setInstanceReference(instanceReference);\n            releaseArtifacts.add(releaseArtifact);\n        }\n        return releaseArtifacts;\n    }\n    \n    @Extension\n    public static final class DescriptorImpl extends BuildStepDescriptor<Publisher>\n    {\n\n        /*\n         * (non-Javadoc)\n         *\n         * @see hudson.tasks.BuildStepDescriptor#isApplicable(java.lang.Class)\n         */\n        @Override\n        public boolean isApplicable(Class<? extends AbstractProject> jobType) \n        {\n            return true;\n        }\n\n        /*\n         * (non-Javadoc)\n         *\n         * @see hudson.model.Descriptor#getDisplayName()\n         */\n        @Override\n        public String getDisplayName() \n        {\n            return \"Trigger release in Azure Devops Server/Services\";\n        }\n\n        public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item owner,\n                                                     @QueryParameter String collectionUrl) {\n            StandardListBoxModel listBoxModel = new StandardListBoxModel();\n            listBoxModel.withEmptySelection();\n            String hostName = null;\n            try {\n                final URI uri = new URI(collectionUrl);\n                hostName = uri.getHost();\n            }\n            catch (final URISyntaxException ignored) {\n            }\n            listBoxModel.withAll(TeamCollectionConfiguration.findCredentials(hostName, owner));\n            return listBoxModel;\n        }\n\n        public ListBoxModel doFillProjectNameItems(@QueryParameter String collectionUrl,\n                                                   @QueryParameter String credentialsId) {\n            StandardListBoxModel listBoxModel = new StandardListBoxModel();\n            listBoxModel.withEmptySelection();\n\n            if (StringUtils.isBlank(collectionUrl) || StringUtils.isBlank(credentialsId)) {\n                return listBoxModel;\n            }\n\n            StandardUsernamePasswordCredentials credential\n                    = TeamCollectionConfiguration.findCredentialsById(credentialsId);\n            if (credential == null) {\n                return listBoxModel;\n            }\n\n            String username = credential.getUsername();\n            Secret password = credential.getPassword();\n\n            try {\n                ReleaseManagementHttpClient releaseManagementHttpClient =\n                        new ReleaseManagementHttpClient(\n                                collectionUrl.toLowerCase(),\n                                username,\n                                password);\n\n                List<Project> projects = releaseManagementHttpClient.GetProjectItems();\n                for (Project project : projects) {\n                    listBoxModel.add(project.getName());\n                }\n            } catch (ReleaseManagementException ex) {\n                logger.log(Level.WARNING,\n                        String.format(\"Get team project for collection url: %s failed.\", collectionUrl),\n                        ex);\n            }\n            return listBoxModel;\n        }\n\n        public ListBoxModel doFillReleaseDefinitionNameItems(@QueryParameter String collectionUrl,\n                                                             @QueryParameter String credentialsId,\n                                                             @QueryParameter String projectName) {\n            StandardListBoxModel listBoxModel = new StandardListBoxModel();\n            listBoxModel.withEmptySelection();\n\n            if (StringUtils.isBlank(collectionUrl)\n                    || StringUtils.isBlank(credentialsId)\n                    || StringUtils.isBlank(projectName)) {\n                return listBoxModel;\n            }\n\n            StandardUsernamePasswordCredentials credential\n                    = TeamCollectionConfiguration.findCredentialsById(credentialsId);\n            if (credential == null) {\n                return listBoxModel;\n            }\n            String username = credential.getUsername();\n            Secret password = credential.getPassword();\n\n            try {\n                ReleaseManagementHttpClient releaseManagementHttpClient =\n                        new ReleaseManagementHttpClient(\n                                collectionUrl.toLowerCase().replaceFirst(\".visualstudio.com\", \".vsrm.visualstudio.com\"),\n                                username,\n                                password);\n\n                List<ReleaseDefinition> releaseDefinitions = releaseManagementHttpClient.GetReleaseDefinitions(projectName);\n                for (ReleaseDefinition releaseDefinition : releaseDefinitions) {\n                    listBoxModel.add(releaseDefinition.getName());\n                }\n            } catch (ReleaseManagementException ex) {\n                logger.log(Level.WARNING,\n                        String.format(\"Get release definition for project: %s failed.\", projectName),\n                        ex);\n            }\n\n            return listBoxModel;\n        }\n\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseManagementException.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class ReleaseManagementException extends Exception\n{\n    public ReleaseManagementException()\n    {\n        super();\n    }\n\n    /**\n     * Constructs an {@code ReleaseManagementExcpetion} with the specified detail message.\n     *\n     * @param message\n     *        The detail message (which is saved for later retrieval\n     *        by the {@link #getMessage()} method)\n     */\n    public ReleaseManagementException(String message)\n    {\n        super(message);\n    }\n\n    /**\n     * Constructs an {@code ReleaseManagementExcpetion} with the specified detail message\n     * and cause.\n     *\n     * <p> Note that the detail message associated with {@code cause} is\n     * <i>not</i> automatically incorporated into this exception's detail\n     * message.\n     *\n     * @param message\n     *        The detail message (which is saved for later retrieval\n     *        by the {@link #getMessage()} method)\n     *\n     * @param cause\n     *        The cause (which is saved for later retrieval by the\n     *        {@link #getCause()} method).  (A null value is permitted,\n     *        and indicates that the cause is nonexistent or unknown.)\n     *\n     * @since 1.6\n     */\n    public ReleaseManagementException(String message, Throwable cause)\n    {\n        super(message, cause);\n    }\n\n    /**\n     * Constructs an {@code ReleaseManagementExcpetion} with the specified cause and a\n     * detail message of {@code (cause==null ? null : cause.toString())}\n     * (which typically contains the class and detail message of {@code cause}).\n     * This constructor is useful for IO exceptions that are little more\n     * than wrappers for other throwables.\n     *\n     * @param cause\n     *        The cause (which is saved for later retrieval by the\n     *        {@link #getCause()} method).  (A null value is permitted,\n     *        and indicates that the cause is nonexistent or unknown.)\n     *\n     * @since 1.6\n     */\n    public ReleaseManagementException(Throwable cause)\n    {\n        super(cause);\n    }    \n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseManagementHttpClient.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport com.google.gson.Gson;\nimport hudson.util.Secret;\n\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.httpclient.HttpClient;\nimport org.apache.commons.httpclient.methods.GetMethod;\nimport org.apache.commons.httpclient.methods.PostMethod;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class ReleaseManagementHttpClient\n{\n    private final HttpClient httpClient;\n    private final String username;\n    private final Secret password;\n    private final String accountUrl;\n    private final String basicAuth;\n    \n    ReleaseManagementHttpClient(String accountUrl, String username, Secret password)\n    {\n        this.accountUrl = accountUrl;\n        this.username = username;\n        this.password = password;\n        this.httpClient = new HttpClient();\n        this.basicAuth = \"Basic \" + new String(Base64.encodeBase64((this.username + \":\" + Secret.toString(this.password)).getBytes(Charset.defaultCharset())), Charset.defaultCharset());\n    }\n    \n    public List<ReleaseDefinition> GetReleaseDefinitions(String project) throws ReleaseManagementException\n    {\n        String url = this.accountUrl + project + \"/_apis/release/definitions?$expand=artifacts\";\n        String response = this.ExecuteGetMethod(url);\n        DefinitionResponse definitionResponse = new Gson().fromJson(response, DefinitionResponse.class);\n        return definitionResponse.getValue();\n    }\n    \n    public String CreateRelease(String project, String body) throws ReleaseManagementException\n    {\n        String url = this.accountUrl + project + \"/_apis/release/releases?api-version=3.0-preview.2\";\n        return this.ExecutePostmethod(url, body);\n    }\n    \n    public ReleaseArtifactVersionsResponse GetVersions(String project, List<Artifact> artifacts) throws ReleaseManagementException\n    {\n        String url = this.accountUrl + project + \"/_apis/release/artifacts/versions?api-version=3.0-preview.1\";\n        final String body = new Gson().toJson(artifacts);\n        String response = this.ExecutePostmethod(url, body);\n        return new Gson().fromJson(response, ReleaseArtifactVersionsResponse.class);\n    }\n\n    public List<Project> GetProjectItems() throws ReleaseManagementException\n    {\n        String url = this.accountUrl + \"/_apis/projects?api-version=1.0\";\n        String response = this.ExecuteGetMethod(url);\n        try {\n            String values = new JSONObject(response).getString(\"value\");\n            return Arrays.asList(new Gson().fromJson(values, Project[].class));\n        } catch (JSONException ex) {\n            throw new ReleaseManagementException(ex);\n        }\n    }\n    \n    private String ExecutePostmethod(String url, String body) throws ReleaseManagementException\n    {\n        PostMethod postMethod = new PostMethod(url);\n        postMethod.addRequestHeader(\"Authorization\", this.basicAuth);\n        postMethod.addRequestHeader(\"Content-Type\", \"application/json\");\n        postMethod.setRequestBody(body);\n        String response;\n        try\n        {\n            int status = this.httpClient.executeMethod(postMethod);\n            response = postMethod.getResponseBodyAsString();\n            if(status >= 300)\n            {\n                throw new ReleaseManagementException(\"Error occurred.%nStatus: \" + status + \"%nResponse: \" + response + \"%n\");\n            }\n        }\n        catch(Exception ex)\n        {\n            throw new ReleaseManagementException(ex);\n        }\n        \n        return response;\n    }\n    \n    private String ExecuteGetMethod(String url) throws ReleaseManagementException\n    {\n        GetMethod getMethod = new GetMethod(url);\n        getMethod.addRequestHeader(\"Authorization\", this.basicAuth);\n        String response;\n        try\n        {\n            int status = this.httpClient.executeMethod(getMethod);\n            response = getMethod.getResponseBodyAsString();\n            if(status >= 300)\n            {\n                throw new ReleaseManagementException(\"Error occurred.%nStatus: \" + status + \"%nResponse: \" + response + \"%n\");\n            }\n        }\n        catch(Exception ex)\n        {\n            throw new ReleaseManagementException(ex);\n        }\n        \n        return response;\n    }\n    \n    private class DefinitionResponse\n    {\n\n        private Integer count;\n        private List<ReleaseDefinition> value = new ArrayList<ReleaseDefinition>();\n        private final Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n        /**\n        * \n        * @return\n        * The count\n        */\n        public Integer getCount()\n        {\n            return count;\n        }\n\n        /**\n        * \n        * @param count\n        * The count\n        */\n        public void setCount(Integer count)\n        {\n            this.count = count;\n        }\n\n        /**\n        * \n        * @return\n        * The value\n        */\n        public List<ReleaseDefinition> getValue()\n        {\n            return value;\n        }\n\n        /**\n        * \n        * @param value\n        * The value\n        */\n        public void setValue(List<ReleaseDefinition> value)\n        {\n            this.value = value;\n        }\n\n        public Map<String, Object> getAdditionalProperties()\n        {\n            return this.additionalProperties;\n        }\n\n        public void setAdditionalProperty(String name, Object value)\n        {\n            this.additionalProperties.put(name, value);\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseSummaryAction.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport hudson.model.InvisibleAction;\nimport org.kohsuke.stapler.export.ExportedBean;\n\n/**\n * Show release summary link in build page.\n */\n\n@ExportedBean\npublic class ReleaseSummaryAction extends InvisibleAction {\n    private String projectName;\n    private int buildNo;\n    private String releaseLink;\n\n    public ReleaseSummaryAction() {\n\n    }\n\n    public ReleaseSummaryAction(final String projectName, final int buildNo, final String releaseLink) {\n        this.projectName = projectName;\n        this.buildNo = buildNo;\n        this.releaseLink = releaseLink;\n    }\n\n    public String getProjectName() {\n        return projectName;\n    }\n\n    public int getBuildNo() {\n        return buildNo;\n    }\n\n    public String getReleaseLink() {\n        return releaseLink;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseWebHook.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport hudson.Extension;\nimport hudson.model.AbstractDescribableImpl;\nimport hudson.model.Descriptor;\nimport hudson.util.FormValidation;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport org.kohsuke.stapler.DataBoundConstructor;\n\nimport java.util.logging.Logger;\nimport org.apache.commons.lang.StringUtils;\nimport org.kohsuke.stapler.QueryParameter;\n\n/**\n *\n * @author Kalyan\n */\npublic class ReleaseWebHook extends AbstractDescribableImpl<ReleaseWebHook> {\n    private static final Logger logger = Logger.getLogger(ReleaseWebHook.class.getName());\n\n    private final String webHookName;\n    private final String payloadUrl;\n    private final String secret;\n\n    @DataBoundConstructor\n    public ReleaseWebHook(final String webHookName, final String payloadUrl, final String secret) {\n        this.webHookName = webHookName;\n        this.payloadUrl = payloadUrl;\n        this.secret = secret;\n    }\n\n    public ReleaseWebHook(final String webHookName, final String payloadUrl) {\n        this.webHookName = webHookName;\n        this.payloadUrl = payloadUrl;\n        this.secret = StringUtils.EMPTY;\n    }\n\n    public String getWebHookName() {\n        return this.webHookName;\n    }\n\n    public String getPayloadUrl() {\n        return this.payloadUrl;\n    }\n\n    public String getSecret() {\n        return this.secret;\n    }\n\n    @Override\n    public DescriptorImpl getDescriptor() {\n        return (DescriptorImpl) super.getDescriptor();\n    }\n\n    /**\n     * DescriptorImpl.\n     */\n    @Extension\n    public static class DescriptorImpl extends Descriptor<ReleaseWebHook> {\n\n        @Override\n        public String getDisplayName() {\n            return \"Release Webhook\";\n        }\n\n        /**\n         * Validates Payload URL.\n         * @param value\n         * @return\n         */\n        @SuppressWarnings(\"unused\")\n        public FormValidation doCheckPayloadUrl(@QueryParameter final String value) {\n            if (StringUtils.isBlank(value)) {\n                return FormValidation.warning(\"Please provide a value\");\n            }\n\n            final URI uri;\n            try {\n                uri = new URI(value);\n            } catch (final URISyntaxException e) {\n                return FormValidation.error(\"Malformed Payload URL (%s)\", e.getMessage());\n            }\n\n            final String hostName = uri.getHost();\n            if (StringUtils.isBlank(hostName)) {\n                return FormValidation.error(\"Please provide a host name\");\n            }\n\n            return FormValidation.ok();\n        }\n\n        /**\n         * Validates WebHook Name.\n         * @param value\n         * @return\n         */\n        @SuppressWarnings(\"unused\")\n        public FormValidation doCheckWebHookName(@QueryParameter final String value) {\n            if (StringUtils.isBlank(value)) {\n                return FormValidation.error(\"Please provide a value\");\n            }\n\n            String pattern = \"^[A-Za-z0-9_-]+$\";\n            if (!value.matches(pattern)) {\n                return FormValidation.error(\"Only allowed characters are alphaphetic, numeric, hypen and underscore\");\n            }\n\n            return FormValidation.ok();\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseWebHookAction.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport hudson.Extension;\nimport hudson.Launcher;\nimport hudson.model.AbstractBuild;\nimport hudson.model.AbstractProject;\nimport hudson.model.BuildListener;\nimport hudson.model.Cause;\nimport hudson.plugins.tfs.JenkinsEventNotifier;\nimport hudson.tasks.BuildStepDescriptor;\nimport hudson.tasks.BuildStepMonitor;\nimport hudson.tasks.Notifier;\nimport hudson.tasks.Publisher;\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.net.HttpURLConnection;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport net.sf.json.JSONObject;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.util.EntityUtils;\nimport org.kohsuke.stapler.DataBoundConstructor;\n\n/**\n * Implements ReleaseWebhook Post build action.\n * @author Kalyan\n */\npublic class ReleaseWebHookAction extends Notifier implements Serializable {\n\n    private static final Logger logger = Logger.getLogger(ReleaseWebHookAction.class.getName());\n    private List<ReleaseWebHookReference> webHookReferences;\n    private final String apiVersion = \"5.0-preview\";\n\n    @DataBoundConstructor\n    public ReleaseWebHookAction(final List<ReleaseWebHookReference> webHookReferences) {\n        this.webHookReferences = webHookReferences;\n    }\n\n    @Override\n    public BuildStepMonitor getRequiredMonitorService() {\n        return BuildStepMonitor.NONE;\n    }\n\n    public List<ReleaseWebHookReference> getWebHookReferences() {\n        return this.webHookReferences;\n    }\n\n    public void setWebHookReferences(final List<ReleaseWebHookReference> webHookReferences) {\n        this.webHookReferences = webHookReferences;\n    }\n\n    @Override\n    public boolean perform(final AbstractBuild<?, ?> build, final Launcher launcher, final BuildListener listener) throws InterruptedException, IOException {\n        logger.entering(\"ReleaseWebhookAction\", \"Perform\");\n\n        JSONObject json = new JSONObject();\n        final String payload = JenkinsEventNotifier.getApiJson(build.getUrl());\n        if (payload != null) {\n            json = JSONObject.fromObject(payload);\n        }\n\n        json.put(\"name\", build.getProject().getFullName());\n        json.put(\"id\", build.getNumber());\n        json.put(\"startedBy\", getStartedBy(build));\n\n        HashMap<String, ReleaseWebHook> nameToWebHookMap = new HashMap<String, ReleaseWebHook>();\n        for (ReleaseWebHook webHook : ReleaseWebHookHelper.getReleaseWebHookConfigurations()) {\n            nameToWebHookMap.put(webHook.getWebHookName(), webHook);\n        }\n\n        List<ReleaseWebHookStatus> webHookStatus = new ArrayList<ReleaseWebHookStatus>();\n        ReleaseWebHook webHook = null;\n        for (ReleaseWebHookReference webHookName : webHookReferences) {\n            if (nameToWebHookMap.containsKey(webHookName.getWebHookName())) {\n                try {\n                    webHook = nameToWebHookMap.get(webHookName.getWebHookName());\n                    logger.fine(String.format(\"Sending payload event to %s\", webHook.getPayloadUrl()));\n                    ReleaseWebHookStatus status = sendJobCompletedEvent(json, webHook);\n\n                    webHookStatus.add(status);\n                } catch (Exception ex) {\n                    logger.log(Level.SEVERE, StringUtils.EMPTY, ex);\n                    webHookStatus.add(new ReleaseWebHookStatus(webHook.getPayloadUrl(), HttpURLConnection.HTTP_INTERNAL_ERROR, ex.toString()));\n                }\n            }\n        }\n\n        build.addAction(new ReleaseWebHookSummaryAction((webHookStatus)));\n        return true;\n    }\n\n    private ReleaseWebHookStatus sendJobCompletedEvent(final JSONObject json, final ReleaseWebHook webHook) throws IOException, NoSuchAlgorithmException, InvalidKeyException {\n        HttpClient client = HttpClientBuilder.create().build();\n        final HttpPost request = new HttpPost(webHook.getPayloadUrl());\n        final String payload = json.toString();\n\n        request.addHeader(\"Content-Type\", \"application/json\");\n        request.addHeader(\"Accept\", \"application/json; api-version=\" + apiVersion);\n\n        if (!StringUtils.isBlank(webHook.getSecret())) {\n            String signature = ReleaseWebHookHelper.getPayloadSignature(webHook.getSecret(), payload);\n            request.addHeader(\"X-Jenkins-Signature\", signature);\n        }\n\n        request.setEntity(new StringEntity(new String(payload.getBytes(\"UTF-8\"))));\n        final HttpResponse response = client.execute(request);\n        final int statusCode = response.getStatusLine().getStatusCode();\n\n        ReleaseWebHookStatus status = null;\n        if (statusCode == HttpURLConnection.HTTP_OK) {\n            logger.log(Level.INFO, \"sent event payload successfully\");\n            status = new ReleaseWebHookStatus(webHook.getPayloadUrl(), statusCode);\n        } else {\n            HttpEntity entity = response.getEntity();\n            String content = EntityUtils.toString(entity);\n            logger.log(Level.WARNING, \"Cannot send the event to webhook. Content:\" + content);\n            status = new ReleaseWebHookStatus(webHook.getPayloadUrl(), statusCode, content);\n        }\n\n        return status;\n    }\n\n    /**\n     * Implementation of DescriptorImpl.\n     */\n    @Extension\n    public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {\n\n        @Override\n        public boolean isApplicable(final Class<? extends AbstractProject> jobType) {\n            return true;\n        }\n\n        @Override\n        public String getDisplayName() {\n            return \"Azure Devops Server/Services Release Webhook\";\n        }\n    }\n\n    private String getStartedBy(final AbstractBuild build) {\n        final Cause.UserIdCause cause = (Cause.UserIdCause) build.getCause(Cause.UserIdCause.class);\n        String startedBy = \"\";\n        if (cause != null && cause.getUserId() != null) {\n            startedBy = cause.getUserId();\n        }\n\n        return startedBy;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseWebHookHelper.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport hudson.plugins.tfs.JenkinsEventNotifier;\nimport hudson.plugins.tfs.TeamPluginGlobalConfig;\nimport java.io.UnsupportedEncodingException;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.List;\n\n/**\n *\n * @author Kalyan\n */\npublic final class ReleaseWebHookHelper {\n    private ReleaseWebHookHelper() {\n    }\n\n    /**\n     * Gets the release webHook configuration from global config.\n     * @return list of release webHook\n     */\n    public static List<ReleaseWebHook> getReleaseWebHookConfigurations() {\n        final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\n        if (config == null) {\n            throw new InternalError(\"Cannot load TFS global configuration\");\n        }\n\n        return config.getReleaseWebHookConfigurations();\n    }\n\n    /**\n     * Saves the release webHooks with the global config.\n     * @param releaseWebHooks\n     */\n    public static void saveReleaseWebHookConfigurations(final List<ReleaseWebHook> releaseWebHooks) {\n        final TeamPluginGlobalConfig config = TeamPluginGlobalConfig.get();\n        if (config == null) {\n            throw new InternalError(\"Cannot load TFS global configuration\");\n        }\n\n        config.setReleaseWebHookConfigurations(releaseWebHooks);\n        config.save();\n    }\n\n    /**\n     * Gets the payload signature for the given event payload.\n     * @param secret\n     * @param payload\n     * @return\n     */\n    public static String getPayloadSignature(final String secret, final String payload) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {\n        return JenkinsEventNotifier.getPayloadSignature(secret, payload);\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseWebHookReference.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport com.cloudbees.plugins.credentials.common.StandardListBoxModel;\nimport hudson.Extension;\nimport hudson.model.AbstractDescribableImpl;\nimport hudson.model.Descriptor;\nimport hudson.util.ListBoxModel;\nimport org.kohsuke.stapler.DataBoundConstructor;\n\nimport java.util.logging.Logger;\n\n/**\n *\n * @author Kalyan\n */\npublic class ReleaseWebHookReference extends AbstractDescribableImpl<ReleaseWebHookReference> {\n    private static final Logger logger = Logger.getLogger(ReleaseWebHookReference.class.getName());\n\n    private final String webHookName;\n\n    @DataBoundConstructor\n    public ReleaseWebHookReference(final String webHookName) {\n        this.webHookName = webHookName;\n    }\n\n    public String getWebHookName() {\n        return this.webHookName;\n    }\n\n    @Override\n    public DescriptorImpl getDescriptor() {\n        return (DescriptorImpl) super.getDescriptor();\n    }\n\n    /**\n     * DescriptorImpl.\n     */\n    @Extension\n    public static class DescriptorImpl extends Descriptor<ReleaseWebHookReference> {\n\n        @Override\n        public String getDisplayName() {\n            return \"Release Webhook\";\n        }\n\n        /**\n         * Fills the webHook name input.\n         * @return\n         */\n        public ListBoxModel doFillWebHookNameItems() {\n            StandardListBoxModel listBoxModel = new StandardListBoxModel();\n\n            for (ReleaseWebHook webHook : ReleaseWebHookHelper.getReleaseWebHookConfigurations()) {\n                listBoxModel.add(webHook.getWebHookName());\n            }\n\n            return listBoxModel;\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseWebHookResource.java",
    "content": "package hudson.plugins.tfs.rm;\n\n/**\n * Implements ReleaseWebHookResource. Model to represent webHook register event.\n * @author Kalyan\n */\npublic class ReleaseWebHookResource {\n    private String operationType;\n    private String webHookName;\n    private String projectName;\n    private String payloadUrl;\n    private String secret;\n\n    public String getOperationType() {\n        return this.operationType;\n    }\n\n    public void setOperationType(final String operationType) {\n        this.operationType = operationType;\n    }\n\n    public String getWebHookName() {\n        return this.webHookName;\n    }\n\n    public void setWebHookName(final String webHookName) {\n        this.webHookName = webHookName;\n    }\n\n    public String getProjectName() {\n        return this.projectName;\n    }\n\n    public void setProjectName(final String jobName) {\n        this.projectName = jobName;\n    }\n\n    public String getPayloadUrl() {\n        return this.payloadUrl;\n    }\n\n    public void setPayloadUrl(final String payloadUrl) {\n        this.payloadUrl = payloadUrl;\n    }\n\n    public String getSecret() {\n        return this.secret;\n    }\n\n    public void setSecret(final String secret) {\n        this.secret = secret;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseWebHookStatus.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * Implements ReleaseWebHookStatus.\n * @author Kalyan\n */\npublic class ReleaseWebHookStatus {\n\n    private final String payloadUrl;\n    private final String timeStamp;\n    private final int statusCode;\n    private String errorMessage;\n\n    public ReleaseWebHookStatus(final String payloadUrl, final int status) {\n        this.payloadUrl = payloadUrl;\n        this.statusCode = status;\n        this.timeStamp = new SimpleDateFormat(\"yyyy.MM.dd.HH.mm.ss\").format(new Date());\n    }\n\n    public ReleaseWebHookStatus(final String payloadUrl, final int status, final String errorMessage) {\n        this(payloadUrl, status);\n        this.errorMessage = errorMessage;\n    }\n\n    public String getPayloadUrl() {\n        return this.payloadUrl;\n    }\n\n    public int getStatusCode() {\n        return this.statusCode;\n    }\n\n    public String getErrorMessage() {\n        return this.errorMessage;\n    }\n\n    public String getTimeStamp() {\n        return this.timeStamp;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/ReleaseWebHookSummaryAction.java",
    "content": "package hudson.plugins.tfs.rm;\n\nimport hudson.model.InvisibleAction;\nimport java.util.List;\n\n/**\n * Implements ReleaseWebhook Post build action.\n * @author Kalyan\n */\npublic class ReleaseWebHookSummaryAction extends InvisibleAction {\n\n    private List<ReleaseWebHookStatus> webHookStatus;\n\n    public ReleaseWebHookSummaryAction(final List<ReleaseWebHookStatus> webHookStatus) {\n        this.webHookStatus = webHookStatus;\n    }\n\n    public List<ReleaseWebHookStatus> getWebHookStatus() {\n        return this.webHookStatus;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/RetentionPolicy.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Ankit Goyal\n */\n\npublic class RetentionPolicy\n{\n    \n    private Integer daysToKeep;\n    private Map<String, Object> additionalProperties = new HashMap<String, Object>();\n\n    /**\n    * \n    * @return\n    * The daysToKeep\n    */\n    public Integer getDaysToKeep()\n    {\n        return daysToKeep;\n    }\n\n    /**\n    * \n    * @param daysToKeep\n    * The daysToKeep\n    */\n    public void setDaysToKeep(Integer daysToKeep)\n    {\n        this.daysToKeep = daysToKeep;\n    }\n\n    public Map<String, Object> getAdditionalProperties()\n    {\n        return this.additionalProperties;\n    }\n\n    public void setAdditionalProperty(String name, Object value)\n    {\n        this.additionalProperties.put(name, value);\n    }\n    \n}\n\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/rm/Version.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.rm;\n\n/**\n *\n * @author angoya\n */\npublic class Version\n{\n    \n    private String id;\n    private String name;\n    private String sourceBranch;\n\n    /**\n    * \n    * @return\n    * The id\n    */\n    public String getId()\n    {\n        return id;\n    }\n\n    /**\n    * \n    * @param id\n    * The id\n    */\n    public void setId(String id)\n    {\n        this.id = id;\n    }\n\n    /**\n    * \n    * @return\n    * The name\n    */\n    public String getName()\n    {\n        return name;\n    }\n\n    /**\n    * \n    * @param name\n    * The name\n    */\n    public void setName(String name)\n    {\n        this.name = name;\n    }\n\n    /**\n    * \n    * @return\n    * The sourceBranch\n    */\n    public String getSourceBranch()\n    {\n        return sourceBranch;\n    }\n\n    /**\n    * \n    * @param sourceBranch\n    * The sourceBranch\n    */\n    public void setSourceBranch(String sourceBranch)\n    {\n        this.sourceBranch = sourceBranch;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/telemetry/TelemetryContextInitializer.java",
    "content": "package hudson.plugins.tfs.telemetry;\n\nimport com.microsoft.applicationinsights.extensibility.ContextInitializer;\nimport com.microsoft.applicationinsights.extensibility.context.ComponentContext;\nimport com.microsoft.applicationinsights.extensibility.context.ContextTagKeys;\nimport com.microsoft.applicationinsights.extensibility.context.DeviceContext;\nimport com.microsoft.applicationinsights.extensibility.context.SessionContext;\nimport com.microsoft.applicationinsights.extensibility.context.UserContext;\nimport com.microsoft.applicationinsights.telemetry.TelemetryContext;\nimport jenkins.model.Jenkins;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.text.MessageFormat;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\n\n/**\n * This class is provided as a ContextInitializer for the application insights TelemetryClient.\n */\npublic class TelemetryContextInitializer implements ContextInitializer {\n    private static final Logger logger = LoggerFactory.getLogger(TelemetryContextInitializer.class);\n\n    private static final String PRODUCT_NAME = \"TFS-Jenkins\";\n    private static final String SYS_PROP_OS_NAME = \"os.name\";\n    private static final String SYS_PROP_OS_VERSION = \"os.version\";\n    private static final String SYS_PROP_USER_NAME = \"user.name\";\n    private static final String SYS_PROP_JAVA_RUNTIME = \"java.runtime.name\";\n    private static final String SYS_PROP_JAVA_VERSION = \"java.version\";\n    private static final String USER_AGENT_FORMAT = \"{0}/{1} {2}/{3} {4}/{5} {6}/{7} ({8})\";\n\n    private static final String PROPERTY_USER_ID = \"User.Id\";\n    private static final String PROPERTY_JENKINS_VERSION = \"Jenkins.Version\";\n    private static final String PROPERTY_PLUGIN_VERSION = \"Plugin.Version\";\n    private static final String PROPERTY_JAVA_NAME = \"Java.Name\";\n    private static final String PROPERTY_JAVA_VERSION = \"Java.Version\";\n    private static final String PROPERTY_OS_PLATFORM = \"VSTS.Core.Machine.OS.Platform\";\n    private static final String PROPERTY_OS_VERSION = \"VSTS.Core.Machine.OS.Version\";\n    private static final String PROPERTY_LOCALE = \"Locale\";\n\n    private String hostname = StringUtils.EMPTY;\n    private boolean isInitialized = false;\n    private final boolean isDeveloperMode;\n\n    public TelemetryContextInitializer(final boolean isDeveloperMode) {\n        this.isDeveloperMode = isDeveloperMode;\n    }\n\n    @Override\n    public void initialize(final TelemetryContext context) {\n        if (!isInitialized) {\n            logger.info(\"Starting TelemetryContext initialization\");\n            initializeInstrumentationKey(context, isDeveloperMode);\n            initializeProperties(context.getProperties());\n            initializeUser(context.getUser());\n            initializeComponent(context.getComponent());\n            initializeDevice(context.getDevice());\n            initializeTags(context.getTags());\n            initializeSession(context.getSession());\n            isInitialized = true;\n            logger.info(\"Ending TelemetryContext initialization\");\n        }\n    }\n\n    /**\n     * Gets the full User Agent used to make requests to TFS/Team Services.\n     */\n    public String getUserAgent(final String defaultUserAgent) {\n        try {\n            return MessageFormat.format(USER_AGENT_FORMAT,\n                    PRODUCT_NAME,\n                    getPluginVersion(),\n                    \"Jenkins\",\n                    Jenkins.getVersion(),\n                    getPlatformName(),\n                    getPlatformVersion(),\n                    getJavaName(),\n                    getJavaVersion(),\n                    defaultUserAgent);\n        } catch (final Throwable t) {\n            logger.warn(\"Error getting UserAgent\", t);\n            return defaultUserAgent;\n        }\n    }\n\n    private void initializeDevice(final DeviceContext device) {\n        device.setOperatingSystem(getPlatformName());\n        device.setOperatingSystemVersion(getPlatformVersion());\n    }\n\n    private void initializeInstrumentationKey(final TelemetryContext context, final boolean isDeveloperMode) {\n        if (isDeveloperMode) {\n            context.setInstrumentationKey(\"149da81b-a0ab-4bdf-a7e9-11e5af9e39bd\");\n        } else {\n            context.setInstrumentationKey(\"0f243a28-b3c3-41f2-b7cc-d10feec45a81\");\n        }\n    }\n\n    private void initializeUser(final UserContext user) {\n        user.setId(getUserId());\n        user.setUserAgent(getUserAgent(\"\"));\n    }\n\n    private String getUserId() {\n        final String computerName = getComputerName();\n        final String userName = getSystemProperty(SYS_PROP_USER_NAME);\n        final String fakeUserId = MessageFormat.format(\"{0}@{1}\", userName, computerName);\n\n        //FIXME: was sha1Hex, but this is available only in commons codec 1.7. TFS SDK 14.0.3 bundles older version\n        return DigestUtils.shaHex(fakeUserId);\n    }\n\n    private String getComputerName() {\n        if (StringUtils.isEmpty(hostname)) {\n            hostname = TelemetryHelper.UNKNOWN;\n\n            try {\n                // on Mac this call can take > 10 secs so don't call multiple times\n                final InetAddress address = InetAddress.getLocalHost();\n                hostname = address.getHostName();\n            } catch (UnknownHostException ex) {\n                // This case is covered by the initial value of hostname above\n            }\n        }\n\n        return hostname;\n    }\n\n    private void initializeComponent(final ComponentContext component) {\n        component.setVersion(getPluginVersion());\n    }\n\n    private void initializeTags(final Map<String, String> tags) {\n        tags.put(ContextTagKeys.getKeys().getApplicationId(), PRODUCT_NAME);\n        tags.put(ContextTagKeys.getKeys().getDeviceOS(), getPlatformName());\n        tags.put(ContextTagKeys.getKeys().getDeviceOSVersion(), getPlatformVersion());\n    }\n\n    private void initializeSession(final SessionContext sessionContext) {\n        sessionContext.setId(UUID.randomUUID().toString());\n    }\n\n    private void initializeProperties(final Map<String, String> properties) {\n        properties.put(PROPERTY_USER_ID, getUserId());\n\n        // Get Jenkins version info\n        properties.put(PROPERTY_JENKINS_VERSION, Jenkins.getVersion().toString());\n        properties.put(PROPERTY_PLUGIN_VERSION, getPluginVersion());\n\n        // Get OS info\n        properties.put(PROPERTY_LOCALE, getLocaleName());\n        properties.put(PROPERTY_OS_PLATFORM, getPlatformName());\n        properties.put(PROPERTY_OS_VERSION, getPlatformVersion());\n\n        // Get Java info\n        properties.put(PROPERTY_JAVA_NAME, getJavaName());\n        properties.put(PROPERTY_JAVA_VERSION, getJavaVersion());\n    }\n\n    private String getSystemProperty(final String propertyName) {\n        return System.getProperty(propertyName, StringUtils.EMPTY);\n    }\n\n    private String getPlatformName() {\n        return getSystemProperty(SYS_PROP_OS_NAME);\n    }\n\n    private String getPlatformVersion() {\n        return getSystemProperty(SYS_PROP_OS_VERSION);\n    }\n\n    private String getLocaleName() {\n        return Locale.getDefault().getDisplayName();\n    }\n\n    private String getJavaName() {\n        return getSystemProperty(SYS_PROP_JAVA_RUNTIME);\n    }\n\n    private String getJavaVersion() {\n        return getSystemProperty(SYS_PROP_JAVA_VERSION);\n    }\n\n    private String getPluginVersion() {\n        final Jenkins instance = Jenkins.getInstance();\n        if (instance != null && instance.getPluginManager() != null) {\n            return instance.getPluginManager().getPlugin(\"tfs\").getVersion();\n        }\n        return StringUtils.EMPTY;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/telemetry/TelemetryHelper.java",
    "content": "package hudson.plugins.tfs.telemetry;\n\nimport com.microsoft.applicationinsights.TelemetryClient;\nimport com.microsoft.applicationinsights.TelemetryConfiguration;\nimport com.microsoft.applicationinsights.channel.TelemetryChannel;\nimport com.microsoft.applicationinsights.extensibility.ContextInitializer;\nimport com.microsoft.applicationinsights.internal.logger.InternalLogger;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.URI;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * The TelemetryHelper class is a singleton that allows the plugin to capture\n * telemetry data when the user initiates events.\n */\npublic final class TelemetryHelper {\n    public static final String UNKNOWN = \"unknown\";\n    private static final String UNIQUE_PREFIX = \"ai-log\";\n    private static final String BASE_FOLDER = \"AppInsights\";\n\n    private static final String PROPERTY_VSTS_IS_HOSTED = \"VSTS.TeamFoundationServer.IsHostedServer\";\n    private static final String PROPERTY_VSTS_SERVER_ID = \"VSTS.TeamFoundationServer.ServerId\";\n    private static final String PROPERTY_VSTS_COLLECTION_ID = \"VSTS.TeamFoundationServer.CollectionId\";\n\n    private static final String ACTION_NAME_FORMAT = \"Action/%s\";\n\n    private static final Logger logger = LoggerFactory.getLogger(TelemetryHelper.class);\n\n    // Instance members\n    private TelemetryClient telemetryClient;\n\n    /**\n     * A private static class to allow safe lazy initialization of the singleton.\n     */\n    private static class TfsTelemetryHelperHolder {\n        private static final TelemetryHelper INSTANCE = new TelemetryHelper();\n    }\n\n    /**\n     * The getInstance method returns the singleton instance. Creating it if necessary\n     */\n    private static TelemetryHelper getInstance() {\n        // Using the Initialization-on-demand holder pattern to make sure this is thread-safe\n        return TfsTelemetryHelperHolder.INSTANCE;\n    }\n\n    // The private constructor keeps the class from being inherited or misused\n    private TelemetryHelper() {\n        final String skip = System.getProperties().getProperty(\"hudson.plugins.tfs.telemetry.skipClientInitialization\");\n        if (StringUtils.isNotEmpty(skip) && StringUtils.equalsIgnoreCase(skip, \"true\")) {\n            // this flag is here for testing purposes in which case we do not want to create a telemetry channel\n            // or client.\n            return;\n        }\n\n        // Initialize the internal logger\n        final Map<String, String> loggerData = new HashMap<String, String>();\n        loggerData.put(\"Level\", InternalLogger.LoggingLevel.ERROR.toString());\n        loggerData.put(\"UniquePrefix\", UNIQUE_PREFIX);\n        loggerData.put(\"BaseFolder\", BASE_FOLDER);\n        InternalLogger.INSTANCE.initialize(InternalLogger.LoggerOutputType.FILE.toString(), loggerData);\n\n        // Initialize the active TelemetryConfiguration\n        final String isDeveloperModeProperty = System.getProperty(\"hudson.plugins.tfs.telemetry.isDeveloperMode\", \"false\");\n        boolean isDeveloperMode = StringUtils.equalsIgnoreCase(isDeveloperModeProperty, \"true\");\n        ContextInitializer initializer = new TelemetryContextInitializer(isDeveloperMode);\n        TelemetryConfiguration.getActive().getContextInitializers().add(initializer);\n\n        // Create a channel to AppInsights\n        final TelemetryChannel channel = TelemetryConfiguration.getActive().getChannel();\n        if (channel != null) {\n            channel.setDeveloperMode(isDeveloperMode);\n        } else {\n            logger.error(\"Failed to load telemetry channel\");\n            return;\n        }\n\n        logger.debug(\"AppInsights telemetry initialized\");\n        logger.debug(\"    Developer Mode: \", channel.isDeveloperMode());\n\n        // Create the telemetry client and cache it for later use\n        telemetryClient = new TelemetryClient();\n    }\n\n    /**\n     * Call sendEvent to track an occurrence of a named event.\n     *\n     * @param name       is the name of the event to be tracked.\n     * @param properties are additional properties to track with the event.\n     */\n    public static void sendEvent(final String name, final Map<String, String> properties) {\n        try {\n            getInstance().sendEventInternal(name, properties);\n        } catch (Exception e) {\n            logger.warn(\"Error sending event telemetry\", e);\n        }\n    }\n\n    /**\n     * Call sendMetric to track the new value of the named metric.\n     *\n     * @param name  is the name of the metric to be tracked.\n     * @param value is the current value of the metric as a double.\n     */\n    public static void sendMetric(final String name, final double value) {\n        try {\n            getInstance().sendMetricInternal(name, value);\n        } catch (Exception e) {\n            logger.warn(\"Error sending metric telemetry\", e);\n        }\n    }\n\n    /**\n     * Call sendException to track an exception that occurred that should be tracked.\n     *\n     * @param exception is the exception to track.\n     */\n    public static void sendException(final Exception exception, final Map<String, String> properties) {\n        try {\n            getInstance().sendExceptionInternal(exception, properties);\n        } catch (Exception e) {\n            logger.warn(\"Error sending exception telemetry\", e);\n        }\n    }\n\n    protected void sendMetricInternal(final String name, final double value) {\n        // Log that the event occurred (this log is used in testing)\n        logger.debug(String.format(\"sendMetric(%s, %f)\", name, value));\n\n        if (telemetryClient != null) {\n            telemetryClient.trackMetric(name, value);\n        }\n    }\n\n    protected void sendEventInternal(final String name, final Map<String, String> properties) {\n        final String eventName = String.format(ACTION_NAME_FORMAT, name);\n        final PropertyMapBuilder builder = new PropertyMapBuilder(properties);\n\n        // Log that the event occurred (this log is used in testing)\n        logger.debug(String.format(\"sendEvent(%s, %s)\", name, builder.toString()));\n\n        if (telemetryClient != null) {\n            telemetryClient.trackEvent(eventName, builder.build(), null);\n        }\n    }\n\n    protected void sendExceptionInternal(final Exception exception, final Map<String, String> properties) {\n        final PropertyMapBuilder builder = new PropertyMapBuilder(properties);\n\n        // Log that the event occurred (this log is used in testing)\n        logger.debug(String.format(\"sendException(%s, %s)\", exception.getMessage(), builder.toString()));\n\n        if (telemetryClient != null) {\n            telemetryClient.trackException(exception, builder.build(), null);\n        }\n    }\n\n    /**\n     * Builder class to gather all properties to be sent to AppInsights into a Map.\n     */\n    public static class PropertyMapBuilder {\n        public static final Map<String, String> EMPTY = new PropertyMapBuilder().build();\n\n        private Map<String, String> properties = new HashMap<String, String>();\n\n        public PropertyMapBuilder() {\n            this(null);\n        }\n\n        public PropertyMapBuilder(final Map<String, String> properties) {\n            if (properties != null) {\n                this.properties = new HashMap<String, String>(properties);\n            } else {\n                this.properties = new HashMap<String, String>();\n            }\n        }\n\n        /**\n         * Returns the map of all key value pairs that were added to the builder.\n         */\n        public Map<String, String> build() {\n            // Make a copy and return it\n            return new HashMap<String, String>(properties);\n        }\n\n        /**\n         * Adds server context information to the properties sent to AppInsights.\n         */\n        public PropertyMapBuilder serverContext(final String serverUrl, final String collectionUrl) {\n            if (serverUrl != null) {\n                final boolean isHosted = StringUtils.containsIgnoreCase(serverUrl, \".visualstudio.com\");\n                add(PROPERTY_VSTS_IS_HOSTED, Boolean.toString(isHosted));\n                add(PROPERTY_VSTS_SERVER_ID, getServerId(serverUrl));\n                add(PROPERTY_VSTS_COLLECTION_ID, getCollectionId(collectionUrl));\n            }\n            return this;\n        }\n\n        /**\n         * Adds a key value pair to the properties sent to AppInsights.\n         */\n        public PropertyMapBuilder pair(final String key, final String value) {\n            if (!StringUtils.isEmpty(key) && !StringUtils.isEmpty(value)) {\n                add(key, value);\n            }\n            return this;\n        }\n\n        private String getServerId(final String serverUrl) {\n            try {\n                if (serverUrl != null) {\n                    return URI.create(serverUrl).getHost();\n                }\n            } catch (Exception ex) {\n                logger.error(\"failed to get server URI\", ex);\n            }\n            return UNKNOWN;\n        }\n\n        private String getCollectionId(final String collectionUrl) {\n            try {\n                if (collectionUrl != null) {\n                    return URI.create(collectionUrl).getPath();\n                }\n            } catch (Exception ex) {\n                logger.error(\"failed to get server URI\", ex);\n            }\n\n            return UNKNOWN;\n        }\n\n        private void add(final String key, final String value) {\n            if (value != null) {\n                // remove any newlines from the value field. Newlines currently cause the event to be lost in AppInsights\n                properties.put(key, value.replace(\"\\r\", \"\").replace(\"\\n\", \" \"));\n            } else {\n                properties.put(key, \"\"); //null values cause exceptions\n            }\n        }\n\n        @Override\n        public String toString() {\n            return properties.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/ActionHelper.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport hudson.model.Action;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\n/**\r\n * Helper class to create actions.\r\n */\r\npublic final class ActionHelper {\r\n\r\n    private ActionHelper() { }\r\n\r\n    /**\r\n     * Adds actions to an existing collection of actions and returns the new array of Actions.\r\n     */\r\n    public static Action[] create(final Collection<Action> actions, final Action... additionalActions) {\r\n        final int totalCount = actions.size() + additionalActions.length;\r\n        final List<Action> allActions = new ArrayList<Action>(totalCount);\r\n        allActions.addAll(actions);\r\n        Collections.addAll(allActions, additionalActions);\r\n        final Action[] result = allActions.toArray(new Action[totalCount]);\r\n        return result;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/BuildVariableResolver.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport java.io.IOException;\r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.logging.Logger;\r\n\r\nimport hudson.Util;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.Computer;\r\nimport hudson.model.Job;\r\nimport hudson.model.TaskListener;\r\nimport hudson.util.VariableResolver;\r\n\r\n/**\r\n * A {@link VariableResolver} that resolves certain Build variables.\r\n * <p>\r\n * The build variable resolver will resolve the following:\r\n * <ul>\r\n * <li> JOB_NAME - The name of the job</li>\r\n * <li> USER_NAME - The system property \"user.name\" on the Node that the Launcher\r\n * is being executed on (slave or master)</li>\r\n * <li> NODE_NAME - The name of the node that the Launcher is being executed on</li>\r\n * <li> Any environment variable that is set on the Node that the Launcher is\r\n * being executed on (slave or master)</li>\r\n * </ul>\r\n *\r\n * @author Erik Ramfelt\r\n */\r\npublic class BuildVariableResolver implements VariableResolver<String> {\r\n\r\n    private Map<String, LazyResolver> lazyResolvers = new HashMap<String, LazyResolver>();\r\n\r\n    private List<VariableResolver<String>> otherResolvers = new ArrayList<VariableResolver<String>>();\r\n\r\n    private final Computer computer;\r\n\r\n    private static final Logger LOGGER = Logger.getLogger(BuildVariableResolver.class.getName());\r\n\r\n    public BuildVariableResolver(final Job<?, ?> job) {\r\n        computer = null;\r\n        lazyResolvers.put(\"JOB_NAME\", new LazyResolver() {\r\n            public String getValue() {\r\n                return job.getName();\r\n            }\r\n        });\r\n    }\r\n\r\n    public BuildVariableResolver(final Job<?, ?> project, final Computer computer) {\r\n        this.computer = computer;\r\n        lazyResolvers.put(\"JOB_NAME\", new LazyResolver() {\r\n            public String getValue() {\r\n                return project.getName();\r\n            }\r\n        });\r\n        lazyResolvers.put(\"NODE_NAME\", new LazyComputerResolver() {\r\n            public String getValue(final Computer computer) {\r\n                return (Util.fixEmpty(computer.getName()) == null ? \"MASTER\" : computer.getName());\r\n            }\r\n        });\r\n        lazyResolvers.put(\"USER_NAME\", new LazyComputerResolver() {\r\n            public String getValue(final Computer computer) throws IOException, InterruptedException {\r\n                return (String) computer.getSystemProperties().get(\"user.name\");\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Constructor that can be used with a {@linkplain AbstractBuild} instance.\r\n     * <p>\r\n     * This constructor should not be called in a method that may be called by\r\n     * {@link AbstractBuild#getEnvVars()}.\r\n     * @param build used to get the project and the build env vars\r\n     * @param computer used to retrieve the name of the remote computer or of the account under which Jenkins runs\r\n     *\r\n     * @throws IOException If an I/O error occurs\r\n     * @throws InterruptedException\r\n     *      If the current thread is interrupted while waiting for the completion.\r\n     */\r\n    public BuildVariableResolver(final AbstractBuild<?, ?> build, final Computer computer)\r\n            throws IOException, InterruptedException {\r\n        this(build.getProject(), computer);\r\n\r\n        final Map<String, String> envVars = build.getEnvironment(TaskListener.NULL);\r\n        if (envVars != null) {\r\n            otherResolvers.add(new VariableResolver.ByMap<String>(envVars));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @return resolved variable or null if the lookup failed\r\n     */\r\n    public String resolve(final String variable) {\r\n        try {\r\n            if (lazyResolvers.containsKey(variable)) {\r\n                return lazyResolvers.get(variable).getValue();\r\n            } else {\r\n                if (computer != null) {\r\n                    otherResolvers.add(new VariableResolver.ByMap<String>(computer.getEnvironment()));\r\n                }\r\n                return new VariableResolver.Union<String>(otherResolvers).resolve(variable);\r\n            }\r\n        } catch (Exception e) {\r\n            LOGGER.warning(\"Variable name '\" + variable + \"' look up failed because of \" + e);\r\n        }\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Simple lazy variable resolver.\r\n     */\r\n    private interface LazyResolver {\r\n        String getValue() throws IOException, InterruptedException;\r\n    }\r\n\r\n    /**\r\n     * Class to handle cases when a Launcher was not created from a computer.\r\n     * @see Launcher#getComputer()\r\n     */\r\n    private abstract class LazyComputerResolver implements LazyResolver {\r\n        protected abstract String getValue(Computer computer) throws IOException, InterruptedException;\r\n        public String getValue() throws IOException, InterruptedException {\r\n            return getValue(computer);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/BuildWorkspaceConfigurationRetriever.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport java.io.IOException;\r\n\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.Node;\r\nimport hudson.model.Run;\r\nimport hudson.plugins.tfs.model.WorkspaceConfiguration;\r\n\r\n/**\r\n * Class for retrieving the latest build configuration for a certain node.\r\n * As the data should be stored together with the workspace, but that is not possible\r\n * today so it is stored in the build itself. Latest build on a certain node always\r\n * contains the SCM configuration for the workspace on that node.\r\n * @author Erik Ramfelt, redsolo\r\n */\r\npublic class BuildWorkspaceConfigurationRetriever {\r\n\r\n    public BuildWorkspaceConfiguration getLatestForNode(Node needleNode, Run<?,?> latestRun) {\r\n        if ((latestRun == null) || !(latestRun instanceof AbstractBuild<?, ?>)) {\r\n            return null;\r\n        }\r\n        \r\n        AbstractBuild<?, ?> build = (AbstractBuild<?, ?>) latestRun;\r\n        while (build != null) {\r\n        \tNode node = build.getBuiltOn();\r\n        \tif (node != null) {\r\n                if (node.getNodeName().equals(needleNode.getNodeName()))\r\n                {\r\n                   break;\r\n                }\r\n        \t}\r\n            build = build.getPreviousBuild();\r\n        }\r\n        \r\n        if (build != null) {\r\n            WorkspaceConfiguration configuration = build.getAction(WorkspaceConfiguration.class);\r\n            if (configuration != null) {\r\n                return new BuildWorkspaceConfiguration(configuration, build);\r\n            }\r\n        }\r\n\r\n        return null;\r\n    }\r\n    \r\n    public static class BuildWorkspaceConfiguration extends WorkspaceConfiguration {\r\n        private static final long serialVersionUID = 1L;\r\n        private final transient AbstractBuild<?, ?> build;\r\n        \r\n        public BuildWorkspaceConfiguration(WorkspaceConfiguration configuration, AbstractBuild<?, ?> build) {\r\n            super(configuration);\r\n            this.build = build;\r\n        }\r\n\r\n        public void save() throws IOException {\r\n            if (!workspaceExists()) {\r\n                build.getAction(WorkspaceConfiguration.class).setWorkspaceWasRemoved();\r\n            }\r\n            build.save();\r\n        }\r\n\r\n        @Override\r\n        public boolean equals(Object o) {\r\n            return super.equals(o);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/DateUtil.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\r\n\r\nimport java.text.DateFormat;\r\nimport java.text.FieldPosition;\r\nimport java.text.ParseException;\r\nimport java.text.SimpleDateFormat;\r\nimport java.util.ArrayList;\r\nimport java.util.Calendar;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.Locale;\r\nimport java.util.SimpleTimeZone;\r\nimport java.util.TimeZone;\r\n\r\npublic class DateUtil {\r\n\r\n    private DateUtil() {        \r\n    }\r\n\r\n    private static final String ISO_8601_DATE_TIME_MINUS_FRACTIONS = \"yyyy-MM-dd'T'HH:mm:ss'Z'\";\r\n\r\n    public static final ThreadLocal<SimpleDateFormat> TFS_DATETIME_FORMATTER = new ThreadLocal<SimpleDateFormat>() {\r\n        @Override\r\n        protected SimpleDateFormat initialValue() {\r\n            SimpleDateFormat dateFormat = new SimpleDateFormat(ISO_8601_DATE_TIME_MINUS_FRACTIONS);\r\n            dateFormat.setTimeZone(new SimpleTimeZone(0,\"GMT\"));\r\n            return dateFormat;\r\n        }\r\n    };\r\n\r\n    public static String toString(final DateVersionSpec dateVersionSpec) {\r\n        final Calendar calendar = dateVersionSpec.getDate();\r\n        return toString(calendar);\r\n    }\r\n\r\n    public static String toString(final Calendar calendar) {\r\n        final Date dateTime = calendar.getTime();\r\n        return toString(dateTime);\r\n    }\r\n\r\n    public static String toString(final Date dateTime) {\r\n        final FieldPosition fieldPosition = new FieldPosition(-1);\r\n        final SimpleDateFormat simpleDateFormat = TFS_DATETIME_FORMATTER.get();\r\n        final StringBuffer sb = new StringBuffer(1 + ISO_8601_DATE_TIME_MINUS_FRACTIONS.length());\r\n        sb.append('D');\r\n        simpleDateFormat.format(dateTime, sb, fieldPosition);\r\n        final String result = sb.toString();\r\n        return result;\r\n    }\r\n\r\n    public static Date parseDate(String dateString) throws ParseException {\r\n        return parseDate(dateString, Locale.getDefault(), TimeZone.getDefault());\r\n    }\r\n    \r\n    @SuppressWarnings(\"deprecation\")\r\n    public static Date parseDate(String dateString, Locale locale, TimeZone timezone) throws ParseException {\r\n        Date date = null;\r\n        dateString = dateString.replaceAll(\"(p|P)\\\\.(m|M)\\\\.\", \"PM\").replaceAll(\"(a|A)\\\\.(m|M)\\\\.\", \"AM\");\r\n        try {\r\n            // Use the deprecated Date.parse method as this is very good at detecting\r\n            // dates commonly output by the US and UK standard locales of dotnet that\r\n            // are output by the Microsoft command line client.\r\n            date = new Date(Date.parse(dateString));\r\n        } catch (IllegalArgumentException e) {\r\n            // ignore - parse failed.\r\n        }\r\n        if (date == null) {\r\n            // The old fashioned way did not work. Let's try it using a more\r\n            // complex alternative.\r\n            DateFormat[] formats = createDateFormatsForLocaleAndTimeZone(locale, timezone);\r\n            return parseWithFormats(dateString, formats);\r\n        }\r\n        return date;\r\n    }\r\n\r\n    static Date parseWithFormats(String input, DateFormat[] formats) throws ParseException {\r\n        ParseException parseException = null;\r\n        for (int i = 0; i < formats.length; i++) {\r\n            try {\r\n                return formats[i].parse(input);\r\n            } catch (ParseException ex) {\r\n                parseException = ex;\r\n            }\r\n        }\r\n        if (parseException == null) {\r\n            throw new IllegalStateException(\"No dateformats found that can be used for parsing '\" + input + \"'\");\r\n        }\r\n        throw parseException;\r\n    }\r\n\r\n    /**\r\n     * Build an array of DateFormats that are commonly used for this locale\r\n     * and timezone.\r\n     */\r\n    static DateFormat[] createDateFormatsForLocaleAndTimeZone(Locale locale, TimeZone timeZone) {\r\n        List<DateFormat> formats = new ArrayList<DateFormat>();\r\n\r\n        addDateTimeFormatsToList(locale, timeZone, formats);\r\n        addDateFormatsToList(locale, timeZone, formats);\r\n\r\n        return formats.toArray(new DateFormat[formats.size()]);\r\n    }\r\n\r\n    static void addDateFormatsToList(Locale locale, TimeZone timeZone, List<DateFormat> formats) {\r\n        for (int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; dateStyle++) {\r\n            DateFormat df = DateFormat.getDateInstance(dateStyle, locale);\r\n            df.setTimeZone(timeZone);\r\n            formats.add(df);\r\n        }\r\n    }\r\n\r\n    static void addDateTimeFormatsToList(Locale locale, TimeZone timeZone, List<DateFormat> formats) {\r\n        for (int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; dateStyle++) {\r\n            for (int timeStyle = DateFormat.FULL; timeStyle <= DateFormat.SHORT; timeStyle++) {\r\n                DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);\r\n                if (timeZone != null) {\r\n                    df.setTimeZone(timeZone);\r\n                }\r\n                formats.add(df);\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/EndpointHelper.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport com.fasterxml.jackson.databind.DeserializationFeature;\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport org.kohsuke.stapler.HttpResponses;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\nimport org.kohsuke.stapler.StaplerResponse;\r\n\r\nimport javax.servlet.ServletException;\r\nimport java.io.IOException;\r\nimport java.io.PrintWriter;\r\n\r\npublic class EndpointHelper {\r\n\r\n    public static final ObjectMapper MAPPER;\r\n\r\n    static {\r\n        MAPPER = new ObjectMapper();\r\n        MAPPER.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);\r\n        MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);\r\n    }\r\n\r\n    public static void error(final int code, final Throwable cause) {\r\n        throw new HttpResponses.HttpResponseException(cause) {\r\n            public void generateResponse(final StaplerRequest req, final StaplerResponse rsp, final Object node) throws IOException, ServletException {\r\n                rsp.setStatus(code);\r\n                rsp.setHeader(\"X-Error-Message\", cause.getMessage());\r\n                rsp.setContentType(\"text/plain;charset=UTF-8\");\r\n\r\n                final PrintWriter w = new PrintWriter(rsp.getWriter());\r\n                // TODO: serialize \"cause\" to JSON write that, instead\r\n                cause.printStackTrace(w);\r\n                w.close();\r\n            }\r\n        };\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/KeyValueTextReader.java",
    "content": "//CHECKSTYLE:OFF\npackage hudson.plugins.tfs.util;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Class that parsers key/values from a reader.\n * This is used when reading text files that contains keys and value pairs where the\n * value can be in one or several rows. First used when doing some more intelligent parsing\n * of the output from the tfs history command.\n *\n * @author redsolo\n */\npublic class KeyValueTextReader {\n\n    private static final Pattern KEY_VALUE_PATTERN = Pattern.compile(\"([\\\\w\\\\s]*):(.*)\");\n    private static final String CONTINUED_VALUE_STRING = \" \";\n\n    /**\n     * Parses a map of KeyValue pairs from a string.\n     */\n    public Map<String, String> parse(final String string) throws IOException {\n        return parse(new BufferedReader(new StringReader(string)));\n    }\n\n    /**\n     * Parses a map of KeyValue pairs from a buffered reader.\n     */\n    public Map<String, String> parse(final BufferedReader reader) throws IOException {\n        HashMap<String, String> map = null;\n        String line = reader.readLine();\n        String value = null;\n        String key = null;\n\n        while (line != null) {\n            if (line.startsWith(CONTINUED_VALUE_STRING)) {\n                value = value + \"\\n\" + line.trim();\n            } else {\n                if ((value != null) && (key != null)) {\n                    if (map == null) {\n                        map = new HashMap<String, String>();\n                    }\n                    map.put(key, value.trim());\n                    key = null;\n                    value = null;\n                }\n                Matcher matcher = KEY_VALUE_PATTERN.matcher(line);\n                if (matcher.matches()) {\n                    key = matcher.group(1);\n                    value = matcher.group(2);\n                }\n            }\n            line = reader.readLine();\n        }\n        if ((value != null) && (key != null)) {\n            if (map == null) {\n                map = new HashMap<String, String>();\n            }\n            map.put(key, value.trim());\n        }\n        return map;\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/License.txt",
    "content": "Git Credential Manager for Mac and Linux\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nAll rights reserved.\r\n\r\nMIT License\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE.\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/MaskedArgumentListBuilder.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport java.util.Collection;\r\nimport java.util.HashSet;\r\n\r\nimport hudson.util.ArgumentListBuilder;\r\n\r\n/**\r\n * ArgumentListBuilder that supports marking arguments as masked.\r\n * \r\n * @author Erik Ramfelt\r\n */\r\npublic class MaskedArgumentListBuilder extends ArgumentListBuilder{\r\n\r\n    private static final long serialVersionUID = 1L;\r\n    \r\n    private Collection<Integer> maskedArgumentIndex;\r\n\r\n    @Override\r\n    public ArgumentListBuilder prepend(String... args) {\r\n        if (maskedArgumentIndex != null) {\r\n            Collection<Integer> newMaskedArgumentIndex = new HashSet<Integer>();\r\n            for (Integer argIndex : maskedArgumentIndex) {\r\n                newMaskedArgumentIndex.add(argIndex + args.length);\r\n            }\r\n            maskedArgumentIndex = newMaskedArgumentIndex;\r\n        }\r\n        return super.prepend(args);        \r\n    }\r\n    \r\n    /**\r\n     * Returns true if there are any masked arguments.\r\n     * @return true if there are any masked arguments; false otherwise\r\n     */\r\n    public boolean hasMaskedArguments() {\r\n        return (maskedArgumentIndex != null);\r\n    }\r\n\r\n    /**\r\n     * Returns an array of booleans where the masked arguments are marked as true\r\n     * @return an array of booleans.\r\n     */\r\n    public boolean[] toMaskArray() {\r\n        String[] commands = toCommandArray();\r\n        boolean[] mask = new boolean[commands.length];\r\n        if (maskedArgumentIndex != null) { \r\n            for (Integer argIndex : maskedArgumentIndex) {\r\n                mask[argIndex] = true;\r\n            }\r\n        }\r\n        return mask;\r\n    }\r\n\r\n    /**\r\n     * Add a masked argument\r\n     * @param string the argument\r\n     */\r\n    public void addMasked(String string) {\r\n        if (maskedArgumentIndex == null) {\r\n            maskedArgumentIndex = new HashSet<Integer>();\r\n        }\r\n        maskedArgumentIndex.add(toCommandArray().length);\r\n        add(string);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/MediaType.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport java.nio.charset.Charset;\r\n\r\n/**\r\n * Media Type constants.\r\n */\r\npublic final class MediaType {\r\n    private MediaType() { }\r\n\r\n    public static final Charset UTF_8 = Charset.forName(\"UTF-8\");\r\n    public static final String APPLICATION_FORM_URLENCODED = \"application/x-www-form-urlencoded\";\r\n    public static final String APPLICATION_JSON = \"application/json\";\r\n    public static final String APPLICATION_JSON_UTF_8 = \"application/json; charset=utf-8\";\r\n    public static final String APPLICATION_JSON_PATCH_JSON = \"application/json-patch+json\";\r\n    public static final String APPLICATION_JSON_PATCH_JSON_UTF_8 = \"application/json-patch+json; charset=utf-8\";\r\n    public static final String APPLICATION_ZIP = \"application/zip\";\r\n    public static final String TEXT_PLAIN = \"text/plain\";\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/QueryString.java",
    "content": "// Copyright (c) Microsoft. All rights reserved.\r\n// Licensed under the MIT license. See sibling License.txt file\r\n\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport java.util.LinkedHashMap;\r\n\r\n/**\r\n * Helper to construct query strings for urls.\r\n */\r\npublic class QueryString extends LinkedHashMap<String, String> {\r\n\r\n    public QueryString() {\r\n    }\r\n\r\n    public QueryString(final String... nameValuePairs) {\r\n        final int length = nameValuePairs.length;\r\n        if (length % 2 != 0) {\r\n            final String message = \"This QueryString constructor needs an even number of parameters\";\r\n            throw new IllegalArgumentException(message);\r\n        }\r\n        for (int i = 0; i < length; i += 2) {\r\n            put(nameValuePairs[i], nameValuePairs[i + 1]);\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return UriHelper.serializeParameters(this);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/ResourceHelper.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport org.apache.commons.io.IOUtils;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\n\r\n/**\r\n * Helper to get resources.\r\n */\r\npublic final class ResourceHelper {\r\n\r\n    private ResourceHelper() { }\r\n\r\n    /**\r\n     * Gets the resource file and returns it as a string.\r\n     */\r\n    public static String fetchAsString(final Class<?> referenceClass, final String fileName) {\r\n        final InputStream stream = referenceClass.getResourceAsStream(fileName);\r\n        try {\r\n            return IOUtils.toString(stream, MediaType.UTF_8);\r\n        } catch (final IOException e) {\r\n            throw new Error(e);\r\n        } finally {\r\n            IOUtils.closeQuietly(stream);\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/StringBodyParameter.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.kohsuke.stapler.AnnotationHandler;\r\nimport org.kohsuke.stapler.InjectedParameter;\r\nimport org.kohsuke.stapler.StaplerRequest;\r\n\r\nimport javax.servlet.ServletException;\r\nimport java.io.IOException;\r\nimport java.lang.annotation.Documented;\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\n\r\n/**\r\n * {@link InjectedParameter} annotation to use on\r\n * {@link org.kohsuke.stapler.WebMethod} parameters to extract the body of the request\r\n * as a single string.\r\n */\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Target(ElementType.PARAMETER)\r\n@Documented\r\n@InjectedParameter(StringBodyParameter.StringBodyHandler.class)\r\npublic @interface StringBodyParameter {\r\n\r\n    /**\r\n     * Webmethod parameter annotation that extracts the body of the request.\r\n     */\r\n    class StringBodyHandler extends AnnotationHandler<StringBodyParameter> {\r\n\r\n        private static final Logger LOGGER = Logger.getLogger(StringBodyHandler.class.getName());\r\n\r\n\r\n        @Override\r\n        public Object parse(final StaplerRequest request, final StringBodyParameter a, final Class type, final String parameterName) throws ServletException {\r\n\r\n            final String rawContentType = request.getContentType();\r\n            final String contentType = StringHelper.determineContentTypeWithoutCharset(rawContentType);\r\n\r\n            if (MediaType.APPLICATION_FORM_URLENCODED.equals(contentType)) {\r\n                return request.getParameter(parameterName);\r\n            }\r\n\r\n            // default to application/json\r\n            final String characterEncoding = request.getCharacterEncoding();\r\n            try {\r\n                return IOUtils.toString(request.getInputStream(), characterEncoding);\r\n            } catch (final IOException e) {\r\n                LOGGER.log(Level.SEVERE, \"Unable to obtain request body: {}\", e.getMessage());\r\n            }\r\n            return null;\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/StringHelper.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\npublic class StringHelper {\r\n\r\n    public static boolean endsWithIgnoreCase(final String haystack, final String needle)\r\n    {\r\n        if (haystack == null)\r\n            throw new IllegalArgumentException(\"Parameter 'haystack' is null.\");\r\n        if (needle == null)\r\n            throw new IllegalArgumentException(\"Parameter 'needle' is null.\");\r\n\r\n        final int nl = needle.length();\r\n        final int hl = haystack.length();\r\n        if (nl == hl)\r\n        {\r\n            return haystack.equalsIgnoreCase(needle);\r\n        }\r\n\r\n        if (nl > hl)\r\n        {\r\n            return false;\r\n        }\r\n\r\n        // Inspired by https://stackoverflow.com/a/19154150/\r\n        final int toffset = hl - nl;\r\n        return haystack.regionMatches(true, toffset, needle, 0, nl);\r\n    }\r\n\r\n    public static boolean equal(final String a, final String b) {\r\n        return innerEqual(a, b, false);\r\n    }\r\n\r\n    public static boolean equalIgnoringCase(final String a, final String b) {\r\n        return innerEqual(a, b, true);\r\n    }\r\n\r\n    static boolean innerEqual(final String a, final String b, final boolean ignoreCase) {\r\n        if (a == null) {\r\n            return b == null;\r\n        }\r\n        if (b == null) {\r\n            return false;\r\n        }\r\n        final int length = a.length();\r\n        if (length != b.length()) {\r\n            return false;\r\n        }\r\n        return a.regionMatches(ignoreCase, 0, b, 0, length);\r\n    }\r\n\r\n    public static String determineContentTypeWithoutCharset(final String contentType) {\r\n        if (contentType == null) {\r\n            return null;\r\n        }\r\n        final int indexOfSemicolon = contentType.indexOf(';');\r\n        if (indexOfSemicolon != -1) {\r\n            final String beforeCharset = contentType.substring(0, indexOfSemicolon);\r\n            return beforeCharset.trim();\r\n        }\r\n        return contentType;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/TeamRestClient.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport com.microsoft.tfs.core.httpclient.HttpClient;\r\nimport com.microsoft.tfs.core.httpclient.NameValuePair;\r\nimport com.microsoft.tfs.util.StringUtil;\r\nimport com.microsoft.visualstudio.services.webapi.patch.Operation;\r\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\r\nimport hudson.plugins.tfs.TeamCollectionConfiguration;\r\nimport hudson.plugins.tfs.model.GitCodePushedEventArgs;\r\nimport hudson.plugins.tfs.model.HttpMethod;\r\nimport hudson.plugins.tfs.model.JobCompletionEventArgs;\r\nimport hudson.plugins.tfs.model.JsonPatchOperation;\r\nimport hudson.plugins.tfs.model.Link;\r\nimport hudson.plugins.tfs.model.ListOfGitRepositories;\r\nimport hudson.plugins.tfs.model.PullRequestMergeCommitCreatedEventArgs;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.TeamGitStatus;\r\nimport hudson.plugins.tfs.model.WorkItem;\r\nimport hudson.util.Secret;\r\nimport net.sf.json.JSON;\r\nimport net.sf.json.JSONArray;\r\nimport net.sf.json.JSONObject;\r\nimport org.apache.commons.io.IOUtils;\r\n\r\nimport javax.xml.bind.DatatypeConverter;\r\nimport java.io.BufferedReader;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.InputStreamReader;\r\nimport java.net.HttpURLConnection;\r\nimport java.net.URI;\r\n\r\npublic class TeamRestClient {\r\n\r\n    private static final String AUTHORIZATION = \"Authorization\";\r\n    private static final String API_VERSION = \"api-version\";\r\n    private static final String NEW_LINE = System.getProperty(\"line.separator\");\r\n\r\n    private final URI collectionUri;\r\n    private final boolean isTeamServices;\r\n    private final String authorization;\r\n    private final Server server;\r\n\r\n    public TeamRestClient(final URI collectionUri) throws IOException {\r\n        this(collectionUri, TeamCollectionConfiguration.findCredentialsForCollection(collectionUri));\r\n    }\r\n\r\n    public TeamRestClient(final URI collectionUri, final StandardUsernamePasswordCredentials credentials) throws IOException {\r\n        this.collectionUri = collectionUri;\r\n        final String hostName = collectionUri.getHost();\r\n        this.server = Server.create(null, null, collectionUri.toString(), credentials, null, null);\r\n        isTeamServices = TeamCollectionConfiguration.isTeamServices(hostName);\r\n        if (isTeamServices && credentials != null) {\r\n            authorization = createAuthorization(credentials);\r\n        }\r\n        else {\r\n            authorization = null;\r\n        }\r\n    }\r\n\r\n    public TeamRestClient(final String collectionUri, final StandardUsernamePasswordCredentials credentials) throws IOException {\r\n        this(URI.create(collectionUri), credentials);\r\n    }\r\n\r\n    static String createAuthorization(final StandardUsernamePasswordCredentials credentials) {\r\n        final String username = credentials.getUsername();\r\n        final Secret secretPassword = credentials.getPassword();\r\n        final String password = secretPassword.getPlainText();\r\n        final String credPair = username + \":\" + password;\r\n        final byte[] credBytes = credPair.getBytes(MediaType.UTF_8);\r\n        final String base64enc = DatatypeConverter.printBase64Binary(credBytes);\r\n        final String result = \"Basic \" + base64enc;\r\n        return result;\r\n    }\r\n\r\n    protected <TRequest, TResponse> TResponse request(\r\n            final Class<TResponse> responseClass,\r\n            final HttpMethod httpMethod,\r\n            final URI requestUri,\r\n            final TRequest requestBody\r\n    ) throws IOException {\r\n        return request(responseClass, httpMethod, requestUri, requestBody, null);\r\n    }\r\n\r\n    protected <TRequest, TResponse> TResponse request(\r\n            final Class<TResponse> responseClass,\r\n            final HttpMethod httpMethod,\r\n            final URI requestUri,\r\n            final TRequest requestBody,\r\n            final NameValuePair[] additionalRequestHeaders\r\n            ) throws IOException {\r\n\r\n        final HttpClient httpClient = server.getHttpClient();\r\n\r\n        final String stringRequestBody;\r\n        if (requestBody != null) {\r\n            final JSON jsonObject;\r\n            if (requestBody instanceof JSON) {\r\n                jsonObject = (JSON) requestBody;\r\n            }\r\n            else {\r\n                jsonObject = JSONObject.fromObject(requestBody);\r\n            }\r\n            stringRequestBody = jsonObject.toString(0);\r\n        }\r\n        else {\r\n            stringRequestBody = null;\r\n        }\r\n\r\n        final com.microsoft.tfs.core.httpclient.HttpMethod clientMethod = httpMethod.createClientMethod(requestUri.toString(), stringRequestBody);\r\n        if (authorization != null) {\r\n            clientMethod.addRequestHeader(AUTHORIZATION, authorization);\r\n        }\r\n\r\n        if (additionalRequestHeaders != null && additionalRequestHeaders.length > 0){\r\n            for(NameValuePair pair : additionalRequestHeaders) {\r\n                clientMethod.addRequestHeader(pair.getName(), pair.getValue());\r\n            }\r\n        }\r\n\r\n        final String stringResponseBody = innerRequest(clientMethod, httpClient);\r\n\r\n        if (responseClass == Void.class) {\r\n            return null;\r\n        }\r\n\r\n        if (responseClass == String.class) {\r\n            return (TResponse) stringResponseBody;\r\n        }\r\n\r\n        final TResponse result = deserialize(responseClass, stringResponseBody);\r\n        return result;\r\n    }\r\n\r\n    public static <TResponse> TResponse deserialize(final Class<TResponse> responseClass, final String stringResponseBody) {\r\n        try {\r\n            return EndpointHelper.MAPPER.readValue(stringResponseBody, responseClass);\r\n        }\r\n        catch (final IOException e) {\r\n            throw new Error(e);\r\n        }\r\n    }\r\n\r\n    static String innerRequest(final com.microsoft.tfs.core.httpclient.HttpMethod clientMethod, final HttpClient httpClient) throws IOException {\r\n\r\n        final int httpStatus = httpClient.executeMethod(clientMethod);\r\n\r\n        final String stringResult;\r\n        InputStream responseStream = null;\r\n        try {\r\n            if (httpStatus >= HttpURLConnection.HTTP_BAD_REQUEST) {\r\n                responseStream = clientMethod.getResponseBodyAsStream();\r\n                final String responseText = readResponseText(responseStream);\r\n                final StringBuilder sb = new StringBuilder(\"HTTP \").append(httpStatus);\r\n                final String statusText = clientMethod.getStatusText();\r\n                if (statusText != null) {\r\n                    sb.append(\" (\").append(statusText).append(\")\");\r\n                }\r\n                if (!StringUtil.isNullOrEmpty(responseText)) {\r\n                    sb.append(\": \").append(responseText);\r\n                }\r\n                throw new IOException(sb.toString());\r\n            }\r\n            responseStream = clientMethod.getResponseBodyAsStream();\r\n            stringResult = readResponseText(responseStream);\r\n        }\r\n        finally {\r\n            IOUtils.closeQuietly(responseStream);\r\n        }\r\n        return stringResult;\r\n    }\r\n\r\n    @SuppressFBWarnings(value = \"DM_DEFAULT_ENCODING\", justification = \"Better mot modify charset in case it might raise errors\")\r\n    static String readResponseText(final InputStream inputStream) throws IOException {\r\n        final InputStreamReader isr = new InputStreamReader(inputStream);\r\n        final BufferedReader reader = new BufferedReader(isr);\r\n        final StringBuilder sb = new StringBuilder();\r\n        try {\r\n            String line;\r\n            while ((line = reader.readLine()) != null) {\r\n                sb.append(line);\r\n                sb.append(NEW_LINE);\r\n            }\r\n        }\r\n        finally {\r\n            IOUtils.closeQuietly(reader);\r\n            IOUtils.closeQuietly(isr);\r\n            IOUtils.closeQuietly(inputStream);\r\n        }\r\n        return sb.toString();\r\n    }\r\n\r\n    public String ping() throws IOException {\r\n        final URI requestUri;\r\n        if (isTeamServices) {\r\n            requestUri = UriHelper.join(collectionUri, \"_apis\", \"connectiondata\");\r\n        }\r\n        else {\r\n            requestUri = UriHelper.join(collectionUri, \"_home\", \"About\");\r\n        }\r\n\r\n        return request(String.class, HttpMethod.GET, requestUri, null);\r\n    }\r\n\r\n    public ListOfGitRepositories getRepositories() throws IOException {\r\n        final QueryString qs = new QueryString(API_VERSION, \"1.0\");\r\n        final URI requestUri = UriHelper.join(\r\n                collectionUri,\r\n                \"_apis\",\r\n                \"git\",\r\n                \"repositories\",\r\n                qs\r\n        );\r\n\r\n        return request(ListOfGitRepositories.class, HttpMethod.GET, requestUri, null);\r\n    }\r\n\r\n    public TeamGitStatus addCommitStatus(final GitCodePushedEventArgs args, final TeamGitStatus status) throws IOException {\r\n\r\n        final QueryString qs = new QueryString(API_VERSION, \"2.1\");\r\n        final URI requestUri = UriHelper.join(\r\n            collectionUri, args.projectId,\r\n            \"_apis\", \"git\",\r\n            \"repositories\", args.repoId,\r\n            \"commits\", args.commit,\r\n            \"statuses\",\r\n            qs);\r\n\r\n        return request(TeamGitStatus.class, HttpMethod.POST, requestUri, status);\r\n    }\r\n\r\n    public WorkItem getWorkItem(final int workItemId) throws IOException {\r\n        final QueryString qs = new QueryString(API_VERSION, \"1.0\");\r\n        final URI requestUri = UriHelper.join(\r\n                collectionUri,\r\n                \"_apis\",\r\n                \"wit\",\r\n                \"workitems\",\r\n                workItemId,\r\n                qs\r\n        );\r\n\r\n        return request(WorkItem.class, HttpMethod.GET, requestUri, null);\r\n    }\r\n\r\n    public void addHyperlinkToWorkItem(final int workItemId, final String hyperlink) throws IOException {\r\n\r\n        final JSONArray doc = new JSONArray();\r\n\r\n        final WorkItem workItem = getWorkItem(workItemId);\r\n        final JsonPatchOperation testRev = new JsonPatchOperation();\r\n        testRev.setOp(Operation.TEST);\r\n        testRev.setPath(\"/rev\");\r\n        testRev.setValue(workItem.getRev());\r\n        doc.add(testRev);\r\n\r\n        // TODO: do we also need to \"add\" to \"/fields/System.History\"?\r\n\r\n        final Link link = new Link(\"Hyperlink\", hyperlink);\r\n        final JsonPatchOperation addRelation = new JsonPatchOperation();\r\n        addRelation.setOp(Operation.ADD);\r\n        addRelation.setPath(\"/relations/-\");\r\n        addRelation.setValue(link);\r\n        doc.add(addRelation);\r\n\r\n        final QueryString qs = new QueryString(API_VERSION, \"1.0\");\r\n        final URI requestUri = UriHelper.join(\r\n            collectionUri,\r\n            \"_apis\",\r\n            \"wit\",\r\n            \"workitems\",\r\n            workItemId,\r\n            qs);\r\n\r\n        // TODO: this call could fail because something else bumped the rev in the meantime; retry?\r\n        request(Void.class, HttpMethod.PATCH, requestUri, doc);\r\n    }\r\n\r\n    public TeamGitStatus addPullRequestStatus(final PullRequestMergeCommitCreatedEventArgs args, final TeamGitStatus status) throws IOException {\r\n\r\n        final QueryString qs = new QueryString(API_VERSION, \"4.1-preview\");\r\n        final URI requestUri = UriHelper.join(\r\n            collectionUri, args.projectId,\r\n            \"_apis\", \"git\",\r\n            \"repositories\", args.repoId,\r\n            \"pullRequests\", args.pullRequestId,\r\n            \"statuses\",\r\n            qs);\r\n\r\n        return request(TeamGitStatus.class, HttpMethod.POST, requestUri, status);\r\n    }\r\n\r\n    public TeamGitStatus addPullRequestIterationStatus(final PullRequestMergeCommitCreatedEventArgs args, final TeamGitStatus status) throws IOException {\r\n\r\n        final QueryString qs = new QueryString(API_VERSION, \"4.1-preview\");\r\n        final URI requestUri = UriHelper.join(\r\n            collectionUri, args.projectId,\r\n            \"_apis\", \"git\",\r\n            \"repositories\", args.repoId,\r\n            \"pullRequests\", args.pullRequestId,\r\n            \"iterations\", args.iterationId,\r\n            \"statuses\",\r\n            qs);\r\n\r\n        return request(TeamGitStatus.class, HttpMethod.POST, requestUri, status);\r\n    }\r\n\r\n\r\n    public void sendJobCompletionEvent(final JobCompletionEventArgs args) throws IOException {\r\n        final QueryString qs = new QueryString(\r\n                API_VERSION, \"3.2\",\r\n                \"publisherId\", \"jenkins\",\r\n                \"channelId\", args.getServerKey());\r\n\r\n        final URI requestUri = UriHelper.join(\r\n                collectionUri,\r\n                \"_apis\", \"public\", \"hooks\", \"externalEvents\",\r\n                qs);\r\n\r\n        final JSONObject json = JSONObject.fromObject(args.getPayload());\r\n\r\n        final NameValuePair[] headers = new NameValuePair[3];\r\n        headers[0] = new NameValuePair(\"X-Event-Key\", \"job:completion\");\r\n        headers[1] = new NameValuePair(\"X-Jenkins-Signature\", args.getPayloadSignature());\r\n        headers[2] = new NameValuePair(\"X-Jenkins-ServerKey\", args.getServerKey());\r\n\r\n        request(Void.class, HttpMethod.POST, requestUri, json, headers);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/TeamStatus.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport hudson.model.Job;\r\nimport hudson.model.Run;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.CommitParameterAction;\r\nimport hudson.plugins.tfs.PullRequestParameterAction;\r\nimport hudson.plugins.tfs.UnsupportedIntegrationAction;\r\nimport hudson.plugins.tfs.model.GitCodePushedEventArgs;\r\nimport hudson.plugins.tfs.model.PullRequestMergeCommitCreatedEventArgs;\r\nimport hudson.plugins.tfs.model.TeamGitStatus;\r\nimport hudson.plugins.tfs.telemetry.TelemetryHelper;\r\n\r\nimport javax.annotation.Nonnull;\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\nimport java.net.URI;\r\n\r\n/**\r\n * Creates and adds a TeamGitStatus to the run.\r\n */\r\npublic final class TeamStatus {\r\n    private TeamStatus() { }\r\n\r\n    /**\r\n     * Creates and adds a TeamGitStatus to the run.\r\n     */\r\n    public static void createFromRun(@Nonnull final Run<?, ?> run, @Nonnull final TaskListener listener, final String featureDisplayName) throws IOException {\r\n\r\n        if (!UnsupportedIntegrationAction.isSupported(run, listener)) {\r\n            final PrintStream logger = listener.getLogger();\r\n            logger.print(\"NOTICE: \");\r\n            logger.print(\"You selected '\");\r\n            logger.print(featureDisplayName);\r\n            logger.println(\"' on your Jenkins job, but this option has no effect when calling the job from the 'Jenkins Queue Job' task in TFS/Team Services.\");\r\n            return;\r\n        }\r\n\r\n        final CommitParameterAction commitParameter = run.getAction(CommitParameterAction.class);\r\n        final GitCodePushedEventArgs gitCodePushedEventArgs;\r\n        final PullRequestMergeCommitCreatedEventArgs pullRequestMergeCommitCreatedEventArgs;\r\n\r\n        if (commitParameter != null) {\r\n            gitCodePushedEventArgs = commitParameter.getGitCodePushedEventArgs();\r\n            if (commitParameter instanceof PullRequestParameterAction) {\r\n                final PullRequestParameterAction prpa = (PullRequestParameterAction) commitParameter;\r\n                pullRequestMergeCommitCreatedEventArgs = prpa.getPullRequestMergeCommitCreatedEventArgs();\r\n            } else {\r\n                pullRequestMergeCommitCreatedEventArgs = null;\r\n            }\r\n        } else {\r\n            // TODO: try to guess based on what we _do_ have (i.e. RevisionParameterAction)\r\n            return;\r\n        }\r\n\r\n        final URI collectionUri = gitCodePushedEventArgs.collectionUri;\r\n        final TeamGitStatus status = TeamGitStatus.fromRun(run);\r\n\r\n        // Send telemetry\r\n        TelemetryHelper.sendEvent(\"team-status\", new TelemetryHelper.PropertyMapBuilder()\r\n                .serverContext(collectionUri.toString(), collectionUri.toString())\r\n                .pair(\"feature\", featureDisplayName)\r\n                .pair(\"status\", status.state.toString())\r\n                .build());\r\n\r\n        addStatus(pullRequestMergeCommitCreatedEventArgs, status);\r\n    }\r\n\r\n    /**\r\n     * Create status for a (queued) Job.\r\n     */\r\n    public static void createFromJob(final PullRequestMergeCommitCreatedEventArgs pullRequestMergeCommitCreatedEventArgs, final Job job) throws IOException {\r\n        final TeamGitStatus status = TeamGitStatus.fromJob(job);\r\n\r\n        addStatus(pullRequestMergeCommitCreatedEventArgs, status);\r\n    }\r\n\r\n    private static void addStatus(final PullRequestMergeCommitCreatedEventArgs gitCodePushedEventArgs, final TeamGitStatus status) throws IOException {\r\n        final PullRequestMergeCommitCreatedEventArgs pullRequestMergeCommitCreatedEventArgs;\r\n\r\n        if (gitCodePushedEventArgs instanceof PullRequestMergeCommitCreatedEventArgs) {\r\n            pullRequestMergeCommitCreatedEventArgs = (PullRequestMergeCommitCreatedEventArgs) gitCodePushedEventArgs;\r\n        } else {\r\n            pullRequestMergeCommitCreatedEventArgs = null;\r\n        }\r\n\r\n        final URI collectionUri = gitCodePushedEventArgs.collectionUri;\r\n        final TeamRestClient client = new TeamRestClient(collectionUri);\r\n\r\n        // TODO: when code is pushed and polling happens, are we sure we built against the requested commit?\r\n        if (pullRequestMergeCommitCreatedEventArgs != null) {\r\n            if (pullRequestMergeCommitCreatedEventArgs.iterationId == -1) {\r\n                client.addPullRequestStatus(pullRequestMergeCommitCreatedEventArgs, status);\r\n            } else {\r\n                client.addPullRequestIterationStatus(pullRequestMergeCommitCreatedEventArgs, status);\r\n            }\r\n        }\r\n        client.addCommitStatus(gitCodePushedEventArgs, status);\r\n\r\n        // TODO: we could contribute an Action to the run, recording the ID of the status we created\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/TextTableParser.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.IOException;\r\nimport java.io.Reader;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\n\r\n/**\r\n * Parser for the text table output from the TF tool.\r\n * The table will always begin with a number of columns that specifies how wide each\r\n * column is. The text table parser will use the number of columns and their width to\r\n * be able to parse the lines that comes after the column definition. Some columns\r\n * are optional, ie they does not contain any data and the line ends before the\r\n * optional column begins. \r\n * <p>\r\n * An example of how a separator definition may look. The table consists of 3 columns; \r\n * column 1 contains a string with at most 5 chars, column 2 contains a string with at most\r\n * 2 chars and column 3 may contain a string with at most 4 chars. The third column is optional.\r\n * <pre>\r\n * ----- -- ----\r\n * Data1 A  Data\r\n * Data2 B\r\n * Data3 C  Data\r\n * </pre>\r\n * <code>\r\n * TextTableParser t = new TextTableParser(reader, 1);\r\n * t.nextRow() // first row\r\n * assertEquals(\"Data1\", t.getColumn(0));\r\n * assertEquals(\"Data\", t.getColumn(2));\r\n * t.nextRow(); // Second row\r\n * assertEquals(\"Data2\", t.getColumn(0));\r\n * assertNull(t.getColumn(2));\r\n * t.nextRow(); // Third row\r\n * assertEquals(\"Data3\", t.getColumn(0));\r\n * assertEquals(\"Data\", t.getColumn(2));\r\n * </code>\r\n\r\n * @author Erik Ramfelt\r\n */\r\npublic class TextTableParser {\r\n\r\n    private static final Pattern SEPARATOR_PATTERN = Pattern.compile(\"(-+)\");\r\n    private final BufferedReader reader;\r\n    private List<ColumnRange> columns;\r\n    \r\n    private String currentLine;\r\n    private final int optionalColumnCount;\r\n    private int lastMandatoryColumnStart;\r\n\r\n    public TextTableParser(Reader reader) throws IOException {\r\n        this(reader, 0);\r\n    }\r\n    \r\n    public TextTableParser(Reader reader, int optionalColumnCount) throws IOException {\r\n        this.reader = new BufferedReader( reader );\r\n        this.optionalColumnCount = optionalColumnCount;\r\n        init();\r\n    }\r\n\r\n    private void init() throws IOException {\r\n        String line = reader.readLine();\r\n        columns = new ArrayList<ColumnRange>();\r\n        while (line != null) {\r\n        \tif (line.startsWith(\"-\")) {\r\n\t            Matcher matcher = SEPARATOR_PATTERN.matcher(line);\r\n\t            if (matcher.find()) {\r\n\t                do  {\r\n\t                    columns.add(new ColumnRange(matcher.start(), matcher.end()));\r\n\t                } while (matcher.find());\r\n\t                break;\r\n\t            }\r\n        \t}\r\n            line = reader.readLine();\r\n        }\r\n        if (columns.size() > 0){\r\n            lastMandatoryColumnStart = columns.get(columns.size() - 1 - optionalColumnCount).start;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the number of columns\r\n     * @return the number of columns\r\n     */\r\n    public int getColumnCount() {\r\n        return columns.size();\r\n    }\r\n\r\n    /**\r\n     * Return the value in the specified column\r\n     * @param index the column index\r\n     * @return the value in the specified column; null if there is no value (the column is optional)\r\n     */\r\n    public String getColumn(int index) {\r\n        if (currentLine == null) {\r\n            throw new IllegalStateException(\"There is no active row.\");\r\n        }\r\n        \r\n        ColumnRange columnRange = columns.get(index);        \r\n        if (currentLine.length() < columnRange.start) {\r\n            return null;\r\n        }\r\n        \r\n        if (currentLine.length() < columnRange.end) {\r\n            return currentLine.substring(columnRange.start).trim();\r\n        } else {\r\n            return currentLine.substring(columnRange.start, columnRange.end).trim();\r\n        }\r\n    }\r\n    \r\n    /**\r\n     * Move to the next row\r\n     * @return true, if there was a next row; false, if there is no next row.\r\n     * @throws IOException If an I/O error occurs\r\n     */\r\n    public boolean nextRow() throws IOException {\r\n        do {\r\n            currentLine = reader.readLine();\r\n        } while ((currentLine != null) && (currentLine.length() < lastMandatoryColumnStart));\r\n        return (currentLine != null);\r\n    }\r\n    \r\n    private static class ColumnRange {\r\n        private final int start;\r\n        private final int end;\r\n        public ColumnRange(int start, int end) {\r\n            this.start = start;\r\n            this.end = end;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/UriHelper.java",
    "content": "//CHECKSTYLE:OFF\r\n// Copyright (c) Microsoft. All rights reserved.\r\n// Licensed under the MIT license. See sibling License.txt file\r\n\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport org.eclipse.jgit.transport.URIish;\r\n\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.net.URI;\r\nimport java.net.URISyntaxException;\r\nimport java.net.URLEncoder;\r\nimport java.util.Collections;\r\nimport java.util.Iterator;\r\nimport java.util.Map;\r\nimport java.util.Scanner;\r\nimport java.util.TreeMap;\r\n\r\npublic class UriHelper {\r\n\r\n    private static final Map<String, Integer> SCHEMES_TO_DEFAULT_PORTS;\r\n    public static final String UTF_8 = \"UTF-8\";\r\n    private static final String DEFAULT_COLLECTION = \"DefaultCollection\";\r\n\r\n    static {\r\n        final Map<String, Integer> defaultPorts =\r\n                new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);\r\n        defaultPorts.put(\"ftp\", 21);\r\n        defaultPorts.put(\"ssh\", 22);\r\n        defaultPorts.put(\"http\", 80);\r\n        defaultPorts.put(\"https\", 443);\r\n        SCHEMES_TO_DEFAULT_PORTS = Collections.unmodifiableMap(defaultPorts);\r\n    }\r\n\r\n    /**\r\n     * Compares two {@link URI} instances to determine if they are equivalent.\r\n     * For example,\r\n     * {@code HTTP://WWW.EXAMPLE.COM:80/}\r\n     * and\r\n     * {@code http://www.example.com}\r\n     * are considered equivalent.\r\n     * This method handles a few more cases than {@link URI#equals(Object)}, such that the scheme's\r\n     * default port number will be considered, as will the default path for hosts.\r\n     *\r\n     * @param a the first URI\r\n     * @param b the second URI\r\n     * @return {@code true} if a and b represent the same resource; {@code false} otherwise.\r\n     */\r\n    public static boolean areSame(final URI a, final URI b) {\r\n        if (a == null) {\r\n            return b == null;\r\n        }\r\n        if (b == null) {\r\n            return false;\r\n        }\r\n\r\n        if (!StringHelper.equalIgnoringCase(a.getScheme(), b.getScheme())) {\r\n            return false;\r\n        }\r\n\r\n        if (!StringHelper.equalIgnoringCase(a.getHost(), b.getHost())) {\r\n            return false;\r\n        }\r\n\r\n        final int aPort = normalizePort(a);\r\n        final int bPort = normalizePort(b);\r\n        if (aPort != bPort) {\r\n            return false;\r\n        }\r\n\r\n        final String aPath = normalizePath(a);\r\n        final String bPath = normalizePath(b);\r\n        if (!StringHelper.equal(aPath, bPath)) {\r\n            return false;\r\n        }\r\n\r\n        if (!StringHelper.equal(a.getQuery(), b.getQuery())) {\r\n            return false;\r\n        }\r\n\r\n        if (!StringHelper.equal(a.getFragment(), b.getFragment())) {\r\n            return false;\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    public static boolean areSameGitRepo(final URIish a, final URIish b) {\r\n        final URI uriA = a == null ? null : URI.create(a.toString());\r\n        final URI uriB = b == null ? null : URI.create(b.toString());\r\n\r\n        return areSameGitRepo(uriA, uriB);\r\n    }\r\n\r\n    public static boolean areSameGitRepo(final URI a, final URI b) {\r\n        if (a == null) {\r\n            return b == null;\r\n        }\r\n        if (b == null) {\r\n            return false;\r\n        }\r\n\r\n        if (StringHelper.equalIgnoringCase(a.getScheme(), b.getScheme())) {\r\n            final int aPort = normalizePort(a);\r\n            final int bPort = normalizePort(b);\r\n            if (aPort != bPort) {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        if (!StringHelper.equalIgnoringCase(a.getHost(), b.getHost())) {\r\n            return false;\r\n        }\r\n\r\n        final String aPath = normalizePath(a);\r\n        final String bPath = normalizePath(b);\r\n        if (StringHelper.equal(aPath, bPath)) {\r\n            return true;\r\n        }\r\n\r\n        final Iterator<String> aPathParts = decomposePath(aPath);\r\n        boolean aSeenDefaultCollection = false;\r\n        final Iterator<String> bPathParts = decomposePath(bPath);\r\n        boolean bSeenDefaultCollection = false;\r\n        while (aPathParts.hasNext() && bPathParts.hasNext()) {\r\n            String aPart = aPathParts.next();\r\n            String bPart = bPathParts.next();\r\n            if (StringHelper.equalIgnoringCase(DEFAULT_COLLECTION, aPart) && aPathParts.hasNext() && !aSeenDefaultCollection) {\r\n                aPart = aPathParts.next();\r\n                aSeenDefaultCollection = true;\r\n            }\r\n            if (StringHelper.equalIgnoringCase(DEFAULT_COLLECTION, bPart) && bPathParts.hasNext() && !bSeenDefaultCollection) {\r\n                bPart = bPathParts.next();\r\n                bSeenDefaultCollection = true;\r\n            }\r\n\r\n            if (!StringHelper.equalIgnoringCase(aPart, bPart)) {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    static int normalizePort(final URI uri) {\r\n        int port = uri.getPort();\r\n        if (port == -1) {\r\n            final String scheme = uri.getScheme();\r\n            if (scheme != null) {\r\n                if (SCHEMES_TO_DEFAULT_PORTS.containsKey(scheme)) {\r\n                    port = SCHEMES_TO_DEFAULT_PORTS.get(scheme);\r\n                }\r\n            }\r\n        }\r\n        return port;\r\n    }\r\n\r\n    static String normalizePath(final URI uri) {\r\n        String path = uri.getPath();\r\n        if (path == null) {\r\n            path = \"/\";\r\n        }\r\n        else {\r\n            if (!path.endsWith(\"/\")) {\r\n                path = path + \"/\";\r\n            }\r\n        }\r\n        return path;\r\n    }\r\n\r\n    static Iterator<String> decomposePath(final String path) {\r\n        return new Scanner(path).useDelimiter(\"/\");\r\n    }\r\n\r\n    public static boolean hasPath(final URI uri) {\r\n        final String path = uri.getPath();\r\n        if (path != null) {\r\n            if (path.length() > 0 && !path.equals(\"/\")) {\r\n                return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    public static boolean isWellFormedUriString(final String uriString) {\r\n        try {\r\n            new URI(uriString);\r\n            return true;\r\n        }\r\n        catch (final URISyntaxException ignored) {\r\n            return false;\r\n        }\r\n    }\r\n\r\n    public static URI join(final URI collectionUri, final Object... components) {\r\n        return join(collectionUri.toString(), components);\r\n    }\r\n\r\n    public static URI join(final String collectionUrl, final Object... components) {\r\n        final StringBuilder sb = new StringBuilder(collectionUrl);\r\n        final boolean baseEndedWithSlash = endsWithSlash(sb);\r\n\r\n        boolean first = true;\r\n        for (final Object component : components) {\r\n            boolean hasSlash = false;\r\n            if (component instanceof QueryString) {\r\n                final QueryString queryString = (QueryString) component;\r\n                if (first) {\r\n                    if (!baseEndedWithSlash) {\r\n                        sb.append('/');\r\n                    }\r\n                }\r\n                sb.append(\"?\");\r\n                sb.append(queryString.toString());\r\n                // a QueryString must be the last of the components\r\n                break;\r\n            }\r\n            else {\r\n                if (first) {\r\n                    first = false;\r\n                    if (!baseEndedWithSlash) {\r\n                        sb.append('/');\r\n                    }\r\n                }\r\n                else {\r\n                    sb.append('/');\r\n                }\r\n                try {\r\n                    final String encodedComponent = URLEncoder.encode(component.toString(), UTF_8);\r\n                    // URLEncoder#encode() encodes spaces as \"+\" but they should be \"%20\"\r\n                    final String correctlyEncodedComponent = encodedComponent.replaceAll(\"\\\\+\", \"%20\");\r\n                    sb.append(correctlyEncodedComponent);\r\n                }\r\n                catch (final UnsupportedEncodingException e) {\r\n                    throw new Error(e);\r\n                }\r\n            }\r\n        }\r\n\r\n        final String uriString = sb.toString();\r\n        return URI.create(uriString);\r\n    }\r\n\r\n    static boolean endsWithSlash(final StringBuilder stringBuilder) {\r\n        final int length = stringBuilder.length();\r\n        return length > 0 && stringBuilder.charAt(length - 1) == '/';\r\n    }\r\n\r\n    public static String serializeParameters(final Map<String, String> parameters) {\r\n        try {\r\n            final StringBuilder sb = new StringBuilder();\r\n            final Iterator<Map.Entry<String, String>> iterator = parameters.entrySet().iterator();\r\n            if (iterator.hasNext()) {\r\n                Map.Entry<String, String> entry;\r\n                String key;\r\n                String encodedKey;\r\n                String value;\r\n                String encodedValue;\r\n\r\n                entry = iterator.next();\r\n                key = entry.getKey();\r\n                encodedKey = URLEncoder.encode(key, UTF_8);\r\n                sb.append(encodedKey);\r\n                value = entry.getValue();\r\n                if (value != null) {\r\n                    encodedValue = URLEncoder.encode(value, UTF_8);\r\n                    sb.append('=').append(encodedValue);\r\n                }\r\n                while (iterator.hasNext()) {\r\n                    sb.append('&');\r\n                    entry = iterator.next();\r\n                    key = entry.getKey();\r\n                    encodedKey = URLEncoder.encode(key, UTF_8);\r\n                    sb.append(encodedKey);\r\n                    value = entry.getValue();\r\n                    if (value != null) {\r\n                        encodedValue = URLEncoder.encode(value, UTF_8);\r\n                        sb.append('=').append(encodedValue);\r\n                    }\r\n                }\r\n            }\r\n            return sb.toString();\r\n        }\r\n        catch (final UnsupportedEncodingException e) {\r\n            throw new Error(e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/java/hudson/plugins/tfs/util/XmlHelper.java",
    "content": "//CHECKSTYLE:OFF\r\npackage hudson.plugins.tfs.util;\r\n\r\nimport org.w3c.dom.Document;\r\nimport org.w3c.dom.Node;\r\nimport org.xml.sax.SAXException;\r\n\r\nimport javax.xml.parsers.DocumentBuilder;\r\nimport javax.xml.parsers.DocumentBuilderFactory;\r\nimport javax.xml.parsers.ParserConfigurationException;\r\nimport javax.xml.transform.Transformer;\r\nimport javax.xml.transform.TransformerException;\r\nimport javax.xml.transform.TransformerFactory;\r\nimport javax.xml.transform.dom.DOMSource;\r\nimport javax.xml.transform.stream.StreamResult;\r\nimport javax.xml.xpath.XPath;\r\nimport javax.xml.xpath.XPathConstants;\r\nimport javax.xml.xpath.XPathExpression;\r\nimport javax.xml.xpath.XPathExpressionException;\r\nimport javax.xml.xpath.XPathFactory;\r\nimport java.io.File;\r\nimport java.io.FileInputStream;\r\nimport java.io.FileNotFoundException;\r\nimport java.io.FileOutputStream;\r\nimport java.io.IOException;\r\n\r\npublic class XmlHelper {\r\n\r\n    private static final XPathFactory XPF = XPathFactory.newInstance();\r\n    private static final DocumentBuilderFactory DBF = DocumentBuilderFactory.newInstance();\r\n    private static final TransformerFactory TF = TransformerFactory.newInstance();\r\n\r\n    public static String peekValue(final Document doc, final String xpathExpression)\r\n            throws XPathExpressionException {\r\n        final XPath xPath = XPF.newXPath();\r\n        final XPathExpression expression = xPath.compile(xpathExpression);\r\n\r\n        final Node node = (Node) expression.evaluate(doc, XPathConstants.NODE);\r\n        final String result = (node != null) ? node.getTextContent() : null;\r\n        return result;\r\n    }\r\n\r\n    public static String peekValue(final File file, final String xpathExpression)\r\n            throws ParserConfigurationException, IOException, SAXException, XPathExpressionException {\r\n        final DocumentBuilder db = DBF.newDocumentBuilder();\r\n        final FileInputStream fis = new FileInputStream(file);\r\n        final Document doc;\r\n        try {\r\n            doc = db.parse(fis);\r\n        }\r\n        finally {\r\n            fis.close();\r\n        }\r\n\r\n        final String result = peekValue(doc, xpathExpression);\r\n        return result;\r\n    }\r\n\r\n    public static void pokeValue(final Document doc, final String xpathExpression, final String value) throws XPathExpressionException {\r\n        final XPath xPath = XPF.newXPath();\r\n        final XPathExpression expression = xPath.compile(xpathExpression);\r\n\r\n        final Node node = (Node) expression.evaluate(doc, XPathConstants.NODE);\r\n        // or setValue()?\r\n        node.setTextContent(value);\r\n    }\r\n\r\n    public static void pokeValue(final File file, final String xpathExpression, final String value)\r\n            throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, TransformerException {\r\n        // TODO: it might be better performance to do a SAX read/write\r\n        final DocumentBuilder db = DBF.newDocumentBuilder();\r\n        final FileInputStream fis = new FileInputStream(file);\r\n        final Document doc;\r\n        try {\r\n            doc = db.parse(fis);\r\n        }\r\n        finally {\r\n            fis.close();\r\n        }\r\n\r\n        pokeValue(doc, xpathExpression, value);\r\n\r\n        final Transformer t = TF.newTransformer();\r\n        final DOMSource source = new DOMSource(doc);\r\n        final FileOutputStream fos = new FileOutputStream(file);\r\n        try {\r\n            final StreamResult result = new StreamResult(fos);\r\n            t.transform(source, result);\r\n        }\r\n        finally {\r\n            fos.close();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TFSLabeler/config.jelly",
    "content": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\n\t<f:entry title=\"Label\" help=\"/plugin/tfs/labelname.html\">\n\t\t<f:textbox name=\"tfsLabeler.labelName\" value=\"${instance.labelName}\" />\n\t</f:entry>\n\t<f:entry title=\"Always\">\n\t\t<f:radio name=\"tfsLabeler.whenToLabel\" value=\"always\" checked=\"${instance.whenToLabel=='always'}\"/>\n\t</f:entry>\n\t<f:entry title=\"If the build is successful\">\n\t\t<f:radio name=\"tfsLabeler.whenToLabel\" value=\"success\" checked=\"${instance.whenToLabel=='success'}\"/>\n\t</f:entry>\n</j:jelly>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TFSLabeler/global.jelly",
    "content": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\n\n</j:jelly>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamBuildDetailsAction/index.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\"\r\n\txmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\"\r\n\txmlns:f=\"/lib/form\" xmlns:i=\"jelly:fmt\">\r\n\t<l:layout>\r\n\t    <l:main-panel>\r\n\t    <h2>${it.displayName}</h2>\r\n\r\n        Triggered by TFS/Team Services build <a href=\"${it.buildUrl}\">${it.buildNumber} of '${it.buildDefinitionName}'</a>\r\n\t    </l:main-panel>\r\n\t</l:layout>\r\n</j:jelly>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamBuildDetailsAction/summary.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\"\r\n\txmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\"\r\n\txmlns:f=\"/lib/form\" xmlns:i=\"jelly:fmt\">\r\n\t<t:summary icon=\"${it.iconFileName}\">\r\n\r\n \tTriggered by TFS/Team Services build <a href=\"${it.buildUrl}\">${it.buildNumber} of '${it.buildDefinitionName}'</a>\r\n\t</t:summary>\r\n</j:jelly>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamBuildEndpoint.html",
    "content": "<html>\r\n    <body>\r\n        <h1>The <code>/%1$s/</code> endpoint</h1>\r\n\r\n        <h2>Security</h2>\r\n        When your Jenkins is secured, you can use HTTP BASIC authentication to authenticate remote API requests. See <a href=\"https://wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients\">Authenticating scripted clients</a> for more details.\r\n        <br />\r\n        <h2>Cross Site Request Forgery (CSRF) protection</h2>\r\n        If your Jenkins uses the \"Prevent Cross Site Request Forgery exploits\" security option (which it should), when you make a POST request, you have to send a CSRF protection token as an HTTP request header.  See <a href=\"https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API#RemoteaccessAPI-CSRFProtection\">CSRF Protection</a> for more details.\r\n        <br />\r\n        <h3>WARNING</h3>\r\n        This endpoint SHOULD be reachable only through a secure channel.\r\n\r\n        <h2>Build commands</h2>\r\n        The following build commands are available to POST to:\r\n        <table border=\"1\">\r\n            <tr>\r\n                <th>Name</th>\r\n                <th>Path</th>\r\n                <th>Sample payload</th>\r\n            </tr>\r\n            %2$s\r\n        </table>\r\n\r\n        <h2>Example</h2>\r\n        Suppose we have a secured Jenkins server at <code>%3$s</code>, a dedicated <em>Remote Trigger</em> user named <code>remote</code> that has an <a href=\"%3$sme/configure\">API Token</a> of <code>92e9d8998a8c005697d252f09a2a311b</code> and the following <code>payload.json</code> file:\r\n        <pre>\r\n{\r\n    \"parameter\":\r\n    [\r\n        {\"name\":\"id\",\"value\":\"123\"},\r\n        {\"name\":\"verbosity\",\"value\":\"high\"}\r\n    ]\r\n}\r\n        </pre>\r\n        The following example demonstrates a GET to the <code>/crumbIssuer</code> endpoint to retrieve a header and then a POST to the <code>ping</code> command for the job named JOB_NAME using the <a href=\"https://curl.haxx.se/\">curl</a> tool:\r\n        <br />\r\n        <pre>\r\ncrumb=$(curl '%3$scrumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)' --user remote:92e9d8998a8c005697d252f09a2a311b)\r\ncurl --request POST %3$s%1$s/ping/JOB_NAME --data-urlencode json@payload.json --user remote:92e9d8998a8c005697d252f09a2a311b --header \"$crumb\"\r\n        </pre>\r\n        The console output should look like the following when the <code>ping</code> command from the <code>%1$s</code> endpoint returns the provided payload, formatted for compactness:\r\n        <pre>\r\n{\"parameter\":[{\"name\":\"id\",\"value\":\"123\"},{\"name\":\"verbosity\",\"value\":\"high\"}]}\r\n        </pre>\r\n    </body>\r\n</html>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamCollectResultsPostBuildAction/config.groovy",
    "content": "package hudson.plugins.tfs.TeamCollectResultsPostBuildAction;\r\n\r\ndef f = namespace(lib.FormTagLib);\r\n\r\n// this would look/feel nicer if the Add button was a drop-down list, like for build steps\r\nf.entry(title: _(\"Build results to collect\")) {\r\n    f.repeatableProperty(field: \"requestedResults\") {\r\n        f.entry {\r\n            div(align: \"right\") {\r\n                f.repeatableDeleteButton()\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamCollectResultsPostBuildAction/help.html",
    "content": "<div>\r\n    At the end of the build, files matching each of the requested result types will be archived for retrieval by TFS/Team Services.\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamCollectionConfiguration/config.groovy",
    "content": "package hudson.plugins.tfs.TeamCollectionConfiguration;\r\n\r\ndef f = namespace(lib.FormTagLib);\r\ndef c = namespace(lib.CredentialsTagLib);\r\n\r\nf.entry(title: _(\"Collection URL\"), field: \"collectionUrl\") {\r\n    f.textbox()\r\n}\r\n\r\nf.entry(title: _(\"Credentials\"), field: \"credentialsId\",\r\n        description: \"Depending on the integration features used, the user account or personal access token may need code_read, code_status and/or work_write permissions\") {\r\n    c.select()\r\n}\r\n\r\nf.block() {\r\n    f.validateButton(\r\n            title: _(\"Test connection\"),\r\n            progress: _(\"Testing...\"),\r\n            method: \"testCredentials\",\r\n            with: \"collectionUrl,credentialsId\"\r\n    )\r\n}\r\n\r\nf.entry {\r\n    div(align: \"right\") {\r\n        f.repeatableDeleteButton()\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamCollectionConfiguration/help-collectionUrl.html",
    "content": "<div>\r\n    The URL to the TFS/Team Services <em>team project collection</em>.<br />\r\n    If you are using Team Services, please omit the <code>/DefaultCollection</code>.<br />\r\n    Examples:<br />\r\n    <ul>\r\n        <li><code>http://tfs.example.com:8080/tfs/DefaultCollection</code></li>\r\n        <li><code>https://tfs.example.com:8080/tfs/CustomCollection</code></li>\r\n        <li><code>https://fabrikam-fiber-inc.visualstudio.com</code></li>\r\n    </ul>\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamCompletedStatusPostBuildAction/help.html",
    "content": "<div>\r\n    At the end of the build, the status of the associated pull request and/or commit will be updated in TFS/Team Services with the results of the build, including a link back to the Jenkins build.\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamEventsEndpoint.html",
    "content": "<html>\r\n    <body>\r\n        <h1>The <code>/%1$s/</code> endpoint</h1>\r\n\r\n        <h2>Cross Site Request Forgery (CSRF) protection</h2>\r\n        If your Jenkins uses the \"Prevent Cross Site Request Forgery exploits\" security option (which it should), when you make a POST request, you have to send a CSRF protection token as an HTTP request header.  See <a href=\"https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API#RemoteaccessAPI-CSRFProtection\">CSRF Protection</a> for more details.\r\n\r\n        <h2>Events</h2>\r\n        The following events are available to POST to:\r\n        <table border=\"1\">\r\n            <tr>\r\n                <th>Name</th>\r\n                <th>Path</th>\r\n                <th>Sample payload</th>\r\n            </tr>\r\n%2$s\r\n        </table>\r\n\r\n        <h2>Example</h2>\r\n        Suppose we have a Jenkins server at <code>%3$s</code> and the following <code>payload.json</code> file:\r\n        <pre>\r\n{\r\n    \"eventType\": \"ping\",\r\n    \"resource\":\r\n    {\r\n        \"message\": \"Hello, world!\"\r\n    }\r\n}\r\n        </pre>\r\n        The following example demonstrates a GET to the <code>/crumbIssuer</code> endpoint to retrieve a header and then a POST to the <code>ping</code> event using the <a href=\"https://curl.haxx.se/\">curl</a> tool:\r\n        <pre>\r\ncrumb=$(curl '%3$scrumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)')\r\ncurl --request POST %3$s%1$s/ping --header 'Content-Type: application/json' --data-binary @payload.json --header \"$crumb\"\r\n        </pre>\r\n        The console output should look like the following when the <code>ping</code> event from the <code>%1$s</code> endpoint returns the provided payload, formatted for compactness:\r\n        <pre>\r\n{\"message\":\"Hello, world!\"}\r\n        </pre>\r\n    </body>\r\n</html>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/config.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\r\n    <f:entry field=\"serverUrl\" title=\"Collection URL\" description=\"The URL to the team project collection\">\r\n        <f:combobox clazz=\"required\" checkMessage=\"${%Collection URL is mandatory.}\"/>\r\n    </f:entry>\r\n    \r\n    <f:entry field=\"projectPath\" title=\"Project path\" description=\"The path to the TFVC project must start with '$/'\">\r\n        <f:textbox checkUrl=\"'${rootURL}/scm/TeamFoundationServerScm/projectPathCheck?value='+escape(this.value)\"/>\r\n    </f:entry>\r\n\r\n    <f:entry>\r\n        <f:dropdownDescriptorSelector\r\n            title=\"Credentials\"\r\n            field=\"credentialsConfigurer\"\r\n            descriptors=\"${descriptor.getCredentialsConfigurerDescriptors()}\" />\r\n    </f:entry>\r\n\r\n    <f:advanced>\r\n\r\n\t\t<f:entry field=\"useUpdate\" title=\"Use update\" description=\"If checked, the workspace will not be deleted and re-created at the start of each build, making the build faster, but this causes the artifacts from the previous build to remain when a new build starts.\">\r\n\t\t\t<f:checkbox default=\"true\"/>\r\n\t\t</f:entry>\r\n    \r\n\t\t<f:entry field=\"useOverwrite\" title=\"Use overwrite\" description=\"If checked, all changed files in workspace will be overwritten by files from the server.\">\r\n\t\t\t<f:checkbox default=\"true\"/>\r\n\t\t</f:entry>\r\n\r\n\t    <f:entry field=\"localPath\" title=\"Local workfolder\">\r\n\t        <f:textbox default=\".\"\r\n\t             clazz=\"required\" checkMessage=\"${%Local workfolder is mandatory, empty field will use job workspace as workfolder.}\"/>\r\n\t    </f:entry>\r\n\r\n        <f:entry field=\"workspaceName\" title=\"Workspace name\">\r\n            <f:textbox default=\"Hudson-$${JOB_NAME}-$${NODE_NAME}\"\r\n             checkUrl=\"'${rootURL}/scm/TeamFoundationServerScm/workspaceNameCheck?value='+escape(this.value)\"/>\r\n        </f:entry>\r\n\r\n        <f:entry field=\"cloakedPaths\" title=\"Cloaked paths\" description=\"A collection of server paths to cloak to exclude from the workspace and from the build trigger.  Multiple entries must be placed onto separate lines.\">\r\n            <f:textarea checkUrl=\"'${rootURL}/scm/TeamFoundationServerScm/cloakedPathsCheck?value='+escape(this.value)\"/>\r\n        </f:entry>\r\n    </f:advanced>\r\n    \r\n    <t:listScmBrowsers name=\"tfs.browser\" />\r\n</j:jelly>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/config_fr.properties",
    "content": "# The MIT License\n#\n# Copyright (c) 2004-2010, Sun Microsystems, Inc.\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nLocal\\ workfolder\\ is\\ mandatory,\\ empty\\ field\\ will\\ use\\ job\\ workspace\\ as\\ workfolder.=Le dossier de travail local est obligatoire, si le champ est vide le workspace du job sera utilis\\u00E9\nCollection\\ URL\\ is\\ mandatory.=L''URL de la collection de projets d''\\u00E9quipe est obligatoire\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/help-cloakedPaths.html",
    "content": "<div>\n  <p>\n    Paths that are cloaked will not be pulled into the local workspace during a GET\n    from the TFVC repository.\n    <br />\n    Check-ins that contain files only in cloaked folders (in other words, fully cloaked)\n    will not trigger a build,\n    whereas a check-in containing any path that isn't cloaked will trigger a build.\n  </p>\n  <p>\n    For example, suppose the <b>Project path</b> is <tt>$/Example/project/path</tt>,\n    and the repository contains the following subfolders:\n    <blockquote>\n      $/Example/project/path/A <br />\n      $/Example/project/path/A/1 <br />\n      $/Example/project/path/A/2 <br />\n      $/Example/project/path/B <br />\n      $/Example/project/path/C <br />\n    </blockquote>\n    Now, suppose the following paths were entered as <b>Cloaked Paths</b>:\n    <blockquote>\n      $/Example/project/path/A/2 <br />\n      $/Example/project/path/B <br />\n    </blockquote>\n    ...then the resulting workspace on the Jenkins server would only have the following folders:\n    <blockquote>\n      $/Example/project/path/A <br />\n      $/Example/project/path/A/1 <br />\n      $/Example/project/path/C <br />\n    </blockquote>\n  </p>\n  <p>\n    To continue with the example,\n    the following check-in <em>will not</em> trigger a build,\n    because it only contains changes under cloaked paths:\n    <blockquote>\n      $/Example/project/path/A/2/alpha.txt <br />\n      $/Example/project/path/A/2/second.txt <br />\n      $/Example/project/path/B/bravo.txt <br />\n    </blockquote>\n    ...whereas this check-in <em>will</em> trigger a build,\n    because it contains at least one path that isn't cloaked:\n    <blockquote>\n      $/Example/project/path/A/1/first.txt <br />\n      $/Example/project/path/A/2/second.txt <br />\n      $/Example/project/path/B/bravo.txt <br />\n    </blockquote>\n  </p>\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/help-credentialsConfigurer.html",
    "content": "<div>\r\n    <b>NEW since 5.1.0:</b>  Credentials for team project collections can now be configured once instead of once per job.\r\n    <dl>\r\n        <dt>Automatic</dt>\r\n        <dd>\r\n            Credentials will be looked up in the global configuration based on the <em>Collection URL</em>.  Make sure you have added your credentials at <b>Jenkins</b> &gt; <b>Manage Jenkins</b> &gt; <b>Configure Credentials</b> and then add <b>Team Project Collections</b> that are linked to their corresponding credentials at <b>Jenkins</b> &gt; <b>Manage Jenkins</b> &gt; <b>Configure System</b>.<br />\r\n            <br />\r\n            Consult the <a href=\"https://github.com/jenkinsci/tfs-plugin#global-configuration\"><b>Global Configuration</b> section in README.md</a> for a walkthrough.\r\n        </dd>\r\n        <dt>Manual</dt>\r\n        <dd>\r\n            Credentials are specified in the job.  This is the legacy behavior.\r\n        </dd>\r\n    </dl>\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/help-localPath.html",
    "content": "<div>\r\n  <p>\r\n\tThe folder where all files will be retrieved into. The folder name is a relative path, under\r\n\tthe workspace of the current job.\r\n  </p>\r\n  <p>\r\n    The default setting is to retrieve the files into the workspace (ie. the workfolder is <i>\".\"</i>. \r\n  </p>\r\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/help-projectPath.html",
    "content": "<div>\r\n  <p>\r\n\tThe name of the project as it is registered on the server.\r\n  </p>\r\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/help-serverUrl.html",
    "content": "<div>\r\n    <b>NEW since 5.1.0:</b> This field now allows you to select from a list that is built from the values configured under <b>Team Project Collections</b> at <b>Jenkins</b> &gt; <b>Manage Jenkins</b> &gt; <b>Configure System</b>.<br />\r\n    <br />\r\n    If you are using Team Services, please omit the <code>/DefaultCollection</code>.<br />\r\n    Examples:<br />\r\n    <ul>\r\n        <li><code>http://tfs.example.com:8080/tfs/DefaultCollection</code></li>\r\n        <li><code>https://tfs.example.com:8080/tfs/CustomCollection</code></li>\r\n        <li><code>https://fabrikam-fiber-inc.visualstudio.com</code></li>\r\n    </ul>\r\n    Learn more about <a href=\"https://msdn.microsoft.com/en-us/library/dd236915(v=vs.120).aspx\">team project collections</a> at MSDN.<br />\r\n\r\n    Note:\r\n    <blockquote>\r\n        Historically, this field was labeled \"Server URL\" because earlier versions of TFS did not support team project collections.\r\n    </blockquote>\r\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamFoundationServerScm/help-workspaceName.html",
    "content": "<div>\r\n  <p>\r\n\tThe name of the Workspace under which the source should be retrieved. This workspace is \r\n\tcreated as needed. You can normally\r\n\tomit the property unless you want to name a workspace to avoid conflicts \r\n\ton the server (i.e. when you have multiple projects on one server talking \r\n\tto TFS/Team Services)\r\n  </p>\r\n  <p>\r\n    The default value is to create a workspace named <tt>Hudson-${JOB_NAME}</tt>. The TFS plugin for Jenkins\r\n    supports the following macros that are replaced in the workspace name:\r\n    <ul>\r\n\t    <li><tt>${JOB_NAME}</tt> - The name of the job.</li>\r\n\t    <li><tt>${USER_NAME}</tt> - The user name that the Hudson server or slave is running as.</li>\r\n\t    <li><tt>${NODE_NAME}</tt> - The name of the node/slave that the plugin currently is executed on. \r\n\t    Note that this is not the hostname, this value is Hudson configured name of the slave/node.</li>\r\n\t    <li><tt>${ENV}</tt> - The environment variable that is set on the master or slave.</li>\r\n    </ul>\r\n  </p>\r\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPRPushTrigger/config.jelly",
    "content": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">>\n  <f:entry title=\"Job Context\" field=\"jobContext\">\n    <f:textbox default=\"Jenkins PR build\" />\n  </f:entry>\n  <f:entry title=\"Target Branches\" field=\"targetBranches\">\n    <f:textbox default=\"*/master\" />\n  </f:entry>\n</j:jelly>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPRPushTrigger/help.html",
    "content": "This job will be triggered if Jenkins receives a notification on code push in a TFS pull request, from TFS/Team Services for a Git repository defined in the Source Code Management section.\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPendingStatusBuildStep/help.html",
    "content": "<div>\r\n    The status of the associated pull request and/or commit will be updated in TFS/Team Services as \"pending\", including a link back to the Jenkins build.\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPluginGlobalConfig/config.groovy",
    "content": "package hudson.plugins.tfs.TeamPluginGlobalConfig;\r\n\r\ndef f = namespace(lib.FormTagLib);\r\n\r\nf.section(title: descriptor.displayName) {\r\n    f.entry(title: _(\"Team Project Collections\"),\r\n            field: \"collectionConfigurations\",\r\n            help: descriptor.getHelpFile()) {\r\n\r\n        f.repeatableProperty(field: \"collectionConfigurations\")\r\n    }\r\n    f.entry(title: _(\"Enable Push Trigger for all jobs\"),\r\n            field: \"enableTeamPushTriggerForAllJobs\",\r\n            description: \"Turning this on is equivalent to adding the 'Build when a change is pushed to TFS/Team Services' trigger to all jobs.\") {\r\n        f.checkbox (default: false)\r\n    }\r\n    f.entry(title: _(\"Enable Team Status for all jobs\"),\r\n            field: \"enableTeamStatusForAllJobs\",\r\n            description: \"Turning this on is equivalent to adding the 'Set build pending status in TFS/Team Services' build step and the 'Set build completion status in TFS/Team Services' post-build action to all jobs.\") {\r\n        f.checkbox (default: false)\r\n    }\r\n    f.entry() {\r\n        f.dropdownDescriptorSelector(\r\n                title: _(\"User account name mapping strategy\"),\r\n                field: \"userAccountMapper\",\r\n                descriptors: descriptor.getUserAccountMapperDescriptors()\r\n        )\r\n    }\r\n    f.advanced() {\r\n        f.entry(title: _(\"Store TFVC configuration in computer-specific folders\"),\r\n                field: \"configFolderPerNode\",\r\n                description: \"Warning: don't turn this on unless you know what you are doing!\") {\r\n            f.checkbox (default: false)\r\n        }\r\n    }\r\n    f.entry(title: _(\"Release WebHooks\"),\r\n            field: \"releaseWebHookConfigurations\") {\r\n\r\n        f.repeatableProperty(field: \"releaseWebHookConfigurations\")\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPluginGlobalConfig/help-configFolderPerNode.html",
    "content": "<div>\r\n    In some environments, the \"home\" directory is mounted over a network and shared between many computers, including Jenkins servers and their associated build nodes, which eventually leads to corruption of the configuration directory used for TFVC workspaces.  If you have such an environment, check the box to use a sub-directory for each computer (using the computers's host name).<br />\r\n    <br />\r\n    In other words, turning on this option means the TFS SDK will use the following base path for its <code>Cache</code>, <code>Configuration</code> and <code>Logs</code> directories:<br />\r\n    <code>~/.microsoft/Team Foundation/4.0/${HOSTNAME}/</code><br />\r\n    <br />\r\n    <h3>WARNING:</h3>\r\n    Turning this on is equivalent to setting the <code>TEE_PROFILE_DIRECTORY</code> environment variable and thus any manual operations performed on nodes using the Command-Line Client (CLC) will need to be performed with the <code>TEE_PROFILE_DIRECTORY</code> environment variable set accordingly.\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPluginGlobalConfig/help-enableTeamPushTriggerForAllJobs.html",
    "content": "<div>\r\n    If enabled, when an event is received from TFS/Team Services for a Git repository, all the Jenkins jobs that use that Git repository will be automatically triggered, even if they didn't enable the \"Build when a change is pushed to TFS/Team Services\" trigger.<br />\r\n    <br />\r\n    Individual jobs can opt-out of this global opt-in by enabling the <b>Poll SCM</b> trigger and checking its <b>Ignore post-commit hooks</b> checkbox.\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPluginGlobalConfig/help-enableTeamStatusForAllJobs.html",
    "content": "<div>\r\n    If enabled, when an event is received from TFS/Team Services for a Git repository, all the Jenkins jobs that use that Git repository will post their status to the associated pull request and/or commit in TFS/Team Services, even if they didn't add the \"Set build pending status in TFS/Team Services\" build step nor the \"Set build completion status in TFS/Team Services\" post-build action.\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPluginGlobalConfig/help-releaseWebhookConfigurations.html",
    "content": "<div>\n    Adds a Release Webhook. Project can refer to this Webhook in its post build action. When a build completes it will send the event payload to the payload url mentioned.\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPluginGlobalConfig/help-userAccountMapper.html",
    "content": "<div>\r\n    <p>\r\n    When interpreting changesets from TFVC, the TFS plugin will attempt to map domain accounts (i.e. <code>DOMAIN\\alias</code>) to Jenkins accounts.\r\n    </p>\r\n    <p>\r\n    The default mapping strategy (<b>Resolve user using 'DOMAIN\\alias'</b>) is to provide the string (received from TFVC) as-is to Jenkins, which causes Jenkins to convert the username from <code>DOMAIN\\alias</code> to <code>DOMAIN_alias</code>.  If your Jenkins users are named with a different convention, try another user mapping strategy.\r\n    </p>\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPluginGlobalConfig/help.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:l=\"/lib/layout\">\r\n    <l:ajax>\r\n        <div>\r\n            Add pairs of Team Project Collections and associated credentials, one for each collection and Team Services account you will be using elsewhere in Jenkins with the TFS plugin.\r\n        </div>\r\n    </l:ajax>\r\n</j:jelly>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPullRequestMergedDetailsAction/index.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\r\n    <l:layout>\r\n        <l:main-panel>\r\n        <h2>${it.displayName}</h2>\r\n\r\n        <dl>\r\n            <dt>Pull request</dt>\r\n            <dd><a href=\"${it.pullRequestUrl}\">#${it.gitPullRequest.pullRequestId}</a>: '${it.gitPullRequest.title}', created by ${it.gitPullRequest.createdBy.displayName}</dd>\r\n\r\n            <dt>Description</dt>\r\n            <dd><pre>${it.gitPullRequest.description}</pre></dd>\r\n\r\n            <dt>Message</dt>\r\n            <dd><pre>${it.detailedMessage}</pre></dd>\r\n\r\n            <dt>Git repository</dt>\r\n            <dd><a href=\"${it.gitPullRequest.repository.remoteUrl}\">${it.gitPullRequest.repository.name}</a></dd>\r\n\r\n            <dt>Project</dt>\r\n            <dd>${it.gitPullRequest.repository.project.name}</dd>\r\n\r\n            <j:if test=\"${it.hasWorkItems()}\">\r\n                <dt>Associated work items</dt>\r\n                <dd>\r\n                    <ul>\r\n                    <j:forEach var=\"workItem\" items=\"${it.workItems}\">\r\n                        <li><a href=\"${workItem.url}\">${workItem.id}</a></li>\r\n                    </j:forEach>\r\n                    </ul>\r\n                </dd>\r\n            </j:if>\r\n        </dl>\r\n        </l:main-panel>\r\n    </l:layout>\r\n</j:jelly>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPullRequestMergedDetailsAction/summary.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\"\r\n    xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\"\r\n    xmlns:f=\"/lib/form\" xmlns:i=\"jelly:fmt\">\r\n    <t:summary icon=\"${it.iconFileName}\">\r\n\r\n    Triggered by TFS/Team Services pull request <a href=\"${it.pullRequestUrl}\">#${it.gitPullRequest.pullRequestId}</a>: '${it.gitPullRequest.title}', created by ${it.gitPullRequest.createdBy.displayName}\r\n    <j:if test=\"${it.hasWorkItems()}\">\r\n        <br />\r\n        Associated work items:\r\n        <ul>\r\n        <j:forEach var=\"workItem\" items=\"${it.workItems}\">\r\n            <li><a href=\"${workItem.url}\">${workItem.id}</a></li>\r\n        </j:forEach>\r\n        </ul>\r\n    </j:if>\r\n    </t:summary>\r\n</j:jelly>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPushTrigger/TeamPollingAction/index.jelly",
    "content": "<!--\r\nThe MIT License\r\n\r\nCopyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE.\r\n-->\r\n\r\n<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\r\n    <l:layout>\r\n        <st:include it=\"${it.owner}\" page=\"sidepanel.jelly\" optional=\"true\"/>\r\n        <l:main-panel>\r\n            <h1>${(it.displayName)}</h1>\r\n            <j:set var=\"log\" value=\"${it.log}\" />\r\n            <j:choose>\r\n                <j:when test=\"${empty(log)}\">\r\n                    ${%Polling has not run yet.}\r\n                </j:when>\r\n                <j:otherwise>\r\n                    <pre>\r\n                        <st:getOutput var=\"output\" />\r\n                        <j:whitespace>${it.writeLogTo(output)}</j:whitespace>\r\n                    </pre>\r\n                </j:otherwise>\r\n            </j:choose>\r\n        </l:main-panel>\r\n    </l:layout>\r\n</j:jelly>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPushTrigger/config.jelly",
    "content": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">>\n  <f:entry title=\"Job Context\" field=\"jobContext\">\n    <f:textbox default=\"Jenkins build\" />\n  </f:entry>\n</j:jelly>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamPushTrigger/help.html",
    "content": "This job will be triggered if Jenkins receives a notification from TFS/Team Services for a Git repository defined in the Source Code Management section.\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/TeamUpdateWorkItemPostBuildAction/help.html",
    "content": "<div>\r\n    At the end of the build, if any work items in TFS/Team Services have been found to be associated with the Jenkins build, a hyperlink back to the Jenkins build will be added to the affected work items.\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/browsers/TeamSystemWebAccessBrowser/config.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:f=\"/lib/form\">\r\n  <f:entry title=\"URL\" help=\"/plugin/tfs/browsers/tswa.html\">\r\n    <f:textbox name=\"tswa.tfs.urlExample\" value=\"${browser.url}\"/>\r\n  </f:entry>\r\n</j:jelly>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/AliasOnlyUserAccountMapper/config.groovy",
    "content": "package hudson.plugins.tfs.model.AliasOnlyUserAccountMapper\r\n\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/BuildCommand.json",
    "content": "{\r\n  \"team-build\":\r\n  {\r\n    \"Build.Repository.Provider\": \"TfGit\",\r\n    \"System.TeamFoundationCollectionUri\": \"https://fabrikam-fiber-inc.visualstudio.com\",\r\n    \"Build.Repository.Uri\": \"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git\",\r\n    \"System.TeamProject\": \"Fabrikam-Fiber-Git\",\r\n    \"Build.Repository.Name\": \"Fabrikam-Fiber-Git\",\r\n    \"Build.SourceVersion\": \"33b55f7cb7e7e245323987634f960cf4a6e6bc74\",\r\n    \"Build.RequestedFor\": \"Jamal Hartnett\"\r\n  }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/BuildWithParametersCommand.json",
    "content": "{\r\n  \"parameter\":\r\n  [\r\n    {\"name\":\"id\",\"value\":\"123\"},\r\n    {\"name\":\"verbosity\",\"value\":\"high\"}\r\n  ],\r\n  \"team-event\":\r\n  {\r\n    \"eventType\": \"git.push\",\r\n    \"resource\": {\r\n      \"commits\": [\r\n        {\r\n          \"commitId\": \"33b55f7cb7e7e245323987634f960cf4a6e6bc74\"\r\n        }\r\n      ],\r\n      \"repository\": {\r\n        \"name\": \"Fabrikam-Fiber-Git\",\r\n        \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249\",\r\n        \"project\": {\r\n          \"name\": \"Fabrikam-Fiber-Git\"\r\n        },\r\n        \"remoteUrl\": \"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git\"\r\n      },\r\n      \"pushedBy\": {\r\n        \"displayName\": \"Jamal Hartnett\"\r\n      }\r\n    }\r\n  }\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/ChangeLogSet/digest.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\r\n  <j:choose>\r\n    <j:when test=\"${it.emptySet}\">\r\n      ${%No changes.}\r\n    </j:when>\r\n    <j:otherwise>\r\n      Changes\r\n      <ol>\r\n        <j:forEach var=\"cs\" items=\"${it.items}\" varStatus=\"loop\">\r\n          <li>\r\n            ${cs.msgAnnotated} (<a href=\"changes#detail${loop.index}\">detail</a>)\r\n          </li>\r\n        </j:forEach>\r\n      </ol>\r\n    </j:otherwise>\r\n  </j:choose>\r\n</j:jelly>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/ChangeLogSet/digest_fr.properties",
    "content": "# The MIT License\n#\n# Copyright (c) 2004-2010, Sun Microsystems, Inc.\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nNo\\ changes.=Aucun changement\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/ChangeLogSet/index.jelly",
    "content": "<?jelly escape-by-default='true'?>\r\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\r\n  <j:set var=\"browser\" value=\"${it.build.parent.scm.effectiveBrowser}\"/>\r\n  \r\n  <h2>${%Summary}</h2>\r\n  <ol>\r\n    <j:forEach var=\"cs\" items=\"${it.items}\">\r\n      <li><st:out value=\"${cs.msg}\"/></li>\r\n    </j:forEach>\r\n  </ol>\r\n  <table class=\"pane\" style=\"border:none\">\r\n    <j:forEach var=\"cs\" items=\"${it.items}\" varStatus=\"loop\">\r\n      <tr class=\"pane\">\r\n        <td colspan=\"2\" class=\"changeset\">\r\n          <a name=\"detail${loop.index}\"></a>\r\n          <div class=\"changeset-message\">\r\n            <b>\r\n              ${%Version} \r\n              <a href=\"${browser.getChangeSetLink(cs)}\">${cs.version}</a> \r\n              by <a href=\"${rootURL}/${cs.author.url}/\">${cs.user}</a>\r\n              <j:if test=\"${cs.checkedInBy!=null}\">\r\n              \t (<i>checked in by <a href=\"${rootURL}/${cs.checkedInByUser.url}/\">${cs.checkedInBy}</a></i>)\r\n              </j:if>\r\n              <j:if test=\"${cs.domain!=null}\">\r\n              \t@${cs.domain}\r\n              </j:if>:\r\n            </b><br/>\r\n            ${cs.msgAnnotated}\r\n          </div>\r\n        </td>\r\n      </tr>\r\n      <j:forEach var=\"item\" items=\"${cs.items}\">\r\n        <tr>\r\n          <td><t:editTypeIcon type=\"${item.editType}\" /></td>\r\n          <td>\r\n          \t<a href=\"${browser.getFileLink(item)}\">${item.path}</a>\r\n          \t<j:set var=\"diff\" value=\"${browser.getDiffLink(item)}\"/>\r\n            <j:if test=\"${diff!=null}\">\r\n              <st:nbsp/>\r\n              <a href=\"${diff}\">(diff)</a>\r\n            </j:if>\r\n          </td>\r\n        </tr>\r\n      </j:forEach>\r\n    </j:forEach>\r\n  </table>\r\n</j:jelly>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/ChangeLogSet/index_fr.properties",
    "content": "# The MIT License\n#\n# Copyright (c) 2004-2010, Sun Microsystems, Inc.\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nSummary=R\\u00E9sum\\u00E9\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/DomainUserAccountMapper/config.groovy",
    "content": "package hudson.plugins.tfs.model.DomainUserAccountMapper\r\n\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/GitPullRequestMergedEvent.json",
    "content": "{\r\n  \"id\": \"6872ee8c-b333-4eff-bfb9-0d5274943566\",\r\n  \"eventType\": \"git.pullrequest.merged\",\r\n  \"publisherId\": \"tfs\",\r\n  \"scope\": \"all\",\r\n  \"message\": {\r\n    \"text\": \"Jamal Hartnett has created a pull request merge commit\",\r\n    \"html\": \"Jamal Hartnett has created a pull request merge commit\",\r\n    \"markdown\": \"Jamal Hartnett has created a pull request merge commit\"\r\n  },\r\n  \"detailedMessage\": {\r\n    \"text\": \"Jamal Hartnett has created a pull request merge commit\\r\\n\\r\\n- Merge status: Succeeded\\r\\n- Merge commit: eef717(https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\\r\\n\",\r\n    \"html\": \"Jamal Hartnett has created a pull request merge commit\\r\\n<ul>\\r\\n<li>Merge status: Succeeded</li>\\r\\n<li>Merge commit: <a href=\\\"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72\\\">eef717</a></li>\\r\\n</ul>\",\r\n    \"markdown\": \"Jamal Hartnett has created a pull request merge commit\\r\\n\\r\\n+ Merge status: Succeeded\\r\\n+ Merge commit: [eef717](https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\\r\\n\"\r\n  },\r\n  \"resource\": {\r\n    \"repository\": {\r\n      \"id\": \"4bc14d40-c903-45e2-872e-0462c7748079\",\r\n      \"name\": \"Fabrikam\",\r\n      \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079\",\r\n      \"project\": {\r\n        \"id\": \"6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c\",\r\n        \"name\": \"Fabrikam\",\r\n        \"url\": \"https://fabrikam.visualstudio.com/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c\",\r\n        \"state\": \"wellFormed\"\r\n      },\r\n      \"defaultBranch\": \"refs/heads/master\",\r\n      \"remoteUrl\": \"https://fabrikam.visualstudio.com/_git/Fabrikam\"\r\n    },\r\n    \"pullRequestId\": 1,\r\n    \"status\": \"completed\",\r\n    \"createdBy\": {\r\n      \"id\": \"54d125f7-69f7-4191-904f-c5b96b6261c8\",\r\n      \"displayName\": \"Jamal Hartnett\",\r\n      \"uniqueName\": \"fabrikamfiber4@hotmail.com\",\r\n      \"url\": \"https://fabrikam.vssps.visualstudio.com/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8\",\r\n      \"imageUrl\": \"https://fabrikam.visualstudio.com/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8\"\r\n    },\r\n    \"creationDate\": \"2014-06-17T16:55:46.589889Z\",\r\n    \"closedDate\": \"2014-06-30T18:59:12.3660573Z\",\r\n    \"title\": \"my first pull request\",\r\n    \"description\": \" - test2\\r\\n\",\r\n    \"sourceRefName\": \"refs/heads/mytopic\",\r\n    \"targetRefName\": \"refs/heads/master\",\r\n    \"mergeStatus\": \"succeeded\",\r\n    \"mergeId\": \"a10bb228-6ba6-4362-abd7-49ea21333dbd\",\r\n    \"lastMergeSourceCommit\": {\r\n      \"commitId\": \"53d54ac915144006c2c9e90d2c7d3880920db49c\",\r\n      \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c\"\r\n    },\r\n    \"lastMergeTargetCommit\": {\r\n      \"commitId\": \"a511f535b1ea495ee0c903badb68fbc83772c882\",\r\n      \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882\"\r\n    },\r\n    \"lastMergeCommit\": {\r\n      \"commitId\": \"eef717f69257a6333f221566c1c987dc94cc0d72\",\r\n      \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72\"\r\n    },\r\n    \"reviewers\": [\r\n      {\r\n        \"reviewerUrl\": null,\r\n        \"vote\": 0,\r\n        \"id\": \"2ea2d095-48f9-4cd6-9966-62f6f574096c\",\r\n        \"displayName\": \"[Mobile]\\\\Mobile Team\",\r\n        \"uniqueName\": \"vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\\\Mobile Team\",\r\n        \"url\": \"https://fabrikam.vssps.visualstudio.com/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c\",\r\n        \"imageUrl\": \"https://fabrikam.visualstudio.com/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c\",\r\n        \"isContainer\": true\r\n      }\r\n    ],\r\n    \"commits\": [\r\n      {\r\n        \"commitId\": \"53d54ac915144006c2c9e90d2c7d3880920db49c\",\r\n        \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c\"\r\n      }\r\n    ],\r\n    \"url\": \"https://fabrikam.visualstudio.com/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1\"\r\n  },\r\n  \"resourceVersion\": \"3.0-preview.1\",\r\n  \"resourceContainers\": {\r\n    \"collection\": {\r\n      \"id\": \"c12d0eb8-e382-443b-9f9c-c52cba5014c2\"\r\n    },\r\n    \"account\": {\r\n      \"id\": \"f844ec47-a9db-4511-8281-8b63f4eaf94e\"\r\n    },\r\n    \"project\": {\r\n      \"id\": \"be9b3917-87e6-42a4-a549-2bc06a7a878f\"\r\n    }\r\n  },\r\n  \"createdDate\": \"2016-06-10T16:32:22.6325371Z\"\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/GitPushEvent.json",
    "content": "{\r\n  \"id\": \"03c164c2-8912-4d5e-8009-3707d5f83734\",\r\n  \"eventType\": \"git.push\",\r\n  \"publisherId\": \"tfs\",\r\n  \"scope\": \"all\",\r\n  \"message\": {\r\n    \"text\": \"Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.\",\r\n    \"html\": \"Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.\",\r\n    \"markdown\": \"Jamal Hartnett pushed updates to branch `master` of repository `Fabrikam-Fiber-Git`.\"\r\n  },\r\n  \"detailedMessage\": {\r\n    \"text\": \"Jamal Hartnett pushed 1 commit to branch master of repository Fabrikam-Fiber-Git.\\n - Fixed bug in web.config file 33b55f7c\",\r\n    \"html\": \"Jamal Hartnett pushed 1 commit to branch <a href=\\\"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/#version=GBmaster\\\">master</a> of repository <a href=\\\"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/\\\">Fabrikam-Fiber-Git</a>.\\n<ul>\\n<li>Fixed bug in web.config file <a href=\\\"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74\\\">33b55f7c</a>\\n</ul>\",\r\n    \"markdown\": \"Jamal Hartnett pushed 1 commit to branch [master](https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/#version=GBmaster) of repository [Fabrikam-Fiber-Git](https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/).\\n* Fixed bug in web.config file [33b55f7c](https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74)\"\r\n  },\r\n  \"resource\": {\r\n    \"commits\": [\r\n      {\r\n        \"commitId\": \"33b55f7cb7e7e245323987634f960cf4a6e6bc74\",\r\n        \"author\": {\r\n          \"name\": \"Jamal Hartnett\",\r\n          \"email\": \"fabrikamfiber4@hotmail.com\",\r\n          \"date\": \"2015-02-25T19:01:00Z\"\r\n        },\r\n        \"committer\": {\r\n          \"name\": \"Jamal Hartnett\",\r\n          \"email\": \"fabrikamfiber4@hotmail.com\",\r\n          \"date\": \"2015-02-25T19:01:00Z\"\r\n        },\r\n        \"comment\": \"Fixed bug in web.config file\",\r\n        \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74\"\r\n      }\r\n    ],\r\n    \"refUpdates\": [\r\n      {\r\n        \"name\": \"refs/heads/master\",\r\n        \"oldObjectId\": \"aad331d8d3b131fa9ae03cf5e53965b51942618a\",\r\n        \"newObjectId\": \"33b55f7cb7e7e245323987634f960cf4a6e6bc74\"\r\n      }\r\n    ],\r\n    \"repository\": {\r\n      \"id\": \"278d5cd2-584d-4b63-824a-2ba458937249\",\r\n      \"name\": \"Fabrikam-Fiber-Git\",\r\n      \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249\",\r\n      \"project\": {\r\n        \"id\": \"6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c\",\r\n        \"name\": \"Fabrikam-Fiber-Git\",\r\n        \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c\",\r\n        \"state\": \"wellFormed\"\r\n      },\r\n      \"defaultBranch\": \"refs/heads/master\",\r\n      \"remoteUrl\": \"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git\"\r\n    },\r\n    \"pushedBy\": {\r\n      \"id\": \"00067FFED5C7AF52@Live.com\",\r\n      \"displayName\": \"Jamal Hartnett\",\r\n      \"uniqueName\": \"Windows Live ID\\\\fabrikamfiber4@hotmail.com\"\r\n    },\r\n    \"pushId\": 14,\r\n    \"date\": \"2014-05-02T19:17:13.3309587Z\",\r\n    \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/pushes/14\"\r\n  },\r\n  \"resourceVersion\": \"3.0-preview.1\",\r\n  \"resourceContainers\": {\r\n    \"collection\": {\r\n      \"id\": \"c12d0eb8-e382-443b-9f9c-c52cba5014c2\"\r\n    },\r\n    \"account\": {\r\n      \"id\": \"f844ec47-a9db-4511-8281-8b63f4eaf94e\"\r\n    },\r\n    \"project\": {\r\n      \"id\": \"be9b3917-87e6-42a4-a549-2bc06a7a878f\"\r\n    }\r\n  },\r\n  \"createdDate\": \"2016-06-10T16:32:21.0569909Z\"\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/ManualCredentialsConfigurer/config.groovy",
    "content": "package hudson.plugins.tfs.model.ManualCredentialsConfigurer;\r\n\r\ndef f = namespace(lib.FormTagLib);\r\n\r\nf.entry(title: \"User name\", field:\"userName\",\r\n        description:\"Domain alias, e-mail address or alternate credentials\") {\r\n    f.textbox()\r\n}\r\n\r\nf.entry(title: \"User password\", field:\"password\") {\r\n    f.password()\r\n}\r\n\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/ManualCredentialsConfigurer/help-userName.html",
    "content": "<div>\r\n  <p>The name of the user that will be connecting to TFS/Team Services to query history, checkout files, etc.\r\n  </p>\r\n  <h2>Team Foundation Server (on-premises)</h2>\r\n  <p>For [on-premises] Team Foundation Server, the user name can be specified in two ways:\r\n    <ol>\r\n      <li><tt>EXAMPLE-DOMAIN\\user</tt></li>\r\n      <li><tt>user@domain.example.com</tt></li>\r\n    </ol>\r\n  </p>\r\n  <h2>Visual Studio Team Services (previously known as Visual Studio Online)</h2>\r\n  <p>For Team Services, there are also two options:\r\n    <ol>\r\n      <li>Personal access tokens (recommended)\r\n        <ol>\r\n          <li>\r\n            In Team Services, click your name in the top right corner and select <b>Security</b>.\r\n          </li>\r\n          <li>\r\n            In the <em>Personal access tokens</em> area, select <b>Add</b>.\r\n          </li>\r\n          <li>\r\n            Describe the token (use something like \"Jenkins server at jenkins.example.com\"), select an expiry timeframe, double-check the Team Services account the token will be valid for and, until the corresponding defect in Team Services is fixed, select <b>All scopes</b>.\r\n          </li>\r\n          <li>\r\n            Click <b>[Create Token]</b> and copy the generated personal access token to the clipboard.\r\n          </li>\r\n          <li>\r\n            Back to Jenkins, enter the e-mail address associated with your Team Services account as the <em>User name</em> and the generated personal access token as the <em>User password</em>.\r\n          </li>\r\n        </ol>\r\n      </li>\r\n      <li>Alternate credentials\r\n        <ol>\r\n          <li>\r\n            In Team Services, click your name in the top right corner and select <b>Security</b>.\r\n          </li>\r\n          <li>\r\n            In the <em>Alternate credentials</em> area, select <b>Enable alternate authentication credentials</b>.\r\n          </li>\r\n          <li>\r\n            Enter a secondary user name and password, then click <b>[Save]</b>.\r\n          </li>\r\n          <li>\r\n            Back to Jenkins, re-enter those credentials in the <em>User name</em> and <em>User password</em> fields.\r\n          </li>\r\n        </ol>\r\n      </li>\r\n    </ol>\r\n  </p>\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/TeamRequestedResult/config.groovy",
    "content": "package hudson.plugins.tfs.model.TeamRequestedResult;\r\n\r\ndef f = namespace(lib.FormTagLib);\r\n\r\nf.entry(title: _(\"Type\"), field: \"teamResultType\") {\r\n    f.select()\r\n}\r\n\r\nf.entry(title: _(\"Files to include\"), field: \"includes\",\r\n        description: \"<a href='http://ant.apache.org/manual/Types/fileset.html'>Fileset 'includes'</a> setting that specifies the files to collect. Basedir of the fileset is <a href='ws/'>the workspace root</a>.\") {\r\n    f.textbox()\r\n}\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/model/TeamRequestedResult/help-includes.html",
    "content": "<div>\r\n    Enter a comma-separated list of file patterns to collect the files relevant to the selected result type.  Examples: <br />\r\n    <ul>\r\n        <li><code>**/target/surefire-reports/TEST-*.xml, **/target/failsafe-reports/TEST-*.xml</code></li>\r\n        <li><code>reports/jacoco.exec</code></li>\r\n        <li><code>**/TestResults/*.xml</code></li>\r\n    </ul>\r\n</div>\r\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/config.jelly",
    "content": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\" xmlns:c=\"/lib/credentials\">\n  <f:entry title=\"Collection url\" field=\"collectionUrl\">\n    <f:textbox field=\"collectionUrl\" />\n  </f:entry>\n  <f:entry title=\"Credentials\" field=\"credentialsId\">\n    <c:select expressionAllowed=\"false\" />\n  </f:entry>\n  <f:entry title=\"Team project\" field=\"projectName\">\n    <f:select />\n  </f:entry>\n  <f:entry title=\"Release definition\" field=\"releaseDefinitionName\">\n    <f:select />\n  </f:entry>\n</j:jelly>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/help-collectionUrl.html",
    "content": "<div>\nProvide the collection URL for your TFS or VS Team Services account. E.g. https://fabfiber.visualstudio.com/DefaultCollection\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/help-credentialsId.html",
    "content": "<div>\nSelect the credential for you collection.\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/help-destinationPath.html",
    "content": "<div>\nSpecify the destination path to save logs from VSTS/TFS. The base directory is the workspace. Leave it blank if you don't need to get logs from VSTS/TFS.\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/help-isArchiveLog.html",
    "content": "<div>\nCheck if you need to add log file to the artifact.\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/help-projectName.html",
    "content": "<div>\nProvide team project name.\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/help-releaseDefinitionName.html",
    "content": "<div>\nProvide release definition name.\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseManagementCI/help.html",
    "content": "<div>\nTrigger a release in TFS or VS Team Services, when the build completes successfully.\nDetailed documentation is available <a href=\"https://github.com/jenkinsci/vsts-cd-plugin/blob/master/README.md\">here</a>.\n</div>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseSummaryAction/summary.jelly",
    "content": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\n    <t:summary icon=\"/plugin/tfs/48x48/logo.png\">\n        Release summary: <a href=\"${it.releaseLink}\">${it.releaseLink}</a>\n    </t:summary>\n</j:jelly>\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHook/config.groovy",
    "content": "package hudson.plugins.tfs.rm.ReleaseWebHook;\n\ndef f = namespace(lib.FormTagLib);\n\nf.entry(title: _(\"WebHook Name\"), field: \"webHookName\") {\n    f.textbox();\n}\n\nf.entry(title: _(\"Payload URL\"), field: \"payloadUrl\") {\n    f.textbox();\n}\n\nf.entry(title: _(\"Secret\"), field: \"secret\") {\n    f.password();\n}\n\nf.entry {\n    div(align: \"right\") {\n        f.repeatableDeleteButton()\n    }\n}"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHook/help-payloadUrl.html",
    "content": "<div>\n    Payload URL to send the event to.\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHook/help-secret.html",
    "content": "<div>\n    If secret is provided, event payload hash will be verified in TFS service. Recommended to add secret always for webhook.\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHook/help-webhookName.html",
    "content": "<div>\n    Provide a name for the Webhook.\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHookAction/config.groovy",
    "content": "package hudson.plugins.tfs.rm.ReleaseWebHookAction;\n\ndef f = namespace(lib.FormTagLib);\n\nf.entry(title: _(\"Release Webhooks\"),\n            field: \"webHookReferences\") {\n\n        f.repeatableProperty(field: \"webHookReferences\")\n    }\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHookReference/config.groovy",
    "content": "package hudson.plugins.tfs.rm.ReleaseWebHookAction;\n\ndef f = namespace(lib.FormTagLib);\n \nf.entry(title: _(\"Release Webhook\"), field: \"webHookName\") {\n    f.select();\n}\n\nf.entry {\n    div(align: \"right\") {\n        f.repeatableDeleteButton()\n    }\n}\n"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHookReference/help-webHookName.html",
    "content": "<div>\n    Select a webhook. Upon job completion event will be send to the selected webhook's payload url.\n</div>"
  },
  {
    "path": "tfs/src/main/resources/hudson/plugins/tfs/rm/ReleaseWebHookSummaryAction/summary.jelly",
    "content": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l=\"/lib/layout\" xmlns:t=\"/lib/hudson\" xmlns:f=\"/lib/form\">\n    <t:summary icon=\"/plugin/tfs/48x48/logo.png\">\n        <b>Release WebHook status</b>\n        ${status.status}\n        <table width=\"50%\" border=\"0\">\n            \n            <j:forEach var=\"status\" items=\"${it.webHookStatus}\">\n                <tr>\n                    <td align=\"center\">\n                        <j:if test=\"${status.statusCode == 200}\"><img src=\"${resURL}/images/16x16/blue.png\" alt=\"Success\" tooltip=\"Success\" style=\"width: 16px; height: 16px; \" class=\"icon-green icon-xlg\" /></j:if>\n                        <j:if test=\"${status.statusCode != 200}\"><img src=\"${resURL}/images/16x16/red.png\" alt=\"Failure\" tooltip=\"Failure\" style=\"width: 16px; height: 16px; \" class=\"icon-red icon-xlg\" /></j:if>\n                    </td>\n                    <td width=\"100%\" style=\"white-space: nowrap\">\n                        <b>${status.payloadUrl}</b>\n                    </td>\n                </tr>\n                <tr>\n                    <td/>\n                    <j:if test=\"${status.statusCode != 200}\">\n                        <td width=\"100%\"><b>Failure reason:</b> ${endIndex} ${status.errorMessage.substring(0, status.errorMessage.length() > 3000 ? 3000 : status.errorMessage.length())}</td>\n                    </j:if>\n                    <j:if test=\"${status.statusCode == 200}\">\n                        <td width=\"100%\" style=\"white-space: nowrap\"><b>Succeeded</b></td>\n                    </j:if>\n                </tr>\n            </j:forEach>\n        </table>\n    </t:summary>\n</j:jelly>\n"
  },
  {
    "path": "tfs/src/main/webapp/WEB-INF/lib/ThirdPartyNotices.html",
    "content": "<html>\r\n<head>\r\n<meta http-equiv=Content-Type content=\"text/html; charset=utf-8\">\r\n<title>Third-Party Software Notices</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tfont-family: Tahoma, Verdana, Arial, Helvetica, sans-serif;\r\n\tfont-size: 11px;\r\n}\r\n.license {\r\n\tpadding: 10px;\r\n\tbackground-color: #e0e0e0;\r\n\tborder: dotted 1px #000000;\r\n}\r\n// -->\r\n</style>\r\n</head>\r\n<body>\r\n\r\n<h1>Third-Party Software Notices</h1>\r\n\r\n<p>Note:  While Microsoft is not the author of the files below, Microsoft is offering you a license subject to the terms of the Microsoft Software License Terms for \r\n    Microsoft Team Foundation Server Software Development Kit for Java (the “Microsoft Program”). Microsoft reserves all other rights. \r\n    The notices below are provided for informational purposes only and are not the license terms under which Microsoft distributes these files.</p>\r\n<p>Microsoft sets forth a copy of the notices and other information below.</p>\r\n<hr />\r\n\r\n<h2>Apache Software Foundation</h2>\r\n\r\n<p>This product includes software developed by the Apache Software Foundation (<a href=\"http://www.apache.org/\">http://www.apache.org/</a>).</p>\r\n\r\n<p>In particular, this product includes software from the following Apache Software Foundation projects: </p>\r\n\r\n<p>Apache Commons Codec</p>\r\n\r\n<p><a href=\"http://commons.apache.org/codec/\">http://commons.apache.org/codec/</a></p>\r\n\r\n<p>Apache Commons Logging</p>\r\n\r\n<p><a href=\"http://commons.apache.org/logging/\">http://commons.apache.org/logging/</a></p>\r\n\r\n<p>Apache HttpClient</p>\r\n\r\n<p><a href=\"http://hc.apache.org/httpclient-3.x/\">http://hc.apache.org/httpclient-3.x/</a></p>\r\n\r\n<p>Apache Commons Lang</p>\r\n\r\n<p><a href=\"http://commons.apache.org/lang\">http://commons.apache.org/lang</a></p>\r\n\r\n<p>Apache log4j </p>\r\n\r\n<p><a href=\"http://logging.apache.org/log4j/\">http://logging.apache.org/log4j/</a></p>\r\n\r\n<p>Apache ServiceMix</p>\r\n\r\n<p><a href=\"http://servicemix.apache.org/\">http://servicemix.apache.org/</a></p>\r\n\r\n<p>Xerces Java Parser</p>\r\n\r\n<p><a href=\"http://xerces.apache.org/xerces-j/\">http://xerces.apache.org/xerces-j/</a></p>\r\n\r\n<hr />\r\n\r\n<p><i>Apache Commons Codec, Apache Commons Logging, Apache HttpClient, Apache Commons Lang, Apache log4j, and Apache ServiceMix are licensed by the Apache Foundation under the Apache License, Version 2.0. </i></p>\r\n\r\n<p><b>Apache License, Version 2.0</b></p>\r\n\r\n<p>Apache License\r\n  <br />Version 2.0, January 2004\r\n\r\n  <br />http://www.apache.org/licenses/</p>\r\n\r\n<p>TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</p>\r\n\r\n<p>1. Definitions.</p>\r\n\r\n<p>&quot;License&quot; shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.</p>\r\n\r\n<p>&quot;Licensor&quot; shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.</p>\r\n\r\n<p>&quot;Legal Entity&quot; shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, &quot;control&quot; means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.</p>\r\n\r\n<p>&quot;You&quot; (or &quot;Your&quot;) shall mean an individual or Legal Entity exercising permissions granted by this License.</p>\r\n\r\n<p>&quot;Source&quot; form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.</p>\r\n\r\n<p>&quot;Object&quot; form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.</p>\r\n\r\n<p>&quot;Work&quot; shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).</p>\r\n\r\n<p>&quot;Derivative Works&quot; shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.</p>\r\n\r\n<p>&quot;Contribution&quot; shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, &quot;submitted&quot; means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as &quot;Not a Contribution.&quot;</p>\r\n\r\n<p>&quot;Contributor&quot; shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.</p>\r\n\r\n<p>2. Grant of Copyright License.</p>\r\n\r\n<p>Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.</p>\r\n\r\n<p>3. Grant of Patent License.</p>\r\n\r\n<p>Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.</p>\r\n\r\n<p>4. Redistribution.</p>\r\n\r\n<p>You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:</p>\r\n\r\n<ol>\r\n  <li>You must give any other recipients of the Work or Derivative Works a copy of this License; and </li>\r\n\r\n  <li>You must cause any modified files to carry prominent notices stating that You changed the files; and </li>\r\n\r\n  <li>You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and </li>\r\n\r\n  <li>If the Work includes a &quot;NOTICE&quot; text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. </li>\r\n</ol>\r\n\r\n<p>You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.</p>\r\n\r\n<p>5. Submission of Contributions.</p>\r\n\r\n<p>Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.</p>\r\n\r\n<p>6. Trademarks.</p>\r\n\r\n<p>This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.</p>\r\n\r\n<p>7. Disclaimer of Warranty.</p>\r\n\r\n<p>Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.</p>\r\n\r\n<p>8. Limitation of Liability.</p>\r\n\r\n<p>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.</p>\r\n\r\n<p>9. Accepting Warranty or Additional Liability.</p>\r\n\r\n<p>While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.</p>\r\n\r\n<p>END OF TERMS AND CONDITIONS</p>\r\n\r\n<hr />\r\n\r\n<p><i>The Apache Foundation's Xerces Java Parser project is licensed by the Apache Foundation under the Apache License, Version 1.1. </i></p>\r\n\r\n<p><b>The Apache Software License, Version 1.1</b></p>\r\n\r\n<p>Copyright © 2000 The Apache Software Foundation. All rights reserved.</p>\r\n\r\n<p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p>\r\n\r\n<p>1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. </p>\r\n\r\n<p>2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.</p>\r\n\r\n<p>3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment:\r\n  <br />&quot;This product includes software developed by the Apache Software Foundation (http://www.apache.org/).&quot;\r\n\r\n  <br />Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear.</p>\r\n\r\n<p>4. The names &quot;Xerces&quot; and &quot;Apache Software Foundation&quot; must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact apache@apache.org.</p>\r\n\r\n<p>5. Products derived from this software may not be called &quot;Apache&quot;, nor may &quot;Apache&quot; appear in their name, without prior written permission of the Apache Software Foundation.</p>\r\n\r\n<p>THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>\r\n\r\n<hr />\r\n\r\n<h2>Codehaus Projects Woodstox and StAX </h2>\r\n\r\n<p>This product includes software from the following Codehaus hosted projects: </p>\r\n\r\n<p>Woodstox XML Processor</p>\r\n\r\n<p><a href=\"http://woodstox.codehaus.org/\">http://woodstox.codehaus.org/</a></p>\r\n\r\n<p>StAX API</p>\r\n\r\n<p><a href=\"http://stax.codehaus.org/Home\">http://stax.codehaus.org/Home</a></p>\r\n\r\n<p><i>Both Woodstox and the StAX API are licensed by their authors under the Apache License, Version 2.0. </i></p>\r\n\r\n<p><b>Apache License, Version 2.0</b></p>\r\n\r\n<p>Apache License\r\n  <br />Version 2.0, January 2004\r\n\r\n  <br />http://www.apache.org/licenses/</p>\r\n\r\n<p>TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</p>\r\n\r\n<p>1. Definitions.</p>\r\n\r\n<p>&quot;License&quot; shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.</p>\r\n\r\n<p>&quot;Licensor&quot; shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.</p>\r\n\r\n<p>&quot;Legal Entity&quot; shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, &quot;control&quot; means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.</p>\r\n\r\n<p>&quot;You&quot; (or &quot;Your&quot;) shall mean an individual or Legal Entity exercising permissions granted by this License.</p>\r\n\r\n<p>&quot;Source&quot; form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.</p>\r\n\r\n<p>&quot;Object&quot; form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.</p>\r\n\r\n<p>&quot;Work&quot; shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).</p>\r\n\r\n<p>&quot;Derivative Works&quot; shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.</p>\r\n\r\n<p>&quot;Contribution&quot; shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, &quot;submitted&quot; means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as &quot;Not a Contribution.&quot;</p>\r\n\r\n<p>&quot;Contributor&quot; shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.</p>\r\n\r\n<p>2. Grant of Copyright License.</p>\r\n\r\n<p>Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.</p>\r\n\r\n<p>3. Grant of Patent License.</p>\r\n\r\n<p>Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.</p>\r\n\r\n<p>4. Redistribution.</p>\r\n\r\n<p>You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:</p>\r\n\r\n<ol>\r\n  <li>You must give any other recipients of the Work or Derivative Works a copy of this License; and </li>\r\n\r\n  <li>You must cause any modified files to carry prominent notices stating that You changed the files; and </li>\r\n\r\n  <li>You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and </li>\r\n\r\n  <li>If the Work includes a &quot;NOTICE&quot; text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. </li>\r\n</ol>\r\n\r\n<p>You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.</p>\r\n\r\n<p>5. Submission of Contributions.</p>\r\n\r\n<p>Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.</p>\r\n\r\n<p>6. Trademarks.</p>\r\n\r\n<p>This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.</p>\r\n\r\n<p>7. Disclaimer of Warranty.</p>\r\n\r\n<p>Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.</p>\r\n\r\n<p>8. Limitation of Liability.</p>\r\n\r\n<p>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.</p>\r\n\r\n<p>9. Accepting Warranty or Additional Liability.</p>\r\n\r\n<p>While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.</p>\r\n\r\n<p>END OF TERMS AND CONDITIONS</p>\r\n\r\n<hr />\r\n\r\n<h2>Hypersonic SQL DB</h2>\r\n\r\n<p>This product includes software from the Hypersonic SQL DB <a href=\"http://hsqldb.org/\">http://hsqldb.org/</a>. </p>\r\n\r\n<pre>Copyright (c) 1995-2000 by the Hypersonic SQL Group.\r\nAll rights reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions are met:\r\n\r\nRedistributions of source code must retain the above copyright notice, this\r\nlist of conditions and the following disclaimer.\r\n\r\nRedistributions in binary form must reproduce the above copyright notice,\r\nthis list of conditions and the following disclaimer in the documentation\r\nand/or other materials provided with the distribution.\r\n\r\nNeither the name of the Hypersonic SQL Group nor the names of its\r\ncontributors may be used to endorse or promote products derived from this\r\nsoftware without specific prior written permission.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\nARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,\r\nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\nThis software consists of voluntary contributions made by many individuals on behalf of the\r\nHypersonic SQL Group.\r\n\r\n\r\nCopyright (c) 2001-2005, The HSQL Development Group\r\nAll rights reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions are met:\r\n\r\nRedistributions of source code must retain the above copyright notice, this\r\nlist of conditions and the following disclaimer.\r\n\r\nRedistributions in binary form must reproduce the above copyright notice,\r\nthis list of conditions and the following disclaimer in the documentation\r\nand/or other materials provided with the distribution.\r\n\r\nNeither the name of the HSQL Development Group nor the names of its\r\ncontributors may be used to endorse or promote products derived from this\r\nsoftware without specific prior written permission.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\nARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,\r\nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</pre>\r\n\r\n<hr />\r\n\r\n<h2>Cryptix</h2>\r\n\r\n<p>This product includes software from the Cryptix project <a href=\"http://www.cryptix.org/\">http://www.cryptix.org/</a>. </p>\r\n\r\n<pre>Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000\r\nThe Cryptix Foundation Limited. All rights reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions\r\nare met:\r\n\r\n1. Redistributions of source code must retain the copyright notice,\r\n   this list of conditions and the following disclaimer.\r\n\r\n2. Redistributions in binary form must reproduce the above copyright\r\n   notice, this list of conditions and the following disclaimer in\r\n   the documentation and/or other materials provided with the\r\n   distribution.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED ``AS IS''\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\r\nPARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR\r\nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r\nUSE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r\nAND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r\n\r\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\r\nTHE POSSIBILITY OF SUCH DAMAGE.</pre>\r\n\r\n<hr>\r\n\r\n<h2>Jackson Version 2.0</h2>\r\n\r\n<p>This product contains the Jackson Version 2.0 software from <a href=\"http://fasterxml.com/\">FasterXML, LLC</a>. Which is licensed under the Apache 2.0 License and Copyright 2009 &copy; <a href=\"http://fasterxml.com/\">FasterXML, LLC</a>.</p>\r\n\r\n<p><b>Apache License, Version 2.0</b></p>\r\n\r\n<p>Apache License\r\n  <br />Version 2.0, January 2004\r\n\r\n  <br />http://www.apache.org/licenses/</p>\r\n\r\n<p>TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</p>\r\n\r\n<p>1. Definitions.</p>\r\n\r\n<p>&quot;License&quot; shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.</p>\r\n\r\n<p>&quot;Licensor&quot; shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.</p>\r\n\r\n<p>&quot;Legal Entity&quot; shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, &quot;control&quot; means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.</p>\r\n\r\n<p>&quot;You&quot; (or &quot;Your&quot;) shall mean an individual or Legal Entity exercising permissions granted by this License.</p>\r\n\r\n<p>&quot;Source&quot; form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.</p>\r\n\r\n<p>&quot;Object&quot; form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.</p>\r\n\r\n<p>&quot;Work&quot; shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).</p>\r\n\r\n<p>&quot;Derivative Works&quot; shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.</p>\r\n\r\n<p>&quot;Contribution&quot; shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, &quot;submitted&quot; means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as &quot;Not a Contribution.&quot;</p>\r\n\r\n<p>&quot;Contributor&quot; shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.</p>\r\n\r\n<p>2. Grant of Copyright License.</p>\r\n\r\n<p>Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.</p>\r\n\r\n<p>3. Grant of Patent License.</p>\r\n\r\n<p>Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.</p>\r\n\r\n<p>4. Redistribution.</p>\r\n\r\n<p>You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:</p>\r\n\r\n<ol>\r\n  <li>You must give any other recipients of the Work or Derivative Works a copy of this License; and </li>\r\n\r\n  <li>You must cause any modified files to carry prominent notices stating that You changed the files; and </li>\r\n\r\n  <li>You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and </li>\r\n\r\n  <li>If the Work includes a &quot;NOTICE&quot; text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. </li>\r\n</ol>\r\n\r\n<p>You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.</p>\r\n\r\n<p>5. Submission of Contributions.</p>\r\n\r\n<p>Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.</p>\r\n\r\n<p>6. Trademarks.</p>\r\n\r\n<p>This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.</p>\r\n\r\n<p>7. Disclaimer of Warranty.</p>\r\n\r\n<p>Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.</p>\r\n\r\n<p>8. Limitation of Liability.</p>\r\n\r\n<p>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.</p>\r\n\r\n<p>9. Accepting Warranty or Additional Liability.</p>\r\n\r\n<p>While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.</p>\r\n\r\n<p>END OF TERMS AND CONDITIONS</p>\r\n\r\n\r\n\r\n</body>\r\n</html>"
  },
  {
    "path": "tfs/src/main/webapp/WEB-INF/lib/license.html",
    "content": "<html>\r\n\r\n<head>\r\n    <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\">\r\n    <title>MICROSOFT SOFTWARE LICENSE TERMS - MICROSOFT TEAM FOUNDATION SERVER SOFTWARE DEVELOPMENT KIT FOR JAVA</title>\r\n    <style type=\"text/css\">\r\n        <!--\r\n        body {\r\n            font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif;\r\n            font-size: 12px;\r\n        }\r\n        // -->\r\n    </style>\r\n</head>\r\n\r\n<body>\r\n\r\n    <h3><strong>MICROSOFT SOFTWARE LICENSE TERMS</strong></h3>\r\n    <h3><strong>MICROSOFT TEAM FOUNDATION SERVER SOFTWARE DEVELOPMENT KIT FOR JAVA</strong></h3>\r\n\r\n    <hr />\r\n\r\n    <p>These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft </p>\r\n\r\n    <ul>\r\n        <li>updates,</li>\r\n\r\n        <li>supplements,</li>\r\n\r\n        <li>Internet-based services, and</li>\r\n\r\n        <li>support services</li>\r\n    </ul>\r\n\r\n    <p>for this software, unless other terms accompany those items. If so, those terms apply. </p>\r\n\r\n    <p><b>By using the software, you accept these terms. If you do not accept them, do not use the software.</b></p>\r\n    <hr />\r\n\r\n    <p>\r\n        <b>If you comply with these license terms, you have the rights below.</b>\r\n    </p>\r\n\r\n    <p><b>1. INSTALLATION AND USE RIGHTS.</b></p>\r\n\r\n    <blockquote>\r\n        <p><b>a. Installation and Use. </b>You may install and use any number of copies of the software on your device to design, develop and test your programs.</p>\r\n\r\n        <p><b>b. Third Party Notices.&#160; </b>The software includes third party code.&#160; This third party code included in the software is licensed to you by Microsoft under this license agreement, rather than licensed to you by any third party under some other license terms.&#160; Notices, if any, for this third party code are included with the software and may also be found in the ThirdPartyNotices.html file or in the software documentation. </p>\r\n    </blockquote>\r\n\r\n    <p><b>2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.</b></p>\r\n\r\n    <p><b>a.</b> <b>Distributable Code.</b> The software contains code that you are permitted to distribute in programs you develop if you comply with the terms below. </p>\r\n\r\n    <blockquote>\r\n        <p><b>i.</b> <b>Right to Use and Distribute. The code and text files listed below are “Distributable Code.”</b> </p>\r\n\r\n        <ul>\r\n            <li><u>REDIST.TXT Files</u>. You may copy and distribute the object code form of code listed in REDIST.TXT files.</li>\r\n\r\n            <li><u>Sample Code</u>. You may modify, copy, and distribute the source and object code form of code marked as “sample.”</li>\r\n\r\n            <li><u>Third Party Distribution</u>. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs.</li>\r\n        </ul>\r\n\r\n        <p><b>ii.</b> <b>Distribution Requirements. For any Distributable Code you distribute, you must</b> </p>\r\n\r\n        <ul>\r\n            <li>add significant primary functionality to it in your programs;</li>\r\n\r\n            <li>require distributors and external end users to agree to terms that protect it at least as much as this agreement; </li>\r\n\r\n            <li>display your valid copyright notice on your programs; and</li>\r\n\r\n            <li>indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your programs.</li>\r\n        </ul>\r\n\r\n        <p><b>iii.</b> <b>Distribution Restrictions. You may not</b> </p>\r\n\r\n        <ul>\r\n            <li>alter any copyright, trademark or patent notice in the Distributable Code;</li>\r\n\r\n            <li>use Microsoft’s trademarks in your programs’ names or in a way that suggests your programs come from or are endorsed by Microsoft;</li>\r\n\r\n            <li>include Distributable Code in malicious, deceptive or unlawful programs; or</li>\r\n\r\n            <li>modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that</li>\r\n\r\n            <li>the code be disclosed or distributed in source code form; or</li>\r\n\r\n            <li>others have the right to modify it.</li>\r\n        </ul>\r\n    </blockquote>\r\n\r\n    <p><b>3. SCOPE OF LICENSE.</b> The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not </p>\r\n\r\n    <ul>\r\n        <li>work around any technical limitations in the software;</li>\r\n\r\n        <li>reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;</li>\r\n\r\n        <li>make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;</li>\r\n\r\n        <li>publish the software for others to copy;</li>\r\n\r\n        <li>rent, lease or lend the software;</li>\r\n\r\n        <li>transfer the software or this agreement to any third party; or</li>\r\n\r\n        <li>use the software for commercial software hosting services.</li>\r\n    </ul>\r\n\r\n    <p><b>4. BACKUP COPY.</b> You may make one backup copy of the software. You may use it only to reinstall the software.</p>\r\n\r\n    <p><b>5. DOCUMENTATION.</b> Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.</p>\r\n\r\n    <p><b>6. EXPORT RESTRICTIONS.</b> The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see <a href=\"http://www.microsoft.com/exporting\">www.microsoft.com/exporting</a>. </p>\r\n\r\n    <p><b>7. SUPPORT SERVICES. </b>Because this software is “as is,” we may not provide support services for it. </p>\r\n\r\n    <p><b>8. ENTIRE AGREEMENT.</b> This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. </p>\r\n    \r\n    <p><b>9. PRIVACY STATEMENT.</b> The <a href=\"http://go.microsoft.com/fwlink/?LinkId=528096&clcid=0x409\">Microsoft Visual Studio Product Family Privacy Statement</a> describes the privacy statement of this software.</p>\r\n\r\n    <p><b>10. APPLICABLE LAW.</b> </p>\r\n\r\n    <blockquote>\r\n        <p><b>a.</b> <b>United States.</b> If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort. </p>\r\n\r\n        <p><b>b.</b> <b>Outside the United States.</b> If you acquired the software in any other country, the laws of that country apply. </p>\r\n    </blockquote>\r\n\r\n    <p><b>11. LEGAL EFFECT.</b> This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so. </p>\r\n\r\n    <p><b>12. DISCLAIMER OF WARRANTY. The software is licensed “as-is.” You bear the risk of using it. Microsoft gives no express warranties, guarantees or conditions. You may have additional consumer rights or statutory guarantees under your local laws which this agreement cannot change. To the extent permitted under your local laws, Microsoft excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.</b></p>\r\n\r\n    <p><b>FOR AUSTRALIA - you have statutory guarantees under the Australian Consumer Law and nothing in these terms is intended to affect those rights.</b></p>\r\n\r\n    <p><b>13. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. You can recover from Microsoft and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages.</b> </p>\r\n\r\n    <p>This limitation applies to</p>\r\n\r\n    <ul>\r\n        <li>anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and</li>\r\n\r\n        <li>claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.</li>\r\n    </ul>\r\n\r\n    <p>It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.</p>\r\n\r\n    <p><b>Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.</b> </p>\r\n\r\n    <p><b>Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français.</b> </p>\r\n\r\n    <p><b>EXONÉRATION DE GARANTIE.</b> Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues.</p>\r\n\r\n    <p><b>LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES.</b> Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices.</p>\r\n\r\n    <p>Cette limitation concerne :</p>\r\n\r\n    <ul>\r\n        <li>tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et</li>\r\n\r\n        <li>les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur.</li>\r\n    </ul>\r\n\r\n    <p>Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard.</p>\r\n\r\n    <p><b>EFFET JURIDIQUE.</b> Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas.</p>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "tfs/src/main/webapp/WEB-INF/lib/redist.txt",
    "content": "=================================\r\nTFS SDK for Java Redistributables\r\n=================================\r\n\r\nYou may redistribute the following files under the \r\nTeam Foundation Server Software Development Kit for Java \r\nSoftware License Terms.\r\n\r\nThirdPartyNotices.html\r\n\r\nlib/com.microsoft.tfs.sdk-14.0.3.jar\r\n\r\nnative/macosx/libnative_misc.jnilib\r\nnative/macosx/libnative_keychain.jnilib\r\nnative/macosx/libnative_synchronization.jnilib\r\nnative/macosx/libnative_auth.jnilib\r\nnative/macosx/libnative_console.jnilib\r\nnative/macosx/libnative_filesystem.jnilib\r\n\r\nnative/aix/ppc/libnative_misc.a\r\nnative/aix/ppc/libnative_filesystem.a\r\nnative/aix/ppc/libnative_console.a\r\nnative/aix/ppc/libnative_auth.a\r\nnative/aix/ppc/libnative_synchronization.a\r\n\r\nnative/win32/x86_64/native_filesystem.dll\r\nnative/win32/x86_64/native_synchronization.dll\r\nnative/win32/x86_64/native_messagewindow.dll\r\nnative/win32/x86_64/native_credential.dll\r\nnative/win32/x86_64/native_auth.dll\r\nnative/win32/x86_64/native_console.dll\r\nnative/win32/x86_64/native_misc.dll\r\nnative/win32/x86_64/native_registry.dll\r\nnative/win32/x86/native_filesystem.dll\r\nnative/win32/x86/native_synchronization.dll\r\nnative/win32/x86/native_messagewindow.dll\r\nnative/win32/x86/native_credential.dll \r\nnative/win32/x86/native_auth.dll\r\nnative/win32/x86/native_console.dll\r\nnative/win32/x86/native_misc.dll\r\nnative/win32/x86/native_registry.dll\r\n\r\nnative/linux/x86_64/libnative_auth.so\r\nnative/linux/x86_64/libnative_filesystem.so\r\nnative/linux/x86_64/libnative_synchronization.so\r\nnative/linux/x86_64/libnative_misc.so\r\nnative/linux/x86_64/libnative_console.so\r\nnative/linux/x86/libnative_auth.so\r\nnative/linux/x86/libnative_filesystem.so\r\nnative/linux/x86/libnative_synchronization.so\r\nnative/linux/x86/libnative_misc.so\r\nnative/linux/x86/libnative_console.so\r\nnative/linux/ppc/libnative_auth.so\r\nnative/linux/ppc/libnative_filesystem.so\r\nnative/linux/ppc/libnative_synchronization.so\r\nnative/linux/ppc/libnative_misc.so\r\nnative/linux/ppc/libnative_console.so\r\nnative/linux/arm/libnative_auth.so \r\nnative/linux/arm/libnative_console.so \r\nnative/linux/arm/libnative_filesystem.so \r\nnative/linux/arm/libnative_misc.so \r\nnative/linux/arm/libnative_synchronization.so \r\n\r\nnative/freebsd/x86_64/libnative_auth.so \r\nnative/freebsd/x86_64/libnative_console.so \r\nnative/freebsd/x86_64/libnative_filesystem.so \r\nnative/freebsd/x86_64/libnative_misc.so \r\nnative/freebsd/x86_64/libnative_synchronization.so \r\nnative/freebsd/x86/libnative_auth.so \r\nnative/freebsd/x86/libnative_console.so \r\nnative/freebsd/x86/libnative_filesystem.so \r\nnative/freebsd/x86/libnative_misc.so \r\nnative/freebsd/x86/libnative_synchronization.so \r\n\r\nnative/hpux/ia64_32/libnative_auth.so\r\nnative/hpux/ia64_32/libnative_filesystem.so\r\nnative/hpux/ia64_32/libnative_synchronization.so\r\nnative/hpux/ia64_32/libnative_misc.so\r\nnative/hpux/ia64_32/libnative_console.so\r\nnative/hpux/PA_RISC/libnative_console.sl\r\nnative/hpux/PA_RISC/libnative_synchronization.sl\r\nnative/hpux/PA_RISC/libnative_misc.sl\r\nnative/hpux/PA_RISC/libnative_auth.sl\r\nnative/hpux/PA_RISC/libnative_filesystem.sl\r\n\r\nnative/solaris/x86_64/libnative_auth.so\r\nnative/solaris/x86_64/libnative_filesystem.so\r\nnative/solaris/x86_64/libnative_synchronization.so\r\nnative/solaris/x86_64/libnative_misc.so\r\nnative/solaris/x86_64/libnative_console.so\r\nnative/solaris/x86/libnative_auth.so\r\nnative/solaris/x86/libnative_filesystem.so\r\nnative/solaris/x86/libnative_synchronization.so\r\nnative/solaris/x86/libnative_misc.so\r\nnative/solaris/x86/libnative_console.so\r\nnative/solaris/sparc/libnative_auth.so\r\nnative/solaris/sparc/libnative_filesystem.so\r\nnative/solaris/sparc/libnative_synchronization.so\r\nnative/solaris/sparc/libnative_misc.so\r\nnative/solaris/sparc/libnative_console.so\r\n"
  },
  {
    "path": "tfs/src/main/webapp/browsers/tswa.html",
    "content": "<div>\r\n  <p>\r\n\tEnter the base URL to use for browsing changesets, files and diffs.  Examples: <tt>http://tfs:8080/tfs/DefaultCollection/teamproject/</tt> or <tt>https://fabrikam-fiber-inc.visualstudio.com/teamproject/</tt>\r\n  </p>\t \r\n  <p>\r\n    If the field is empty then the plugin will build URLs using the Collection URL.\r\n  </p>\r\n  <p>\r\n    One reason for providing a value here is if Jenkins connects to the TFS server on the LAN using the short host name and the Jenkins instance is also accessible through the internet and so links to TFS should use the Fully-Qualified Domain Name (FQDN) of the TFS server.\r\n  </p>\r\n</div>"
  },
  {
    "path": "tfs/src/main/webapp/labelname.html",
    "content": "<div>\n    <p>\n        The name of the label to be created.<br>\n        It supports the usage of environment variables for example ${BUILD_NUMBER}, ${JOB_NAME} and ${BUILD_TAG}.\n    </p>\n</div>"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/ChangeSetReaderTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport static org.junit.Assert.*;\r\n\r\nimport hudson.plugins.tfs.model.ChangeLogSet;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.plugins.tfs.model.ChangeSet.Item;\r\n\r\nimport java.io.Reader;\r\nimport java.io.StringReader;\r\n\r\nimport org.junit.Test;\r\n\r\npublic class ChangeSetReaderTest {\r\n\r\n    @Test\r\n    public void assertParsingTwoXmlChangeSets() throws Exception {\r\n        Reader reader = new StringReader(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                            \"<changeset version=\\\"1122\\\">\" +\r\n                                \"<date>2009-01-12T00:00:00Z</date>\" +\r\n                                \"<user>snd\\\\user</user>\" +\r\n                                \"<comment>comment</comment>\" +\r\n                                \"<items>\" +\r\n                                    \"<item action=\\\"add\\\">path</item>\" +\r\n                                    \"<item action=\\\"delete\\\">path2</item>\" +\r\n                                \"</items>\" +\r\n                            \"</changeset>\" +\r\n                        \"</changelog>\");\r\n        \r\n        ChangeSetReader changesetReader = new ChangeSetReader();\r\n        ChangeLogSet logset = changesetReader.parse(null, null, reader);\r\n        \r\n        ChangeSet changeset = logset.iterator().next();\r\n        assertEquals(\"User is incorrect\", \"user\", changeset.getUser());\r\n        assertEquals(\"Domain is incorrect\", \"snd\", changeset.getDomain());\r\n        assertEquals(\"Comment is incorrect\", \"comment\", changeset.getComment());\r\n        assertEquals(\"Version is incorrect\", \"1122\", changeset.getVersion());\r\n        assertEquals(\"Date is incorrect\", Util.getCalendar(2009, 1, 12).getTime(), changeset.getDate());\r\n        \r\n        assertEquals(\"Number of items in change set was incorrect\", 2, changeset.getItems().size());\r\n        Item item = changeset.getItems().get(0);\r\n        assertEquals(\"Action is incorrect\", \"add\", item.getAction());\r\n        assertEquals(\"Path is incorrect\", \"path\", item.getPath());\r\n        \r\n        item = changeset.getItems().get(1);\r\n        assertEquals(\"Action is incorrect\", \"delete\", item.getAction());\r\n        assertEquals(\"Path is incorrect\", \"path2\", item.getPath());\r\n    }\r\n\r\n    @Test\r\n    public void assertItemHasParent() throws Exception {\r\n        Reader reader = new StringReader(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                            \"<changeset version=\\\"1122\\\">\" +\r\n                                \"<date>2009-01-12T00:00:00Z</date>\" +\r\n                                \"<user>snd\\\\user</user>\" +\r\n                                \"<comment>comment</comment>\" +\r\n                                \"<items>\" +\r\n                                    \"<item action=\\\"add\\\">path</item>\" +\r\n                                    \"<item action=\\\"delete\\\">path2</item>\" +\r\n                                \"</items>\" +\r\n                            \"</changeset>\" +\r\n                        \"</changelog>\");\r\n        \r\n        ChangeSetReader changesetReader = new ChangeSetReader();\r\n        ChangeLogSet logset = changesetReader.parse(null, null, reader);\r\n        \r\n        ChangeSet changeset = logset.iterator().next();\r\n        Item item = changeset.getItems().get(0);\r\n        assertNotNull(\"The item's parent change set cant be null\", item.getParent());\r\n        assertSame(\"The item's parent is not the same as the change set it belongs to\", changeset, item.getParent());\r\n    }\r\n\r\n    public void assertXmlWithEscapedCharsIsReadCorrectly() throws Exception {\r\n        Reader reader = new StringReader(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                \"<changeset version=\\\"1122\\\">\" +\r\n                    \"<date>2009-01-12T00:00:00Z</date>\" +\r\n                    \"<user>snd\\\\user</user>\" +\r\n                    \"<comment>Just &lt;testing&gt; &quot;what&quot; happens when I use the &amp; character...Hudson does not seem to like it!</comment>\" +\r\n                    \"<items>\" +\r\n                        \"<item action=\\\"add\\\">path</item>\" +\r\n                        \"<item action=\\\"delete\\\">path2</item>\" +\r\n                    \"</items>\" +\r\n                \"</changeset>\" +\r\n            \"</changelog>\");\r\n\r\n        ChangeSetReader changesetReader = new ChangeSetReader();\r\n        ChangeLogSet logset = changesetReader.parse(null, null, reader);\r\n        \r\n        ChangeSet changeset = logset.iterator().next();\r\n        assertEquals(\"The chage set's comment is incorrect\", \"Just <testing> \\\"what\\\" happens when I use the & character...Hudson does not seem to like it!\", changeset.getComment());\r\n    }\r\n\r\n    @Test\r\n    public void assertParsingOfKeywordCheckedInByIsParsed() throws Exception {\r\n        Reader reader = new StringReader(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                            \"<changeset version=\\\"1122\\\">\" +\r\n                                \"<date>2009-01-12T00:00:00Z</date>\" +\r\n                                \"<user>snd\\\\user</user>\" +\r\n                                \"<checked_in_by_user>snd\\\\other_user</checked_in_by_user>\" +\r\n                                \"<comment>comment</comment>\" +\r\n                                \"<items>\" +\r\n                                    \"<item action=\\\"add\\\">path</item>\" +\r\n                                    \"<item action=\\\"delete\\\">path2</item>\" +\r\n                                \"</items>\" +\r\n                            \"</changeset>\" +\r\n                        \"</changelog>\");\r\n        \r\n        ChangeSetReader changesetReader = new ChangeSetReader();\r\n        ChangeLogSet logset = changesetReader.parse(null, null, reader);\r\n        \r\n        ChangeSet changeset = logset.iterator().next();\r\n        assertEquals(\"Checked in by user is incorrect\", \"other_user\", changeset.getCheckedInBy());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/ChangeSetWriterTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport static org.custommonkey.xmlunit.XMLAssert.*;\r\nimport java.io.StringWriter;\r\nimport java.util.ArrayList;\r\n\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\n\r\nimport org.custommonkey.xmlunit.XMLUnit;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\n\r\npublic class ChangeSetWriterTest {\r\n\r\n    @Before\r\n    public void setUp() {\r\n        XMLUnit.setIgnoreWhitespace(true);\r\n        XMLUnit.setNormalizeWhitespace(true);\r\n        XMLUnit.setIgnoreComments(true);\r\n    }\r\n\r\n    @Test\r\n    public void assertWriterOutputsCorrectChangeLogXml() throws Exception {\r\n        ChangeSet changeset = new ChangeSet(\"1122\", Util.getCalendar(2008, 12, 12).getTime(), \"rnd\\\\user\", \"comment\");\r\n        changeset.getItems().add(new ChangeSet.Item(\"path\", \"add\"));\r\n        changeset.getItems().add(new ChangeSet.Item(\"path2\", \"delete\"));\r\n        ArrayList<ChangeSet> sets = new ArrayList<ChangeSet>();\r\n        sets.add(changeset);\r\n\r\n        ChangeSetWriter changesetWriter = new ChangeSetWriter();\r\n        StringWriter output = new StringWriter();\r\n        changesetWriter.write(sets, output);\r\n        assertXMLEqual(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                            \"<changeset version=\\\"1122\\\">\" +\r\n                                \"<date>2008-12-12T00:00:00Z</date>\" +\r\n                                \"<user>rnd\\\\user</user>\" +\r\n                                \"<comment>comment</comment>\" +\r\n                                \"<items>\" +\r\n                                    \"<item action=\\\"add\\\">path</item>\" +\r\n                                    \"<item action=\\\"delete\\\">path2</item>\" +\r\n                                \"</items>\" +\r\n                            \"</changeset>\" +\r\n        \t\t\"</changelog>\", output.getBuffer().toString());\r\n    }\r\n\r\n    @Test\r\n    public void assertWriterIgnoredNullDomain() throws Exception {\r\n        ChangeSet changeset = new ChangeSet(\"1122\", Util.getCalendar(2008, 12, 12).getTime(), \"user\", \"comment\");\r\n        ArrayList<ChangeSet> sets = new ArrayList<ChangeSet>();\r\n        sets.add(changeset);\r\n\r\n        ChangeSetWriter changesetWriter = new ChangeSetWriter();\r\n        StringWriter output = new StringWriter();\r\n        changesetWriter.write(sets, output);\r\n        assertXMLEqual(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                            \"<changeset version=\\\"1122\\\">\" +\r\n                                \"<date>2008-12-12T00:00:00Z</date>\" +\r\n                                \"<user>user</user>\" +\r\n                                \"<comment>comment</comment>\" +\r\n                            \"</changeset>\" +\r\n                        \"</changelog>\", output.getBuffer().toString());\r\n    }\r\n\r\n    @Test\r\n    public void assertXmlCharsAreEscaped() throws Exception {\r\n        ChangeSet changeset = new ChangeSet(\"1122\", Util.getCalendar(2008, 12, 12).getTime(), \"user\", \"Just <testing> \\\"what\\\" happens when I use the & character...Hudson does not seem to like it!\");\r\n        ArrayList<ChangeSet> sets = new ArrayList<ChangeSet>();\r\n        sets.add(changeset);\r\n\r\n        ChangeSetWriter changesetWriter = new ChangeSetWriter();\r\n        StringWriter output = new StringWriter();\r\n        changesetWriter.write(sets, output);\r\n        assertXMLEqual(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                            \"<changeset version=\\\"1122\\\">\" +\r\n                                \"<date>2008-12-12T00:00:00Z</date>\" +\r\n                                \"<user>user</user>\" +\r\n                                \"<comment>Just &lt;testing&gt; &quot;what&quot; happens when I use the &amp; character...Hudson does not seem to like it!</comment>\" +\r\n                            \"</changeset>\" +\r\n                        \"</changelog>\", output.getBuffer().toString());\r\n    }\r\n\r\n    @Test\r\n    public void assertCheckedInByUserIsWritten() throws Exception {\r\n        ChangeSet changeset = new ChangeSet(\"1122\", Util.getCalendar(2008, 12, 12).getTime(), \"user\", \"Just <testing> \\\"what\\\" happens when I use the & character...Hudson does not seem to like it!\");\r\n        changeset.setCheckedInBy(\"another_user\");\r\n        ArrayList<ChangeSet> sets = new ArrayList<ChangeSet>();\r\n        sets.add(changeset);\r\n\r\n        ChangeSetWriter changesetWriter = new ChangeSetWriter();\r\n        StringWriter output = new StringWriter();\r\n        changesetWriter.write(sets, output);\r\n        assertXMLEqual(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><changelog>\" +\r\n                            \"<changeset version=\\\"1122\\\">\" +\r\n                                \"<date>2008-12-12T00:00:00Z</date>\" +\r\n                                \"<user>user</user>\" +\r\n                                \"<checked_in_by_user>another_user</checked_in_by_user>\" +\r\n                                \"<comment>Just &lt;testing&gt; &quot;what&quot; happens when I use the &amp; character...Hudson does not seem to like it!</comment>\" +\r\n                            \"</changeset>\" +\r\n                        \"</changelog>\", output.getBuffer().toString());\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/CommitParameterActionTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link CommitParameterAction}.\r\n */\r\npublic class CommitParameterActionTest {\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/EndToEndTfs.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.GetOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.PendChangesOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceLocation;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.LockLevel;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.PendingChange;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.PendingSet;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.WorkingFolder;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;\r\nimport hudson.plugins.tfs.model.ExtraSettings;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.util.XmlHelper;\r\nimport hudson.util.Secret;\r\nimport hudson.util.SecretOverride;\r\nimport org.apache.commons.io.FileUtils;\r\nimport org.junit.Assert;\r\nimport org.junit.runner.Description;\r\nimport org.jvnet.hudson.test.JenkinsRecipe;\r\nimport org.jvnet.hudson.test.JenkinsRule;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.lang.annotation.Documented;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.Target;\r\nimport java.net.URISyntaxException;\r\n\r\nimport static java.lang.annotation.ElementType.METHOD;\r\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\r\n\r\n/**\r\n * Setup/teardown of the TFS server configured by the {@code tfs_server_name} property,\r\n * will create the necessary structure in source control.\r\n */\r\n@Documented\r\n@JenkinsRecipe(EndToEndTfs.RunnerImpl.class)\r\n@Target(METHOD)\r\n@Retention(RUNTIME)\r\npublic @interface EndToEndTfs {\r\n\r\n    /**\r\n     * Specifies the class that will be given a chance to participate.\r\n     */\r\n    Class<? extends StubRunner> value();\r\n\r\n    /**\r\n     * The {@link EndToEndTfs} annotation requires a value of type {@link Class}.\r\n     * This class provides an implementation that does almost nothing.\r\n     */\r\n    class StubRunner extends JenkinsRecipe.Runner<EndToEndTfs> {\r\n        private RunnerImpl parent;\r\n        private IntegrationTestHelper helper;\r\n        private String encryptedPassword;\r\n\r\n        public String getEncryptedPassword() {\r\n            return encryptedPassword;\r\n        }\r\n\r\n        protected RunnerImpl getParent() {\r\n            return parent;\r\n        }\r\n\r\n        private void setParent(final RunnerImpl parent) {\r\n            this.parent = parent;\r\n        }\r\n\r\n        protected IntegrationTestHelper getHelper() {\r\n            return helper;\r\n        }\r\n\r\n        private void setHelper(final IntegrationTestHelper helper) {\r\n            this.helper = helper;\r\n        }\r\n\r\n        @Override\r\n        public void decorateHome(final JenkinsRule jenkinsRule, final File home) throws Exception {\r\n            final String jobFolder = parent.getJobFolder();\r\n            final String configXmlPath = jobFolder + \"config.xml\";\r\n            final File configXmlFile = new File(home, configXmlPath);\r\n\r\n            final String tfsServerUrl = helper.getServerUrl();\r\n            XmlHelper.pokeValue(configXmlFile, \"/project/scm/serverUrl\", tfsServerUrl);\r\n\r\n            final String projectPath = parent.getPathInTfvc();\r\n            XmlHelper.pokeValue(configXmlFile, \"/project/scm/projectPath\", projectPath);\r\n\r\n            final String workspaceName = \"Hudson-${JOB_NAME}-${COMPUTERNAME}\";\r\n            XmlHelper.pokeValue(configXmlFile, \"/project/scm/workspaceName\", workspaceName);\r\n\r\n            final String userName = helper.getUserName();\r\n            XmlHelper.pokeValue(configXmlFile, \"/project/scm/userName\", userName);\r\n\r\n            final String userPassword = helper.getUserPassword();\r\n            final SecretOverride secretOverride = new SecretOverride();\r\n            try {\r\n                final Secret secret = Secret.fromString(userPassword);\r\n                encryptedPassword = secret.getEncryptedValue();\r\n            }\r\n            finally {\r\n                try {\r\n                    secretOverride.close();\r\n                } catch (IOException e) {\r\n                    // ignore\r\n                }\r\n            }\r\n            final String projectScmPassword = \"/project/scm/password\";\r\n            final String currentPassword = XmlHelper.peekValue(configXmlFile, projectScmPassword);\r\n            if (currentPassword != null) {\r\n                XmlHelper.pokeValue(configXmlFile, projectScmPassword, encryptedPassword);\r\n            }\r\n        }\r\n    }\r\n\r\n    class RunnerImpl extends JenkinsRecipe.Runner<EndToEndTfs>  {\r\n\r\n        private static final String workspaceComment = \"Created by the TFS plugin for Jenkins functional tests.\";\r\n\r\n        private final IntegrationTestHelper helper;\r\n        private final String serverUrl;\r\n\r\n        private File localBaseFolderFile;\r\n        private StubRunner runner;\r\n        private Server server = null;\r\n        private String testClassName;\r\n        private String testCaseName;\r\n        private String workspaceName;\r\n        private String pathInTfvc;\r\n        private Workspace workspace;\r\n\r\n        public RunnerImpl() throws URISyntaxException {\r\n            helper = new IntegrationTestHelper();\r\n            serverUrl = helper.getServerUrl();\r\n        }\r\n\r\n        @Override\r\n        public void setup(JenkinsRule jenkinsRule, EndToEndTfs recipe) throws Exception {\r\n            final Description testDescription = jenkinsRule.getTestDescription();\r\n            final Class clazz = testDescription.getTestClass();\r\n            testClassName = clazz.getSimpleName();\r\n            testCaseName = testDescription.getMethodName();\r\n            final String hostName = IntegrationTestHelper.tryToDetermineHostName();\r\n            final File currentFolder = new File(\"\").getAbsoluteFile();\r\n            final File workspaces = new File(currentFolder, \"workspaces\");\r\n            // TODO: Consider NOT using the Server class\r\n            server = new Server(null, null, serverUrl, helper.getUserName(), helper.getUserPassword(), null, ExtraSettings.DEFAULT);\r\n\r\n            final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n\r\n            // workspaceName MUST be unique across computers hitting the same server\r\n            workspaceName = hostName + \"-\" + testCaseName;\r\n            workspace = createWorkspace(vcc, workspaceName);\r\n\r\n            pathInTfvc = IntegrationTestHelper.determinePathInTfvcForTestCase(testDescription);\r\n            final File localTestClassFolder = new File(workspaces, testClassName);\r\n            localBaseFolderFile = new File(localTestClassFolder, testCaseName);\r\n            //noinspection ResultOfMethodCallIgnored\r\n            localBaseFolderFile.mkdirs();\r\n            final String localBaseFolder = localBaseFolderFile.getAbsolutePath();\r\n            final WorkingFolder workingFolder = new WorkingFolder(pathInTfvc, localBaseFolder);\r\n            workspace.createWorkingFolder(workingFolder);\r\n\r\n            // TODO: Is this necessary if we're about to delete it, anyway?\r\n            workspace.get(GetOptions.NONE);\r\n\r\n            // Delete the folder associated with this test in TFVC\r\n            workspace.pendDelete(\r\n                    new String[]{pathInTfvc},\r\n                    RecursionType.FULL,\r\n                    LockLevel.UNCHANGED,\r\n                    GetOptions.NONE,\r\n                    PendChangesOptions.NONE);\r\n            checkIn(\"Cleaning up for the \" + testCaseName + \" test.\");\r\n            // we don't need to verify this check-in, because a first run on a server will be a no-op\r\n\r\n            // create the folder in TFVC\r\n            workspace.pendAdd(\r\n                    new String[]{localBaseFolder},\r\n                    false,\r\n                    null,\r\n                    LockLevel.UNCHANGED,\r\n                    GetOptions.NONE,\r\n                    PendChangesOptions.NONE);\r\n            final int changeSet = checkIn(\"Setting up for the \" + testCaseName + \" test.\");\r\n            Assert.assertTrue(changeSet >= 0);\r\n\r\n            final Class<? extends StubRunner> runnerClass = recipe.value();\r\n            if (runnerClass != null) {\r\n                runner = runnerClass.newInstance();\r\n                runner.setParent(this);\r\n                runner.setHelper(this.helper);\r\n                runner.setup(jenkinsRule, recipe);\r\n            }\r\n        }\r\n\r\n        public File getLocalBaseFolderFile() {\r\n            return localBaseFolderFile;\r\n        }\r\n\r\n        public String getPathInTfvc() {\r\n            return pathInTfvc;\r\n        }\r\n\r\n        public String getWorkspaceName() {\r\n            return workspaceName;\r\n        }\r\n\r\n        public String getTestCaseName() {\r\n            return testCaseName;\r\n        }\r\n\r\n        public String getTestClassName() {\r\n            return testClassName;\r\n        }\r\n\r\n        public String getServerUrl() {\r\n            return serverUrl;\r\n        }\r\n\r\n        public Server getServer() {\r\n            return server;\r\n        }\r\n\r\n        public String getJobFolder() {\r\n            return \"jobs/\" + testCaseName + \"/\";\r\n        }\r\n\r\n        public <T extends StubRunner> T getInnerRunner(final Class<T> type) {\r\n            return type.cast(runner);\r\n        }\r\n\r\n        public Workspace getWorkspace() {\r\n            return workspace;\r\n        }\r\n\r\n        public int checkIn(final String comment) {\r\n            return checkIn(workspace, comment);\r\n        }\r\n\r\n        static int checkIn(Workspace workspace, String comment) {\r\n            final PendingSet pendingSet = workspace.getPendingChanges();\r\n            int result = -1;\r\n            if (pendingSet != null) {\r\n                final PendingChange[] pendingChanges = pendingSet.getPendingChanges();\r\n                if (pendingChanges != null) {\r\n                    result = workspace.checkIn(pendingChanges, comment);\r\n                }\r\n            }\r\n            return result;\r\n        }\r\n\r\n        static Workspace createWorkspace(final MockableVersionControlClient vcc, final String workspaceName) {\r\n            deleteWorkspace(vcc, workspaceName);\r\n\r\n            final Workspace workspace = vcc.createWorkspace(\r\n                    null,\r\n                    workspaceName,\r\n                    VersionControlConstants.AUTHENTICATED_USER,\r\n                    VersionControlConstants.AUTHENTICATED_USER,\r\n                    workspaceComment,\r\n                    WorkspaceLocation.LOCAL,\r\n                    WorkspaceOptions.NONE);\r\n            return workspace;\r\n        }\r\n\r\n        static void deleteWorkspace(final MockableVersionControlClient vcc, final String workspaceName) {\r\n            final Workspace[] workspaces = vcc.queryWorkspaces(workspaceName, null, /* TODO: computer */null, WorkspacePermissions.NONE_OR_NOT_SUPPORTED);\r\n            for (final Workspace workspace : workspaces) {\r\n                for (WorkingFolder workingFolder : workspace.getFolders()) {\r\n                    final String localItem = workingFolder.getLocalItem();\r\n                    if (localItem != null) {\r\n                        final File file = new File(localItem);\r\n                        FileUtils.deleteQuietly(file);\r\n                    }\r\n                }\r\n                vcc.deleteWorkspace(workspace);\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public void decorateHome(JenkinsRule jenkinsRule, File home) throws Exception {\r\n            if (runner != null) {\r\n                runner.decorateHome(jenkinsRule, home);\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public void tearDown(JenkinsRule jenkinsRule, EndToEndTfs recipe) throws Exception {\r\n            if (runner != null) {\r\n                runner.tearDown(jenkinsRule, recipe);\r\n            }\r\n            final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n            deleteWorkspace(vcc, workspaceName);\r\n            if (server != null) {\r\n                server.close();\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/FunctionalTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.GetOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.PendChangesOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlConstants;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.LockLevel;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.VersionControlLabel;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.ChangesetVersionSpec;\r\nimport com.microsoft.tfs.jni.helpers.LocalHost;\r\nimport hudson.FilePath;\r\nimport hudson.Functions;\r\nimport hudson.Launcher;\r\nimport hudson.ProxyConfiguration;\r\nimport hudson.console.AnnotatedLargeText;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.BuildListener;\r\nimport hudson.model.Cause;\r\nimport hudson.model.Computer;\r\nimport hudson.model.Project;\r\nimport hudson.model.Queue;\r\nimport hudson.model.Result;\r\nimport hudson.model.TaskListener;\r\nimport hudson.model.labels.LabelAtom;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.util.DateUtil;\r\nimport hudson.plugins.tfs.util.XmlHelper;\r\nimport hudson.remoting.VirtualChannel;\r\nimport hudson.scm.ChangeLogSet;\r\nimport hudson.scm.PollingResult;\r\nimport hudson.scm.SCM;\r\nimport hudson.slaves.DumbSlave;\r\nimport hudson.slaves.SlaveComputer;\r\nimport hudson.triggers.SCMTrigger;\r\nimport hudson.util.Scrambler;\r\nimport hudson.util.Secret;\r\nimport jenkins.model.Jenkins;\r\nimport org.apache.commons.io.FileUtils;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.junit.Assert;\r\nimport org.junit.Ignore;\r\nimport org.junit.Rule;\r\nimport org.junit.Test;\r\nimport org.junit.experimental.categories.Category;\r\nimport org.jvnet.hudson.test.JenkinsRecipe;\r\nimport org.jvnet.hudson.test.JenkinsRule;\r\nimport org.jvnet.hudson.test.TestBuilder;\r\nimport org.jvnet.hudson.test.recipes.LocalData;\r\nimport org.littleshoot.proxy.HttpProxyServer;\r\nimport org.littleshoot.proxy.impl.DefaultHttpProxyServer;\r\nimport org.xml.sax.SAXException;\r\n\r\nimport javax.xml.parsers.ParserConfigurationException;\r\nimport javax.xml.xpath.XPathExpressionException;\r\nimport java.io.ByteArrayOutputStream;\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.net.InetSocketAddress;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Calendar;\r\nimport java.util.GregorianCalendar;\r\nimport java.util.HashSet;\r\nimport java.util.List;\r\nimport java.util.concurrent.ExecutionException;\r\nimport java.util.concurrent.Future;\r\n\r\n/**\r\n * Tests that exercise real-world functionality, using temporary Jenkins instances.\r\n * These are so-called functional (L3) tests.\r\n * Tests may connect to a TFS server identified by the tfs_server_name property.\r\n */\r\n@Category(IntegrationTests.class)\r\npublic class FunctionalTest {\r\n\r\n    /**\r\n     * A special version of {@link JenkinsRule} that assumes {@link EndToEndTfs} decorates a test,\r\n     * giving access to the {@link hudson.plugins.tfs.EndToEndTfs.RunnerImpl} and all the cool\r\n     * stuff it has.\r\n     */\r\n    public class TfsJenkinsRule extends JenkinsRule{\r\n        /**\r\n          * https://wiki.jenkins-ci.org/display/JENKINS/Unit+Test+on+Windows#UnitTestonWindows-UnabletodeleteslaveslaveX.log\r\n          *\r\n          */\r\n        private void purgeSlaves() {\r\n            List<Computer> disconnectingComputers = new ArrayList<Computer>();\r\n            List<VirtualChannel> closingChannels = new ArrayList<VirtualChannel>();\r\n            for (Computer computer: jenkins.getComputers()) {\r\n                if (!(computer instanceof SlaveComputer)) {\r\n                    continue;\r\n                }\r\n                // disconnect slaves.\r\n                // retrieve the channel before disconnecting.\r\n                // even a computer gets offline, channel delays to close.\r\n                if (!computer.isOffline()) {\r\n                    VirtualChannel ch = computer.getChannel();\r\n                    computer.disconnect(null);\r\n                    disconnectingComputers.add(computer);\r\n                    closingChannels.add(ch);\r\n                }\r\n            }\r\n\r\n            try {\r\n                // Wait for all computers disconnected and all channels closed.\r\n                for (Computer computer: disconnectingComputers) {\r\n                    computer.waitUntilOffline();\r\n                }\r\n                for (VirtualChannel ch: closingChannels) {\r\n                    ch.join();\r\n                }\r\n            } catch (InterruptedException e) {\r\n                e.printStackTrace();\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public void after() throws Exception {\r\n            if (Functions.isWindows()) {\r\n                purgeSlaves();\r\n            }\r\n            super.after();\r\n        }\r\n\r\n        public EndToEndTfs.RunnerImpl getTfsRunner() {\r\n            EndToEndTfs.RunnerImpl result = null;\r\n            for (final JenkinsRecipe.Runner recipe : recipes) {\r\n                if (recipe instanceof EndToEndTfs.RunnerImpl) {\r\n                    result = (EndToEndTfs.RunnerImpl) recipe;\r\n                    break;\r\n                }\r\n            }\r\n            return result;\r\n        }\r\n    }\r\n\r\n    @Rule public TfsJenkinsRule j = new TfsJenkinsRule();\r\n\r\n    /**\r\n     * Runs the project's {@link SCMTrigger} to poll for changes, which may schedule a build.\r\n     *\r\n     * If it does schedule a build, we'll wait for that build to complete and return it;\r\n     * otherwise we return {@code null}.\r\n     *\r\n     * This assumes Jenkins (or the project/job) was configured with a quietPeriod, to give us\r\n     * time to retrieve the item from the queue (especially when execution is paused in the debugger)\r\n     * so we can wait on it.\r\n     *\r\n     * @param project The {@link Project} for which to poll and build.\r\n     * @return The {@link AbstractBuild} that resulted from the build, if applicable; otherwise {@code null}.\r\n     */\r\n    public static AbstractBuild runScmPollTrigger(final Project project)\r\n            throws InterruptedException, ExecutionException {\r\n        final SCMTrigger scmTrigger = (SCMTrigger) project.getTrigger(SCMTrigger.class);\r\n        // This is a roundabout way of calling SCMTrigger#run(),\r\n        // because if we set SCMTrigger#synchronousPolling to true\r\n        // Trigger#checkTriggers() unconditionally runs the trigger,\r\n        // even if we set its schedule (spec) to an empty string\r\n        // (which normally disables the schedule).\r\n        // Having synchronous polling (& building!) in our tests\r\n        // is more important than skipping the usual method call chain.\r\n        // http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html\r\n        final SCMTrigger.Runner runner = scmTrigger.new Runner();\r\n        runner.run();\r\n\r\n        final AbstractBuild build = waitForQueuedBuild(project);\r\n        return build;\r\n    }\r\n\r\n    public static AbstractBuild runUserTrigger(final Project project)\r\n            throws InterruptedException, ExecutionException {\r\n        final Cause.UserIdCause cause = new Cause.UserIdCause();\r\n        project.scheduleBuild(cause);\r\n\r\n        final AbstractBuild build = waitForQueuedBuild(project);\r\n        return build;\r\n    }\r\n\r\n    static AbstractBuild waitForQueuedBuild(final Project project)\r\n            throws InterruptedException, ExecutionException {\r\n        final Jenkins jenkins = (Jenkins) project.getParent();\r\n        final Queue queue = jenkins.getQueue();\r\n        final Queue.Item[] items = queue.getItems();\r\n        final boolean buildQueued = items.length == 1;\r\n        final AbstractBuild build;\r\n        if (buildQueued) {\r\n            final Queue.WaitingItem queuedItem = (Queue.WaitingItem) items[0];\r\n            // now that we have the queued item, we can \"shorten the quiet period to zero\"\r\n            final GregorianCalendar due = new GregorianCalendar();\r\n            due.add(Calendar.SECOND, -1);\r\n            queuedItem.timestamp = due;\r\n            // force re-evaluation of the queue, which should notice the item shouldn't wait anymore\r\n            queue.maintain();\r\n            queue.scheduleMaintenance();\r\n\r\n            final Future<? extends AbstractBuild> future = (Future) queuedItem.getFuture();\r\n            build = future.get();\r\n        }\r\n        else {\r\n            build = null;\r\n        }\r\n        return build;\r\n    }\r\n\r\n    @LocalData\r\n    @EndToEndTfs(CreateLabel.class)\r\n    @Test public void createLabel() throws ExecutionException, InterruptedException, IOException {\r\n        final Jenkins jenkins = j.jenkins;\r\n        final TaskListener taskListener = j.createTaskListener();\r\n        final EndToEndTfs.RunnerImpl tfsRunner = j.getTfsRunner();\r\n        final CreateLabel innerRunner = tfsRunner.getInnerRunner(CreateLabel.class);\r\n        final String generatedLabelName = innerRunner.getGeneratedLabelName();\r\n        final Server server = tfsRunner.getServer();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final List<Project> projects = jenkins.getProjects();\r\n        final Project project = projects.get(0);\r\n        final int latestChangesetID = vcc.getLatestChangesetID();\r\n\r\n        // setup build\r\n        runUserTrigger(project);\r\n\r\n        // polling should report no changes\r\n        final PollingResult pollingResult = project.poll(taskListener);\r\n\r\n        Assert.assertEquals(PollingResult.Change.NONE, pollingResult.change);\r\n\r\n        // trigger build\r\n        final AbstractBuild build = runUserTrigger(project);\r\n\r\n        // verify new label created against latestChangesetId\r\n        Assert.assertNotNull(build);\r\n        assertBuildSuccess(build);\r\n        final ChangeLogSet changeSet = build.getChangeSet();\r\n        Assert.assertEquals(0, changeSet.getItems().length);\r\n        final TFSRevisionState revisionState = build.getAction(TFSRevisionState.class);\r\n        Assert.assertEquals(latestChangesetID, revisionState.changesetVersion);\r\n        final String owner = VersionControlConstants.AUTHENTICATED_USER;\r\n        final ChangesetVersionSpec spec = new ChangesetVersionSpec(latestChangesetID);\r\n        final VersionControlLabel[] labels = vcc.queryLabels(generatedLabelName, null, owner, false, null, spec);\r\n        Assert.assertEquals(1, labels.length);\r\n        final VersionControlLabel label = labels[0];\r\n        Assert.assertFalse(StringUtils.isEmpty(label.getComment()));\r\n    }\r\n\r\n    public void assertBuildSuccess(final AbstractBuild build) throws IOException {\r\n        final Result result = build.getResult();\r\n        if (!Result.SUCCESS.equals(result)) {\r\n            final AnnotatedLargeText logText = build.getLogText();\r\n            final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r\n            logText.writeLogTo(0, baos);\r\n\r\n            final String headerTemplate = \"Build result: %s\\n---Log Start---\\n\";\r\n            final String header = String.format(headerTemplate, result);\r\n            final String message = header + baos.toString() + \"---Log End---\\n\\n\";\r\n            Assert.fail(message);\r\n        }\r\n    }\r\n\r\n    public static class CreateLabel extends CurrentChangesetInjector {\r\n\r\n        private final String generatedLabelName;\r\n\r\n        public CreateLabel(){\r\n            final Calendar now = Calendar.getInstance();\r\n            final String iso8601DateString = DateUtil.toString(now);\r\n            generatedLabelName = \"CreateLabel_\" + iso8601DateString.replace(':', '-');\r\n        }\r\n\r\n        public String getGeneratedLabelName() {\r\n            return generatedLabelName;\r\n        }\r\n\r\n        @Override public void decorateHome(final JenkinsRule jenkinsRule, final File home) throws Exception {\r\n            super.decorateHome(jenkinsRule, home);\r\n\r\n            final EndToEndTfs.RunnerImpl parent = getParent();\r\n            final String jobFolder = parent.getJobFolder();\r\n            final String configXmlPath = jobFolder + \"config.xml\";\r\n            final File configXmlFile = new File(home, configXmlPath);\r\n\r\n            final String labelNameXPath = \"/project/publishers/hudson.plugins.tfs.TFSLabeler/labelName\";\r\n            XmlHelper.pokeValue(configXmlFile, labelNameXPath, generatedLabelName);\r\n        }\r\n    }\r\n\r\n    @LocalData\r\n    @EndToEndTfs(CurrentChangesetInjector.class)\r\n    @Test public void agent() throws Exception {\r\n        final Jenkins jenkins = j.jenkins;\r\n        final List<Project> projects = jenkins.getProjects();\r\n        final Project project = projects.get(0);\r\n        final EndToEndTfs.RunnerImpl tfsRunner = j.getTfsRunner();\r\n        checkInEmptyFile(tfsRunner);\r\n        final LabelAtom label = new LabelAtom(\"agent\");\r\n        final DumbSlave agent = j.createOnlineSlave(label);\r\n        project.getBuildersList().add(new TestBuilder() {\r\n            @Override\r\n            public boolean perform(final AbstractBuild<?, ?> build, final Launcher launcher, final BuildListener listener)\r\n                    throws InterruptedException, IOException {\r\n                final FilePath workspace = build.getWorkspace();\r\n                final FilePath child = workspace.child(\"TODO.txt\");\r\n                final boolean result = child.exists();\r\n                return result;\r\n            }\r\n        });\r\n\r\n        final AbstractBuild firstBuild = runScmPollTrigger(project);\r\n\r\n        Assert.assertNotNull(firstBuild);\r\n        assertBuildSuccess(firstBuild);\r\n\r\n        final FilePath workspace = firstBuild.getWorkspace();\r\n        final FilePath workspaceParent = workspace.getParent();\r\n        final FilePath assumedRootPath = workspaceParent.getParent();\r\n        final FilePath agentRootPath = agent.getRootPath();\r\n        Assert.assertEquals(agentRootPath, assumedRootPath);\r\n\r\n        assertEmptyFileIsInWorkspace(workspace);\r\n    }\r\n\r\n    @LocalData\r\n    @EndToEndTfs(EndToEndTfs.StubRunner.class)\r\n    @Test public void newJob() throws InterruptedException, ExecutionException, IOException {\r\n        final Jenkins jenkins = j.jenkins;\r\n        final TaskListener taskListener = j.createTaskListener();\r\n        final EndToEndTfs.RunnerImpl tfsRunner = j.getTfsRunner();\r\n        final Server server = tfsRunner.getServer();\r\n        final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n        final List<Project> projects = jenkins.getProjects();\r\n        final Project project = projects.get(0);\r\n        int latestChangesetID;\r\n\r\n        // first poll should queue a build because we were never built\r\n        latestChangesetID = vcc.getLatestChangesetID();\r\n        final AbstractBuild firstBuild = runScmPollTrigger(project);\r\n\r\n        Assert.assertNotNull(firstBuild);\r\n        assertBuildSuccess(firstBuild);\r\n        final ChangeLogSet firstChangeSet = firstBuild.getChangeSet();\r\n        Assert.assertEquals(true, firstChangeSet.isEmptySet());\r\n        final TFSRevisionState firstRevisionState = firstBuild.getAction(TFSRevisionState.class);\r\n        Assert.assertEquals(latestChangesetID, firstRevisionState.changesetVersion);\r\n        final List<Cause> firstCauses = firstBuild.getCauses();\r\n        Assert.assertEquals(1, firstCauses.size());\r\n        final Cause firstCause = firstCauses.get(0);\r\n        Assert.assertTrue(firstCause instanceof SCMTrigger.SCMTriggerCause);\r\n\r\n        // second poll should report no changes since last build\r\n        final PollingResult secondPoll = project.poll(taskListener);\r\n\r\n        Assert.assertEquals(PollingResult.Change.NONE, secondPoll.change);\r\n\r\n        // make a change in source control\r\n        final int changeSet = checkInEmptyFile(tfsRunner);\r\n        Assert.assertTrue(changeSet >= 0);\r\n\r\n        // third poll should trigger a build\r\n        latestChangesetID = vcc.getLatestChangesetID();\r\n        final AbstractBuild secondBuild = runScmPollTrigger(project);\r\n\r\n        Assert.assertNotNull(secondBuild);\r\n        assertBuildSuccess(secondBuild);\r\n        final ChangeLogSet secondChangeSet = secondBuild.getChangeSet();\r\n        Assert.assertEquals(1, secondChangeSet.getItems().length);\r\n        final TFSRevisionState secondRevisionState = secondBuild.getAction(TFSRevisionState.class);\r\n        Assert.assertEquals(latestChangesetID, secondRevisionState.changesetVersion);\r\n        final List<Cause> secondCauses = secondBuild.getCauses();\r\n        Assert.assertEquals(1, secondCauses.size());\r\n        final Cause secondCause = secondCauses.get(0);\r\n        Assert.assertTrue(secondCause instanceof SCMTrigger.SCMTriggerCause);\r\n        final FilePath jenkinsWorkspace = secondBuild.getWorkspace();\r\n        assertEmptyFileIsInWorkspace(jenkinsWorkspace);\r\n\r\n        // force a build via a manual trigger\r\n        final AbstractBuild thirdBuild = runUserTrigger(project);\r\n\r\n        Assert.assertNotNull(thirdBuild);\r\n        assertBuildSuccess(thirdBuild);\r\n        final ChangeLogSet thirdChangeSet = thirdBuild.getChangeSet();\r\n        Assert.assertEquals(0, thirdChangeSet.getItems().length);\r\n        final TFSRevisionState thirdRevisionState = thirdBuild.getAction(TFSRevisionState.class);\r\n        Assert.assertEquals(latestChangesetID, thirdRevisionState.changesetVersion);\r\n        final List<Cause> thirdCauses = thirdBuild.getCauses();\r\n        Assert.assertEquals(1, thirdCauses.size());\r\n        final Cause thirdCause = thirdCauses.get(0);\r\n        Assert.assertTrue(thirdCause instanceof Cause.UserIdCause);\r\n        final FilePath thirdBuildWorkspace = thirdBuild.getWorkspace();\r\n        assertEmptyFileIsInWorkspace(thirdBuildWorkspace);\r\n\r\n        // finally, delete the project, which should first remove the workspace\r\n        final TeamFoundationServerScm scm = (TeamFoundationServerScm) project.getScm();\r\n        final Computer computer = Computer.currentComputer();\r\n        final String hostName = LocalHost.getShortName();\r\n        final String workspaceName = scm.getWorkspaceName(thirdBuild, computer).replace(\"${COMPUTERNAME}\", hostName);\r\n        Assert.assertTrue(jenkinsWorkspace.exists());\r\n        final Workspace[] workspacesBeforeDeletion = vcc.queryWorkspaces(workspaceName, VersionControlConstants.AUTHENTICATED_USER, hostName, WorkspacePermissions.NONE_OR_NOT_SUPPORTED);\r\n        Assert.assertEquals(1, workspacesBeforeDeletion.length);\r\n\r\n        project.delete();\r\n\r\n        Assert.assertFalse(jenkinsWorkspace.exists());\r\n        final Workspace[] workspacesAfterDeletion = vcc.queryWorkspaces(workspaceName, VersionControlConstants.AUTHENTICATED_USER, hostName, WorkspacePermissions.NONE_OR_NOT_SUPPORTED);\r\n        Assert.assertEquals(0, workspacesAfterDeletion.length);\r\n    }\r\n\r\n    public void assertEmptyFileIsInWorkspace(final FilePath workspace) throws IOException, InterruptedException {\r\n        final FilePath[] workspaceFiles = workspace.list(\"*.*\", \"$tf\");\r\n        Assert.assertEquals(1, workspaceFiles.length);\r\n        final FilePath workspaceFile = workspaceFiles[0];\r\n        Assert.assertEquals(\"TODO.txt\", workspaceFile.getName());\r\n    }\r\n\r\n    public static int checkInEmptyFile(final EndToEndTfs.RunnerImpl tfsRunner) throws IOException {\r\n        return checkInFile(tfsRunner, \"Add a file.\", null);\r\n    }\r\n\r\n    public static int checkInFile(final EndToEndTfs.RunnerImpl tfsRunner, final String changeMessage, final String fileContents) throws IOException {\r\n        final Workspace workspace = tfsRunner.getWorkspace();\r\n        final File todoFile = new File(tfsRunner.getLocalBaseFolderFile(), \"TODO.txt\");\r\n        final boolean alreadyExisted = todoFile.isFile();\r\n        FileUtils.writeStringToFile(todoFile, fileContents, \"UTF-8\");\r\n        final String[] paths = {todoFile.getAbsolutePath()};\r\n        if (alreadyExisted) {\r\n            workspace.pendEdit(\r\n                    paths,\r\n                    RecursionType.NONE,\r\n                    LockLevel.UNCHANGED,\r\n                    null,\r\n                    GetOptions.NONE,\r\n                    PendChangesOptions.NONE);\r\n        }\r\n        else {\r\n            workspace.pendAdd(\r\n                    paths,\r\n                    false,\r\n                    null,\r\n                    LockLevel.UNCHANGED,\r\n                    GetOptions.NONE,\r\n                    PendChangesOptions.NONE);\r\n        }\r\n        return tfsRunner.checkIn(tfsRunner.getTestCaseName() + \" \" + changeMessage);\r\n    }\r\n\r\n    @LocalData\r\n    @EndToEndTfs(CloakedPaths.class)\r\n    @Test public void cloakedPaths() throws Exception {\r\n        final Jenkins jenkins = j.jenkins;\r\n        final TaskListener taskListener = j.createTaskListener();\r\n        final EndToEndTfs.RunnerImpl tfsRunner = j.getTfsRunner();\r\n        final Server server = tfsRunner.getServer();\r\n        final String testCaseName = tfsRunner.getTestCaseName();\r\n        final Workspace workspace = tfsRunner.getWorkspace();\r\n        final List<Project> projects = jenkins.getProjects();\r\n        final Project jenkinsProject = projects.get(0);\r\n        final TeamFoundationServerScm tfsScm = (TeamFoundationServerScm) jenkinsProject.getScm();\r\n        Assert.assertNotEquals(StringUtils.EMPTY, tfsScm.getCloakedPaths());\r\n        int latestChangesetID;\r\n\r\n        // arrange: create structure\r\n        final File root = tfsRunner.getLocalBaseFolderFile();\r\n        final String[] paths = {\r\n                createWorkspaceFile(root, \"root.txt\"),\r\n                createWorkspaceFile(root, \"A/A.txt\"),\r\n                createWorkspaceFile(root, \"A/1/A1.txt\"),\r\n                createWorkspaceFile(root, \"A/2/A2.txt\"),\r\n                createWorkspaceFile(root, \"B/B.txt\"),\r\n                createWorkspaceFile(root, \"C/C.txt\"),\r\n        };\r\n        workspace.pendAdd(\r\n                paths,\r\n                false,\r\n                null,\r\n                LockLevel.UNCHANGED,\r\n                GetOptions.NONE,\r\n                PendChangesOptions.NONE);\r\n        final int structureChangeSet = tfsRunner.checkIn(testCaseName + \" Create structure.\");\r\n        Assert.assertTrue(structureChangeSet >= 0);\r\n\r\n        // act: poll trigger\r\n        final AbstractBuild firstBuild = runScmPollTrigger(jenkinsProject);\r\n\r\n        // assert\r\n        Assert.assertNotNull(\"First poll should queue a build\", firstBuild);\r\n        assertBuildSuccess(firstBuild);\r\n        assertCloakedPathsWorkspaceContents(firstBuild.getWorkspace());\r\n\r\n        // arrange: make a change in a non-cloaked path (fully uncloaked)\r\n        final File aOne = new File(root, \"A/1/A1.txt\");\r\n        FileUtils.writeStringToFile(aOne, \"Now with content!\", \"UTF-8\");\r\n        workspace.pendEdit(\r\n                new String[]{aOne.getAbsolutePath()},\r\n                RecursionType.NONE,\r\n                LockLevel.UNCHANGED,\r\n                null,\r\n                GetOptions.NONE,\r\n                PendChangesOptions.NONE);\r\n        latestChangesetID = tfsRunner.checkIn(testCaseName + \" Add content to A1.txt\");\r\n\r\n        // act: poll trigger\r\n        final AbstractBuild secondBuild = runScmPollTrigger(jenkinsProject);\r\n\r\n        // assert\r\n        Assert.assertNotNull(\"Second poll should queue a build\", secondBuild);\r\n        assertCloakedPathsWorkspaceContents(secondBuild.getWorkspace());\r\n\r\n        // arrange: make a changeset that has an item in a cloaked path\r\n        final File aTwo = new File(root, \"A/2/A2.txt\");\r\n        FileUtils.writeStringToFile(aOne, \"Now with content!\", \"UTF-8\");\r\n        workspace.pendEdit(\r\n                new String[]{aTwo.getAbsolutePath()},\r\n                RecursionType.NONE,\r\n                LockLevel.UNCHANGED,\r\n                null,\r\n                GetOptions.NONE,\r\n                PendChangesOptions.NONE);\r\n        latestChangesetID = tfsRunner.checkIn(testCaseName + \" Add content to A2.txt\");\r\n\r\n        // act: poll (no need to poll trigger)\r\n        final PollingResult thirdPoll = jenkinsProject.poll(taskListener);\r\n\r\n        // assert\r\n        Assert.assertEquals(\"Third poll should NOT find any significant changes\", PollingResult.Change.NONE, thirdPoll.change);\r\n\r\n        // arrange: create a changeset that has changes in both cloaked and uncloaked paths\r\n        final File a = new File(root, \"A/A.txt\");\r\n        FileUtils.writeStringToFile(a, \"Now with content!\", \"UTF-8\");\r\n        final File b = new File(root, \"B/B.txt\");\r\n        FileUtils.writeStringToFile(b, \"Now with content!\", \"UTF-8\");\r\n        workspace.pendEdit(\r\n                new String[]{\r\n                        a.getAbsolutePath(),\r\n                        b.getAbsolutePath(),\r\n                },\r\n                RecursionType.NONE,\r\n                LockLevel.UNCHANGED,\r\n                null,\r\n                GetOptions.NONE,\r\n                PendChangesOptions.NONE);\r\n        latestChangesetID = tfsRunner.checkIn(testCaseName + \" Add content to A.txt and B.txt\");\r\n\r\n        // act: poll trigger\r\n        final AbstractBuild thirdBuild = runScmPollTrigger(jenkinsProject);\r\n\r\n        // assert\r\n        Assert.assertNotNull(\"Fourth poll should queue a build\", thirdBuild);\r\n        assertCloakedPathsWorkspaceContents(thirdBuild.getWorkspace());\r\n    }\r\n\r\n    /** workspace should only contain:\r\nroot.txt\r\nA/A.txt\r\nA/1/A1.txt\r\nC/C.txt\r\n    */\r\n    private static void assertCloakedPathsWorkspaceContents(final FilePath workspace) throws Exception {\r\n        final FilePath[] workspaceFiles = workspace.list(\"**\", \"$tf\");\r\n        final HashSet<String> expectedFileNames = new HashSet<String>(Arrays.asList(\"root.txt\", \"A.txt\", \"A1.txt\", \"C.txt\"));\r\n        for (final FilePath workspaceFile : workspaceFiles) {\r\n            final String actualFileName = workspaceFile.getName();\r\n            if (expectedFileNames.contains(actualFileName)) {\r\n                expectedFileNames.remove(actualFileName);\r\n            }\r\n            else {\r\n                final String message = \"Did not expect to find \" + actualFileName + \" in the workspace.\";\r\n                Assert.fail(message);\r\n            }\r\n        }\r\n        Assert.assertEquals(\"All expected files should have been found in the workspace\", 0, expectedFileNames.size());\r\n    }\r\n\r\n    static String createWorkspaceFile(final File root, final String relFilePath) throws IOException {\r\n        final File file = new File(root, relFilePath);\r\n        final File folder = file.getParentFile();\r\n        //noinspection ResultOfMethodCallIgnored\r\n        folder.mkdirs();\r\n        //noinspection ResultOfMethodCallIgnored\r\n        file.createNewFile();\r\n        return file.getAbsolutePath();\r\n    }\r\n\r\n    public static class CloakedPaths extends CurrentChangesetInjector {\r\n\r\n        @Override public void decorateHome(final JenkinsRule jenkinsRule, final File home)\r\n                throws Exception {\r\n            super.decorateHome(jenkinsRule, home);\r\n\r\n            final EndToEndTfs.RunnerImpl parent = getParent();\r\n            final String jobFolder = parent.getJobFolder();\r\n            final String configXmlPath = jobFolder + \"config.xml\";\r\n            final File configXmlFile = new File(home, configXmlPath);\r\n\r\n            final String projectPath = parent.getPathInTfvc();\r\n            XmlHelper.pokeValue(configXmlFile, \"/project/scm/cloakedPaths/string[1]\", projectPath + \"/A/2\");\r\n            XmlHelper.pokeValue(configXmlFile, \"/project/scm/cloakedPaths/string[2]\", projectPath + \"/B\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * If there's no SCMRevisionState present, we revert to old-school polling,\r\n     * using the timestamp of the last build to see if there have been any changes in TFVC,\r\n     * at the project's path, since the specified time.\r\n     *\r\n     * Even though the @EndToEndTfs annotation caused some commits,\r\n     * the OldPollingFallback runner poked the current time (after said commits)\r\n     * in the build.xml, which should cause polling to not find any changes.\r\n     */\r\n    @LocalData\r\n    @EndToEndTfs(OldPollingFallback.class)\r\n    @Ignore @Test public void oldPollingFallback() throws IOException {\r\n        final Jenkins jenkins = j.jenkins;\r\n        final List<Project> projects = jenkins.getProjects();\r\n        final Project project = projects.get(0);\r\n        final TaskListener taskListener = j.createTaskListener();\r\n\r\n        final PollingResult actual = project.poll(taskListener);\r\n\r\n        Assert.assertEquals(PollingResult.NO_CHANGES, actual);\r\n    }\r\n\r\n    /**\r\n     * Injects the current time in milliseconds into the <code>/build/timestamp</code> element\r\n     * of the last <code>build.xml</code>.\r\n     */\r\n    public static class OldPollingFallback extends EndToEndTfs.StubRunner {\r\n\r\n        @Override public void decorateHome(final JenkinsRule jenkinsRule, final File home)\r\n                throws Exception {\r\n            super.decorateHome(jenkinsRule, home);\r\n\r\n            // Add a small pause to make sure we record the timestamp one second later\r\n            // than the last check-in, otherwise we have the polling occurring on the same\r\n            // second as the check-in and finding an SCM change where there should be none.\r\n            Thread.sleep(1000 /* ms */);\r\n\r\n            final EndToEndTfs.RunnerImpl parent = getParent();\r\n            final String jobFolder = parent.getJobFolder();\r\n            final String lastBuildXmlPath = jobFolder + \"builds/2015-07-15_20-37-42/build.xml\";\r\n            final File lastBuildXmlFile = new File(home, lastBuildXmlPath);\r\n            final long rightNowMilliseconds = System.currentTimeMillis();\r\n            final String value = String.valueOf(rightNowMilliseconds);\r\n            XmlHelper.pokeValue(lastBuildXmlFile, \"/build/timestamp\", value);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * As of version 3.2.0, passwords are no longer encoded but encrypted.\r\n     * Such a job should have its encoded password upgraded to encrypted\r\n     * and still be able to poll and build.\r\n     */\r\n    @LocalData\r\n    @EndToEndTfs(UpgradeEncodedPassword.class)\r\n    @Test public void upgradeEncodedPassword()\r\n            throws IOException, XPathExpressionException, ExecutionException, InterruptedException,\r\n\t\tSAXException, ParserConfigurationException {\r\n        final Jenkins jenkins = j.jenkins;\r\n        final TaskListener taskListener = j.createTaskListener();\r\n        final EndToEndTfs.RunnerImpl tfsRunner = j.getTfsRunner();\r\n        final EndToEndTfs.StubRunner stubRunner = tfsRunner.getInnerRunner(EndToEndTfs.StubRunner.class);\r\n        final String encryptedPassword = stubRunner.getEncryptedPassword();\r\n        final List<Project> projects = jenkins.getProjects();\r\n        final Project project = projects.get(0);\r\n        final TeamFoundationServerScm scm = (TeamFoundationServerScm) project.getScm();\r\n        final Secret passwordSecret = scm.getPassword();\r\n        Assert.assertEquals(encryptedPassword, passwordSecret.getEncryptedValue());\r\n        PollingResult actualPollingResult;\r\n\r\n        // setup build\r\n        runUserTrigger(project);\r\n\r\n        actualPollingResult = project.poll(taskListener);\r\n        Assert.assertEquals(PollingResult.Change.NONE, actualPollingResult.change);\r\n\r\n        project.save(/* force the project to be written to disk, which should encrypt the password */);\r\n\r\n        actualPollingResult = project.poll(taskListener);\r\n        Assert.assertEquals(PollingResult.Change.NONE, actualPollingResult.change);\r\n        final File home = j.jenkins.getRootDir();\r\n        final String configXmlPath = \"jobs/upgradeEncodedPassword/config.xml\";\r\n        final File configXmlFile = new File(home, configXmlPath);\r\n        final String userPassword = XmlHelper.peekValue(configXmlFile, \"/project/scm/userPassword\");\r\n        Assert.assertEquals(\"Encoded password should no longer be there\", null, userPassword);\r\n        final String password = XmlHelper.peekValue(configXmlFile, \"/project/scm/password\");\r\n        Assert.assertEquals(\"Encrypted password should be there\", encryptedPassword, password);\r\n\r\n        // TODO: Check in & record changeset, poll & assert SIGNIFICANT\r\n        // TODO: build & assert new last build recorded changeset from above\r\n        // TODO: poll & assert NONE\r\n    }\r\n\r\n    public static class UpgradeEncodedPassword extends CurrentChangesetInjector {\r\n        @Override public void decorateHome(final JenkinsRule jenkinsRule, final File home) throws Exception {\r\n            super.decorateHome(jenkinsRule, home);\r\n\r\n            final EndToEndTfs.RunnerImpl parent = getParent();\r\n            final String jobFolder = parent.getJobFolder();\r\n            final IntegrationTestHelper helper = getHelper();\r\n            final String userPassword = helper.getUserPassword();\r\n            final String scrambledPassword = Scrambler.scramble(userPassword);\r\n            final String configXmlPath = jobFolder + \"config.xml\";\r\n            final File configXmlFile = new File(home, configXmlPath);\r\n            XmlHelper.pokeValue(configXmlFile, \"/project/scm/userPassword\", scrambledPassword);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Verifies that we can still poll and GET from a server when going through a proxy server.\r\n     */\r\n    @LocalData\r\n    @EndToEndTfs(UseWebProxyServer.class)\r\n    @Test public void useWebProxyServer() throws Exception {\r\n        final Jenkins jenkins = j.jenkins;\r\n\r\n        // double-check proxy configuration was loaded and is available\r\n        final ProxyConfiguration proxyConfiguration = jenkins.proxy;\r\n        Assert.assertNotNull(proxyConfiguration);\r\n        final String proxyServerSetting = hudson.Util.fixEmpty(proxyConfiguration.name);\r\n        Assert.assertNotNull(proxyServerSetting);\r\n\r\n        final TaskListener taskListener = j.createTaskListener();\r\n        final EndToEndTfs.RunnerImpl tfsRunner = j.getTfsRunner();\r\n        final UseWebProxyServer innerRunner = tfsRunner.getInnerRunner(UseWebProxyServer.class);\r\n        final List<Project> projects = jenkins.getProjects();\r\n        final Project project = projects.get(0);\r\n\r\n        final HttpProxyServer proxyServer = innerRunner.getServer();\r\n        final LoggingFiltersSourceAdapter adapter = innerRunner.getAdapter();\r\n        final int previousChangeSet;\r\n        try {\r\n            Assert.assertFalse(adapter.proxyWasUsed());\r\n\r\n            // setup build\r\n            runUserTrigger(project);\r\n\r\n            // first poll should report no changes since last build\r\n            final PollingResult firstPoll = project.poll(taskListener);\r\n\r\n            Assert.assertEquals(PollingResult.Change.NONE, firstPoll.change);\r\n            Assert.assertTrue(adapter.proxyWasUsed());\r\n\r\n            adapter.reset();\r\n            // make a change in source control\r\n            previousChangeSet = checkInEmptyFile(tfsRunner);\r\n            Assert.assertTrue(previousChangeSet >= 0);\r\n            Assert.assertFalse(adapter.proxyWasUsed());\r\n\r\n            // second poll should queue a build\r\n            final AbstractBuild firstBuild = runScmPollTrigger(project);\r\n\r\n            Assert.assertNotNull(firstBuild);\r\n            assertBuildSuccess(firstBuild);\r\n            Assert.assertTrue(adapter.proxyWasUsed());\r\n        }\r\n        finally {\r\n            proxyServer.stop();\r\n        }\r\n\r\n        // make a change in source control\r\n        final String fileContents = \"1. Pick up vegetables.\\nPrevious changeset:\" + previousChangeSet;\r\n        final int changeSet = checkInFile(tfsRunner, \"Now with content.\", fileContents);\r\n        Assert.assertTrue(changeSet >= 0);\r\n        adapter.reset();\r\n\r\n        // third poll should claim \"no changes\" due to being unable to reach the proxy server\r\n        final InterceptingTaskListener itl = new InterceptingTaskListener(taskListener);\r\n        // TODO: this takes over 70 seconds to execute, because there's a retry with backoff\r\n        // We might be able to inject an interception that turns off the retry for this operation\r\n        final PollingResult thirdPoll = project.poll(itl);\r\n        Assert.assertEquals(\"Error during polling => NO_CHANGES\", PollingResult.NO_CHANGES, thirdPoll);\r\n        final List<String> fatalErrors = itl.getFatalErrors();\r\n        Assert.assertEquals(1, fatalErrors.size());\r\n        Assert.assertFalse(adapter.proxyWasUsed());\r\n    }\r\n\r\n    public static class UseWebProxyServer extends CurrentChangesetInjector {\r\n\r\n        private final LoggingFiltersSourceAdapter adapter;\r\n        private final HttpProxyServer server;\r\n\r\n        public UseWebProxyServer() {\r\n            adapter = new LoggingFiltersSourceAdapter();\r\n            server =\r\n                DefaultHttpProxyServer\r\n                    .bootstrap()\r\n                    .withPort(0 /* \"...let the system pick up an ephemeral port in a bind operation.\" */)\r\n                    .withFiltersSource(adapter)\r\n                    .start();\r\n\r\n        }\r\n\r\n        @Override public void decorateHome(final JenkinsRule jenkinsRule, final File home) throws Exception {\r\n            super.decorateHome(jenkinsRule, home);\r\n            final InetSocketAddress proxyAddress = server.getListenAddress();\r\n\r\n            final File proxyXmlFile = new File(home, \"proxy.xml\");\r\n            XmlHelper.pokeValue(proxyXmlFile, \"/proxy/name\", proxyAddress.getHostName());\r\n            XmlHelper.pokeValue(proxyXmlFile, \"/proxy/port\", Integer.toString(proxyAddress.getPort(), 10));\r\n        }\r\n\r\n        public HttpProxyServer getServer() {\r\n            return server;\r\n        }\r\n\r\n        public LoggingFiltersSourceAdapter getAdapter() {\r\n            return adapter;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Injects some values into the last <code>build.xml</code> to pretend we're up-to-date with TFS.\r\n     */\r\n    public static class CurrentChangesetInjector extends EndToEndTfs.StubRunner {\r\n\r\n        @Override public void decorateHome(final JenkinsRule jenkinsRule, final File home)\r\n                throws Exception {\r\n            super.decorateHome(jenkinsRule, home);\r\n\r\n            final EndToEndTfs.RunnerImpl parent = getParent();\r\n            final String jobFolder = parent.getJobFolder();\r\n            final String lastBuildXmlPath = jobFolder + \"builds/2015-07-15_20-37-42/build.xml\";\r\n            final File lastBuildXmlFile = new File(home, lastBuildXmlPath);\r\n\r\n            final String projectPath = parent.getPathInTfvc();\r\n            final String serverUrl = getHelper().getServerUrl();\r\n            final Server server = parent.getServer();\r\n            final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n            final int latestChangesetID = vcc.getLatestChangesetID();\r\n            final String changesetVersion = String.valueOf(latestChangesetID);\r\n\r\n            XmlHelper.pokeValue(lastBuildXmlFile, \"/build/actions/hudson.plugins.tfs.model.WorkspaceConfiguration/projectPath\", projectPath);\r\n            XmlHelper.pokeValue(lastBuildXmlFile, \"/build/actions/hudson.plugins.tfs.model.WorkspaceConfiguration/serverUrl\", serverUrl);\r\n\r\n            XmlHelper.pokeValue(lastBuildXmlFile, \"/build/actions/hudson.plugins.tfs.TFSRevisionState/changesetVersion\", changesetVersion);\r\n            XmlHelper.pokeValue(lastBuildXmlFile, \"/build/actions/hudson.plugins.tfs.TFSRevisionState/projectPath\", projectPath);\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/IntegrationTestHelper.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.*;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.junit.Assert;\r\nimport org.junit.runner.Description;\r\n\r\nimport javax.xml.bind.DatatypeConverter;\r\nimport java.net.Inet4Address;\r\nimport java.net.Inet6Address;\r\nimport java.net.InetAddress;\r\nimport java.net.NetworkInterface;\r\nimport java.net.SocketException;\r\nimport java.net.URI;\r\nimport java.net.URISyntaxException;\r\nimport java.net.UnknownHostException;\r\nimport java.util.Enumeration;\r\n\r\npublic class IntegrationTestHelper {\r\n\r\n    private final String serverUrl;\r\n    private final String userName;\r\n    private final String userPassword;\r\n\r\n    public IntegrationTestHelper() throws URISyntaxException {\r\n        this(\r\n                propertyOrFail(\"tfs_collection_url\"),\r\n                propertyOrFail(\"tfs_server_name\"),\r\n                propertyOrNull(\"tfs_user_name\"),\r\n                propertyOrNull(\"tfs_user_password\")\r\n        );\r\n    }\r\n\r\n    public IntegrationTestHelper(final String tfsServerName) throws URISyntaxException {\r\n        this(\r\n            (TeamCollectionConfiguration.isTeamServices(tfsServerName)) ?\r\n                new URI(\"https\", null, tfsServerName, 443, \"/\", null, null).toString() :\r\n                new URI(\"http\", null, tfsServerName, 8080, \"/tfs/\" + \"jenkins-tfs-plugin\", null, null).toString(),\r\n            tfsServerName,\r\n            null,\r\n            null\r\n        );\r\n    }\r\n\r\n    public IntegrationTestHelper(final String tfsServerUrl, final String tfsServerName, final String tfsUserName, final String tfsUserPassword) throws URISyntaxException {\r\n        final URI serverUri = new URI(tfsServerUrl);\r\n        if (TeamCollectionConfiguration.isTeamServices(tfsServerName)) {\r\n            this.userName = tfsUserName;\r\n            this.userPassword = tfsUserPassword;\r\n        } else {\r\n            this.userName = (tfsUserName != null) ? tfsUserName : \"jenkins-tfs-plugin\";\r\n            this.userPassword = (tfsUserPassword != null) ? tfsUserPassword : \"for-test-only\";\r\n        }\r\n        serverUrl = serverUri.toString();\r\n    }\r\n\r\n    static String propertyOrNull(final String propertyName) {\r\n        final String value = System.getProperty(propertyName);\r\n        return hudson.Util.fixEmptyAndTrim(value);\r\n    }\r\n\r\n    static String propertyOrFail(final String propertyName) {\r\n        final String result = propertyOrNull(propertyName);\r\n        if (result == null) {\r\n            Assert.fail(\"The '\" + propertyName + \"' property MUST be provided a [non-empty] value.\");\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * A string representing the URL to a VSO account or a default TFS server installation.\r\n     */\r\n    public String getServerUrl() {\r\n        return serverUrl;\r\n    }\r\n\r\n    public String getUserName() {\r\n        return userName;\r\n    }\r\n\r\n    public String getUserPassword() {\r\n        return userPassword;\r\n    }\r\n\r\n    /**\r\n     * Creates a string representing a path in TFVC where the specified {@param testDescription}\r\n     * will perform its work.\r\n     *\r\n     * @param testDescription metadata about the currently executing test method.\r\n     * @return a string that looks like <code>$/FunctionalTests/TestClass/testMethod</code>\r\n     */\r\n    public static String determinePathInTfvcForTestCase(Description testDescription) {\r\n        final Class clazz = testDescription.getTestClass();\r\n        final String testClassName = clazz.getSimpleName();\r\n        final String testCaseName = testDescription.getMethodName();\r\n        return \"$/FunctionalTests\" + \"/\" + testClassName + \"/\" + testCaseName;\r\n    }\r\n\r\n    // Adapted from http://stackoverflow.com/a/20793241\r\n    public static String tryToDetermineHostName() {\r\n        String result;\r\n        try {\r\n            result = InetAddress.getLocalHost().getHostName();\r\n            if (StringUtils.isNotEmpty(result)) {\r\n                return result;\r\n            }\r\n        } catch (UnknownHostException e) {\r\n            // Probably failed due to reasons listed here: http://stackoverflow.com/a/7800008\r\n        }\r\n\r\n        result = System.getenv(\"COMPUTERNAME\");\r\n        if (result != null) {\r\n            return result;\r\n        }\r\n\r\n        result = System.getenv(\"HOSTNAME\");\r\n        if (result != null) {\r\n            return result;\r\n        }\r\n\r\n        result = inventHostName();\r\n        if (result == null) {\r\n            result = \"unknown\";\r\n        }\r\n        return result;\r\n    }\r\n\r\n    // Adapted from http://stackoverflow.com/q/8765578\r\n    public static String inventHostName() {\r\n        String result = null;\r\n        String ipv4Address = null, ipv6Address = null;\r\n        try {\r\n            final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\r\n            while (ipv6Address == null && interfaces.hasMoreElements()) {\r\n                final NetworkInterface current = interfaces.nextElement();\r\n                try {\r\n                    if (!current.isUp() || current.isLoopback() || current.isVirtual()) {\r\n                        continue;\r\n                    }\r\n                } catch (SocketException e) {\r\n                    continue;\r\n                }\r\n                final Enumeration<InetAddress> addresses = current.getInetAddresses();\r\n                while (addresses.hasMoreElements()) {\r\n                    final InetAddress currentAddress = addresses.nextElement();\r\n                    if (currentAddress.isLoopbackAddress()) {\r\n                        continue;\r\n                    }\r\n                    final byte[] addressBytes = currentAddress.getAddress();\r\n                    if (currentAddress instanceof Inet6Address) {\r\n                        ipv6Address = formatFriendlyName(addressBytes);\r\n                        break;\r\n                    }\r\n                    if (currentAddress instanceof Inet4Address) {\r\n                        ipv4Address = formatFriendlyName(addressBytes);\r\n                    }\r\n                }\r\n            }\r\n            if (ipv6Address != null) {\r\n                result = ipv6Address;\r\n            }\r\n            else if (ipv4Address != null) {\r\n                result = ipv4Address;\r\n            }\r\n        } catch (SocketException e) {\r\n            // result will stay null\r\n        }\r\n        return result;\r\n    }\r\n\r\n    public static String formatFriendlyName(final byte[] addressBytes) {\r\n        final String base64 = DatatypeConverter.printBase64Binary(addressBytes);\r\n        final String slashToMinus = base64.replace('/', '-');\r\n        return slashToMinus;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/IntegrationTestHelperTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\npublic class IntegrationTestHelperTest {\r\n\r\n    @Test public void buildServerUrl_onPremiseTfsServer() throws Exception {\r\n        final IntegrationTestHelper cut = new IntegrationTestHelper(\"tfs2013\");\r\n\r\n        final String actual = cut.getServerUrl();\r\n\r\n        Assert.assertEquals(\"http://tfs2013:8080/tfs/jenkins-tfs-plugin\", actual);\r\n    }\r\n\r\n    @Test public void buildServerUrl_designatedVsoAccount() throws Exception {\r\n        final IntegrationTestHelper cut = new IntegrationTestHelper(\"automated-testing.visualstudio.com\");\r\n\r\n        final String actual = cut.getServerUrl();\r\n\r\n        Assert.assertEquals(\"https://automated-testing.visualstudio.com:443/\", actual);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/IntegrationTests.java",
    "content": "package hudson.plugins.tfs;\r\n\r\n/**\r\n * To be used with the JUnit Category annotation on a method, like so:\r\n * @Category(hudson.plugins.tfs.IntegationTests.class)\r\n */\r\npublic interface IntegrationTests {\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/InterceptingTaskListener.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.console.ConsoleNote;\r\nimport hudson.model.TaskListener;\r\n\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\nimport java.io.PrintWriter;\r\nimport java.util.ArrayList;\r\nimport java.util.Formatter;\r\nimport java.util.List;\r\n\r\npublic class InterceptingTaskListener implements TaskListener {\r\n\r\n    private final TaskListener victim;\r\n    private final List<String> errors = new ArrayList<String>();\r\n    private final List<String> fatalErrors = new ArrayList<String>();\r\n\r\n    public InterceptingTaskListener(final TaskListener victim) {\r\n        this.victim = victim;\r\n    }\r\n\r\n    public PrintStream getLogger() {\r\n        return victim.getLogger();\r\n    }\r\n\r\n    public void annotate(final ConsoleNote ann) throws IOException {\r\n        victim.annotate(ann);\r\n    }\r\n\r\n    public void hyperlink(final String url, final String text) throws IOException {\r\n        victim.hyperlink(url, text);\r\n    }\r\n\r\n    private static void add(final List<String> destination, final String format, final Object... args) {\r\n        final Formatter formatter = new Formatter();\r\n        formatter.format(format, args);\r\n        final String message = formatter.toString();\r\n        destination.add(message);\r\n    }\r\n\r\n    public PrintWriter error(final String msg) {\r\n        errors.add(msg);\r\n        return victim.error(msg);\r\n    }\r\n\r\n    public PrintWriter error(final String format, final Object... args) {\r\n        add(errors, format, args);\r\n        return victim.error(format, args);\r\n    }\r\n\r\n    public PrintWriter fatalError(final String msg) {\r\n        fatalErrors.add(msg);\r\n        return victim.fatalError(msg);\r\n    }\r\n\r\n    public PrintWriter fatalError(final String format, final Object... args) {\r\n        add(fatalErrors, format, args);\r\n        return victim.fatalError(format, args);\r\n    }\r\n\r\n    public List<String> getErrors() {\r\n        return errors;\r\n    }\r\n\r\n    public List<String> getFatalErrors() {\r\n        return fatalErrors;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/LoggingFiltersSourceAdapter.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.handler.codec.http.FullHttpRequest;\r\nimport io.netty.handler.codec.http.FullHttpResponse;\r\nimport io.netty.handler.codec.http.HttpObject;\r\nimport io.netty.handler.codec.http.HttpRequest;\r\nimport io.netty.handler.codec.http.HttpResponse;\r\nimport org.littleshoot.proxy.HttpFilters;\r\nimport org.littleshoot.proxy.HttpFiltersAdapter;\r\nimport org.littleshoot.proxy.HttpFiltersSourceAdapter;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\npublic class LoggingFiltersSourceAdapter extends HttpFiltersSourceAdapter {\r\n\r\n    private final List<FullHttpRequest> requests = new ArrayList<FullHttpRequest>();\r\n    private final List<FullHttpResponse> responses = new ArrayList<FullHttpResponse>();\r\n\r\n    /*\r\n    https://github.com/adamfisk/LittleProxy\r\n    \"\"\"\r\n    To enable aggregator and inflater you have to return a value greater than 0 in your\r\n    `HttpFiltersSource#get(Request/Response)BufferSizeInBytes()` methods.\r\n    This provides to you a `FullHttp(Request/Response)`\r\n    with the complete content in your filter uncompressed.\r\n    Otherwise you have to handle the chunks yourself.\r\n    \"\"\"\r\n     */\r\n\r\n    @Override public int getMaximumRequestBufferSizeInBytes() {\r\n        return 10 * 1024 * 1024;\r\n    }\r\n\r\n    @Override public int getMaximumResponseBufferSizeInBytes() {\r\n        return 10 * 1024 * 1024;\r\n    }\r\n\r\n    @Override public HttpFilters filterRequest(final HttpRequest originalRequest, final ChannelHandlerContext ctx) {\r\n        return new HttpFiltersAdapter(originalRequest, ctx) {\r\n            @Override public HttpResponse clientToProxyRequest(final HttpObject httpObject) {\r\n                requests.add((FullHttpRequest) httpObject);\r\n                return /* \"[return] null to continue processing as usual\" */ null;\r\n            }\r\n\r\n            @Override public HttpObject serverToProxyResponse(final HttpObject httpObject) {\r\n                responses.add((FullHttpResponse) httpObject);\r\n                return /* [return] the unmodified HttpObject */ httpObject;\r\n            }\r\n        };\r\n    }\r\n\r\n    public boolean proxyWasUsed() {\r\n        return requests.size() > 0;\r\n    }\r\n\r\n    public void reset() {\r\n        requests.clear();\r\n        responses.clear();\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/SwedishLocaleTestCase.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport java.util.Locale;\r\n\r\nimport org.junit.After;\r\nimport org.junit.Before;\r\n\r\n/**\r\n * Test class that helps setting (and resetting) the locale to swedish so \r\n * dates in logs can be parsed properly.\r\n * \r\n * @author Erik Ramfelt\r\n */\r\npublic abstract class SwedishLocaleTestCase {\r\n\r\n    Locale defaultLocale;\r\n    \r\n    @Before\r\n    public void setToSwedishLocale() {\r\n        defaultLocale = Locale.getDefault();\r\n        Locale.setDefault(new Locale(\"sv\", \"SE\"));\r\n    }\r\n    \r\n    @After\r\n    public void resetDefaultLocale() {\r\n        Locale.setDefault(defaultLocale);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/TFSRevisionStateTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport static org.junit.Assert.fail;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport org.junit.Test;\r\nimport org.kohsuke.stapler.export.Model;\r\nimport org.kohsuke.stapler.export.ModelBuilder;\r\nimport org.kohsuke.stapler.export.Property;\r\n\r\npublic class TFSRevisionStateTest {\r\n\r\n    @Test\r\n    public void exportedProperties() {\r\n        ModelBuilder mb = new ModelBuilder();\r\n        Model<TFSRevisionState> m = mb.get(TFSRevisionState.class);\r\n\r\n        List<Property> actual = m.getProperties();\r\n\r\n        List<String> actualPropertyNames = new ArrayList<String>();\r\n        for (Property p : actual) {\r\n            actualPropertyNames.add(p.name);\r\n        }\r\n        assertCollectionContains(actualPropertyNames, \"changesetVersion\", \"projectPath\");\r\n    }\r\n    \r\n    private static final String NewLine = System.getProperty(\"line.separator\");\r\n    \r\n    private static <T> void assertCollectionContains(Iterable<T> actual, T... expected)\r\n    {\r\n        ArrayList<T> expectedItems = new ArrayList<T>(expected.length);\r\n        for (T t : expected) {\r\n            expectedItems.add(t);\r\n        }\r\n        \r\n        ArrayList<T> extraItems = new ArrayList<T>();\r\n        for (T a : actual) {\r\n            if (expectedItems.contains(a)) {\r\n                expectedItems.remove(a);\r\n            }\r\n            else {\r\n                extraItems.add(a);\r\n            }\r\n        }\r\n        StringBuilder sb = null;\r\n        if (expectedItems.size() > 0) {\r\n            sb = new StringBuilder();\r\n            sb.append(\"Expected the following item\");\r\n            if (expectedItems.size() != 1) {\r\n                sb.append('s');\r\n            }\r\n            sb.append(':').append(NewLine);\r\n            for (T t : expectedItems) {\r\n                sb.append('<').append(t).append('>').append(NewLine);\r\n            }\r\n        }\r\n        if (extraItems.size() > 0) {\r\n            if (sb == null) {\r\n                sb = new StringBuilder();\r\n            }\r\n            sb.append(\"Did not expect the following item\");\r\n            if (extraItems.size() != 1) {\r\n                sb.append('s');\r\n            }\r\n            sb.append(':').append(NewLine);\r\n            for (T t : extraItems) {\r\n                sb.append('<').append(t).append('>').append(NewLine);\r\n            }\r\n        }\r\n        if (sb != null){\r\n            fail(sb.toString());\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/TeamBuildEndpointTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link TeamBuildEndpoint}.\r\n */\r\npublic class TeamBuildEndpointTest {\r\n\r\n    @Test public void decodeCommandAndJobNames_typical() throws Exception {\r\n        final TeamBuildEndpoint cut = new TeamBuildEndpoint();\r\n        final String input = TeamBuildEndpoint.URL_PREFIX + \"ping/a\";\r\n\r\n        final boolean actual = cut.decodeCommandAndJobNames(input);\r\n\r\n        Assert.assertEquals(true, actual);\r\n        Assert.assertEquals(\"ping\", cut.getCommandName());\r\n        Assert.assertEquals(\"a\", cut.getJobName());\r\n    }\r\n\r\n    @Test public void decodeCommandAndJobNames_withDecoding() throws Exception {\r\n        final TeamBuildEndpoint cut = new TeamBuildEndpoint();\r\n\r\n        final String input = TeamBuildEndpoint.URL_PREFIX + \"ping/a+job%20name%2Fcontaining%3Dencoded+characters%3F\";\r\n        final boolean actual = cut.decodeCommandAndJobNames(input);\r\n\r\n        Assert.assertEquals(true, actual);\r\n        Assert.assertEquals(\"ping\", cut.getCommandName());\r\n        Assert.assertEquals(\"a job name/containing=encoded characters?\", cut.getJobName());\r\n    }\r\n\r\n    @Test public void decodeCommandAndJobNames_noJob() throws Exception {\r\n        final TeamBuildEndpoint cut = new TeamBuildEndpoint();\r\n        final String input = TeamBuildEndpoint.URL_PREFIX + \"ping/\";\r\n\r\n        final boolean actual = cut.decodeCommandAndJobNames(input);\r\n\r\n        Assert.assertEquals(false, actual);\r\n        Assert.assertEquals(\"ping\", cut.getCommandName());\r\n    }\r\n\r\n    @Test public void decodeCommandAndJobNames_noJobNoSlash() throws Exception {\r\n        final TeamBuildEndpoint cut = new TeamBuildEndpoint();\r\n        final String input = TeamBuildEndpoint.URL_PREFIX + \"ping\";\r\n\r\n        final boolean actual = cut.decodeCommandAndJobNames(input);\r\n\r\n        Assert.assertEquals(false, actual);\r\n        Assert.assertEquals(\"ping\", cut.getCommandName());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/TeamCollectionConfigurationTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.util.FormValidation;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\nimport java.net.URI;\r\n\r\n/**\r\n * A class to test {@link TeamCollectionConfiguration}.\r\n */\r\npublic class TeamCollectionConfigurationTest {\r\n\r\n    private static void assertSameCollectionUri(final String a, final String b) {\r\n        areSameCollectionUri(a, b, true);\r\n    }\r\n\r\n    private static void areSameCollectionUri(final String a, final String b, boolean expected) {\r\n        final URI uriA = a == null ? null : URI.create(a);\r\n        final URI uriB = b == null ? null : URI.create(b);\r\n        final String template = \"Expected '%s' and '%s' to be considered%s the same.\";\r\n        final String message = String.format(template, a, b, expected ? \"\" : \" NOT\");\r\n        Assert.assertEquals(message, expected, TeamCollectionConfiguration.areSameCollectionUri(uriA, uriB));\r\n        Assert.assertEquals(message, expected, TeamCollectionConfiguration.areSameCollectionUri(uriB, uriA));\r\n    }\r\n\r\n    @Test public void areSameCollectionUri_identity() throws Exception {\r\n        final String input = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n        assertSameCollectionUri(input, input);\r\n    }\r\n\r\n    @Test public void areSameCollectionUri_typical() throws Exception {\r\n        final String a = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n        final String b = \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection\";\r\n\r\n        assertSameCollectionUri(a, b);\r\n    }\r\n\r\n    @Test public void areSameCollectionUri_withSlashes() throws Exception {\r\n        final String a = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n        final String b = \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/\";\r\n\r\n        assertSameCollectionUri(a, b);\r\n    }\r\n\r\n    @Test public void areSameCollectionUri_withoutSlashes() throws Exception {\r\n        final String a = \"https://fabrikam-fiber-inc.visualstudio.com\";\r\n        final String b = \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection\";\r\n\r\n        assertSameCollectionUri(a, b);\r\n    }\r\n\r\n\r\n    @Test public void checkTeamServices_serverOnly() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com\");\r\n\r\n        final FormValidation actual = TeamCollectionConfiguration.checkTeamServices(input);\r\n\r\n        Assert.assertEquals(FormValidation.Kind.OK, actual.kind);\r\n    }\r\n\r\n    @Test public void checkTeamServices_serverWithSlash() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/\");\r\n\r\n        final FormValidation actual = TeamCollectionConfiguration.checkTeamServices(input);\r\n\r\n        Assert.assertEquals(FormValidation.Kind.OK, actual.kind);\r\n    }\r\n\r\n    @Test public void checkTeamServices_serverWithDefaultCollection() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection\");\r\n\r\n        final FormValidation actual = TeamCollectionConfiguration.checkTeamServices(input);\r\n\r\n        Assert.assertEquals(FormValidation.Kind.ERROR, actual.kind);\r\n    }\r\n\r\n    @Test public void checkTeamServices_serverWithDefaultCollectionSlash() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/\");\r\n\r\n        final FormValidation actual = TeamCollectionConfiguration.checkTeamServices(input);\r\n\r\n        Assert.assertEquals(FormValidation.Kind.ERROR, actual.kind);\r\n    }\r\n\r\n    @Test public void checkTeamServices_gitUrl() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam\");\r\n\r\n        final FormValidation actual = TeamCollectionConfiguration.checkTeamServices(input);\r\n\r\n        Assert.assertEquals(FormValidation.Kind.ERROR, actual.kind);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/TeamEventsEndpointTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport com.microsoft.teamfoundation.common.model.ProjectState;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitPush;\r\nimport hudson.plugins.tfs.model.AbstractHookEvent;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport hudson.plugins.tfs.model.servicehooks.ResourceContainer;\r\nimport hudson.plugins.tfs.util.ResourceHelper;\r\nimport net.sf.json.JSONObject;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\n/**\r\n * A class to test {@link TeamEventsEndpoint}.\r\n */\r\npublic class TeamEventsEndpointTest {\r\n\r\n    private static final String GIT_PUSH_SAMPLE_JSON =\r\n            ResourceHelper.fetchAsString(TeamEventsEndpointTest.class, \"git.push-sample.json\");\r\n\r\n    @Test\r\n    public void deserializeEvent_sample() throws Exception {\r\n        final Event actual = TeamEventsEndpoint.deserializeEvent(GIT_PUSH_SAMPLE_JSON);\r\n\r\n        Assert.assertEquals(\"git.push\", actual.getEventType());\r\n        final Map<String, ResourceContainer> containers = actual.getResourceContainers();\r\n        final ResourceContainer collection = containers.get(\"collection\");\r\n        Assert.assertEquals(\"https://fabrikam-fiber-inc.visualstudio.com/\", collection.getBaseUrl());\r\n    }\r\n\r\n    @Test\r\n    public void innerDispatch_fakedGitPushEventHandling() throws Exception {\r\n        final Map<String, AbstractHookEvent.Factory> factories = new HashMap<String, AbstractHookEvent.Factory>();\r\n        final String eventName = \"fakedGitPush\";\r\n        factories.put(eventName, FakedGitPush.FACTORY);\r\n\r\n        TeamEventsEndpoint.innerDispatch(GIT_PUSH_SAMPLE_JSON, eventName, factories);\r\n    }\r\n\r\n    private static class FakedGitPush extends AbstractHookEvent {\r\n\r\n        public static final AbstractHookEvent.Factory FACTORY = new Factory() {\r\n            @Override\r\n            public AbstractHookEvent create() {\r\n                return new FakedGitPush();\r\n            }\r\n\r\n            @Override\r\n            public String getSampleRequestPayload() {\r\n                return null;\r\n            }\r\n        };\r\n\r\n        @Override\r\n        public JSONObject perform(final ObjectMapper mapper, final Event serviceHookEvent, final String message, final String detailedMessage) {\r\n            final Object resource = serviceHookEvent.getResource();\r\n            final GitPush actual = mapper.convertValue(resource, GitPush.class);\r\n            Assert.assertEquals(ProjectState.WELL_FORMED, actual.getRepository().getProject().getState());\r\n            return null;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/TeamFoundationServerScmIntegrationTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.util.Secret;\r\nimport org.junit.Assert;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\nimport org.junit.experimental.categories.Category;\r\n\r\nimport java.net.URISyntaxException;\r\n\r\n/**\r\n * Tests that connect to a TFS server identified by the tfs_server_name property.\r\n * These are so-called integration (L2) tests.\r\n */\r\n@Category(IntegrationTests.class)\r\npublic class TeamFoundationServerScmIntegrationTest {\r\n\r\n    private TeamFoundationServerScm scm;\r\n\r\n    @Before\r\n    public void connectToTfs() throws URISyntaxException {\r\n        final IntegrationTestHelper helper = new IntegrationTestHelper();\r\n        final String serverUrl = helper.getServerUrl();\r\n        scm = new TeamFoundationServerScm(serverUrl, \"projectPath\", \"workspaceName\", null, null);\r\n        scm.setLocalPath(\"localPath\");\r\n    }\r\n\r\n    @Test\r\n    public void sample() {\r\n        Assert.assertNotNull(scm);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/TeamFoundationServerScmTest.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\r\nimport com.thoughtworks.xstream.XStream;\r\nimport hudson.FilePath;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.BuildListener;\r\nimport hudson.model.Computer;\r\nimport hudson.model.Node;\r\nimport hudson.model.ParametersAction;\r\nimport hudson.plugins.tfs.model.Project;\r\nimport hudson.util.Secret;\r\nimport hudson.util.SecretOverride;\r\nimport hudson.util.XStream2;\r\nimport org.apache.commons.lang.SystemUtils;\r\nimport org.junit.After;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.util.Arrays;\r\nimport java.util.Collection;\r\nimport java.util.Collections;\r\nimport java.util.GregorianCalendar;\r\nimport java.util.HashMap;\r\nimport java.util.Iterator;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport static org.hamcrest.CoreMatchers.is;\r\nimport static org.junit.Assert.assertEquals;\r\nimport static org.junit.Assert.assertFalse;\r\nimport static org.junit.Assert.assertThat;\r\nimport static org.junit.Assert.assertTrue;\r\nimport static org.junit.Assume.assumeTrue;\r\nimport static org.mockito.Matchers.isA;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.times;\r\nimport static org.mockito.Mockito.verify;\r\nimport static org.mockito.Mockito.verifyNoMoreInteractions;\r\nimport static org.mockito.Mockito.when;\r\n\r\n\r\n@SuppressWarnings(\"unchecked\")\r\npublic class TeamFoundationServerScmTest {\r\n\r\n    private FilePath workspace;\r\n\r\n    @After public void tearDown() throws Exception {\r\n        if (workspace != null) {\r\n            workspace.deleteRecursive();\r\n            workspace = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     Up until version 3.1.1, the plugin used to store the password in a base64-encoded string.\r\n     As of bd98b91ea614c307a6bb1e0af36d9dd2a5646e29, an encrypted version of the password is stored.\r\n     This test makes sure a job can be upgraded without loss of the password.\r\n     */\r\n    @Test public void upgradeFromScrambledPassword() {\r\n        SecretOverride secretOverride = null;\r\n        try {\r\n            secretOverride = new SecretOverride();\r\n            final String xmlString =\r\n                    \"<scm class='hudson.plugins.tfs.TeamFoundationServerScm' plugin='tfs@3.1.1'>\\n\" +\r\n                    \"    <serverUrl>http://example.tfs.server.invalid:8080/tfs</serverUrl>\\n\" +\r\n                    \"    <projectPath>$/example/path</projectPath>\\n\" +\r\n                    \"    <localPath>.</localPath>\\n\" +\r\n                    \"    <workspaceName>Hudson-${JOB_NAME}-${NODE_NAME}</workspaceName>\\n\" +\r\n                    \"    <userPassword>ZXhhbXBsZVBhc3N3b3Jk</userPassword>\\n\" +\r\n                    \"    <userName>example\\\\tfsbuilder</userName>\\n\" +\r\n                    \"    <useUpdate>false</useUpdate>\\n\" +\r\n                    \"</scm>\";\r\n            final XStream serializer = new XStream2();\r\n\r\n            final TeamFoundationServerScm tfsScmObject = (TeamFoundationServerScm) serializer.fromXML(xmlString);\r\n\r\n            final String actual = tfsScmObject.getUserPassword();\r\n            assertEquals(\"examplePassword\", actual);\r\n            assertEquals(\"examplePassword\", Secret.toString(tfsScmObject.getPassword()));\r\n\r\n            final String expectedUpgradedXml =\r\n                    \"<hudson.plugins.tfs.TeamFoundationServerScm>\\n\" +\r\n                            \"  <serverUrl>http://example.tfs.server.invalid:8080/tfs</serverUrl>\\n\" +\r\n                            \"  <projectPath>$/example/path</projectPath>\\n\" +\r\n                            \"  <localPath>.</localPath>\\n\" +\r\n                            \"  <workspaceName>Hudson-${JOB_NAME}-${NODE_NAME}</workspaceName>\\n\" +\r\n                            \"  <password>GZ3wK9L4iJXsMwXnJ4NieiVpOlxj0AVrthfe7MIr9w0=</password>\\n\" +\r\n                            \"  <userName>example\\\\tfsbuilder</userName>\\n\" +\r\n                            \"  <credentialsConfigurer class=\\\"hudson.plugins.tfs.model.ManualCredentialsConfigurer\\\"/>\\n\" +\r\n                            \"  <useUpdate>false</useUpdate>\\n\" +\r\n                            \"  <useOverwrite>false</useOverwrite>\\n\" +\r\n                            \"</hudson.plugins.tfs.TeamFoundationServerScm>\";\r\n\r\n            final String actualUpgradedXml = serializer.toXML(tfsScmObject);\r\n\r\n            // This assert only works if you are on the same machine that is running the build (i.e. it fails on a Jenkins linux node)\r\n            //assertEquals(expectedUpgradedXml, actualUpgradedXml);\r\n\r\n            final TeamFoundationServerScm tfsScmObject2 = (TeamFoundationServerScm) serializer.fromXML(actualUpgradedXml);\r\n            final String actual2 = tfsScmObject2.getUserPassword();\r\n            assertEquals(\"examplePassword\", actual2);\r\n            assertEquals(\"examplePassword\", Secret.toString(tfsScmObject.getPassword()));\r\n        }\r\n        finally {\r\n            if (secretOverride != null) {\r\n                try {\r\n                    secretOverride.close();\r\n                } catch (IOException e) {\r\n                    // ignore\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    @Test\r\n    public void assertWorkspaceNameReplacesJobName() {\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        AbstractProject project = mock(AbstractProject.class);\r\n        when(build.getProject()).thenReturn(project);\r\n        when(project.getName()).thenReturn(\"ThisIsAJob\");\r\n\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(null, null, \"erik_${JOB_NAME}\");\r\n        assertEquals(\"Workspace name was incorrect\", \"erik_ThisIsAJob\", scm.getWorkspaceName(build, mock(Computer.class)));\r\n    }\r\n\r\n    @Test \r\n    public void assertDoProjectPathCheckRegexWorks() {\r\n        assertFalse(\"Project path regex matched an invalid project path\", TeamFoundationServerScm.DescriptorImpl.PROJECT_PATH_REGEX.matcher(\"tfsandbox\").matches());\r\n        assertFalse(\"Project path regex matched an invalid project path\", TeamFoundationServerScm.DescriptorImpl.PROJECT_PATH_REGEX.matcher(\"tfsandbox/with/sub/pathes\").matches());\r\n        assertFalse(\"Project path regex matched an invalid project path\", TeamFoundationServerScm.DescriptorImpl.PROJECT_PATH_REGEX.matcher(\"tfsandbox$/with/sub/pathes\").matches());\r\n        assertTrue(\"Project path regex did not match a valid project path\", TeamFoundationServerScm.DescriptorImpl.PROJECT_PATH_REGEX.matcher(\"$/tfsandbox\").matches());\r\n        assertTrue(\"Project path regex did not match a valid project path\", TeamFoundationServerScm.DescriptorImpl.PROJECT_PATH_REGEX.matcher(\"$/tfsandbox/path with space/subpath\").matches());\r\n    }\r\n    \r\n    @Test \r\n    public void assertDoWorkspaceNameCheckRegexWorks() {\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"work space \").matches());\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"work.space.\").matches());\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"work*space\").matches());\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"work/space\").matches());\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"work\\\"space\").matches());\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"workspace*\").matches());\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"workspace/\").matches());\r\n        assertFalse(\"Workspace name regex matched an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"workspace\\\"\").matches());\r\n        assertTrue(\"Workspace name regex dit not match an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"work.space\").matches());\r\n        assertTrue(\"Workspace name regex dit not match an invalid workspace name\", TeamFoundationServerScm.DescriptorImpl.WORKSPACE_NAME_REGEX.matcher(\"work space\").matches());\r\n    }\r\n    \r\n    @Test\r\n    public void assertCloakedPathsCheckRegexWorks() {\r\n\r\n        final String shouldNotMatch = \"Cloaked paths regex matched an invalid cloaked path\";\r\n        assertFalse(shouldNotMatch, isCloakedPathValid(\"tfsandbox\"));\r\n        assertFalse(shouldNotMatch, isCloakedPathValid(\"tfsandbox/with/sub/pathes\"));\r\n        assertFalse(shouldNotMatch, isCloakedPathValid(\"tfsandbox$/with/sub/pathes\"));\r\n        assertFalse(shouldNotMatch, isCloakedPathValid(\"$/tfsandbox/path1;$/tfsandbox/path2\"));\r\n        assertFalse(shouldNotMatch, isCloakedPathValid(\"$/tfsandbox/path1 ; $/tfsandbox/path2 ; $/tfsandbox/path3\"));\r\n        assertFalse(shouldNotMatch, isCloakedPathValid(\"$/foo/;$/bar/;$/baz/\"));\r\n        assertFalse(shouldNotMatch, isCloakedPathValid(\"$/foo/;\\n$/bar/;\\n$/baz/\"));\r\n\r\n        final String shoudMatch = \"Cloaked paths regex did not match a valid cloaked path\";\r\n        assertTrue(shoudMatch, isCloakedPathValid(\"$/tfsandbox\"));\r\n        assertTrue(shoudMatch, isCloakedPathValid(\"$/tfsandbox/path with space/subpath\"));\r\n        assertTrue(shoudMatch, isCloakedPathValid(\"$/tfsandbox/with/${parameter}/path\"));\r\n        assertTrue(shoudMatch, isCloakedPathValid(\"$/foo/\\n$/bar/\\n$/baz/\"));\r\n        assertTrue(shoudMatch, isCloakedPathValid(\" $/foo/ \\n $/bar/ \\n $/baz/ \"));\r\n        assertTrue(shoudMatch, isCloakedPathValid(\"\\n$/foo/\\n\\n$/bar/\\n\\n$/baz/\\n\"));\r\n    }\r\n\r\n    private static boolean isCloakedPathValid(final String path) {\r\n        return TeamFoundationServerScm.DescriptorImpl.CLOAKED_PATHS_REGEX.matcher(path).matches();\r\n    }\r\n\r\n    @Test\r\n    public void serializeCloakedPathCollectionToString_one() {\r\n        final List<String> cloakedPaths = Collections.singletonList(\"$/foo\");\r\n\r\n        final String actual = TeamFoundationServerScm.serializeCloakedPathCollectionToString(cloakedPaths);\r\n\r\n        Assert.assertEquals(\"$/foo\", actual);\r\n    }\r\n\r\n    @Test\r\n    public void serializeCloakedPathCollectionToString_two() {\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/foo\", \"$/bar\");\r\n\r\n        final String actual = TeamFoundationServerScm.serializeCloakedPathCollectionToString(cloakedPaths);\r\n\r\n        Assert.assertEquals(\"$/foo\\n$/bar\", actual);\r\n    }\r\n\r\n    @Test\r\n    public void serializeCloakedPathCollectionToString_many() {\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/foo/\", \"$/bar/\", \"$/baz/\");\r\n\r\n        final String actual = TeamFoundationServerScm.serializeCloakedPathCollectionToString(cloakedPaths);\r\n\r\n        Assert.assertEquals(\"$/foo/\\n$/bar/\\n$/baz/\", actual);\r\n    }\r\n\r\n    @Test\r\n    public void splitCloakedPaths_one() {\r\n        final String input = \"$/foo/\";\r\n\r\n        final Collection<String> actual = TeamFoundationServerScm.splitCloakedPaths(input);\r\n\r\n        areEqual(actual, input);\r\n    }\r\n\r\n    @Test\r\n    public void splitCloakedPaths_newlinesMany() {\r\n        final String input = \"$/foo/\\n$/bar/\\n$/baz/\";\r\n\r\n        final Collection<String> actual = TeamFoundationServerScm.splitCloakedPaths(input);\r\n\r\n        areEqual(actual, \"$/foo/\", \"$/bar/\", \"$/baz/\");\r\n    }\r\n\r\n    @Test\r\n    public void splitCloakedPaths_newlinesWithLiberalSpacing() {\r\n        final String input = \" $/foo/ \\n $/bar/ \\n $/baz/ \";\r\n\r\n        final Collection<String> actual = TeamFoundationServerScm.splitCloakedPaths(input);\r\n\r\n        areEqual(actual, \"$/foo/\", \"$/bar/\", \"$/baz/\");\r\n    }\r\n\r\n    @Test\r\n    public void splitCloakedPaths_newlinesWithBlankLines() {\r\n        final String input = \"\\n$/foo/\\n\\n$/bar/\\n\\n$/baz/\\n\";\r\n\r\n        final Collection<String> actual = TeamFoundationServerScm.splitCloakedPaths(input);\r\n\r\n        areEqual(actual, \"$/foo/\", \"$/bar/\", \"$/baz/\");\r\n    }\r\n\r\n    private static <T> void areEqual(final Collection<T> actual, T... expected) {\r\n        final Iterator<T> ai = actual.iterator();\r\n        int ei = 0;\r\n        while (ei < expected.length && ai.hasNext()) {\r\n            final T expectedItem = expected[ei];\r\n            final T actualItem = ai.next();\r\n            Assert.assertEquals(expectedItem, actualItem);\r\n            ei++;\r\n        }\r\n        if (ei == expected.length) {\r\n            if (ai.hasNext()) {\r\n                Assert.fail(\"There were more elements than expected\");\r\n            }\r\n        }\r\n        else {\r\n            if (!ai.hasNext()) {\r\n                Assert.fail(\"Some elements were missing from actual.\");\r\n            }\r\n        }\r\n    }\r\n    @Test\r\n    public void assertDefaultValueIsUsedForNullLocalPath() {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"workspace\");\r\n        assertEquals(\"Default value for work folder was incorrect\", \".\", scm.getLocalPath());\r\n    }\r\n\r\n    @Test\r\n    public void assertDefaultValueIsUsedForEmptyLocalPath() {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"workspace\");\r\n        scm.setLocalPath(\"\");\r\n        assertEquals(\"Default value for work folder was incorrect\", \".\", scm.getLocalPath());\r\n    }\r\n\r\n    \r\n    @Test\r\n    public void assertDefaultValueIsUsedForEmptyWorkspaceName() {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"\");\r\n        assertEquals(\"Default value for workspace was incorrect\", \"Hudson-${JOB_NAME}-${NODE_NAME}\", scm.getWorkspaceName());\r\n    }\r\n    \r\n    @Test\r\n    public void assertGetModuleRootReturnsWorkFolder() throws Exception {\r\n        workspace = Util.createTempFilePath();\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"\");\r\n        scm.setLocalPath(\"workfolder\");\r\n        FilePath moduleRoot = scm.getModuleRoot(workspace);\r\n        assertEquals(\"Name for module root was incorrect\", \"workfolder\", moduleRoot.getName());\r\n        assertEquals(\"The parent for module root was incorrect\", workspace.getName(), moduleRoot.getParent().getName());\r\n    }\r\n    \r\n    @Test\r\n    public void assertGetModuleRootWorksForDotWorkFolder() throws Exception {\r\n        workspace = Util.createTempFilePath();\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"\");\r\n        FilePath moduleRoot = scm.getModuleRoot(workspace);\r\n        assertTrue(\"The module root was reported as not existing even if its virtually the same as workspace\",\r\n                moduleRoot.exists());\r\n        assertEquals(\"The module root was not the same as workspace\", moduleRoot.lastModified(), workspace.lastModified());\r\n    }\r\n\r\n    @Test\r\n    public void assertTeamServicesBuildVariablesAreAddedToEnvVars() throws Exception {\r\n        //Add a couple of variables that will be present during a TFS/Team Services build\r\n        Map<String, String> buildVariables = new HashMap<String, String>();\r\n        buildVariables.put(\"System.DefaultWorkingDirectory\", \"C:\\\\build-agent\\\\_work\\\\1\\\\s\");\r\n        buildVariables.put(\"Build.Repository.Git.SubmoduleCheckout\", \"false\");\r\n        //These three are needed to create the action's buildUrl\r\n        buildVariables.put(\"System.TeamFoundationCollectionUri\", \"https://RESOLVED.com\");\r\n        buildVariables.put(\"System.TeamProject\", \"TEAM_PROJECT\");\r\n        buildVariables.put(\"Build.BuildId\", \"42\");\r\n        TeamBuildDetailsAction action = new TeamBuildDetailsAction(buildVariables);\r\n\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        when(build.getAction(TeamBuildDetailsAction.class)).thenReturn(action);\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"WORKSPACE_SAMPLE\");\r\n        AbstractProject project = mock(AbstractProject.class);\r\n        when(build.getProject()).thenReturn(project);\r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(build, env);\r\n\r\n        //Ensure . is replaced with _, keys are UPPERCASE\r\n        assertEquals(\"The key or value for System.DefaultWorkingDirectory was incorrect\", \"C:\\\\build-agent\\\\_work\\\\1\\\\s\", env.get(\"SYSTEM_DEFAULTWORKINGDIRECTORY\"));\r\n        assertEquals(\"The key or value for Build.Repository.Git.SubmoduleCheckout was incorrect\", \"false\", env.get(\"BUILD_REPOSITORY_GIT_SUBMODULECHECKOUT\"));\r\n        assertEquals(\"The key or value for System.TeamFoundationCollectionUri was incorrect\", \"https://RESOLVED.com\", env.get(\"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI\"));\r\n        assertEquals(\"The key or value for System.TeamProject was incorrect\", \"TEAM_PROJECT\", env.get(\"SYSTEM_TEAMPROJECT\"));\r\n        assertEquals(\"The key or value for Build.BuildId was incorrect\", \"42\", env.get(\"BUILD_BUILDID\"));\r\n    }\r\n\r\n    @Test\r\n    public void assertWorkspaceNameIsAddedToEnvVars() throws Exception {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"WORKSPACE_SAMPLE\");\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        AbstractProject project = mock(AbstractProject.class);\r\n        when(build.getProject()).thenReturn(project);\r\n        scm.getWorkspaceName(build, mock(Computer.class));\r\n        \r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(build, env);\r\n        assertEquals(\"The workspace name was incorrect\", \"WORKSPACE_SAMPLE\", env.get(TeamFoundationServerScm.WORKSPACE_ENV_STR));\r\n    }\r\n    \r\n    private TeamFoundationServerScm createForEnvVars() {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverurl\", \"projectpath\", \"WORKSPACE_SAMPLE\", \"user\", null);\r\n        scm.setLocalPath(\"PATH\");\r\n        return scm;\r\n    }\r\n\r\n    @Test\r\n    public void assertWorksfolderPathIsAddedToEnvVars() throws Exception {\r\n        final TeamFoundationServerScm scm = createForEnvVars();\r\n        \r\n        Map<String, String> env = new HashMap<String, String>();\r\n        env.put(\"WORKSPACE\", \"/this/is/a\");\r\n        scm.buildEnvVars(mock(AbstractBuild.class), env );        \r\n        assertEquals(\"The workfolder path was incorrect\", \"/this/is/a\" + File.separator + \"PATH\", env.get(TeamFoundationServerScm.WORKFOLDER_ENV_STR));\r\n    }\r\n    \r\n    @Test\r\n    public void assertProjectPathIsAddedToEnvVars() throws Exception {\r\n        final TeamFoundationServerScm scm = createForEnvVars();\r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(mock(AbstractBuild.class), env );        \r\n        assertEquals(\"The project path was incorrect\", \"projectpath\", env.get(TeamFoundationServerScm.PROJECTPATH_ENV_STR));\r\n    }\r\n    \r\n    @Test\r\n    public void assertServerUrlIsAddedToEnvVars() throws Exception {\r\n        final TeamFoundationServerScm scm = createForEnvVars();\r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(mock(AbstractBuild.class), env );        \r\n        assertEquals(\"The server URL was incorrect\", \"serverurl\", env.get(TeamFoundationServerScm.SERVERURL_ENV_STR));\r\n    }\r\n    \r\n    @Test\r\n    public void assertTfsUserNameIsAddedToEnvVars() throws Exception {\r\n        final TeamFoundationServerScm scm = createForEnvVars();\r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(mock(AbstractBuild.class), env );        \r\n        assertEquals(\"The TFS user name was incorrect\", \"user\", env.get(TeamFoundationServerScm.USERNAME_ENV_STR));\r\n    }\r\n    \r\n    @Test\r\n    public void assertTfsWorkspaceChangesetIsAddedToEnvVars() throws Exception {\r\n        final TeamFoundationServerScm scm = createForEnvVars();\r\n        scm.setWorkspaceChangesetVersion(\"12345\");\r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(mock(AbstractBuild.class), env );        \r\n        assertEquals(\"Workspace changeset version was incorrect\", \"12345\", env.get(TeamFoundationServerScm.WORKSPACE_CHANGESET_ENV_STR));\r\n    }\r\n  \r\n    @Test\r\n    public void assertTfsWorkspaceChangesetIsNotAddedToEnvVarsIfEmpty() throws Exception {\r\n        final TeamFoundationServerScm scm = createForEnvVars();\r\n        scm.setWorkspaceChangesetVersion(\"\");\r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(mock(AbstractBuild.class), env );        \r\n        assertEquals(\"Workspace changeset version was not null\", null, env.get(TeamFoundationServerScm.WORKSPACE_CHANGESET_ENV_STR));\r\n    }\r\n\r\n    @Test\r\n    public void assertTfsWorkspaceChangesetIsNotAddedToEnvVarsIfNull() throws Exception {\r\n        final TeamFoundationServerScm scm = createForEnvVars();\r\n        scm.setWorkspaceChangesetVersion(null);\r\n        Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(mock(AbstractBuild.class), env );        \r\n        assertEquals(\"Workspace changeset version was not null\", null, env.get(TeamFoundationServerScm.WORKSPACE_CHANGESET_ENV_STR));\r\n    }\r\n\r\n    @Test public void recordWorkspaceChangesetVersion() throws Exception {\r\n        final TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverUrl\", \"projectPath\", \"workspace\");\r\n        scm.setLocalPath(\"localPath\");\r\n        final AbstractBuild build = mock(AbstractBuild.class);\r\n        when(build.getTimestamp()).thenReturn(new GregorianCalendar(2015, 03, 28, 22, 04));\r\n        final BuildListener listener = null;\r\n        final Project project = mock(Project.class);\r\n        when(project.getRemoteChangesetVersion(isA(VersionSpec.class))).thenReturn(42);\r\n        final String projectPath = \"projectPath\";\r\n        final String singleVersionSpec = null;\r\n\r\n        final int actual = scm.recordWorkspaceChangesetVersion(build, listener, project, projectPath, singleVersionSpec);\r\n\r\n        Assert.assertEquals(42, actual);\r\n        final Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(build, env);\r\n        assertEquals(\"42\", env.get(TeamFoundationServerScm.WORKSPACE_CHANGESET_ENV_STR));\r\n    }\r\n\r\n    @Test public void recordWorkspaceChangesetVersionWithSingleVersionSpec() throws Exception {\r\n        final TeamFoundationServerScm scm = new TeamFoundationServerScm(\"serverUrl\", \"projectPath\", \"workspace\");\r\n        scm.setLocalPath(\"localPath\");\r\n        final AbstractBuild build = mock(AbstractBuild.class);\r\n        final BuildListener listener = null;\r\n        final Project project = mock(Project.class);\r\n        when(project.getRemoteChangesetVersion(isA(VersionSpec.class))).thenReturn(42);\r\n        final String projectPath = \"projectPath\";\r\n        final String singleVersionSpec = \"Lfoo\";\r\n\r\n        final int actual = scm.recordWorkspaceChangesetVersion(build, listener, project, projectPath, singleVersionSpec);\r\n\r\n        Assert.assertEquals(42, actual);\r\n        final Map<String, String> env = new HashMap<String, String>();\r\n        scm.buildEnvVars(build, env);\r\n        assertEquals(\"42\", env.get(TeamFoundationServerScm.WORKSPACE_CHANGESET_ENV_STR));\r\n    }\r\n\r\n    /**\r\n     * Workspace name must be less than 64 characters, cannot end with a space or period, and cannot contain any of the following characters: \"/:<>|*?\r\n     */\r\n    @Test\r\n    public void assertWorkspaceNameReplacesInvalidChars() {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(null, null, \"A\\\"B/C:D<E>F|G*H?I\");\r\n        assertEquals(\"Workspace name contained invalid chars\", \"A_B_C_D_E_F_G_H_I\", scm.getWorkspaceName(null, null));\r\n    }\r\n    \r\n    /**\r\n     * Workspace name must be less than 64 characters, cannot end with a space or period, and cannot contain any of the following characters: \"/:<>|*?\r\n     */\r\n    @Test\r\n    public void assertWorkspaceNameReplacesEndingPeriod() {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(null, null, \"Workspace.Name.\");\r\n        assertEquals(\"Workspace name ends with period\", \"Workspace.Name_\", scm.getWorkspaceName(null, null));\r\n    }\r\n    \r\n    /**\r\n     * Workspace name must be less than 64 characters, cannot end with a space or period, and cannot contain any of the following characters: \"/:<>|*?\r\n     */\r\n    @Test\r\n    public void assertWorkspaceNameReplacesEndingSpace() {\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(null, null, \"Workspace Name \");\r\n        assertEquals(\"Workspace name ends with space\", \"Workspace Name_\", scm.getWorkspaceName(null, null));\r\n    }    \r\n    \r\n    @Test public void assertServerUrlResolvesBuildVariables() {\r\n        ParametersAction action = mock(ParametersAction.class);\r\n        when(action.substitute(isA(AbstractBuild.class), isA(String.class))).thenReturn(\"https://RESOLVED.com\");\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        when(build.getAction(ParametersAction.class)).thenReturn(action);\r\n\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"https://${PARAM}.com\", null, \"\");\r\n        assertEquals(\"The server url wasnt resolved\", \"https://RESOLVED.com\", scm.getServerUrl(build));\r\n    }    \r\n    \r\n    @Test public void assertProjectPathResolvesBuildVariables() {\r\n        ParametersAction action = mock(ParametersAction.class);\r\n        when(action.substitute(isA(AbstractBuild.class), isA(String.class))).thenReturn(\"$/RESOLVED/path\");\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        when(build.getAction(ParametersAction.class)).thenReturn(action);\r\n\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(null, \"$/$PARAM/path\", \"\");\r\n        assertEquals(\"The project path wasnt resolved\", \"$/RESOLVED/path\", scm.getProjectPath(build));\r\n    }    \r\n    \r\n    @Test public void assertWorkspaceNameResolvesBuildVariables() {\r\n        ParametersAction action = mock(ParametersAction.class);\r\n        when(action.substitute(isA(AbstractBuild.class), isA(String.class))).thenReturn(\"WS-RESOLVED\");\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        when(build.getAction(ParametersAction.class)).thenReturn(action);\r\n\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(null, null, \"WS-${PARAM}\");\r\n        assertEquals(\"The workspace name wasnt resolved\", \"WS-RESOLVED\", scm.getWorkspaceName(build, mock(Computer.class)));\r\n    }\r\n    \r\n    @Test public void assertTfsWorkspaceIsntRemovedIfThereIsNoBuildWhenProcessWorkspaceBeforeDeletion() throws Exception {\r\n        AbstractProject project = mock(AbstractProject.class);\r\n        Node node = mock(Node.class);\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"server\", \"projectpath\", \"workspace\");\r\n        assertThat(scm.processWorkspaceBeforeDeletion(project, workspace, node), is(true));\r\n        verify(project).getLastBuild();\r\n        verifyNoMoreInteractions(project);\r\n    }\r\n\r\n    @Test public void assertWorkspaceIsntRemoveIfThereIsNoBuildOnSpecifiedNodeAndHudsonWantsToRemoveWorkspaceOnNode() throws Exception {\r\n        AbstractProject project = mock(AbstractProject.class);\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        Node node = mock(Node.class);\r\n        Node inNode = mock(Node.class);\r\n        when(project.getLastBuild()).thenReturn(build);\r\n        when(build.getPreviousBuild()).thenReturn(build).thenReturn(null);\r\n        when(build.getBuiltOn()).thenReturn(node).thenReturn(node);\r\n        when(node.getNodeName()).thenReturn(\"node1\").thenReturn(\"node2\");\r\n        when(inNode.getNodeName()).thenReturn(\"needleNode\").thenReturn(\"needleNode\");\r\n        TeamFoundationServerScm scm = new TeamFoundationServerScm(\"server\", \"projectpath\", \"workspace\");\r\n        assertThat( scm.processWorkspaceBeforeDeletion(project, workspace, inNode), is(true));\r\n        verify(project).getLastBuild();\r\n        verify(node, times(2)).getNodeName();\r\n        verify(build, times(2)).getBuiltOn();\r\n        verify(build, times(2)).getPreviousBuild();\r\n\r\n        verifyNoMoreInteractions(project);\r\n        verifyNoMoreInteractions(node);\r\n        verifyNoMoreInteractions(build);        \r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/Util.java",
    "content": "package hudson.plugins.tfs;\r\n\r\nimport hudson.FilePath;\r\n\r\nimport java.io.File;\r\nimport java.util.Calendar;\r\nimport java.util.TimeZone;\r\n\r\npublic class Util {\r\n\r\n    private Util() {\r\n    }\r\n\r\n    public static Calendar getCalendar(int year, int month, int day) {\r\n        return getCalendar(year, month, day, 0, 0, 0, \"GMT\");\r\n    }\r\n    \r\n    public static Calendar getCalendar(int year, int month, int day, int hour, int min, int sec) {\r\n        return getCalendar(year, month, day, hour, min, sec, \"GMT\");\r\n    }\r\n\r\n    public static Calendar getCalendar(int year, int month, int day, int hour, int min, int sec, String timezone) {\r\n        return getCalendar(year, month, day, hour, min, sec, TimeZone.getTimeZone(timezone));\r\n    }\r\n\r\n    public static Calendar getCalendar(int year, int month, int day, int hour, int min, int sec, TimeZone timezone) {\r\n        Calendar calendar = Calendar.getInstance();\r\n        calendar.clear();\r\n        calendar.set(Calendar.YEAR, year);\r\n        calendar.set(Calendar.MONTH, month - 1);\r\n        calendar.set(Calendar.DATE, day);\r\n        calendar.set(Calendar.HOUR_OF_DAY, hour);\r\n        calendar.set(Calendar.MINUTE, min);\r\n        calendar.set(Calendar.SECOND, sec);\r\n        calendar.setTimeZone(timezone);\r\n        return calendar;\r\n    }\r\n    \r\n    public static FilePath createTempFilePath() throws Exception {\r\n        File parentFile = hudson.Util.createTempDir();\r\n        FilePath workspace = new FilePath(parentFile);\r\n        parentFile.delete();\r\n        workspace.mkdirs();\r\n        return workspace;\r\n    }\r\n\r\n    /**\r\n     * Create a boxed copy of the boolean array since JUnit assertArrayEquals() does not take boolean[]\r\n     * @param array copy from\r\n     * @return a boxed copy of the array\r\n     */\r\n    public static Boolean[] toBoxedArray(boolean[] array) {\r\n        Boolean[] copy = new Boolean[array.length];\r\n        for (int i = 0; i < array.length; i++) {\r\n            copy[i] = array[i];\r\n        }\r\n        return copy;\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/actions/CheckoutActionTest.java",
    "content": "package hudson.plugins.tfs.actions;\r\n\r\nimport static org.junit.Assert.*;\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport java.io.FileFilter;\r\nimport java.util.ArrayList;\r\nimport java.util.Calendar;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\r\nimport hudson.FilePath;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.Util;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.plugins.tfs.model.Project;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.Workspace;\r\nimport hudson.plugins.tfs.model.Workspaces;\r\n\r\nimport hudson.remoting.VirtualChannel;\r\nimport org.hamcrest.CustomMatcher;\r\nimport org.junit.After;\r\nimport org.junit.Assert;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\nimport org.jvnet.hudson.test.Bug;\r\nimport org.mockito.Mock;\r\nimport org.mockito.MockitoAnnotations;\r\n\r\npublic class CheckoutActionTest {\r\n\r\n    private static final List<String> EMPTY_CLOAKED_PATHS_LIST = Collections.emptyList();\r\n    private static final String MY_LABEL = \"MyLabel\";\r\n    private FilePath hudsonWs;\r\n    private @Mock Server server;\r\n    private @Mock Workspaces workspaces;\r\n    private @Mock Workspace workspace;\r\n    private @Mock Project project;\r\n    private @Mock TaskListener taskListener;\r\n\r\n    @Before public void setup() throws Exception {\r\n        MockitoAnnotations.initMocks(this);\r\n        hudsonWs = Util.createTempFilePath();\r\n    }\r\n\r\n    @After public void teardown() throws Exception {\r\n        if (hudsonWs != null) {\r\n            hudsonWs.deleteRecursive();\r\n        }\r\n    }\r\n\r\n    private void prepareCommonMocks() {\r\n        when(server.getWorkspaces()).thenReturn(workspaces);\r\n        when(server.getProject(\"project\")).thenReturn(project);\r\n\r\n        when(server.getListener()).thenReturn(taskListener);\r\n        when(taskListener.getLogger()).thenReturn(System.out);\r\n        when(workspaces.getWorkspaceMapping(anyString())).thenReturn(\"workspace\");\r\n    }\r\n    \r\n    @Test\r\n    public void assertFirstCheckoutBySingleVersionSpecNotUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n    \twhen(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n    \twhen(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n    \t\r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n    \tverify(project).getFiles(isA(String.class), eq(MY_LABEL), eq(false));\r\n    \tverify(workspaces).deleteWorkspace(workspace);    \t\r\n    }\r\n    \r\n    @Test\r\n    public void assertFirstCheckoutNotUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n        \r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(project).getFiles(isA(String.class), eq(\"D2009-09-24T00:00:00Z\"), eq(false));\r\n        verify(workspaces).deleteWorkspace(workspace);\r\n    }\r\n\r\n    @Test\r\n    public void assertFirstCheckoutBySingleVersionSpecUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n        when(workspaces.exists(new Workspace(\"workspace\"))).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n        \r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(project).getFiles(isA(String.class), eq(MY_LABEL), eq(false));\r\n        verify(workspaces, never()).deleteWorkspace(isA(Workspace.class));\r\n    }\r\n\r\n    @Test\r\n    public void assertFirstCheckoutUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n    \twhen(workspaces.exists(new Workspace(\"workspace\"))).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n    \t\r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n    \t\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n    \tverify(project).getFiles(isA(String.class), eq(\"D2009-09-24T00:00:00Z\"), eq(false));\r\n    \tverify(workspaces, never()).deleteWorkspace(isA(Workspace.class));\r\n    }\r\n    \r\n    @Test\r\n    public void assertSecondCheckoutBySingleVersionSpecUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n\r\n        verify(project).getFiles(isA(String.class), eq(MY_LABEL), eq(false));\r\n        verify(workspaces, never()).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(workspaces, never()).deleteWorkspace(isA(Workspace.class));\r\n    }\r\n    \r\n    @Test\r\n    public void assertSecondCheckoutUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n\r\n        verify(project).getFiles(isA(String.class), eq(\"D2009-09-24T00:00:00Z\"), eq(false));\r\n        verify(workspaces, never()).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(workspaces, never()).deleteWorkspace(isA(Workspace.class));\r\n    }\r\n\r\n    @Test\r\n    public void assertSecondCheckoutBySingleVersionSpecNotUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(project).getFiles(isA(String.class), eq(MY_LABEL), eq(false));\r\n        verify(workspaces).deleteWorkspace(workspace);\r\n    }\r\n\r\n    @Test\r\n    public void assertSecondCheckoutNotUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(project).getFiles(isA(String.class), eq(\"D2009-09-24T00:00:00Z\"), eq(false));\r\n        verify(workspaces).deleteWorkspace(workspace);\r\n    }\r\n   \r\n    @Test\r\n    public void assertDetailedHistoryIsNotRetrievedInFirstBuildCheckingOutByLabel() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n        \r\n        verify(project, never()).getDetailedHistory(isA(Calendar.class), isA(Calendar.class));\r\n    }\r\n   \r\n    @Test\r\n    public void assertDetailedHistoryIsNotRetrievedInFirstBuild() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n        \r\n        verify(project, never()).getDetailedHistory(isA(Calendar.class), isA(Calendar.class));\r\n    }\r\n    \r\n    @Test\r\n    public void assertDetailedHistoryIsRetrievedInSecondBuildCheckingOutByLabel() throws Exception {\r\n        List<ChangeSet> list = new ArrayList<ChangeSet>();\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        when(project.getDetailedHistory(isA(String.class))).thenReturn(list);\r\n        \r\n        CheckoutAction action = new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false);\r\n        List<ChangeSet> actualList = action.checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n        assertSame(\"The list from the detailed history, was not the same as returned from checkout\", list, actualList);\r\n        \r\n        verify(project).getDetailedHistory(isA(String.class));\r\n    }\r\n    \r\n    @Test\r\n    public void assertDetailedHistoryIsRetrievedInSecondBuild() throws Exception {\r\n        List<ChangeSet> list = new ArrayList<ChangeSet>();\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        when(project.getDetailedHistoryWithoutCloakedPaths(isA(VersionSpec.class), isA(VersionSpec.class), anyCollection())).thenReturn(list);\r\n\r\n        CheckoutAction action = new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false);\r\n        final Calendar startDate = Util.getCalendar(2008, 9, 24);\r\n        final Calendar endDate = Util.getCalendar(2008, 10, 24);\r\n        List<ChangeSet> actualList = action.checkout(server, hudsonWs, startDate, endDate);\r\n        assertEquals(\"The list from the detailed history, was not the same as returned from checkout\", list, actualList);\r\n        \r\n        final DateVersionSpec startDateVersionSpec = new DateVersionSpec(startDate);\r\n        verify(project).getDetailedHistoryWithoutCloakedPaths(argThat(new DateVersionSpecMatcher(startDateVersionSpec)), isA(VersionSpec.class), eq(EMPTY_CLOAKED_PATHS_LIST));\r\n    }\r\n    \r\n    @Test\r\n    public void assertWorkFolderIsCleanedIfNotUsingUpdate() throws Exception {\r\n        hudsonWs.createTempFile(\"temp\", \"txt\");\r\n        FilePath tfsWs = hudsonWs.child(\"tfs-ws\");\r\n        tfsWs.mkdirs();\r\n        tfsWs.createTempFile(\"temp\", \"txt\");\r\n        \r\n        prepareCommonMocks();\r\n        when(workspaces.exists(new Workspace(\"workspace\"))).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \"tfs-ws\", false, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n        \r\n        assertTrue(\"The local folder was removed\", tfsWs.exists());\r\n        assertEquals(\"The local TFS folder was not cleaned\", 0, tfsWs.list((FileFilter)null).size());\r\n        assertEquals(\"The Hudson workspace path was cleaned\", 2, hudsonWs.list((FileFilter)null).size());\r\n    }\r\n    \r\n    @Test\r\n    public void assertWorkFolderIsCleanedIfNotUsingUpdateCheckingOutByLabel() throws Exception {\r\n        hudsonWs.createTempFile(\"temp\", \"txt\");\r\n        FilePath tfsWs = hudsonWs.child(\"tfs-ws\");\r\n        tfsWs.mkdirs();\r\n        tfsWs.createTempFile(\"temp\", \"txt\");\r\n        \r\n        prepareCommonMocks();\r\n        when(workspaces.exists(new Workspace(\"workspace\"))).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \"tfs-ws\", false, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n        \r\n        assertTrue(\"The local folder was removed\", tfsWs.exists());\r\n        assertEquals(\"The local TFS folder was not cleaned\", 0, tfsWs.list((FileFilter)null).size());\r\n        assertEquals(\"The Hudson workspace path was cleaned\", 2, hudsonWs.list((FileFilter)null).size());\r\n    }\r\n\r\n    @Test\r\n    public void assertWorkspaceIsNotCleanedIfUsingUpdate() throws Exception {\r\n        FilePath tfsWs = hudsonWs.child(\"tfs-ws\");\r\n        tfsWs.mkdirs();\r\n        tfsWs.createTempFile(\"temp\", \"txt\");\r\n        \r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \"tfs-ws\", true, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n\r\n        assertTrue(\"The local folder was removed\", tfsWs.exists());\r\n        assertEquals(\"The TFS workspace path was cleaned\", 1, hudsonWs.list((FileFilter)null).size());\r\n    }\r\n    \r\n    @Bug(3882)\r\n    @Test\r\n    public void assertCheckoutBySingleVersionSpecDeletesWorkspaceAtStartIfNotUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(false);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n        \r\n        verify(server).getWorkspaces();\r\n        verify(workspaces, times(2)).exists(\"workspace\");\r\n        verify(workspaces).getWorkspace(\"workspace\");\r\n        verify(workspaces).deleteWorkspace(workspace);\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(workspaces).getWorkspaceMapping(anyString());\r\n        verifyNoMoreInteractions(workspaces);\r\n    }\r\n    \r\n    @Bug(3882)\r\n    @Test\r\n    public void assertCheckoutDeletesWorkspaceAtStartIfNotUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(false);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n        \r\n        verify(server).getWorkspaces();\r\n        verify(workspaces, times(2)).exists(\"workspace\");\r\n        verify(workspaces).getWorkspace(\"workspace\");\r\n        verify(workspaces).deleteWorkspace(workspace);\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(workspaces).getWorkspaceMapping(anyString());\r\n        verifyNoMoreInteractions(workspaces);\r\n    }\r\n    \r\n    @Bug(3882)\r\n    @Test\r\n    public void assertCheckoutDoesNotDeleteWorkspaceAtStartIfUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n        \r\n        verify(server).getWorkspaces();\r\n        verify(workspaces, times(2)).exists(\"workspace\");\r\n        verify(workspaces).getWorkspace(\"workspace\");\r\n        verify(workspaces).getWorkspaceMapping(anyString());\r\n        verifyNoMoreInteractions(workspaces);\r\n    }\r\n    \r\n    @Bug(3882)\r\n    @Test\r\n    public void assertCheckoutBySingleVersionSpecDoesNotDeleteWorkspaceAtStartIfUsingUpdate() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        \r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n        \r\n        verify(server).getWorkspaces();\r\n        verify(workspaces, times(2)).exists(\"workspace\");\r\n        verify(workspaces).getWorkspace(\"workspace\");\r\n        verify(workspaces).getWorkspaceMapping(anyString());\r\n        verifyNoMoreInteractions(workspaces);\r\n    }\r\n    \r\n    @Bug(3882)\r\n    @Test\r\n    public void assertCheckoutDoesNotDeleteWorkspaceIfNotUsingUpdateAndThereIsNoWorkspace() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(false).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n\r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkout(server, hudsonWs, null, Util.getCalendar(2009, 9, 24));\r\n        \r\n        verify(server).getWorkspaces();\r\n        verify(workspaces, times(2)).exists(\"workspace\");\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(workspaces).getWorkspaceMapping(anyString());\r\n        verifyNoMoreInteractions(workspaces);\r\n    }\r\n    \r\n    @Bug(3882)\r\n    @Test\r\n    public void assertCheckoutBySingleVersionSpecDoesNotDeleteWorkspaceIfNotUsingUpdateAndThereIsNoWorkspace() throws Exception {\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(false).thenReturn(false);\r\n        when(workspaces.newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class))).thenReturn(workspace);\r\n        when(project.getProjectPath()).thenReturn(\"project\");\r\n\r\n        new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", false, false).checkoutBySingleVersionSpec(server, hudsonWs, MY_LABEL);\r\n        \r\n        verify(server).getWorkspaces();\r\n        verify(workspaces, times(2)).exists(\"workspace\");\r\n        verify(workspaces).newWorkspace(eq(\"workspace\"), eq(\"project\"), eq(EMPTY_CLOAKED_PATHS_LIST), isA(String.class));\r\n        verify(workspaces).getWorkspaceMapping(anyString());\r\n        verifyNoMoreInteractions(workspaces);\r\n    }\r\n    \r\n    @Bug(6596)\r\n    @Test\r\n    public void assertCheckoutOnlyRetrievesChangesToTheStartTimestampForCurrentBuild() throws Exception {\r\n        List<ChangeSet> list = new ArrayList<ChangeSet>();\r\n        prepareCommonMocks();\r\n        when(workspaces.exists(\"workspace\")).thenReturn(true);\r\n        when(workspaces.getWorkspace(\"workspace\")).thenReturn(workspace);\r\n        when(workspace.getComputer()).thenReturn(\"LocalComputer\");\r\n        when(project.getDetailedHistoryWithoutCloakedPaths(isA(VersionSpec.class), isA(VersionSpec.class), anyCollection())).thenReturn(list);\r\n        \r\n        CheckoutAction action = new CheckoutAction(\"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \".\", true, false);\r\n        final Calendar startDate = Util.getCalendar(2008, 9, 24);\r\n        final Calendar endDate = Util.getCalendar(2009, 9, 24);\r\n        List<ChangeSet> actualList = action.checkout(server, hudsonWs, startDate, endDate);\r\n        assertEquals(\"The list from the detailed history, was not the same as returned from checkout\", list, actualList);\r\n\r\n        final DateVersionSpec startDateVersionSpec = new DateVersionSpec(startDate);\r\n        final DateVersionSpec endDateVersionSpec = new DateVersionSpec(endDate);\r\n        verify(project).getDetailedHistoryWithoutCloakedPaths(\r\n                argThat(new DateVersionSpecMatcher(startDateVersionSpec)),\r\n                argThat(new DateVersionSpecMatcher(endDateVersionSpec)),\r\n                eq(EMPTY_CLOAKED_PATHS_LIST));\r\n        verify(project).getFiles(isA(String.class), eq(\"D2009-09-24T00:00:00Z\"), eq(false));\r\n    }\r\n\r\n    private static class DateVersionSpecMatcher extends CustomMatcher<DateVersionSpec> {\r\n\r\n        private final DateVersionSpec base;\r\n\r\n        public DateVersionSpecMatcher(final DateVersionSpec base) {\r\n            super(base == null ? \"(null)\" : base.toString());\r\n            this.base = base;\r\n        }\r\n\r\n        public boolean matches(final Object item) {\r\n            if (base == null) {\r\n                return item == null;\r\n            }\r\n            if (item != null && item instanceof DateVersionSpec) {\r\n                final DateVersionSpec candidate = (DateVersionSpec) item;\r\n                final Calendar baseDate = base.getDate();\r\n                final Calendar candidateDate = candidate.getDate();\r\n                return baseDate.equals(candidateDate);\r\n            }\r\n            return false;\r\n        }\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_absoluteOverrideOnNix() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String nixPath = \"/opt/.jenkins/jobs/tfs-plugin/workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, nixPath);\r\n        final String localFolder = \"/home/jenkins/tfs-plugin\";\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, localFolder);\r\n\r\n        Assert.assertEquals(localFolder, actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_absoluteOverrideOnWindows() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String windowsPath = \"C:\\\\.jenkins\\\\jobs\\\\tfs-plugin\\\\workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, windowsPath);\r\n        final String localFolder = \"C:\\\\Users\\\\Jenkins\\\\tfs-plugin\";\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, localFolder);\r\n\r\n        Assert.assertEquals(localFolder, actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_absoluteOverrideOnWindowsWithForwardSlashes() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String windowsPath = \"C:/.jenkins/jobs/tfs-plugin/workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, windowsPath);\r\n        final String localFolder = \"C:/Users/Jenkins/tfs-plugin\";\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, localFolder);\r\n\r\n        Assert.assertEquals(localFolder, actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_defaultOnNix() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String nixPath = \"/opt/.jenkins/jobs/tfs-plugin/workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, nixPath);\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, \".\");\r\n\r\n        Assert.assertEquals(nixPath, actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_defaultOnWindows() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String windowsPath = \"C:\\\\.jenkins\\\\jobs\\\\tfs-plugin\\\\workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, windowsPath);\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, \".\");\r\n\r\n        Assert.assertEquals(windowsPath, actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_defaultOnWindowsWithForwardSlashes() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String windowsPath = \"C:/.jenkins/jobs/tfs-plugin/workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, windowsPath);\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, \".\");\r\n\r\n        Assert.assertEquals(windowsPath, actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_relativeOnNix() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String nixPath = \"/opt/.jenkins/jobs/tfs-plugin/workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, nixPath);\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, \"../files\");\r\n\r\n        Assert.assertEquals(\"/opt/.jenkins/jobs/tfs-plugin/files\", actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_relativeOnWindows() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String windowsPath = \"C:\\\\.jenkins\\\\jobs\\\\tfs-plugin\\\\workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, windowsPath);\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, \"..\\\\files\");\r\n\r\n        Assert.assertEquals(\"C:\\\\.jenkins\\\\jobs\\\\tfs-plugin\\\\files\", actual);\r\n    }\r\n\r\n    @Test\r\n    public void determineCheckoutPath_relativeOnWindowsWithForwardSlashes() {\r\n        final VirtualChannel vc = mock(VirtualChannel.class);\r\n        final String windowsPath = \"C:/.jenkins/jobs/tfs-plugin/workspace\";\r\n        final FilePath workspacePath = new FilePath(vc, windowsPath);\r\n\r\n        final String actual = CheckoutAction.determineCheckoutPath(workspacePath, \"../files\");\r\n\r\n        Assert.assertEquals(\"C:/.jenkins/jobs/tfs-plugin/files\", actual);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/actions/RemoveWorkspaceActionTest.java",
    "content": "package hudson.plugins.tfs.actions;\r\n\r\nimport static org.hamcrest.CoreMatchers.*;\r\nimport static org.mockito.Matchers.*;\r\nimport static org.mockito.Mockito.*;\r\nimport static org.junit.Assert.*;\r\n\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.Workspace;\r\nimport hudson.plugins.tfs.model.Workspaces;\r\n\r\nimport org.junit.*;\r\nimport org.mockito.Mock;\r\nimport org.mockito.MockitoAnnotations;\r\n\r\npublic class RemoveWorkspaceActionTest {\r\n    @Mock private Server server;        \r\n    @Mock private Workspaces workspaces;\r\n    @Mock private Workspace workspace;\r\n\r\n    @Before public void setUp() throws Exception {\r\n        MockitoAnnotations.initMocks(this);\r\n    }\r\n\r\n    @Test\r\n    public void assertNoSuchWorkspaceNameDoesNothing() throws Exception {\r\n        when(server.getWorkspaces()).thenReturn(workspaces);\r\n        when(workspaces.exists(anyString())).thenReturn(false);\r\n        \r\n        RemoveWorkspaceAction action = new RemoveWorkspaceAction(\"workspace\");\r\n        assertThat(action.remove(server), is(false));\r\n\r\n        verify(server).getWorkspaces();\r\n        verify(workspaces).exists(\"workspace\");\r\n        verifyNoMoreInteractions(workspace);\r\n        verifyNoMoreInteractions(workspaces);\r\n        verifyNoMoreInteractions(server);\r\n    }\r\n\r\n    @Test\r\n    public void assertWorkspaceIsDeleted() throws Exception  {\r\n        when(server.getWorkspaces()).thenReturn(workspaces);\r\n        when(workspaces.exists(anyString())).thenReturn(true);\r\n        when(workspaces.getWorkspace(anyString())).thenReturn(workspace);\r\n        \r\n        RemoveWorkspaceAction action = new RemoveWorkspaceAction(\"workspace\");\r\n        assertThat(action.remove(server), is(true));\r\n\r\n        verify(server).getWorkspaces();\r\n        verify(workspaces).exists(\"workspace\");\r\n        verify(workspaces).getWorkspace(\"workspace\");\r\n        verify(workspaces).deleteWorkspace(workspace);\r\n        verifyNoMoreInteractions(workspace);\r\n        verifyNoMoreInteractions(workspaces);\r\n        verifyNoMoreInteractions(server);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/browsers/TeamSystemWebAccessBrowserTest.java",
    "content": "package hudson.plugins.tfs.browsers;\r\n\r\nimport static org.junit.Assert.*;\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.plugins.tfs.TeamFoundationServerScm;\r\nimport hudson.plugins.tfs.model.ChangeLogSet;\r\nimport hudson.plugins.tfs.model.ChangeSet;\r\nimport hudson.plugins.tfs.model.ChangeSet.Item;\r\n\r\nimport java.net.URL;\r\n\r\nimport hudson.util.Secret;\r\nimport org.junit.Test;\r\nimport org.jvnet.hudson.test.Bug;\r\n\r\n@SuppressWarnings(\"rawtypes\")\r\npublic class TeamSystemWebAccessBrowserTest {\r\n\r\n    @Test public void assertChangeSetLinkWithServerUrlWithPort() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs:8080/\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        URL actual = browser.getChangeSetLink(changeSet);\r\n        assertEquals(\"The change set link was incorrect\", \"http://tfs:8080/_versionControl/changeset/99\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertChangeSetLinkWithRealisticServerUrlWithPort() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs:8080/tfs/coll\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        URL actual = browser.getChangeSetLink(changeSet);\r\n        assertEquals(\"The change set link was incorrect\", \"http://tfs:8080/tfs/coll/_versionControl/changeset/99\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertChangeSetLinkWithRealisticServerUrl() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs/tfs/coll\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        URL actual = browser.getChangeSetLink(changeSet);\r\n        assertEquals(\"The change set link was incorrect\", \"http://tfs/tfs/coll/_versionControl/changeset/99\", actual.toString());\r\n    }\r\n\r\n\t@Bug(7394)\r\n\t@Test\r\n\tpublic void assertChangeSetLinkWithOnlyServerUrl() throws Exception {\r\n\t\tTeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs\");\r\n\t\tChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n\t\tURL actual = browser.getChangeSetLink(changeSet);\r\n\t\tassertEquals(\"The change set link was incorrect\", \"http://tfs/_versionControl/changeset/99\", actual.toString());\r\n\t}\r\n\r\n\t@Bug(7394)\r\n\t@Test\r\n\tpublic void assertChangeSetLinkWithOnlyServerUrlWithTrailingSlash() throws Exception {\r\n\t\tTeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs/\");\r\n\t\tChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n\t\tURL actual = browser.getChangeSetLink(changeSet);\r\n\t\tassertEquals(\"The change set link was incorrect\",\"http://tfs/_versionControl/changeset/99\", actual.toString());\r\n\t}\r\n    \r\n    private static TeamFoundationServerScm createTestScm(String serverUrl) {\r\n        serverUrl = serverUrl != null ? serverUrl : \"http://server:80/tfs/collection/\";\r\n        final String projectPath = \"$/project/folder/folder/branch\";\r\n        final Secret password = null;\r\n        final String userName = null;\r\n        final TeamFoundationServerScm result = new TeamFoundationServerScm(serverUrl, projectPath, null, userName, password);\r\n\r\n        final TeamFoundationServerRepositoryBrowser repositoryBrowser = mock(TeamFoundationServerRepositoryBrowser.class);\r\n        result.setRepositoryBrowser(repositoryBrowser);\r\n\r\n        return result;\r\n    }\r\n\r\n    @Test public void assertChangeSetLinkUsesScmConfiguration() throws Exception {\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        AbstractProject<?,?> project = mock(AbstractProject.class);\r\n        when(build.getProject()).thenReturn(project);\r\n        final TeamFoundationServerScm testScm = createTestScm(null);\r\n        when(project.getScm()).thenReturn(testScm);\r\n        \r\n        ChangeSet changeset = new ChangeSet(\"62643\", null, \"user\", \"comment\");\r\n        new ChangeLogSet(build, new ChangeSet[]{ changeset});        \r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"\"); // configured but no URL specified\r\n\r\n        URL actual = browser.getChangeSetLink(changeset);\r\n        assertEquals(\"The change set link was incorrect\", \"http://server:80/tfs/collection/_versionControl/changeset/62643\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertChangeSetLinkUsesScmConfigurationNoSlash() throws Exception {\r\n      AbstractBuild build = mock(AbstractBuild.class);\r\n      AbstractProject<?,?> project = mock(AbstractProject.class);\r\n      when(build.getProject()).thenReturn(project);\r\n      // the server URL has not trailing slash...\r\n      final TeamFoundationServerScm testScm = createTestScm(\"http://server:80/tfs/collection\");\r\n      when(project.getScm()).thenReturn(testScm);\r\n\r\n      ChangeSet changeset = new ChangeSet(\"62643\", null, \"user\", \"comment\");\r\n      new ChangeLogSet(build, new ChangeSet[]{ changeset});\r\n      TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"\"); // configured but no URL specified\r\n\r\n      URL actual = browser.getChangeSetLink(changeset);\r\n      assertEquals(\"The change set link was incorrect\", \"http://server:80/tfs/collection/_versionControl/changeset/62643\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertFileLinkUsesScmConfiguration() throws Exception {\r\n      AbstractBuild build = mock(AbstractBuild.class);\r\n      AbstractProject<?,?> project = mock(AbstractProject.class);\r\n      when(build.getProject()).thenReturn(project);\r\n      final TeamFoundationServerScm testScm = createTestScm(null);\r\n      when(project.getScm()).thenReturn(testScm);\r\n\r\n      ChangeSet changeset = new ChangeSet(\"62643\", null, \"user\", \"comment\");\r\n      ChangeSet.Item item = new Item(\"$/project/folder/folder/branch/some/path/to/some/file.txt\", \"action\");\r\n      changeset.add(item);\r\n      new ChangeLogSet(build, new ChangeSet[]{ changeset});\r\n      TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"\"); // configured but no URL specified\r\n\r\n      URL actual = browser.getFileLink(item);\r\n      assertEquals(\"The file link was incorrect\", \"http://server:80/tfs/collection/_versionControl/changeset/62643#path=%24%2Fproject%2Ffolder%2Ffolder%2Fbranch%2Fsome%2Fpath%2Fto%2Fsome%2Ffile.txt&version=62643&_a=contents\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertDiffLinkUsesScmConfiguration() throws Exception {\r\n      AbstractBuild build = mock(AbstractBuild.class);\r\n      AbstractProject<?,?> project = mock(AbstractProject.class);\r\n      when(build.getProject()).thenReturn(project);\r\n      final TeamFoundationServerScm testScm = createTestScm(null);\r\n      when(project.getScm()).thenReturn(testScm);\r\n\r\n      ChangeSet changeset = new ChangeSet(\"62643\", null, \"user\", \"comment\");\r\n      new ChangeLogSet(build, new ChangeSet[]{ changeset});\r\n      ChangeSet.Item item = new Item(\"$/project/folder/folder/branch/some/path/to/some/file.txt\", \"action\");\r\n      changeset.add(item);\r\n\r\n      TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"\"); // configured but no URL specified\r\n      URL actual = browser.getDiffLink(item);\r\n      assertEquals(\"The diff link was incorrect\", \"http://server:80/tfs/collection/_versionControl/changeset/62643#path=%24%2Fproject%2Ffolder%2Ffolder%2Fbranch%2Fsome%2Fpath%2Fto%2Fsome%2Ffile.txt&version=62643&_a=compare\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertFileLink() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs:8080/\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        ChangeSet.Item item = new ChangeSet.Item(\"$/Project/Folder/file.cs\", \"add\");\r\n        changeSet.add(item);\r\n        URL actual = browser.getFileLink(item);\r\n        assertEquals(\"The file link was incorrect\", \"http://tfs:8080/_versionControl/changeset/99#path=%24%2FProject%2FFolder%2Ffile.cs&version=99&_a=contents\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertFileLinkWithRealisticServerUrl() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs:8080/tfs/coll\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        ChangeSet.Item item = new ChangeSet.Item(\"$/Project/Folder/file.cs\", \"add\");\r\n        changeSet.add(item);\r\n        URL actual = browser.getFileLink(item);\r\n        assertEquals(\"The file link was incorrect\", \"http://tfs:8080/tfs/coll/_versionControl/changeset/99#path=%24%2FProject%2FFolder%2Ffile.cs&version=99&_a=contents\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertDiffLink() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs:8080/\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        ChangeSet.Item item = new ChangeSet.Item(\"$/Project/Folder/file.cs\", \"edit\");\r\n        changeSet.add(item);\r\n        URL actual = browser.getDiffLink(item);\r\n        assertEquals(\"The diff link was incorrect\", \"http://tfs:8080/_versionControl/changeset/99#path=%24%2FProject%2FFolder%2Ffile.cs&version=99&_a=compare\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertDiffLinkWithRealisticServerUrl() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs:8080/tfs/coll\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        ChangeSet.Item item = new ChangeSet.Item(\"$/Project/Folder/file.cs\", \"edit\");\r\n        changeSet.add(item);\r\n        URL actual = browser.getDiffLink(item);\r\n        assertEquals(\"The diff link was incorrect\", \"http://tfs:8080/tfs/coll/_versionControl/changeset/99#path=%24%2FProject%2FFolder%2Ffile.cs&version=99&_a=compare\", actual.toString());\r\n    }\r\n\r\n    @Test public void assertNullDiffLinkForAddedFile() throws Exception {\r\n        TeamSystemWebAccessBrowser browser = new TeamSystemWebAccessBrowser(\"http://tfs:8080/\");\r\n        ChangeSet changeSet = new ChangeSet(\"99\", null, \"user\", \"comment\");\r\n        ChangeSet.Item item = new ChangeSet.Item(\"$/Project/Folder/file.cs\", \"add\");\r\n        changeSet.add(item);\r\n        assertNull(\"The diff link should be null for new files\", browser.getDiffLink(item));\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/AbstractCallableCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.ChangesetVersionSpec;\r\nimport hudson.model.TaskListener;\r\nimport hudson.plugins.tfs.model.ExtraSettings;\r\nimport hudson.plugins.tfs.model.MockableVersionControlClient;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.WebProxySettings;\r\nimport hudson.remoting.Callable;\r\nimport hudson.util.Secret;\r\nimport hudson.util.SecretOverride;\r\nimport org.apache.commons.collections.IteratorUtils;\r\nimport org.junit.Assert;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.ByteArrayInputStream;\r\nimport java.io.ByteArrayOutputStream;\r\nimport java.io.IOException;\r\nimport java.io.InputStreamReader;\r\nimport java.io.ObjectOutputStream;\r\nimport java.io.PrintStream;\r\nimport java.util.Arrays;\r\nimport java.util.Iterator;\r\nimport java.util.List;\r\nimport java.util.regex.Pattern;\r\n\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.when;\r\n\r\npublic abstract class AbstractCallableCommandTest {\r\n\r\n    protected Server server;\r\n    protected MockableVersionControlClient vcc;\r\n    protected TaskListener listener;\r\n    protected ByteArrayOutputStream outputStream;\r\n\r\n    @Before\r\n    public void configureDefaultMocks() {\r\n        server = mock(Server.class);\r\n        vcc = mock(MockableVersionControlClient.class);\r\n        listener = mock(TaskListener.class);\r\n        outputStream = new ByteArrayOutputStream();\r\n\r\n        when(server.getVersionControlClient()).thenReturn(vcc);\r\n        when(server.getListener()).thenReturn(listener);\r\n        when(listener.getLogger()).thenReturn(new PrintStream(outputStream));\r\n    }\r\n\r\n    protected void assertLog(final String... expectedLines) throws IOException {\r\n        final byte[] outputBytes = outputStream.toByteArray();\r\n        final ByteArrayInputStream inputStream = new ByteArrayInputStream(outputBytes);\r\n        final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);\r\n        final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);\r\n        final Iterator<String> expectedIterator = IteratorUtils.arrayIterator(expectedLines);\r\n\r\n        String line;\r\n        int lineCounter = 1;\r\n        while ((line = bufferedReader.readLine()) != null) {\r\n            if (expectedIterator.hasNext()) {\r\n                final String expected = expectedIterator.next();\r\n                Assert.assertEquals(\"Lines differ at line #\" + lineCounter + \".\", expected, line);\r\n            } else {\r\n                Assert.fail(\"Log contained more lines than expected.\");\r\n            }\r\n        }\r\n        Assert.assertFalse(\"Log contained less lines than expected.\", expectedIterator.hasNext());\r\n    }\r\n\r\n    protected abstract AbstractCallableCommand createCommand(final ServerConfigurationProvider serverConfig);\r\n\r\n    @Test public void verifySerializable() throws IOException {\r\n        final ServerConfigurationProvider server = new ServerConfigurationProvider() {\r\n            public String getUrl() {\r\n                return null;\r\n            }\r\n\r\n            public String getUserName() {\r\n                return null;\r\n            }\r\n\r\n            public String getUserPassword() {\r\n                return null;\r\n            }\r\n\r\n            public TaskListener getListener() {\r\n                return null;\r\n            }\r\n\r\n            public WebProxySettings getWebProxySettings() {\r\n                final List<Pattern> patterns = Arrays.asList(\r\n                        Pattern.compile(\".+\\\\.com\"),\r\n                        Pattern.compile(\".+\\\\.org\")\r\n                );\r\n                final Secret secret;\r\n                final SecretOverride secretOverride = new SecretOverride();\r\n                try {\r\n                    secret = Secret.fromString(\"password\");\r\n                }\r\n                finally {\r\n                    try {\r\n                        secretOverride.close();\r\n                    }\r\n                    catch (final IOException ignored) {\r\n                    }\r\n                }\r\n                return new WebProxySettings(\"localhost\", 8080, patterns, \"user\", secret);\r\n            }\r\n\r\n            @Override\r\n            public ExtraSettings getExtraSettings() {\r\n                return ExtraSettings.DEFAULT;\r\n            }\r\n        };\r\n        final AbstractCallableCommand command = createCommand(server);\r\n        final Callable<?, Exception> callable = command.getCallable();\r\n        final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r\n        final ObjectOutputStream oos = new ObjectOutputStream(baos);\r\n\r\n        oos.writeObject(callable);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/AbstractCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\r\n\r\nimport static org.junit.Assert.*;\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport hudson.plugins.tfs.util.MaskedArgumentListBuilder;\r\nimport hudson.util.ArgumentListBuilder;\r\n\r\nimport org.junit.Test;\r\n\r\npublic class AbstractCommandTest {\r\n\r\n    @Test\r\n    public void assertAddingServerArguments() {\r\n        ServerConfigurationProvider config = mock(ServerConfigurationProvider.class);\r\n        when(config.getUrl()).thenReturn(\"https://tfs02.codeplex.com\");\r\n        \r\n        AbstractCommand command = new AbstractCommandImpl(config);\r\n        ArgumentListBuilder builder = new ArgumentListBuilder();\r\n        command.addServerArgument(builder);\r\n        assertEquals(\"The server URL was incorrect\", \"-server:https://tfs02.codeplex.com\", builder.toCommandArray()[0]);\r\n    }\r\n    \r\n    @Test\r\n    public void assertAddingUserCredentials() {\r\n        ServerConfigurationProvider config = mock(ServerConfigurationProvider.class);\r\n        when(config.getUserName()).thenReturn(\"user\");\r\n        when(config.getUserPassword()).thenReturn(\"password\");\r\n        \r\n        AbstractCommand command = new AbstractCommandImpl(config);\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        command.addLoginArgument(builder);\r\n        assertEquals(\"The login argument was incorrect\", \"-login:user,password\", builder.toCommandArray()[0]);\r\n        assertTrue(\"The login argument was not masked\", builder.toMaskArray()[0]);\r\n    }\r\n    \r\n    @Test\r\n    public void assertNotAddingInvalidUserCredentials() {\r\n        ServerConfigurationProvider config = mock(ServerConfigurationProvider.class);\r\n        when(config.getUserName()).thenReturn(\"user\");\r\n        when(config.getUserPassword()).thenReturn(null);\r\n        \r\n        AbstractCommand command = new AbstractCommandImpl(config);\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        command.addLoginArgument(builder);\r\n        assertTrue(\"The login argument was added\", builder.toCommandArray().length == 0);\r\n        assertTrue(\"The login argument was added\", builder.toMaskArray().length == 0);\r\n    }\r\n    \r\n    @Test\r\n    public void assertNotAddingUserCredentialsForEmptyName() {\r\n        ServerConfigurationProvider config = mock(ServerConfigurationProvider.class);\r\n        when(config.getUserName()).thenReturn(\"\");\r\n        when(config.getUserPassword()).thenReturn(\"\");\r\n        \r\n        AbstractCommand command = new AbstractCommandImpl(config);\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        command.addLoginArgument(builder);\r\n        assertTrue(\"The login argument was added\", builder.toCommandArray().length == 0);\r\n        assertTrue(\"The login argument was added\", builder.toMaskArray().length == 0);\r\n    }\r\n    \r\n    @Test\r\n    public void assertAddingUserCredentialsForEmptyPassword() {\r\n        ServerConfigurationProvider config = mock(ServerConfigurationProvider.class);\r\n        when(config.getUserName()).thenReturn(\"aname\");\r\n        when(config.getUserPassword()).thenReturn(\"\");\r\n        \r\n        AbstractCommand command = new AbstractCommandImpl(config);\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        command.addLoginArgument(builder);\r\n        assertEquals(\"The login argument was incorrect\", \"-login:aname,\", builder.toCommandArray()[0]);\r\n        assertTrue(\"The login argument was not masked\", builder.toMaskArray()[0]);\r\n    }\r\n    \r\n    private static class AbstractCommandImpl extends AbstractCommand {\r\n        \r\n        public AbstractCommandImpl(ServerConfigurationProvider provider) {\r\n            super(provider);\r\n        }\r\n\r\n        public MaskedArgumentListBuilder getArguments() {\r\n            throw new IllegalStateException();\r\n        }\r\n        \r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/DeleteWorkspaceCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.remoting.Callable;\r\nimport org.junit.Test;\r\nimport org.mockito.Matchers;\r\n\r\nimport java.io.IOException;\r\n\r\nimport static org.mockito.Matchers.anyObject;\r\nimport static org.mockito.Mockito.doNothing;\r\nimport static org.mockito.Mockito.isA;\r\nimport static org.mockito.Mockito.when;\r\n\r\n\r\npublic class DeleteWorkspaceCommandTest extends AbstractCallableCommandTest {\r\n\r\n    @Test\r\n    public void assertLogging() throws Exception {\r\n        when(server.getUserName()).thenReturn(\"snd\\\\user_cp\");\r\n        final Workspace[] emptyWorkspaceList = new Workspace[0];\r\n        when(vcc.queryWorkspaces(isA(String.class), Matchers.<String>anyObject(), isA(String.class), isA(WorkspacePermissions.class))).thenReturn(emptyWorkspaceList);\r\n        final DeleteWorkspaceCommand command = new DeleteWorkspaceCommand(server, \"TheWorkspaceName\", \"computerName\") {\r\n            @Override\r\n            public Server createServer() {\r\n                return server;\r\n            }\r\n        };\r\n        final Callable<Void, IOException> callable = command.getCallable();\r\n\r\n        callable.call();\r\n\r\n        assertLog(\r\n                \"Deleting workspaces named 'TheWorkspaceName' from computer 'computerName'...\",\r\n                \"Deleted 0 workspace(s) named 'TheWorkspaceName'.\"\r\n        );\r\n    }\r\n\r\n    @Override protected AbstractCallableCommand createCommand(final ServerConfigurationProvider serverConfig) {\r\n        return new DeleteWorkspaceCommand(serverConfig, \"workspaceName\", \"computerName\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/GetFilesToWorkFolderCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\r\n\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport java.io.IOException;\r\nimport java.io.PrintStream;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.events.GetEvent;\r\nimport hudson.remoting.Callable;\r\nimport org.junit.Ignore;\r\nimport org.junit.Test;\r\n\r\n\r\npublic class GetFilesToWorkFolderCommandTest extends AbstractCallableCommandTest {\r\n\r\n    @Ignore(\"Finish test when we have MockableWorkspace and MockableVersionControlEventEngine\")\r\n    @Test public void assertLogging() throws Exception {\r\n        when(vcc.queryWorkspace(\r\n                isA(String.class),\r\n                isA(String.class))).thenReturn(null);\r\n        final GetFilesToWorkFolderCommand command = new GetFilesToWorkFolderCommand(server, \"c:/jenkins/jobs/newJob/workspace\", \"C618\", false);\r\n        final Callable<Void, Exception> callable = command.getCallable();\r\n\r\n        callable.call();\r\n\r\n        assertLog(\r\n                \"Getting version 'C618' to 'c:/jenkins/jobs/newJob/workspace'...\",\r\n                \"Finished getting version 'C618'.\"\r\n        );\r\n    }\r\n\r\n    @Test public void onGet_typical() throws IOException {\r\n        final GetEvent getEvent = mock(GetEvent.class);\r\n        final String pathToFile = \"C:\\\\.jenkins\\\\jobs\\\\typical\\\\workspace\\\\TODO.txt\";\r\n        when(getEvent.getTargetLocalItem()).thenReturn(pathToFile);\r\n        final GetFilesToWorkFolderCommand cut = new GetFilesToWorkFolderCommand(server, null, null, false, true);\r\n        cut.setLogger(new PrintStream(this.outputStream));\r\n\r\n        cut.onGet(getEvent);\r\n\r\n        assertLog(\r\n                pathToFile\r\n        );\r\n    }\r\n\r\n    @Override protected AbstractCallableCommand createCommand(final ServerConfigurationProvider serverConfig) {\r\n        return new GetFilesToWorkFolderCommand(serverConfig, \"workFolder\", \"versionSpec\", false);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/LabelCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\n\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.LabelChildOption;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.LabelResult;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.VersionControlLabel;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.LabelItemSpec;\nimport hudson.plugins.tfs.model.Server;\nimport hudson.remoting.Callable;\nimport ms.tfs.versioncontrol.clientservices._03._LabelResult;\nimport ms.tfs.versioncontrol.clientservices._03._LabelResultStatus;\nimport org.junit.Test;\nimport org.mockito.Matchers;\n\nimport static org.mockito.Mockito.when;\n\npublic class LabelCommandTest extends AbstractCallableCommandTest {\n\n    @Test public void assertLogging() throws Exception {\n        final LabelResult labelResult = new LabelResult(new _LabelResult(\"label\", \"scope\", _LabelResultStatus.Created));\n        final LabelResult[] labelResults = {labelResult};\n\n        when(vcc.createLabel(\n                Matchers.<VersionControlLabel>anyObject(),\n                Matchers.<LabelItemSpec[]>anyObject(),\n                Matchers.<LabelChildOption>anyObject())).thenReturn(labelResults);\n\n        final LabelCommand command = new LabelCommand(server, \"labelName\", \"hudson-createLabel-TFS2013\", \"$/project/path\") {\n            @Override\n            public Server createServer() {\n                return server;\n            }\n        };\n        final Callable<Void, Exception> callable = command.getCallable();\n\n        callable.call();\n\n        assertLog(\n                \"Creating label 'labelName' on '$/project/path' as of the current version in workspace 'hudson-createLabel-TFS2013'...\",\n                \"Created label 'labelName'.\"\n        );\n    }\n\n    @Override protected AbstractCallableCommand createCommand(final ServerConfigurationProvider serverConfig) {\n        return new LabelCommand(serverConfig, \"labelName\", \"workspaceName\", \"$/projectPath\");\n    }\n}\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/ListWorkspacesCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceLocation;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspacePermissions;\r\nimport com.microsoft.tfs.core.httpclient.UsernamePasswordCredentials;\r\nimport hudson.plugins.tfs.IntegrationTestHelper;\r\nimport hudson.plugins.tfs.IntegrationTests;\r\nimport hudson.plugins.tfs.model.NativeLibraryManager;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.plugins.tfs.model.Workspace;\r\nimport hudson.remoting.Callable;\r\nimport org.junit.Test;\r\nimport org.junit.experimental.categories.Category;\r\nimport org.jvnet.hudson.test.Bug;\r\n\r\nimport java.io.IOException;\r\nimport java.io.StringReader;\r\nimport java.net.URI;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport static org.junit.Assert.assertEquals;\r\nimport static org.junit.Assert.assertNotNull;\r\nimport static org.mockito.Matchers.isA;\r\nimport static org.mockito.Mockito.anyString;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.when;\r\n\r\npublic class ListWorkspacesCommandTest extends AbstractCallableCommandTest {\r\n\r\n    @Category(IntegrationTests.class)\r\n    @Test public void assertLoggingWithComputer() throws Exception {\r\n        final IntegrationTestHelper helper = new IntegrationTestHelper();\r\n        final String serverUrl = helper.getServerUrl();\r\n        final URI serverUri = URI.create(serverUrl);\r\n        NativeLibraryManager.initialize();\r\n        final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(\r\n                helper.getUserName(), helper.getUserPassword());\r\n        final TFSTeamProjectCollection tpc = new TFSTeamProjectCollection(serverUri, credentials);\r\n\r\n        try {\r\n            final VersionControlClient vcc = tpc.getVersionControlClient();\r\n            final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace[] workspaces\r\n                    = new com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace[1];\r\n            workspaces[0] = new com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace(\r\n                    vcc,\r\n                    \"Hudson.JOBXXXXXXXXXXXXXX\",\r\n                    \"First.LastXX\",\r\n                    \"This is a comment\",\r\n                    null,\r\n                    \"XXXX-XXXX-007\",\r\n                    WorkspaceLocation.SERVER\r\n            );\r\n            when(server.getUrl()).thenReturn(\"http://tfs.invalid:8080/tfs/DefaultCollection/\");\r\n            when(this.vcc.queryWorkspaces(null, null, \"XXXX-XXXX-007\", WorkspacePermissions.NONE_OR_NOT_SUPPORTED))\r\n                    .thenReturn(workspaces);\r\n            final ListWorkspacesCommand command = new ListWorkspacesCommand(server, \"XXXX-XXXX-007\", true) {\r\n                @Override\r\n                public Server createServer() {\r\n                    return server;\r\n                }\r\n            };\r\n            final Callable<List<Workspace>, Exception> callable = command.getCallable();\r\n\r\n            callable.call();\r\n\r\n            assertLog(\r\n                \"Downloading list of workspaces from http://tfs.invalid:8080/tfs/DefaultCollection/...\",\r\n                \"Workspace                Owner        Computer      Comment          \",\r\n                \"------------------------ ------------ ------------- -----------------\",\r\n                \"Hudson.JOBXXXXXXXXXXXXXX First.LastXX XXXX-XXXX-007 This is a comment\"\r\n            );\r\n        } finally {\r\n            tpc.close();\r\n        }\r\n    }\r\n\r\n    @Category(IntegrationTests.class)\r\n    @Test public void assertLoggingWithoutComputer() throws Exception {\r\n        final IntegrationTestHelper helper = new IntegrationTestHelper();\r\n        final String serverUrl = helper.getServerUrl();\r\n        final URI serverUri = URI.create(serverUrl);\r\n        NativeLibraryManager.initialize();\r\n        final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(\r\n                helper.getUserName(), helper.getUserPassword());\r\n        final TFSTeamProjectCollection tpc = new TFSTeamProjectCollection(serverUri, credentials);\r\n\r\n        try {\r\n            final VersionControlClient vcc = tpc.getVersionControlClient();\r\n            final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace[] workspaces\r\n                    = new com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace[1];\r\n            workspaces[0] = new com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace(\r\n                    vcc,\r\n                    \"Hudson.JOBXXXXXXXXXXXXXX\",\r\n                    \"First.LastXX\",\r\n                    \"This is a comment\",\r\n                    null,\r\n                    \"XXXX-XXXX-007\",\r\n                    WorkspaceLocation.SERVER\r\n            );\r\n            when(server.getUrl()).thenReturn(\"http://tfs.invalid:8080/tfs/DefaultCollection/\");\r\n            when(this.vcc.queryWorkspaces(anyString(), anyString(), anyString(), isA(WorkspacePermissions.class)))\r\n                    .thenReturn(workspaces);\r\n            final ListWorkspacesCommand command = new ListWorkspacesCommand(server, null, true) {\r\n                @Override\r\n                public Server createServer() {\r\n                    return server;\r\n                }\r\n            };\r\n            final Callable<List<Workspace>, Exception> callable = command.getCallable();\r\n\r\n            callable.call();\r\n\r\n            assertLog(\r\n                    \"Downloading list of workspaces from http://tfs.invalid:8080/tfs/DefaultCollection/...\",\r\n                    \"Workspace                Owner        Computer      Comment          \",\r\n                    \"------------------------ ------------ ------------- -----------------\",\r\n                    \"Hudson.JOBXXXXXXXXXXXXXX First.LastXX XXXX-XXXX-007 This is a comment\"\r\n            );\r\n        } finally {\r\n            tpc.close();\r\n        }\r\n    }\r\n\r\n    @Test\r\n    public void assertEmptyListWithEmptyOutput() throws Exception {\r\n        ListWorkspacesCommand command = new ListWorkspacesCommand(mock(Server.class));\r\n        List<Workspace> list = command.parse(new StringReader(\"\"));\r\n        assertNotNull(\"List can not be null\", list);\r\n        assertEquals(\"Number of workspaces was incorrect\", 0, list.size());\r\n    }\r\n\r\n    @Test\r\n    public void assertListWithValidOutput() throws Exception {\r\n        StringReader reader = new StringReader(\r\n                \"Server: https://tfs02.codeplex.com/\\n\" +\r\n                \"Workspace Owner          Computer Comment\\n\" +\r\n                \"--------- -------------- -------- ----------------------------------------------------------------------------------------------------------\\n\" +\r\n                \"\\n\" +\r\n                \"asterix2  SND\\\\redsolo_cp ASTERIX\\n\" +\r\n                \"astreix   SND\\\\redsolo_cp ASTERIX  This is a comment\\n\");\r\n        \r\n        ListWorkspacesCommand command = new ListWorkspacesCommand(\r\n                mock(Server.class));\r\n        List<Workspace> list = command.parse(reader);\r\n        assertNotNull(\"List can not be null\", list);\r\n        assertEquals(\"Number of workspaces was incorrect\", 2, list.size());\r\n        Workspace workspace = list.get(0);\r\n        assertEquals(\"The workspace name is incorrect\", \"asterix2\", workspace.getName());\r\n        assertEquals(\"The owner name is incorrect\", \"SND\\\\redsolo_cp\", workspace.getOwner());\r\n        assertEquals(\"The computer name is incorrect\", \"ASTERIX\", workspace.getComputer());\r\n        workspace = list.get(1);\r\n        assertEquals(\"The workspace name is incorrect\", \"astreix\", workspace.getName());\r\n        assertEquals(\"The owner name is incorrect\", \"SND\\\\redsolo_cp\", workspace.getOwner());\r\n        assertEquals(\"The computer name is incorrect\", \"ASTERIX\", workspace.getComputer());\r\n        assertEquals(\"The comment is incorrect\", \"This is a comment\", workspace.getComment());\r\n    }\r\n\r\n    @Test\r\n    public void assertListWithWorkspaceContainingSpace() throws Exception {\r\n        StringReader reader = new StringReader(\r\n                \"Server: https://tfs02.codeplex.com/\\n\" +\r\n                \"Workspace          Owner      Computer Comment\\n\" +\r\n                \"------------------ ---------- -------- ----------------------------------------\\n\" +\r\n                \"Hudson-node lookup redsolo_cp ASTERIX\\n\");\r\n        \r\n        ListWorkspacesCommand command = new ListWorkspacesCommand(\r\n                mock(Server.class));\r\n        List<Workspace> list = command.parse(reader);\r\n        assertNotNull(\"List can not be null\", list);\r\n        assertEquals(\"Number of workspaces was incorrect\", 1, list.size());\r\n        Workspace workspace = list.get(0);\r\n        assertEquals(\"The workspace name is incorrect\", \"Hudson-node lookup\", workspace.getName());\r\n    }\r\n\r\n    @Bug(4666)\r\n    @Test\r\n    public void assertNoIndexOutOfBoundsIsThrown() throws Exception {\r\n\r\n        StringReader reader = new StringReader(\r\n                \"Server: teamserver-01\\n\" +\r\n                \"Workspace         Owner  Computer    Comment\\n\" +\r\n                \"----------------- ------ ----------- ------------------------------------------\\n\" +\r\n                \"Hudson-Scrumboard dennis W7-DENNIS-1\\n\" + \r\n                \"W7-DENNIS-1       dennis W7-DENNIS-1\\n\");\r\n\r\n        new ListWorkspacesCommand(mock(Server.class)).parse(reader);\r\n    }\r\n\r\n    @Bug(4726)\r\n    @Test\r\n    public void assertNoIndexOutOfBoundsIsThrownSecondEdition() throws Exception {\r\n\r\n        StringReader reader = new StringReader(\r\n                \"Server: xxxx-xxxx-010\\n\" +\r\n                \"Workspace                Owner        Computer      Comment\\n\" +\r\n                \"------------------------ ------------ ------------- ---------------------------\\n\" +\r\n                \"Hudson.JOBXXXXXXXXXXXXXX First.LastXX XXXX-XXXX-007\\n\");\r\n\r\n        new ListWorkspacesCommand(mock(Server.class)).parse(reader);\r\n    }\r\n\r\n    @Test public void logWithNoWorkspaces() throws IOException {\r\n\r\n        ListWorkspacesCommand.log(new ArrayList<Workspace>(0), listener.getLogger());\r\n\r\n        assertLog(\r\n                \"Workspace Owner Computer Comment\",\r\n                \"--------- ----- -------- -------\"\r\n        );\r\n    }\r\n\r\n    @Test public void logWithManyWorkspaces() throws IOException {\r\n\r\n        final ArrayList<Workspace> workspaces = new ArrayList<Workspace>();\r\n        workspaces.add(new Workspace(\"Hudson.JOBXXXXXXXXXXXXXX\", \"XXXX-XXXX-007\", \"First.LastXX\", \"This is a comment\"));\r\n        workspaces.add(new Workspace(\"Hudson-newJob-MASTER\", \"COMPUTER\", \"jenkins-tfs-plugin\", \"Created by the Jenkins tfs-plugin functional tests.\"));\r\n\r\n        ListWorkspacesCommand.log(workspaces, listener.getLogger());\r\n\r\n        assertLog(\r\n                \"Workspace                Owner              Computer      Comment                                            \",\r\n                \"------------------------ ------------------ ------------- ---------------------------------------------------\",\r\n                \"Hudson.JOBXXXXXXXXXXXXXX First.LastXX       XXXX-XXXX-007 This is a comment                                  \",\r\n                \"Hudson-newJob-MASTER     jenkins-tfs-plugin COMPUTER      Created by the Jenkins tfs-plugin functional tests.\"\r\n        );\r\n    }\r\n\r\n    @Test public void logWithOneWorkspace() throws IOException {\r\n\r\n        final ArrayList<Workspace> workspaces = new ArrayList<Workspace>(1);\r\n        workspaces.add(new Workspace(\"asterix\", \"ASTERIX\", \"redsolo_cp\", \"This is a comment\"));\r\n\r\n        ListWorkspacesCommand.log(workspaces, listener.getLogger());\r\n\r\n        assertLog(\r\n                \"Workspace Owner      Computer Comment          \",\r\n                \"--------- ---------- -------- -----------------\",\r\n                \"asterix   redsolo_cp ASTERIX  This is a comment\"\r\n        );\r\n    }\r\n\r\n    @Override protected AbstractCallableCommand createCommand(final ServerConfigurationProvider serverConfig) {\r\n        return new ListWorkspacesCommand(serverConfig, \"computer\", true);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/NewWorkspaceCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\r\n\r\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceLocation;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.WorkspaceOptions;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.WorkingFolder;\r\nimport hudson.plugins.tfs.model.Server;\r\nimport hudson.remoting.Callable;\r\nimport org.junit.Test;\r\n\r\nimport static org.mockito.AdditionalMatchers.aryEq;\r\nimport static org.mockito.Matchers.isA;\r\nimport static org.mockito.Mockito.when;\r\n\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\npublic class NewWorkspaceCommandTest extends AbstractCallableCommandTest {\r\n\r\n    private static final List<String> EMPTY_CLOAKED_PATHS = Collections.emptyList();\r\n\r\n    @Test public void assertLogging() throws Exception {\r\n        when(server.getUserName()).thenReturn(\"snd\\\\user_cp\");\r\n        when(vcc.createWorkspace(aryEq((WorkingFolder[]) null),\r\n                isA(String.class),\r\n                isA(String.class),\r\n                isA(String.class),\r\n                isA(String.class),\r\n                isA(WorkspaceLocation.class),\r\n                isA(WorkspaceOptions.class))).thenReturn(null);\r\n        final NewWorkspaceCommand command = new NewWorkspaceCommand(server, \"TheWorkspaceName\", null, EMPTY_CLOAKED_PATHS, null) {\r\n            @Override\r\n            public Server createServer() {\r\n                return server;\r\n            }\r\n\r\n            @Override\r\n            protected void updateCache(final TFSTeamProjectCollection connection) {\r\n                // no-op for tests\r\n            }\r\n        };\r\n        final Callable<Void, Exception> callable = command.getCallable();\r\n\r\n        callable.call();\r\n\r\n        assertLog(\r\n                \"Creating workspace 'TheWorkspaceName' owned by 'snd\\\\user_cp'...\",\r\n                \"Created workspace 'TheWorkspaceName'.\"\r\n        );\r\n    }\r\n\r\n    @Test public void assertLoggingWhenAlsoMapping() throws Exception {\r\n        final List<String> cloakedPaths = Collections.singletonList(\"$/Stuff/Hide\");\r\n\r\n        when(server.getUserName()).thenReturn(\"snd\\\\user_cp\");\r\n        when(vcc.createWorkspace(aryEq((WorkingFolder[]) null),\r\n                isA(String.class),\r\n                isA(String.class),\r\n                isA(String.class),\r\n                isA(String.class),\r\n                isA(WorkspaceLocation.class),\r\n                isA(WorkspaceOptions.class))).thenReturn(null);\r\n        final NewWorkspaceCommand command = new NewWorkspaceCommand(server, \"TheWorkspaceName\", \"$/Stuff\", cloakedPaths, \"/home/jenkins/jobs/stuff/workspace\") {\r\n            @Override\r\n            public Server createServer() {\r\n                return server;\r\n            }\r\n\r\n            @Override\r\n            protected void updateCache(final TFSTeamProjectCollection connection) {\r\n                // no-op for tests\r\n            }\r\n        };\r\n        final Callable<Void, Exception> callable = command.getCallable();\r\n\r\n        callable.call();\r\n\r\n        assertLog(\r\n                \"Creating workspace 'TheWorkspaceName' owned by 'snd\\\\user_cp'...\",\r\n                \"Mapping '$/Stuff' to local folder '/home/jenkins/jobs/stuff/workspace' in workspace 'TheWorkspaceName'...\",\r\n                \"Cloaking '$/Stuff/Hide' in workspace 'TheWorkspaceName'...\",\r\n                \"Created workspace 'TheWorkspaceName'.\"\r\n        );\r\n    }\r\n\r\n    @Override protected AbstractCallableCommand createCommand(final ServerConfigurationProvider serverConfig) {\r\n        return new NewWorkspaceCommand(serverConfig, \"workspaceName\", \"$/serverPath\", EMPTY_CLOAKED_PATHS, \"local/path\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/commands/RemoteChangesetVersionCommandTest.java",
    "content": "package hudson.plugins.tfs.commands;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.Matchers.anyBoolean;\nimport static org.mockito.Matchers.anyInt;\nimport static org.mockito.Matchers.isA;\nimport static org.mockito.Matchers.isNull;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.ChangeType;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Changeset;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Item;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.ItemType;\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.RecursionType;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.LabelSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.ChangesetVersionSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.LabelVersionSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.LatestVersionSpec;\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.VersionSpec;\nimport hudson.model.User;\nimport hudson.plugins.tfs.Util;\nimport hudson.plugins.tfs.model.Server;\n\nimport java.io.StringReader;\n\nimport hudson.plugins.tfs.model.UserLookup;\nimport hudson.remoting.Callable;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class RemoteChangesetVersionCommandTest extends AbstractCallableCommandTest {\n\n    private static final DateVersionSpec fixedPointInTime = new DateVersionSpec(Util.getCalendar(2013, 07, 02, 15, 40, 50, \"UTC\"));\n\n    @Test public void assertLoggingWhenChangeset() throws Exception {\n        final User user = mock(User.class);\n        when(user.getId()).thenReturn(\"piedefer\");\n        final UserLookup userLookup = mock(UserLookup.class);\n        when(userLookup.find(\"piedefer\")).thenReturn(user);\n        final Item item = new Item();\n        item.setServerItem(\"Arithmetica.iTeX\");\n        item.setItemType(ItemType.FILE);\n        final Change serverChange = new Change(item, ChangeType.EDIT, null);\n        final Changeset serverChangeset = new Changeset(\n                new Change[]{serverChange},\n                \"I have discovered a truly marvellous proof of this, which this margin is too narrow to contain.\",\n                null,\n                null,\n                \"piedefer\",\n                \"Pierre de Fermat\",\n                fixedPointInTime.getDate(),\n                1637,\n                \"piedefer\",\n                \"Pierre de Fermat\",\n                null\n        );\n        final Changeset[] serverChangesets = new Changeset[]{serverChangeset};\n        when(vcc.queryHistory(\n                isA(String.class),\n                isA(VersionSpec.class),\n                anyInt(),\n                isA(RecursionType.class),\n                (String) isNull(),\n                (VersionSpec) isNull(),\n                (VersionSpec) isNull(),\n                anyInt(),\n                anyBoolean(),\n                anyBoolean(),\n                anyBoolean(),\n                anyBoolean())).thenReturn(serverChangesets);\n        final RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(server, \"$/RemotePath\", LatestVersionSpec.INSTANCE) {\n            @Override\n            public Server createServer() {\n                return server;\n            }\n        };\n        final Callable<Integer, Exception> callable = command.getCallable();\n\n        final Integer actual = callable.call();\n\n        Assert.assertNotNull(actual);\n        Assert.assertEquals(1637, (int)actual);\n        assertLog(\n                \"Querying for remote changeset at '$/RemotePath' as of 'T'...\",\n                \"Query result is: Changeset #1637 by 'piedefer' on '2013-07-02T15:40:50Z'.\"\n        );\n    }\n\n    @Test public void assertLoggingWhenNoResult() throws Exception {\n        when(vcc.queryHistory(\n                isA(String.class),\n                isA(VersionSpec.class),\n                anyInt(),\n                isA(RecursionType.class),\n                (String) isNull(),\n                (VersionSpec) isNull(),\n                (VersionSpec) isNull(),\n                anyInt(),\n                anyBoolean(),\n                anyBoolean(),\n                anyBoolean(),\n                anyBoolean())).thenReturn(null);\n        final RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(server, \"$/RemotePath\", LatestVersionSpec.INSTANCE) {\n            @Override\n            public Server createServer() {\n                return server;\n            }\n        };\n        final Callable<Integer, Exception> callable = command.getCallable();\n\n        final Integer result = callable.call();\n\n        Assert.assertNull(result);\n        assertLog(\n                \"Querying for remote changeset at '$/RemotePath' as of 'T'...\",\n                \"Query returned no result!\"\n        );\n    }\n\n    @Test\n    public void assertNoChangesWithEmptyOutput() throws Exception {\n        RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(mock(Server.class), \"$/tfsandbox\", fixedPointInTime);\n        String changesetNumber = command.parse(new StringReader(\"\"));\n        assertEquals(\"Change set number was incorrect\", \"\", changesetNumber);\n    }\n    \n    @Test\n    public void assertChangesWithEmptyToolOutput() throws Exception {\n        RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(mock(Server.class), \"$/tfsandbox\", fixedPointInTime);\n        StringReader reader = new StringReader(\"No history entries were found for the item and version combination specified.\\n\\n\");\n        String changesetNumber = command.parse(reader);\n        assertEquals(\"Change set number was incorrect\", \"\", changesetNumber);\n    }    \n    \n    @Test\n    public void assertChangesWithChangeOutput() throws Exception {\n        StringReader reader = new StringReader(\n                \"Changeset User           Date                 Comment\\n\" +\n                \"--------- -------------- -------------------- ----------------------------------------------------------------------------\\n\" +\n                \"\\n\" +\n                \"12495     SND\\\\redsolo_cp 2008-jun-27 13:21:25 changed and created one\\n\");\n        \n        RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(mock(Server.class), \"$/tfsandbox\", fixedPointInTime);\n        String changesetNumber = command.parse(reader);\n        assertEquals(\"Change set number was incorrect\", \"12495\", changesetNumber);\n    }    \n    \n    @Test\n    public void assertChangesWithNoComment() throws Exception {\n        StringReader reader = new StringReader(\n                \"Changeset User           Date                 Comment\\n\" +\n                \"--------- -------------- -------------------- ----------------------------------------------------------------------------\\n\" +\n                \"\\n\" +\n                \"12495     SND\\\\redsolo_cp 2008-jun-27 13:21:25\\n\");\n        \n        RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(mock(Server.class), \"$/tfsandbox\", fixedPointInTime);\n        String changesetNumber = command.parse(reader);\n        assertEquals(\"Change set number was incorrect\", \"12495\", changesetNumber);\n    }    \n\n    @Test\n    public void assertChangesNoEmptyLine() throws Exception {\n        StringReader reader = new StringReader(\n                \"Changeset User           Date                 Comment\\n\" +\n                \"--------- -------------- -------------------- ----------------------------------------------------------------------------\\n\" +\n                \"12497     SND\\\\redsolo_cp 2008-jun-27 13:21:25\\n\");\n        \n        RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(mock(Server.class), \"$/tfsandbox\", fixedPointInTime);\n        String changesetNumber = command.parse(reader);\n        assertEquals(\"Change set number was incorrect\", \"12497\", changesetNumber);\n    }\n\n    @Test public void getVersionSpecificationWhenDateVersionSpec() {\n\n        final String actual = RemoteChangesetVersionCommand.toString(fixedPointInTime);\n\n        assertEquals(\"D2013-07-02T15:40:50Z\", actual);\n    }\n\n    @Test public void getVersionSpecificationWhenChangesetVersionSpec() {\n        final ChangesetVersionSpec versionSpec = new ChangesetVersionSpec(42);\n\n        final String actual = RemoteChangesetVersionCommand.toString(versionSpec);\n\n        assertEquals(\"C42\", actual);\n    }\n\n    @Test public void getVersionSpecificationWhenLabelVersionSpecWithoutScope() {\n        final LabelVersionSpec versionSpec = new LabelVersionSpec(new LabelSpec(\"Foo\", null));\n\n        final String actual = RemoteChangesetVersionCommand.toString(versionSpec);\n\n        assertEquals(\"LFoo\", actual);\n    }\n\n    @Test public void getVersionSpecificationWhenLabelVersionSpecWithScope() {\n        final LabelVersionSpec versionSpec = new LabelVersionSpec(new LabelSpec(\"Foo\", \"$/Bar\"));\n\n        final String actual = RemoteChangesetVersionCommand.toString(versionSpec);\n\n        assertEquals(\"LFoo@$/Bar\", actual);\n    }\n\n    @Override protected AbstractCallableCommand createCommand(final ServerConfigurationProvider serverConfig) {\n        final ChangesetVersionSpec versionSpec = new ChangesetVersionSpec(42);\n        final RemoteChangesetVersionCommand command = new RemoteChangesetVersionCommand(serverConfig, \"$/remotePath\", versionSpec);\n        return command;\n    }\n}\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/AbstractHookEventTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport org.eclipse.jgit.transport.URIish;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link AbstractHookEvent}.\r\n */\r\npublic class AbstractHookEventTest {\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/ChangeLogSetIntegrationTest.java",
    "content": "package hudson.plugins.tfs.model;\n\nimport org.jvnet.hudson.test.Bug;\nimport org.jvnet.hudson.test.HudsonTestCase;\nimport org.jvnet.hudson.test.recipes.LocalData;\n\nimport com.gargoylesoftware.htmlunit.html.HtmlPage;\n\npublic class ChangeLogSetIntegrationTest extends HudsonTestCase {\n\n    /**\n     * Asserts that polling now longer throws an exception.\n     * @throws Exception thrown if problem\n     */\n    @LocalData\n    @Bug(4943)\n    public void testThatLogSetContainsCheckedInByUserReference() throws Exception {\n    \tHtmlPage page = new WebClient().getPage(hudson.getItem(\"4943\"), \"2/changes\");\n    \tassertXPath(page, \"//a[@href=\\\"/user/dude/\\\"]\");\n    }\n}\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/ChangeLogSetTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport static org.junit.Assert.*;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport org.junit.Test;\r\n\r\n\r\npublic class ChangeLogSetTest {\r\n\r\n    @Test\r\n    public void assertChangeSetsHaveLogSetParent() throws Exception {        \r\n        List<ChangeSet> changesets = new ArrayList<ChangeSet>();\r\n        changesets.add(new ChangeSet(\"version\", null, \"user\", \"comment\"));        \r\n        ChangeLogSet logset = new ChangeLogSet(null, null, changesets);\r\n        ChangeSet changeset = logset.iterator().next();\r\n        assertNotNull(\"Log set parent was null change set\", changeset.getParent());\r\n    }\r\n\r\n    @Test\r\n    public void assertIsEmptyReturnsFalseWhenNoChangesets() throws Exception {        \r\n        List<ChangeSet> changesets = new ArrayList<ChangeSet>();    \r\n        ChangeLogSet logset = new ChangeLogSet(null, null, changesets);\r\n        assertTrue(\"The isEmpty did not return true with an empty log set\", logset.isEmptySet());\r\n    }\r\n\r\n    @Test\r\n    public void assertIsEmptyReturnsTrueWithChangesets() throws Exception {        \r\n        List<ChangeSet> changesets = new ArrayList<ChangeSet>();\r\n        changesets.add(new ChangeSet(\"version\", null, \"user\", \"comment\"));        \r\n        ChangeLogSet logset = new ChangeLogSet(null, null, changesets);\r\n        assertFalse(\"The isEmpty did not return false with a log set with change sets\", logset.isEmptySet());\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/ChangeSetTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport static org.junit.Assert.*;\r\n\r\nimport java.util.Collection;\r\nimport java.util.Iterator;\r\n\r\nimport hudson.plugins.tfs.model.ChangeSet.Item;\r\nimport hudson.scm.EditType;\r\n\r\nimport org.junit.Test;\r\n\r\n\r\npublic class ChangeSetTest {\r\n\r\n    @Test\r\n    public void assertMsgReturnsComment() {\r\n        ChangeSet changeset = new ChangeSet(\"0\", null, \"snd\\\\user\", \"comment\");\r\n        assertSame(\"The getMsg() did not return the comment\", \"comment\", changeset.getMsg());\r\n    }\r\n    \r\n    @Test\r\n    public void assertAffectedPathsReturnsPaths() {\r\n        ChangeSet changeset = new ChangeSet(\"0\", null, \"snd\\\\user\", \"comment\");\r\n        changeset.getItems().add(new Item(\"filename\", \"add\"));\r\n        changeset.getItems().add(new Item(\"filename2\", \"edit\"));\r\n        Collection<String> paths = changeset.getAffectedPaths();\r\n        assertNotNull(\"Affected paths can not be null\", paths);\r\n        assertEquals(\"The number of affected paths was incorrect\", 2, paths.size());\r\n        Iterator<String> iterator = paths.iterator();\r\n        assertEquals(\"The first path is incorrect\", \"filename\", iterator.next());\r\n        assertEquals(\"The first path is incorrect\", \"filename2\", iterator.next());\r\n    }\r\n    \r\n    @Test\r\n    public void assertAddedItemReturnsAddEditType() {\r\n        Item item = new Item(\"path\", \"add\");\r\n        assertSame(\"Incorrect edit type returned for Add action\", EditType.ADD, item.getEditType());\r\n    }\r\n    \r\n    @Test\r\n    public void assertDeletedItemReturnsDeleteEditType() {\r\n        Item item = new Item(\"path\", \"delete\");\r\n        assertSame(\"Incorrect edit type returned for Delete action\", EditType.DELETE, item.getEditType());\r\n    }\r\n    \r\n    @Test\r\n    public void assertModifiedItemReturnsEditEditType() {\r\n        Item item = new Item(\"path\", \"edit\");\r\n        assertSame(\"Incorrect edit type returned for Edit action\", EditType.EDIT, item.getEditType());\r\n    }\r\n    \r\n    @Test\r\n    public void assertUserNameIsSetCorrectly() {\r\n        ChangeSet changeset = new ChangeSet(\"0\", null, \"RNO\\\\_MCLWEB\", \"comment\");\r\n        assertEquals(\"The user name was incorrect\", \"_MCLWEB\", changeset.getUser());\r\n    }\r\n    \r\n    @Test\r\n    public void assertDomainNameIsSetCorrectly() {\r\n        ChangeSet changeset = new ChangeSet(\"0\", null, \"RNO\\\\_MCLWEB\", \"comment\");\r\n        assertEquals(\"The domain name was incorrect\", \"RNO\", changeset.getDomain());\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/GitCodePushedEventArgsTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link GitCodePushedEventArgs}.\r\n */\r\npublic class GitCodePushedEventArgsTest {\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/GitPullRequestMergedEventTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport net.sf.json.JSONObject;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\nimport java.net.URI;\r\n\r\n/**\r\n * A class to test {@link GitPullRequestMergedEvent}.\r\n */\r\npublic class GitPullRequestMergedEventTest {\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/GitPushEventTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport com.microsoft.teamfoundation.core.webapi.model.TeamProjectReference;\r\nimport com.microsoft.teamfoundation.sourcecontrol.webapi.model.GitRefUpdate;\r\nimport com.microsoft.visualstudio.services.webapi.model.IdentityRef;\r\nimport hudson.plugins.tfs.model.servicehooks.Event;\r\nimport hudson.plugins.tfs.model.servicehooks.ResourceContainer;\r\nimport hudson.plugins.tfs.util.EndpointHelper;\r\nimport net.sf.json.JSONArray;\r\nimport net.sf.json.JSONObject;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\nimport java.net.URI;\r\nimport java.util.ArrayList;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.Map;\r\nimport java.util.UUID;\r\n\r\n/**\r\n * A class to test {@link GitPushEvent}.\r\n */\r\npublic class GitPushEventTest {\r\n\r\n    @Test\r\n    public void determineCollectionUri_sample() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249\");\r\n\r\n        final URI actual = GitPushEvent.determineCollectionUri(input);\r\n\r\n        final URI expected = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/\");\r\n        Assert.assertEquals(expected, actual);\r\n    }\r\n\r\n    @Test\r\n    public void perform_noCommitsInPayload() throws Exception {\r\n\r\n        final GitPushEvent gpe = new GitPushEvent();\r\n        final ObjectMapper mapper = EndpointHelper.MAPPER;\r\n        final Event event = new Event();\r\n        final ResourceContainer collectionResourceContainer = new ResourceContainer() {{\r\n            setId(UUID.fromString(\"c12d0eb8-e382-443b-9f9c-c52cba5014c2\"));\r\n        }};\r\n        final Map<String, ResourceContainer> resourceContainers = new LinkedHashMap<String, ResourceContainer>() {{\r\n            put(\"collection\", collectionResourceContainer);\r\n        }};\r\n        event.setResourceContainers(resourceContainers);\r\n        final TeamProjectReference project = new TeamProjectReference() {{\r\n            setName(\"Fabrikam-Fiber-Git\");\r\n        }};\r\n        final Map<String, Object> repository = new LinkedHashMap<String, Object>() {{\r\n            put(\"url\", \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249\");\r\n            put(\"project\", project);\r\n            put(\"remoteUrl\", \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_git/Fabrikam-Fiber-Git\");\r\n        }};\r\n        final IdentityRef pushedBy = new IdentityRef() {{\r\n            setDisplayName(\"Jamal Hartnett\");\r\n        }};\r\n        final ArrayList<GitRefUpdate> refUpdates = new ArrayList<GitRefUpdate>();\r\n        final GitRefUpdate gitRefUpdate = new GitRefUpdate();\r\n        gitRefUpdate.setName(\"master\");\r\n        refUpdates.add(gitRefUpdate);\r\n        final Map<String, Object> resource = new LinkedHashMap<String, Object>() {{\r\n            put(\"commits\", null);\r\n            put(\"repository\", repository);\r\n            put(\"pushedBy\", pushedBy);\r\n            put(\"refUpdates\", refUpdates);\r\n        }};\r\n        event.setResource(resource);\r\n\r\n\r\n        final JSONObject actual = gpe.perform(mapper, event, null, null);\r\n\r\n        final JSONArray messages = actual.getJSONArray(\"messages\");\r\n        Assert.assertEquals(1, messages.size());\r\n        final String message = messages.getString(0).trim();\r\n        Assert.assertEquals(\"No commits were pushed, skipping further event processing.\", message);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/GitStatusContextTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link GitStatusContext}.\r\n */\r\npublic class GitStatusContextTest {\r\n\r\n    public static final String FORMATTED_INPUT =\r\n        \"{\\n\" +\r\n        \"    \\\"name\\\":\\\"Build123\\\",\\n\" +\r\n        \"    \\\"genre\\\":\\\"continuous-integration\\\"\\n\" +\r\n        \"}\";\r\n\r\n    @Test public void fromJsonString_typical() throws Exception {\r\n\r\n        final GitStatusContext actual = GitStatusContext.fromJsonString(FORMATTED_INPUT);\r\n\r\n        Assert.assertEquals(\"Build123\", actual.name);\r\n        Assert.assertEquals(\"continuous-integration\", actual.genre);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/NativeLibraryManagerTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport com.microsoft.tfs.core.persistence.PersistenceStore;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\nimport org.mockito.Matchers;\r\n\r\nimport java.io.ByteArrayOutputStream;\r\nimport java.io.IOException;\r\n\r\nimport static org.mockito.Matchers.isA;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.times;\r\nimport static org.mockito.Mockito.verify;\r\nimport static org.mockito.Mockito.when;\r\n\r\npublic class NativeLibraryManagerTest {\r\n\r\n    @Test public void buildPathToNativeFile_threeComponents() throws Exception {\r\n\r\n        final String actual = NativeLibraryManager.buildPathToNativeFile(\"win32\", \"x86\", \"native_auth.dll\");\r\n\r\n        Assert.assertEquals(\"native/win32/x86/native_auth.dll\", actual);\r\n    }\r\n\r\n    @Test public void buildPathToNativeFile_twoComponents() throws Exception {\r\n\r\n        final String actual = NativeLibraryManager.buildPathToNativeFile(\"macosx\", null, \"libnative_auth.jnilib\");\r\n\r\n        Assert.assertEquals(\"native/macosx/libnative_auth.jnilib\", actual);\r\n    }\r\n\r\n    @Test public void extractFile() throws IOException {\r\n        final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r\n        final PersistenceStore store = mock(PersistenceStore.class);\r\n        when(store.containsItem(isA(String.class))).thenReturn(false);\r\n        when(store.getItemOutputStream(isA(String.class))).thenReturn(baos);\r\n        final NativeLibraryManager manager = new NativeLibraryManager(store);\r\n\r\n        manager.extractFile(\"win32\", \"x86\", \"native_auth.dll\");\r\n\r\n        Assert.assertEquals(67240, baos.size());\r\n    }\r\n\r\n    @Test public void extractFile_noArch() throws IOException {\r\n        final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r\n        final PersistenceStore store = mock(PersistenceStore.class);\r\n        when(store.containsItem(isA(String.class))).thenReturn(false);\r\n        when(store.getItemOutputStream(isA(String.class))).thenReturn(baos);\r\n        final NativeLibraryManager manager = new NativeLibraryManager(store);\r\n\r\n        manager.extractFile(\"macosx\", null, \"libnative_auth.jnilib\");\r\n\r\n        Assert.assertEquals(118960, baos.size());\r\n    }\r\n\r\n    @Test public void extractFiles() throws Exception {\r\n        final NativeLibraryExtractor extractor = mock(NativeLibraryExtractor.class);\r\n\r\n        NativeLibraryManager.extractFiles(extractor);\r\n\r\n        verify(extractor, times(82)).extractFile(isA(String.class), Matchers.<String>anyObject(), isA(String.class));\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/ProjectTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport static org.junit.Assert.*;\r\nimport static org.mockito.Matchers.*;\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport java.io.IOException;\r\nimport java.io.Reader;\r\nimport java.io.StringReader;\r\nimport java.net.URISyntaxException;\r\nimport java.util.Arrays;\r\nimport java.util.Calendar;\r\nimport java.util.Collections;\r\nimport java.util.Date;\r\nimport java.util.List;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.ChangesetVersionSpec;\r\nimport hudson.model.User;\r\nimport hudson.plugins.tfs.IntegrationTestHelper;\r\nimport hudson.plugins.tfs.IntegrationTests;\r\nimport hudson.plugins.tfs.SwedishLocaleTestCase;\r\nimport hudson.plugins.tfs.Util;\r\nimport hudson.plugins.tfs.commands.RemoteChangesetVersionCommand;\r\nimport hudson.plugins.tfs.model.ChangeSet.Item;\r\nimport hudson.plugins.tfs.util.MaskedArgumentListBuilder;\r\nimport hudson.tasks.Mailer;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.ChangeType;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Changeset;\r\nimport com.microsoft.tfs.core.clients.versioncontrol.soapextensions.ItemType;\r\nimport org.junit.experimental.categories.Category;\r\n\r\npublic class ProjectTest extends SwedishLocaleTestCase {\r\n\r\n    private com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change createServerChange() {\r\n        final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Item serverItem\r\n            = new com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Item();\r\n        serverItem.setItemType(ItemType.FILE);\r\n        serverItem.setServerItem(\"$/tfsandbox\");\r\n        final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change serverChange\r\n            = new Change(serverItem, ChangeType.ADD, null);\r\n        return serverChange;\r\n    }\r\n\r\n    @Test\r\n    public void assertConvertServerChange() throws Exception {\r\n        final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change serverChange = createServerChange();\r\n        \r\n        final Item actual = Project.convertServerChange(serverChange);\r\n        \r\n        assertEquals(\"$/tfsandbox\", actual.getPath());\r\n        assertEquals(\"add\", actual.getAction());\r\n    }\r\n    \r\n    private UserLookup createMockUserLookup(String accountName, String displayName, String emailAddress) {\r\n        UserLookup userLookup = mock(UserLookup.class);\r\n        User user = mock(User.class);\r\n        // this portion stolen from User.get()\r\n        final String id = accountName.replace('\\\\', '_').replace('/', '_').replace('<','_')\r\n                .replace('>','_');  // 4 replace() still faster than regex\r\n        // end stolen portion\r\n        when(user.getId()).thenReturn(id);\r\n        when(user.getDisplayName()).thenReturn(displayName);\r\n        when(user.getProperty(Mailer.UserProperty.class)).thenReturn(new Mailer.UserProperty(emailAddress));\r\n\r\n        when(userLookup.find(accountName)).thenReturn(user);\r\n        return userLookup;\r\n    }\r\n    \r\n    @Test\r\n    public void assertConvertServerChangeset() throws Exception {\r\n        final com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Change serverChange = createServerChange();\r\n        final String comment = \"Created team project folder $/tfsandbox via the Team Project Creation Wizard\";\r\n        final Calendar juneTwentySeventh = Util.getCalendar(2008, 06, 27, 11, 16, 06);\r\n        final String userString = \"EXAMPLE\\\\ljenkins\";\r\n        Changeset serverChangeset = new Changeset(userString, comment, null, null);\r\n        serverChangeset.setChangesetID(12472);\r\n        serverChangeset.setCommitter(userString);\r\n        serverChangeset.setDate(juneTwentySeventh);\r\n        final Change[] changes = new Change[] { serverChange };\r\n        serverChangeset.setChanges(changes);\r\n        final String userDisplayName = \"Leeroy Jenkins\";\r\n        final String userEmailAddress = \"leeroy.jenkins@example.com\";\r\n        final UserLookup userLookup = createMockUserLookup(userString, userDisplayName, userEmailAddress);\r\n\r\n        hudson.plugins.tfs.model.ChangeSet actual = Project.convertServerChangeset(serverChangeset, userLookup);\r\n\r\n        final User author = actual.getAuthor();\r\n        assertEquals(\"The version was incorrect\", \"12472\", actual.getVersion());\r\n        assertEquals(\"The author's user ID was incorrect\", \"EXAMPLE_ljenkins\", author.getId());\r\n        assertEquals(\"The author's display name was incorrect\", userDisplayName, author.getDisplayName());\r\n        final String actualEmailAddress = author.getProperty(Mailer.UserProperty.class).getAddress();\r\n        assertEquals(\"The author's e-mail address was incorrect\", userEmailAddress, actualEmailAddress);\r\n        assertEquals(\"The date was incorrect\", juneTwentySeventh.getTime(), actual.getDate());\r\n        assertEquals(\"The comment was incorrect\", comment, actual.getComment());\r\n\r\n        Item item = actual.getItems().get(0);\r\n        assertEquals(\"The item path was incorrect\", \"$/tfsandbox\", item.getPath());\r\n        assertEquals(\"The item action was incorrect\", \"add\", item.getAction());\r\n\r\n    }\r\n\r\n    @Test\r\n    public void findLatestUncloakedChangeset_latestIsUncloaked() {\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/MyProject/A/2\", \"$/MyProject/B\");\r\n        final ChangeSet changeSet42 = createChangeSet(42, \"$/MyProject/A/foo\", \"$/MyProject/A/bar\");\r\n        final ChangeSet changeSet43 = createChangeSet(43, \"$/MyProject/A/bar\");\r\n        final ChangeSet changeSet44 = createChangeSet(44, \"$/MyProject/A/foo\");\r\n        final List<ChangeSet> changeSets = Arrays.asList(changeSet44, changeSet43, changeSet42);\r\n\r\n        final ChangeSet actual = Project.findLatestUncloakedChangeset(cloakedPaths, changeSets);\r\n\r\n        Assert.assertEquals(\"44\", actual.getVersion());\r\n    }\r\n\r\n    @Test\r\n    public void findLatestUncloakedChangeset_latestIsCloaked() {\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/MyProject/A/2\", \"$/MyProject/B\");\r\n        final ChangeSet changeSet42 = createChangeSet(42, \"$/MyProject/A/foo\", \"$/MyProject/A/bar\");\r\n        final ChangeSet changeSet43 = createChangeSet(43, \"$/MyProject/A/bar\");\r\n        final ChangeSet changeSet44 = createChangeSet(44, \"$/MyProject/A/2/foo\");\r\n        final List<ChangeSet> changeSets = Arrays.asList(changeSet44, changeSet43, changeSet42);\r\n\r\n        final ChangeSet actual = Project.findLatestUncloakedChangeset(cloakedPaths, changeSets);\r\n\r\n        Assert.assertEquals(\"43\", actual.getVersion());\r\n    }\r\n\r\n    @Test\r\n    public void findLatestUncloakedChangeset_everythingIsCloaked() {\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/MyProject/A/2\", \"$/MyProject/B\");\r\n        final ChangeSet changeSet42 = createChangeSet(42, \"$/MyProject/A/2/foo\", \"$/MyProject/B/bar\");\r\n        final ChangeSet changeSet43 = createChangeSet(43, \"$/MyProject/B/bar\");\r\n        final ChangeSet changeSet44 = createChangeSet(44, \"$/MyProject/A/2/foo\");\r\n        final List<ChangeSet> changeSets = Arrays.asList(changeSet44, changeSet43, changeSet42);\r\n\r\n        final ChangeSet actual = Project.findLatestUncloakedChangeset(cloakedPaths, changeSets);\r\n\r\n        Assert.assertEquals(null, actual);\r\n    }\r\n\r\n    private static ChangeSet createChangeSet(final int version, final String... itemPaths) {\r\n        final String stringVersion = Integer.toString(version);\r\n        final Calendar calendar = Util.getCalendar(2016, 1, 5, 10, version, 0);\r\n        final Date date = calendar.getTime();\r\n        final ChangeSet result = new ChangeSet(stringVersion, date, \"ljenkins\", \"synthetic for testing\");\r\n\r\n        for (final String itemPath : itemPaths) {\r\n            final Item item = new Item(itemPath, \"edit\");\r\n            result.add(item);\r\n        }\r\n\r\n        return result;\r\n    }\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_nullCloakedPaths() {\r\n        final List<String> changesetPaths = Arrays.asList(\"$/foo\", \"$/foo/bar.baz\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, null);\r\n\r\n        Assert.assertEquals(false, actual);\r\n    }\r\n\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_independentCloakedPaths() {\r\n        final List<String> changesetPaths = Arrays.asList(\"$/foo\", \"$/foo/bar.baz\");\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/fizz\", \"$/fizz/FizzBuzz.java\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, cloakedPaths);\r\n\r\n        Assert.assertEquals(false, actual);\r\n    }\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_caseInsensitiveCloakedPaths() {\r\n        final List<String> changesetPaths = Arrays.asList(\"$/foo/bar/test.baz\");\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/fOo/bAr/\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, cloakedPaths);\r\n\r\n        Assert.assertEquals(true, actual);\r\n    }\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_cloakingChild() {\r\n        final List<String> changesetPaths = Arrays.asList(\"$/foo\", \"$/foo/bar.baz\");\r\n        final List<String> cloakedPaths = Collections.singletonList(\"$/foo/bar.baz\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, cloakedPaths);\r\n\r\n        Assert.assertEquals(false, actual);\r\n    }\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_partiallyCloakedPaths() {\r\n        final List<String> changesetPaths = Arrays.asList(\"$/foo\", \"$/bar\");\r\n        final List<String> cloakedPaths = Collections.singletonList(\"$/foo\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, cloakedPaths);\r\n\r\n        Assert.assertEquals(false, actual);\r\n    }\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_fullyCloakedPath() {\r\n        final List<String> changesetPaths = Arrays.asList(\"$/foo\", \"$/foo/bar.baz\");\r\n        final List<String> cloakedPaths = Collections.singletonList(\"$/foo\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, cloakedPaths);\r\n\r\n        Assert.assertEquals(true, actual);\r\n    }\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_fullyCloakedPaths() {\r\n        final List<String> changesetPaths = Collections.singletonList(\"$/foo/bar.baz\");\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/foo\", \"$/bar\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, cloakedPaths);\r\n\r\n        Assert.assertEquals(true, actual);\r\n    }\r\n\r\n    @Test\r\n    public void isChangesetFullyCloaked_manyToMany() {\r\n        final List<String> changesetPaths = Arrays.asList(\"$/foo/bar.baz\", \"$/bar/foo.baz\");\r\n        final List<String> cloakedPaths = Arrays.asList(\"$/foo\", \"$/bar\");\r\n\r\n        final boolean actual = Project.isChangesetFullyCloaked(changesetPaths, cloakedPaths);\r\n\r\n        Assert.assertEquals(true, actual);\r\n    }\r\n\r\n    @Category(IntegrationTests.class)\r\n    @Test public void getDetailedHistory_singleVersionSpec() throws URISyntaxException, IOException {\r\n        final IntegrationTestHelper helper = new IntegrationTestHelper();\r\n        final String serverUrl = helper.getServerUrl();\r\n        final String userName = helper.getUserName();\r\n        final String userPassword = helper.getUserPassword();\r\n        final Server server = new Server(null, null, serverUrl, userName, userPassword, null, ExtraSettings.DEFAULT);\r\n        try {\r\n            final Project project = new Project(server, \"$/FunctionalTests\");\r\n            final UserLookup userLookup = mock(UserLookup.class);\r\n            final User fakeUser = mock(User.class);\r\n            when(userLookup.find(isA(String.class))).thenReturn(fakeUser);\r\n            project.setUserLookup(userLookup);\r\n            final MockableVersionControlClient vcc = server.getVersionControlClient();\r\n            final int latestChangesetID = vcc.getLatestChangesetID();\r\n            final ChangesetVersionSpec spec = new ChangesetVersionSpec(latestChangesetID);\r\n            final String singleVersionSpecString = RemoteChangesetVersionCommand.toString(spec);\r\n\r\n            final List<ChangeSet> actual = project.getDetailedHistory(singleVersionSpecString);\r\n\r\n            Assert.assertEquals(1, actual.size());\r\n            final ChangeSet changeSet = actual.get(0);\r\n            final String latestChangesetString = Integer.toString(latestChangesetID, 10);\r\n            Assert.assertEquals(latestChangesetString, changeSet.getVersion());\r\n        }\r\n        finally {\r\n            server.close();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/PullRequestMergeCommitCreatedEventArgsTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link PullRequestMergeCommitCreatedEventArgs}.\r\n */\r\npublic class PullRequestMergeCommitCreatedEventArgsTest {\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/ServerIntegrationTest.java",
    "content": "package hudson.plugins.tfs.model;\n\nimport org.jvnet.hudson.test.JenkinsRule;\nimport org.junit.Rule;\nimport org.junit.Test;\n\nimport com.microsoft.tfs.core.TFSTeamProjectCollection;\nimport com.microsoft.tfs.core.exceptions.TECoreException;\n\nimport java.io.IOException;\n\npublic class ServerIntegrationTest {\n\n    @Rule public JenkinsRule j = new JenkinsRule();\n\n    @Test(expected = TECoreException.class)\n    /**\n     * It's OK for this test to throw a TECoreException for \"unknown host\";\n     * it means we were able to load the native libraries,\n     * otherwise an @link UnsatisfiedLinkError would have been thrown earlier.\n     */\n    public void canFindTfsSdkNativeLibraries() throws IOException {\n        final Server server = new Server(null, null, \"http://tfs.invalid:8080/tfs\", \"username\", \"password\");\n        try {\n            server.getVersionControlClient();\n        } finally {\n            server.close();\n        }\n    }\n}\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/ServerTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport static org.junit.Assert.*;\r\n\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\nimport org.mockito.MockitoAnnotations;\r\n\r\nimport java.io.IOException;\r\n\r\npublic class ServerTest {\r\n\r\n    @Before\r\n    public void setup() {\r\n        MockitoAnnotations.initMocks(this);\r\n    }\r\n\r\n    static Server createServer() throws IOException {\r\n        return new Server(null, null, \"url\", null, null, null, ExtraSettings.DEFAULT);\r\n    }\r\n\r\n    @Test\r\n    public void assertGetWorkspacesReturnSameObject() throws IOException {\r\n        Server server = createServer();\r\n        assertNotNull(\"Workspaces object can not be null\", server.getWorkspaces());\r\n        assertSame(\"getWorkspaces() returned different objects\", server.getWorkspaces(), server.getWorkspaces());\r\n    }\r\n\r\n    @Test\r\n    public void assertGetProjectWithSameProjectPathReturnsSameInstance() throws IOException {\r\n        Server server = createServer();\r\n        assertNotNull(\"Project object can not be null\", server.getProject(\"$/projectPath\"));\r\n        assertSame(\"getProject() returned different objects\", \r\n                server.getProject(\"$/projectPath\"), server.getProject(\"$/projectPath\"));\r\n    }\r\n    \r\n    @Test\r\n    public void assertGetProjectWithDifferentProjectPathReturnsNotSameInstance() throws IOException {\r\n        Server server = createServer();\r\n        assertNotSame(\"getProject() did not return different objects\", \r\n                server.getProject(\"$/projectPath\"), server.getProject(\"$/otherPath\"));\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/TeamGitStatusTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport hudson.plugins.tfs.util.TeamRestClient;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link TeamGitStatus}.\r\n */\r\npublic class TeamGitStatusTest {\r\n\r\n    @Test public void toJson_typical() {\r\n        final TeamGitStatus cut = new TeamGitStatus();\r\n        cut.state = GitStatusState.Pending;\r\n        cut.description = \"The build is in progress\";\r\n        cut.targetUrl = \"https://ci.fabrikam.com/my-project/build/124\";\r\n        cut.context = new GitStatusContext(\"Build124\", \"continuous-integration\");\r\n\r\n        final String actual = cut.toJson();\r\n\r\n        final String expected =\r\n            \"{\" +\r\n                \"\\\"state\\\":\\\"Pending\\\",\" +\r\n                \"\\\"description\\\":\\\"The build is in progress\\\",\" +\r\n                \"\\\"targetUrl\\\":\\\"https://ci.fabrikam.com/my-project/build/124\\\",\" +\r\n                \"\\\"context\\\":\" +\r\n                \"{\" +\r\n                    \"\\\"name\\\":\\\"Build124\\\",\" +\r\n                    \"\\\"genre\\\":\\\"continuous-integration\\\"\" +\r\n                \"}\" +\r\n            \"}\";\r\n        Assert.assertEquals(expected, actual);\r\n    }\r\n\r\n    @Test public void fromJsonString_server() throws Exception {\r\n        final String input =\r\n            \"{\" +\r\n                \"\\\"state\\\":\\\"succeeded\\\",\" +\r\n                \"\\\"description\\\":\\\"SUCCESS\\\",\" +\r\n                \"\\\"targetUrl\\\":\\\"https://ci.fabrikam.com/my-project/build/124\\\",\" +\r\n                \"\\\"context\\\":\" +\r\n                \"{\" +\r\n                    \"\\\"name\\\":\\\"Build124\\\",\" +\r\n                    \"\\\"genre\\\":\\\"continuous-integration\\\"\" +\r\n                \"}\" +\r\n            \"}\";\r\n\r\n        final TeamGitStatus actual = TeamRestClient.deserialize(TeamGitStatus.class, input);\r\n\r\n        Assert.assertEquals(GitStatusState.Succeeded, actual.state);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/WorkspaceConfigurationTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport static org.hamcrest.CoreMatchers.*;\r\nimport static org.junit.Assert.*;\r\n\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\nimport org.junit.Test;\r\n\r\npublic class WorkspaceConfigurationTest {\r\n\r\n    private static final List<String> EMPTY_CLOAKED_PATHS_LIST = Collections.emptyList();\r\n\r\n    @Test public void assertConfigurationsEquals() {\r\n        final List<String> cloakList = Collections.singletonList(\"cloak\");\r\n\r\n        WorkspaceConfiguration one = new WorkspaceConfiguration(\"server\", \"workspace\", \"project\", cloakList, \"workfolder\");\r\n        WorkspaceConfiguration two = new WorkspaceConfiguration(\"server\", \"workspace\", \"project\", cloakList, \"workfolder\");\r\n        assertThat(one, is(two));\r\n        assertThat(two, is(one));\r\n        assertThat(one, is(one));\r\n        assertThat(one, not(new WorkspaceConfiguration(\"aserver\", \"workspace\", \"project\", cloakList, \"workfolder\")));\r\n        assertThat(one, not(new WorkspaceConfiguration(\"server\", \"aworkspace\", \"project\", cloakList, \"workfolder\")));\r\n        assertThat(one, not(new WorkspaceConfiguration(\"server\", \"workspace\", \"aproject\", cloakList, \"workfolder\")));\r\n        assertThat(one, not(new WorkspaceConfiguration(\"server\", \"workspace\", \"project\", cloakList, \"aworkfolder\")));\r\n        assertThat(one, not(new WorkspaceConfiguration(\"server\", \"workspace\", \"project\", EMPTY_CLOAKED_PATHS_LIST, \"workfolder\")));\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/WorkspacesTest.java",
    "content": "package hudson.plugins.tfs.model;\r\n\r\nimport java.io.IOException;\r\nimport java.io.Reader;\r\nimport java.io.StringReader;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\nimport hudson.plugins.tfs.commands.ListWorkspacesCommand;\r\n\r\nimport static org.junit.Assert.*;\r\nimport static org.mockito.Matchers.*;\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport hudson.remoting.Callable;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\nimport org.mockito.Mock;\r\nimport org.mockito.MockitoAnnotations;\r\n\r\npublic class WorkspacesTest {\r\n\r\n    private static final List<String> EMPTY_CLOAKED_PATHS_LIST = Collections.emptyList();\r\n\r\n    @Mock private Server server;\r\n    private ListWorkspacesCommand parser;\r\n    \r\n    @Before\r\n    public void setup() {\r\n        MockitoAnnotations.initMocks(this);\r\n        parser = new ListWorkspacesCommand(server);\r\n    }\r\n\r\n    private List<Workspace> parse(final String s) throws IOException {\r\n        final Reader reader = new StringReader(s);\r\n        return parser.parse(reader);\r\n    }\r\n\r\n    @Test\r\n    public void assertListFromServerIsParsedProperly() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(parse(\r\n                \"--------- -------------- -------- ----------------------------------------------------------------------------------------------------------\\n\" +\r\n                \"\\n\" +\r\n                \"name1     SND\\\\redsolo_cp COMPUTER\\n\"));\r\n        \r\n        Workspaces workspaces = new Workspaces(server);\r\n        Workspace workspace = workspaces.getWorkspace(\"name1\");\r\n        assertNotNull(\"Workspace was null\", workspace);\r\n    }\r\n    \r\n    @Test\r\n    public void assertListFromServerIsRetrievedOnce() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(parse(\r\n                \"--------- -------------- -------- ----------------------------------------------------------------------------------------------------------\\n\" +\r\n                \"\\n\" +\r\n                \"name1     SND\\\\redsolo_cp COMPUTER\\n\"));\r\n        \r\n        Workspaces workspaces = new Workspaces(server);\r\n        Workspace workspace = workspaces.getWorkspace(\"name1\");\r\n        assertNotNull(\"Workspace was null\", workspace);\r\n        workspace = workspaces.getWorkspace(\"name1\");\r\n        assertNotNull(\"Workspace was null\", workspace);\r\n        \r\n        verify(server, times(1)).execute(isA(Callable.class));\r\n    }\r\n\r\n    @Test\r\n    public void assertExistsWorkspace() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(parse(\r\n                \"--------- -------------- -------- ----------------------------------------------------------------------------------------------------------\\n\" +\r\n                \"\\n\" +\r\n                \"name1     SND\\\\redsolo_cp COMPUTER\\n\"));\r\n        \r\n        Workspaces workspaces = new Workspaces(server);\r\n        assertTrue(\"The workspace was reported as non existant\", workspaces.exists(new Workspace(\"name1\")));\r\n    }\r\n\r\n    @Test\r\n    public void assertWorkspaceExistsWithOnlyName() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(parse(\r\n                \"--------- -------------- -------- ----------------------------------------------------------------------------------------------------------\\n\" +\r\n                \"\\n\" +\r\n                \"name1     SND\\\\redsolo_cp COMPUTER\\n\"));\r\n        \r\n        Workspaces workspaces = new Workspaces(server);\r\n        assertTrue(\"The workspace was reported as non existant\", workspaces.exists(\"name1\"));\r\n    }\r\n\r\n    @Test\r\n    public void assertNewWorkspaceIsAddedToMap() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(null);\r\n        \r\n        Workspaces workspaces = new Workspaces(server);\r\n        Workspace workspace = workspaces.newWorkspace(\"name1\", null, EMPTY_CLOAKED_PATHS_LIST, null);\r\n        assertNotNull(\"The new workspace was null\", workspace);\r\n        assertTrue(\"The workspace was reported as non existant\", workspaces.exists(workspace));\r\n    }\r\n\r\n    @Test\r\n    public void assertGettingNewWorkspaceIsNotRetrievingServerList() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(null);\r\n        \r\n        Workspaces workspaces = new Workspaces(server);\r\n        workspaces.newWorkspace(\"name1\", null, EMPTY_CLOAKED_PATHS_LIST, null);\r\n        assertNotNull(\"The get new workspace returned null\", workspaces.getWorkspace(\"name1\"));\r\n        verify(server, times(1)).execute(isA(Callable.class));\r\n    }\r\n\r\n    @Test\r\n    public void assertNewWorkspaceExistsIsNotRetrievingServerList() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(null);\r\n        \r\n        Workspaces workspaces = new Workspaces(server);\r\n        Workspace workspace = workspaces.newWorkspace(\"name1\", null, EMPTY_CLOAKED_PATHS_LIST, null);\r\n        assertTrue(\"The get new workspace did not exists\", workspaces.exists(workspace));\r\n        verify(server, times(1)).execute(isA(Callable.class));\r\n    }\r\n\r\n    @Test\r\n    public void assertWorkspaceIsDeletedFromMap() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(parse(\"\"));\r\n        Workspaces workspaces = new Workspaces(server);\r\n        // Populate the map in test object\r\n        assertFalse(\"The workspace was reported as existant\", workspaces.exists(new Workspace(\"name\")));\r\n        Workspace workspace = workspaces.newWorkspace(\"name\", null, EMPTY_CLOAKED_PATHS_LIST, null);\r\n        assertTrue(\"The workspace was reported as non existant\", workspaces.exists(new Workspace(\"name\")));\r\n        workspaces.deleteWorkspace(workspace);\r\n        assertFalse(\"The workspace was reported as existant\", workspaces.exists(workspace));\r\n    }\r\n    \r\n    @Test\r\n    public void assertGetUnknownWorkspaceReturnsNull() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(parse(\"\"));\r\n        Workspaces workspaces = new Workspaces(server);\r\n        assertNull(\"The unknown workspace was not null\", workspaces.getWorkspace(\"name1\"));\r\n    }\r\n    \r\n    @Test\r\n    public void assertUnknownWorkspaceDoesNotExists() throws Exception {\r\n        when(server.execute(isA(Callable.class))).thenReturn(parse(\"\"));\r\n        Workspaces workspaces = new Workspaces(server);\r\n        assertFalse(\"The unknown workspace was reported as existing\", workspaces.exists(new Workspace(\"name1\")));\r\n    }\r\n    \r\n    @Test\r\n    public void assertWorkspaceFactory() {        \r\n        ListWorkspacesCommand.WorkspaceFactory factory = new Workspaces(server);\r\n        Workspace workspace = factory.createWorkspace(\"name\", \"computer\", \"owner\", \"comment\");\r\n        assertEquals(\"Workspace name was incorrect\", \"name\", workspace.getName());\r\n        assertEquals(\"Workspace comment was incorrect\", \"comment\", workspace.getComment());\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/model/servicehooks/EventScopeTest.java",
    "content": "package hudson.plugins.tfs.model.servicehooks;\r\n\r\nimport hudson.plugins.tfs.util.EndpointHelper;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link EventScope}.\r\n */\r\npublic class EventScopeTest {\r\n\r\n    @Test\r\n    public void deserialize_enumCasing() throws Exception {\r\n        final String input = \"{\\\"scope\\\": \\\"all\\\"}\";\r\n\r\n        final Event actual = EndpointHelper.MAPPER.readValue(input, Event.class);\r\n\r\n        Assert.assertEquals(EventScope.All, actual.getScope());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/BuildVariableResolverTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport static org.junit.Assert.*;\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport java.io.IOException;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\nimport hudson.EnvVars;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.AbstractProject;\r\nimport hudson.model.Computer;\r\n\r\nimport hudson.model.TaskListener;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\nimport org.mockito.Mock;\r\nimport org.mockito.MockitoAnnotations;\r\n\r\n@SuppressWarnings(\"unchecked\")\r\npublic class BuildVariableResolverTest {\r\n\r\n    @Mock private AbstractProject<?, ?> project;\r\n    @Mock private Computer computer;\r\n    @Mock private AbstractBuild build;\r\n\r\n    @Before public void before() throws Exception {\r\n        MockitoAnnotations.initMocks(this);\r\n    }\r\n\r\n    @Test public void assertConstructorBuildUsesProject() throws IOException, InterruptedException {\r\n        when(build.getProject()).thenReturn(project);\r\n        new BuildVariableResolver(build, computer);\r\n        verify(build).getProject();\r\n        verifyZeroInteractions(project);\r\n        verifyZeroInteractions(computer);\r\n    }\r\n    \r\n    @Test public void assertJobNameIsResolved() {\r\n        when(project.getName()).thenReturn(\"ThisIsAJob\");\r\n\r\n        BuildVariableResolver resolver = new BuildVariableResolver(project, computer);\r\n        assertEquals(\"Variable resolution was incorrect\", \"ThisIsAJob\", resolver.resolve(\"JOB_NAME\"));\r\n        verifyZeroInteractions(computer);\r\n    }\r\n    \r\n    @Test public void assertJobNameWithoutComputerIsResolved() {\r\n        when(project.getName()).thenReturn(\"ThisIsAJob\");\r\n\r\n        BuildVariableResolver resolver = new BuildVariableResolver(project);\r\n        assertEquals(\"Variable resolution was incorrect\", \"ThisIsAJob\", resolver.resolve(\"JOB_NAME\"));\r\n        assertNull(\"Variable resolution was performed\", resolver.resolve(\"NONE_EXISTING_KEY\"));\r\n    }\r\n    \r\n    @Test public void assertComputerEnvVarIsResolved() throws Exception {\r\n        EnvVars map = new EnvVars();\r\n        map.put(\"ENV_VAR\", \"This is an env var\");\r\n        \r\n        when(computer.getEnvironment()).thenReturn(map);\r\n\r\n        BuildVariableResolver resolver = new BuildVariableResolver(project, computer);\r\n        assertEquals(\"Variable resolution was incorrect\", \"This is an env var\", resolver.resolve(\"ENV_VAR\"));\r\n        verifyZeroInteractions(project);\r\n    }\r\n    \r\n    @Test public void assertComputerUserNameIsResolved() throws Exception {\r\n        Map<Object, Object> map = new HashMap<Object, Object>();\r\n        map.put(\"user.name\", \"Other_user\");\r\n        \r\n        when(computer.getSystemProperties()).thenReturn(map);\r\n\r\n        BuildVariableResolver resolver = new BuildVariableResolver(project, computer);\r\n        assertEquals(\"Variable resolution was incorrect\", \"Other_user\", resolver.resolve(\"USER_NAME\"));\r\n        verifyZeroInteractions(project);\r\n    }\r\n    \r\n    @Test public void assertNodeNameIsResolved() {\r\n        when(computer.getName()).thenReturn(\"AKIRA\");\r\n        \r\n        BuildVariableResolver resolver = new BuildVariableResolver(project, computer);\r\n        assertEquals(\"Variable resolution was incorrect\", \"AKIRA\", resolver.resolve(\"NODE_NAME\"));\r\n        verifyZeroInteractions(project);\r\n    }\r\n    \r\n    /**\r\n     * Asserts that NODE_NAME works on the master computer, as the MasterComputer.getName() returns null.\r\n     */\r\n    @Test public void assertMasterNodeNameIsResolved() {\r\n        when(computer.getName()).thenReturn(\"\");\r\n        \r\n        BuildVariableResolver resolver = new BuildVariableResolver(project, computer);\r\n        assertEquals(\"Variable resolution was incorrect\", \"MASTER\", resolver.resolve(\"NODE_NAME\"));\r\n        verifyZeroInteractions(project);\r\n    }\r\n    \r\n    @Test public void assertNoComputeraDoesNotThrowNPEWhenResolvingNodeName() {\r\n        BuildVariableResolver resolver = new BuildVariableResolver(project);\r\n        assertNull(\"Variable resolution was incorrect\", resolver.resolve(\"NODE_NAME\"));\r\n        verifyZeroInteractions(project);\r\n    }\r\n    \r\n    @Test public void assertBuildEnvVarIsResolved() throws Exception {\r\n        EnvVars map = new EnvVars();\r\n        map.put(\"BUILD_ID\", \"121212\");\r\n\r\n        when(build.getProject()).thenReturn(project);\r\n        when(build.getEnvironment(TaskListener.NULL)).thenReturn(map);\r\n\r\n        BuildVariableResolver resolver = new BuildVariableResolver(build, computer);\r\n        assertEquals(\"Variable resolution was incorrect\", \"121212\", resolver.resolve(\"BUILD_ID\"));\r\n        verify(build).getEnvironment(TaskListener.NULL);\r\n        verifyZeroInteractions(project);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/BuildWorkspaceConfigurationRetrieverTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport static org.hamcrest.CoreMatchers.*;\r\nimport static org.junit.Assert.*;\r\nimport static org.mockito.Mockito.*;\r\n\r\nimport java.io.IOException;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.Node;\r\nimport hudson.model.Run;\r\nimport hudson.plugins.tfs.model.WorkspaceConfiguration;\r\nimport hudson.plugins.tfs.util.BuildWorkspaceConfigurationRetriever.BuildWorkspaceConfiguration;\r\n\r\nimport org.junit.Test;\r\nimport org.jvnet.hudson.test.Bug;\r\n\r\n@SuppressWarnings(\"unchecked\")\r\npublic class BuildWorkspaceConfigurationRetrieverTest {\r\n\r\n    private static final List<String> EMPTY_CLOAKED_PATHS_LIST = Collections.emptyList();\r\n\r\n    @Test\r\n    public void assertGetLatestConfgiurationOnNode() {\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        Node node = mock(Node.class);\r\n        Node needleNode = mock(Node.class);\r\n        WorkspaceConfiguration configuration = new WorkspaceConfiguration(\"serverUrl\", \"workspaceName\", \"projectPath\", EMPTY_CLOAKED_PATHS_LIST, \"workfolder\");\r\n        when(build.getPreviousBuild()).thenReturn(build).thenReturn(null);\r\n        when(build.getBuiltOn()).thenReturn(node, node, null);\r\n        when(node.getNodeName()).thenReturn(\"node1\", \"needleNode\");\r\n        when(needleNode.getNodeName()).thenReturn(\"needleNode\", \"needleNode\");\r\n        when(build.getAction(WorkspaceConfiguration.class)).thenReturn(configuration);\r\n        \r\n        assertThat( new BuildWorkspaceConfigurationRetriever().getLatestForNode(needleNode, build), equalTo(configuration));\r\n        \r\n        verify(build, times(2)).getBuiltOn();\r\n        verify(node, times(2)).getNodeName();\r\n        verify(build).getPreviousBuild();\r\n        verify(build).getAction(WorkspaceConfiguration.class);\r\n        verifyNoMoreInteractions(node);\r\n        verifyNoMoreInteractions(build);  \r\n    }\r\n    \r\n    @Test\r\n    public void assertGetLatestConfgiurationOnNodeWithNoPrevioudBuild() {\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        Node node = mock(Node.class);\r\n        Node needleNode = mock(Node.class);\r\n        when(build.getPreviousBuild()).thenReturn(null);\r\n        when(build.getBuiltOn()).thenReturn(node);\r\n        when(node.getNodeName()).thenReturn(\"node1\");\r\n        when(needleNode.getNodeName()).thenReturn(\"needleNode\");\r\n        \r\n        BuildWorkspaceConfigurationRetriever retriever = new BuildWorkspaceConfigurationRetriever();\r\n        assertThat( retriever.getLatestForNode(needleNode, build), nullValue());\r\n        \r\n        verify(build).getBuiltOn();\r\n        verify(node).getNodeName();\r\n        verify(build).getPreviousBuild();\r\n        verifyNoMoreInteractions(node);\r\n        verifyNoMoreInteractions(build);  \r\n    }\r\n    \r\n    @Test\r\n    public void assertGetLatestConfigurationOnNodeWithNoPrevioudScmConfiguration() {\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        Node node = mock(Node.class);\r\n        Node needleNode = mock(Node.class);\r\n        when(build.getBuiltOn()).thenReturn(node);\r\n        when(node.getNodeName()).thenReturn(\"needleNode\");\r\n        when(needleNode.getNodeName()).thenReturn(\"needleNode\");\r\n        \r\n        assertThat( new BuildWorkspaceConfigurationRetriever().getLatestForNode(needleNode, build), nullValue());\r\n        \r\n        verify(build).getBuiltOn();\r\n        verify(node).getNodeName();\r\n        verify(build).getAction(WorkspaceConfiguration.class);\r\n        verifyNoMoreInteractions(node);\r\n        verifyNoMoreInteractions(build);  \r\n    }\r\n    \r\n    @Test\r\n    public void assertGetLatestConfgiurationOnNodeWithNoAbstractBuild() {\r\n        Run run = mock(Run.class);\r\n        Node node = mock(Node.class);\r\n        assertThat( new BuildWorkspaceConfigurationRetriever().getLatestForNode(node, run), nullValue());\r\n        verifyNoMoreInteractions(run);\r\n        verifyNoMoreInteractions(node);\r\n    }\r\n\r\n    @Test\r\n    public void assertSaveWorkspaceConfigurationUsesSaveOnBuild() throws IOException {\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        Node node = mock(Node.class);\r\n        when(build.getPreviousBuild()).thenReturn(build);\r\n        when(build.getBuiltOn()).thenReturn(node);\r\n        when(node.getNodeName()).thenReturn(\"needleNode\");\r\n        when(build.getAction(WorkspaceConfiguration.class)).thenReturn(new WorkspaceConfiguration(\"serverUrl\", \"workspaceName\", \"projectPath\", EMPTY_CLOAKED_PATHS_LIST, \"workfolder\"));\r\n        \r\n        BuildWorkspaceConfiguration configuration = new BuildWorkspaceConfigurationRetriever().getLatestForNode(node, build);\r\n        assertThat( configuration.getWorkspaceName(), is(\"workspaceName\"));\r\n        configuration.save();\r\n        \r\n        verify(build).save();  \r\n    }\r\n    \r\n    @Bug(8322)\r\n    @Test\r\n    public void assertGetLatestConfgiurationOnPreviousDeletedNode() {\r\n        AbstractBuild build = mock(AbstractBuild.class);\r\n        Node node = mock(Node.class);\r\n        Node needleNode = mock(Node.class);\r\n        WorkspaceConfiguration configuration = new WorkspaceConfiguration(\"serverUrl\", \"workspaceName\", \"projectPath\", EMPTY_CLOAKED_PATHS_LIST, \"workfolder\");\r\n        when(build.getPreviousBuild()).thenReturn(build).thenReturn(null);\r\n        when(build.getBuiltOn()).thenReturn(null);\r\n\r\n\r\n        assertThat( new BuildWorkspaceConfigurationRetriever().getLatestForNode(needleNode, build), nullValue());  \r\n    }\r\n }\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/DateUtilTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport com.microsoft.tfs.core.clients.versioncontrol.specs.version.DateVersionSpec;\r\nimport hudson.plugins.tfs.Util;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\nimport java.util.Calendar;\r\nimport java.util.Date;\r\n\r\npublic class DateUtilTest {\r\n\r\n    private static final Calendar fixedPointInTime = Util.getCalendar(2013, 07, 02, 15, 40, 50);\r\n    private static final DateVersionSpec dateVersionSpec = new DateVersionSpec(fixedPointInTime);\r\n\r\n    @Test\r\n    public void toString_date() throws Exception {\r\n        final String actual = DateUtil.toString(new Date(1372779650000L));\r\n\r\n        Assert.assertEquals(\"D2013-07-02T15:40:50Z\", actual);\r\n    }\r\n\r\n    @Test\r\n    public void toString_calendar() throws Exception {\r\n        final String actual = DateUtil.toString(fixedPointInTime);\r\n\r\n        Assert.assertEquals(\"D2013-07-02T15:40:50Z\", actual);\r\n    }\r\n\r\n    @Test\r\n    public void toString_dateVersionSpec() throws Exception {\r\n        final String actual = DateUtil.toString(dateVersionSpec);\r\n\r\n        Assert.assertEquals(\"D2013-07-02T15:40:50Z\", actual);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/KeyValueTextReaderTest.java",
    "content": "package hudson.plugins.tfs.util;\n\nimport static org.junit.Assert.*;\nimport static org.hamcrest.CoreMatchers.*;\n\nimport java.util.Map;\nimport org.junit.Test;\n\npublic class KeyValueTextReaderTest {\n\n\t@Test\n\tpublic void assertKeysAreRead() throws Exception {\n\t\tMap<String, String> map = new KeyValueTextReader().parse(\"Key:Data\\nOtherKey:  More data\");\n\t\tassertThat(map.get(\"Key\"), is(\"Data\"));\n\t\tassertThat(map.get(\"OtherKey\"), is(\"More data\"));\n\t}\n\t\n\t@Test\n\tpublic void assertValueIsTrimmed() throws Exception {\n\t\tMap<String, String> map = new KeyValueTextReader().parse(\"Changeset: 12492\");\n\t\tassertThat(map.get(\"Changeset\"), is(\"12492\"));\n\t}\n\t\n\t@Test\n\tpublic void assertKeyContainsSpace() throws Exception {\n\t\tMap<String, String> map = new KeyValueTextReader().parse(\"Change set: 12492\");\n\t\tassertThat(map.get(\"Change set\"), is(\"12492\"));\n\t}\n\t\n\t@Test\n\tpublic void assertMultilineDataIsRead() throws Exception {\n\t\tMap<String, String> map = new KeyValueTextReader().parse(\"Key:Data\\n  Some more information\");\n\t\tassertThat(map.get(\"Key\"), is(\"Data\\nSome more information\"));\n\t}\n\t\n\t@Test\n\tpublic void asserOnlyKeyIsReadIfValueContainsColon() throws Exception {\n\t\tMap<String, String> map = new KeyValueTextReader().parse(\"Key:Data 23:23:12\");\n\t\tassertThat(map.get(\"Key\"), is(\"Data 23:23:12\"));\n\t}\n\t\n\t@Test\n\tpublic void assertValueBeginingOnNextRowIsParsedWithoutPrefixedEndline() throws Exception {\n\t\tMap<String, String> map = new KeyValueTextReader().parse(\"Comment:\\n  Reviewer: \\n  Approver: \\n\");\n\t\tassertThat(map.get(\"Comment\"), is(\"Reviewer:\\nApprover:\"));\n\t}\n}\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/MaskedArgumentListBuilderTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport static org.junit.Assert.*;\r\nimport hudson.plugins.tfs.Util;\r\n\r\nimport org.junit.Test;\r\n\r\n\r\npublic class MaskedArgumentListBuilderTest {\r\n\r\n    @Test\r\n    public void assertEmptyMask() {\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        builder.add(\"arg\");\r\n        builder.add(\"other\", \"arguments\");\r\n        \r\n        assertFalse(\"There shouldnt be any masked arguments\", builder.hasMaskedArguments());\r\n        boolean[] array = builder.toMaskArray();\r\n        assertNotNull(\"The mask array should not be null\", array);\r\n        assertArrayEquals(\"The mask array was incorrect\", new Boolean[]{false,false,false}, Util.toBoxedArray(array));\r\n    }\r\n    \r\n    @Test\r\n    public void assertLastArgumentIsMasked() {\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        builder.add(\"arg\");\r\n        builder.addMasked(\"ismasked\");\r\n        \r\n        assertTrue(\"There should be masked arguments\", builder.hasMaskedArguments());\r\n        boolean[] array = builder.toMaskArray();\r\n        assertNotNull(\"The mask array should not be null\", array);\r\n        assertArrayEquals(\"The mask array was incorrect\", new Boolean[]{false,true}, Util.toBoxedArray(array));\r\n    }\r\n    \r\n    @Test\r\n    public void assertSeveralMaskedArguments() {\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        builder.add(\"arg\");\r\n        builder.addMasked(\"ismasked\");\r\n        builder.add(\"non masked arg\");\r\n        builder.addMasked(\"ismasked2\");\r\n        \r\n        assertTrue(\"There should be masked arguments\", builder.hasMaskedArguments());\r\n        boolean[] array = builder.toMaskArray();\r\n        assertNotNull(\"The mask array should not be null\", array);\r\n        assertArrayEquals(\"The mask array was incorrect\", new Boolean[]{false,true, false, true}, Util.toBoxedArray(array));\r\n    }\r\n    \r\n    @Test\r\n    public void assertPrependAfterAddingMasked() {\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        builder.addMasked(\"ismasked\");\r\n        builder.add(\"arg\");\r\n        builder.prepend(\"first\", \"second\");\r\n        \r\n        assertTrue(\"There should be masked arguments\", builder.hasMaskedArguments());\r\n        boolean[] array = builder.toMaskArray();\r\n        assertNotNull(\"The mask array should not be null\", array);\r\n        assertArrayEquals(\"The mask array was incorrect\", new Boolean[]{false,false,true,false}, Util.toBoxedArray(array));\r\n    }\r\n    \r\n    @Test\r\n    public void assertPrependBeforeAddingMasked() {\r\n        MaskedArgumentListBuilder builder = new MaskedArgumentListBuilder();\r\n        builder.prepend(\"first\", \"second\");\r\n        builder.addMasked(\"ismasked\");\r\n        builder.add(\"arg\");\r\n        \r\n        assertTrue(\"There should be masked arguments\", builder.hasMaskedArguments());\r\n        boolean[] array = builder.toMaskArray();\r\n        assertNotNull(\"The mask array should not be null\", array);\r\n        assertArrayEquals(\"The mask array was incorrect\", new Boolean[]{false,false,true,false}, Util.toBoxedArray(array));\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/QueryStringTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link QueryString}.\r\n */\r\npublic class QueryStringTest {\r\n\r\n    @Test public void toString_typical() throws Exception {\r\n        final QueryString cut = new QueryString();\r\n        cut.put(\"answer\", \"42\");\r\n\r\n        final String actual = cut.toString();\r\n\r\n        Assert.assertEquals(\"answer=42\", actual);\r\n    }\r\n\r\n    @Test public void constructor_typical() throws Exception {\r\n        //noinspection MismatchedQueryAndUpdateOfCollection\r\n        final QueryString cut = new QueryString(\"answer\", \"42\");\r\n\r\n        final String actual = cut.toString();\r\n\r\n        Assert.assertEquals(\"answer=42\", actual);\r\n    }\r\n\r\n    @Test public void constructor_twoPairs() throws Exception {\r\n        //noinspection MismatchedQueryAndUpdateOfCollection\r\n        final QueryString cut = new QueryString(\"answer\", \"42\", \"question\", \"whatdoyoug\");\r\n\r\n        final String actual = cut.toString();\r\n\r\n        Assert.assertEquals(\"answer=42&question=whatdoyoug\", actual);\r\n    }\r\n\r\n    @Test(expected = IllegalArgumentException.class)\r\n    public void constructor_oddParameters() throws Exception {\r\n        new QueryString(\"answer\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/StringHelperTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\n\r\n/**\r\n * A class to test {@link StringHelper}.\r\n */\r\npublic class StringHelperTest {\r\n\r\n    @Test public void determineContentTypeWithoutCharset_null() throws Exception {\r\n        final String actual = StringHelper.determineContentTypeWithoutCharset(null);\r\n\r\n        Assert.assertEquals(null, actual);\r\n    }\r\n\r\n    @Test public void determineContentTypeWithoutCharset_withoutCharset() throws Exception {\r\n        final String input = \"application/json\";\r\n\r\n        final String actual = StringHelper.determineContentTypeWithoutCharset(input);\r\n\r\n        Assert.assertEquals(\"application/json\", actual);\r\n    }\r\n\r\n    @Test public void determineContentTypeWithoutCharset_withCharset() throws Exception {\r\n        final String input = \"application/json; charset=utf-8\";\r\n\r\n        final String actual = StringHelper.determineContentTypeWithoutCharset(input);\r\n\r\n        Assert.assertEquals(\"application/json\", actual);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/TeamRestClientTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport com.cloudbees.plugins.credentials.CredentialsScope;\r\nimport com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;\r\nimport com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;\r\nimport hudson.plugins.tfs.IntegrationTestHelper;\r\nimport hudson.plugins.tfs.IntegrationTests;\r\nimport hudson.util.SecretOverride;\r\nimport org.junit.After;\r\nimport org.junit.Assert;\r\nimport org.junit.Before;\r\nimport org.junit.Ignore;\r\nimport org.junit.Test;\r\nimport org.junit.experimental.categories.Category;\r\n\r\nimport java.net.URI;\r\n\r\n/**\r\n * A class to test {@link TeamRestClient}.\r\n */\r\npublic class TeamRestClientTest {\r\n\r\n    private SecretOverride secretOverride = null;\r\n\r\n    @Before public void setUp() throws Exception {\r\n        secretOverride = new SecretOverride();\r\n    }\r\n\r\n    @After public void tearDown() throws Exception {\r\n        if (secretOverride != null) {\r\n            secretOverride.close();\r\n        }\r\n    }\r\n\r\n    @Test public void createAuthorization_typical() throws Exception {\r\n        final String personalAccessToken = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";\r\n        final StandardUsernamePasswordCredentials creds = new UsernamePasswordCredentialsImpl(\r\n            CredentialsScope.SYSTEM,\r\n            \"buildAccount\",\r\n            null,\r\n            \"PAT\",\r\n            personalAccessToken);\r\n\r\n        final String actual = TeamRestClient.createAuthorization(creds);\r\n\r\n        Assert.assertEquals(\"Basic UEFUOmFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=\", actual);\r\n    }\r\n\r\n    @Ignore(\"Only works on visualstudio.com due to the use of the Authorization header\")\r\n    @Category(IntegrationTests.class)\r\n    @Test public void ping() throws Exception {\r\n        final IntegrationTestHelper helper = new IntegrationTestHelper();\r\n        final URI collectionUri = new URI(helper.getServerUrl());\r\n        final StandardUsernamePasswordCredentials creds = new UsernamePasswordCredentialsImpl(\r\n                CredentialsScope.SYSTEM,\r\n                \"buildAccount\",\r\n                null,\r\n                helper.getUserName(),\r\n                helper.getUserPassword());\r\n        final TeamRestClient cut = new TeamRestClient(collectionUri, creds);\r\n\r\n        cut.ping();\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/TextTableParserTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport static org.junit.Assert.*;\r\n\r\nimport java.io.StringReader;\r\n\r\nimport org.junit.Test;\r\nimport org.jvnet.hudson.test.Bug;\r\n\r\n\r\npublic class TextTableParserTest {\r\n\r\n    @Test public void assertThatReaderWithoutTableIsParsed() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\"Just some text to be ignored\"));\r\n        assertFalse(\"There should not be any row\", listParser.nextRow());\r\n    }\r\n    \r\n    @Test public void assertColumnCount() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\"Just some text to be ignored\\n\" +\r\n                \"----- -- ------\\n\"));\r\n        assertEquals(\"The column count was incorrect\", 3, listParser.getColumnCount());\r\n    }\r\n    \r\n    @Bug(4666)\r\n    @Test public void assertDashInTextIsIgnored() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\"Server: server-name\\n\" +\r\n                \"----- -- ------\\n\"));\r\n        assertEquals(\"The column count was incorrect\", 3, listParser.getColumnCount());\r\n    }\r\n\r\n    @Test public void assertGetColumn() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\"Just some text to be ignored\\n\" +\r\n                \"----- -- ------\\n\" +\r\n                \"AAAAA BB CCCCCC\"));\r\n        listParser.nextRow();\r\n        assertEquals(\"The column one was incorrect\", \"AAAAA\", listParser.getColumn(0));\r\n        assertEquals(\"The column two was incorrect\", \"BB\", listParser.getColumn(1));\r\n        assertEquals(\"The column three was incorrect\", \"CCCCCC\", listParser.getColumn(2));\r\n    }\r\n\r\n    @Test public void assertNextRow() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\"Just some text to be ignored\\n\" +\r\n                \"----- -- ------\\n\" +\r\n                \"AAAAA BB CCCCCC\\n\" + \r\n                \"LLLLL DD ZZZZZZ\"));\r\n        assertTrue(\"The nextLine() returned false\", listParser.nextRow());\r\n        assertTrue(\"The nextLine() returned false\", listParser.nextRow());\r\n        assertFalse(\"The nextLine() returned true\", listParser.nextRow());\r\n    }\r\n\r\n    @Test public void assertNextRowWithNonsenseLine() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\"Just some text to be ignored\\n\" +\r\n                \"----- -- ------\\n\" +\r\n                \"\\n\" +\r\n                \"AAAAA BB CCCCCC\" +\r\n                \"\\n\" +\r\n                \"AAAAA BB CCCCCC\"));\r\n        assertTrue(\"The nextLine() returned false\", listParser.nextRow());\r\n        assertEquals(\"The column one was incorrect\", \"AAAAA\", listParser.getColumn(0));\r\n        assertTrue(\"The nextLine() returned false\", listParser.nextRow());\r\n        assertFalse(\"The nextLine() returned true\", listParser.nextRow());\r\n    }\r\n\r\n    @Test public void assertGetColumnWorksIfLastcolumnIsShorterThanLastColumnLength() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\"Just some text to be ignored\\n\" +\r\n                \"----- -- ------\\n\" +\r\n                \"AAAAA BB CCC\"));\r\n        listParser.nextRow();\r\n        assertEquals(\"The column one was incorrect\", \"AAAAA\", listParser.getColumn(0));\r\n        assertEquals(\"The column two was incorrect\", \"BB\", listParser.getColumn(1));\r\n        assertEquals(\"The column three was incorrect\", \"CCC\", listParser.getColumn(2));\r\n    }\r\n\r\n    @Test public void assertGetColumnWorksIfColumnIsShorter() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\r\n                \"----- -- ------\\n\" +\r\n                \"AA    BB CCCCCC\"));\r\n        listParser.nextRow();\r\n        assertEquals(\"The column one was incorrect\", \"AA\", listParser.getColumn(0));\r\n    }\r\n\r\n    @Test public void assertTableStartsImmediately() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\r\n                \"----- -- ------\\n\" +\r\n                \"AAAAA BB CCCCCC\"));\r\n        listParser.nextRow();\r\n        assertEquals(\"The column one was incorrect\", \"AAAAA\", listParser.getColumn(0));\r\n        assertEquals(\"The column two was incorrect\", \"BB\", listParser.getColumn(1));\r\n        assertEquals(\"The column three was incorrect\", \"CCCCCC\", listParser.getColumn(2));\r\n    }\r\n\r\n    @Test public void assertNextRowWorksWithOptionalColumns() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\r\n                \"----- -- ------\\n\" +\r\n                \"AAAAA BB\\n\" +\r\n                \"AAAAA BB DDDDDD\"), 1);\r\n        listParser.nextRow();\r\n        assertEquals(\"The column one was incorrect\", \"AAAAA\", listParser.getColumn(0));\r\n        assertEquals(\"The column two was incorrect\", \"BB\", listParser.getColumn(1));\r\n        assertNull(\"The column three was incorrect\", listParser.getColumn(2));\r\n        listParser.nextRow();\r\n        assertEquals(\"The column three was incorrect\", \"DDDDDD\", listParser.getColumn(2));\r\n    }\r\n\r\n    @Test(expected=IllegalStateException.class) public void assertGetColumnAfterLastRowThrowsException() throws Exception {\r\n        TextTableParser listParser = new TextTableParser(new StringReader(\r\n                \"----- -- ------\\n\" +\r\n                \"AAAAA BB\"));\r\n        listParser.nextRow();\r\n        listParser.nextRow();\r\n        listParser.getColumn(0);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/UriHelperTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport org.junit.Assert;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\n\r\nimport java.net.URI;\r\n\r\n/**\r\n * A class to test {@link UriHelper}.\r\n */\r\npublic class UriHelperTest {\r\n\r\n    private QueryString lifeUniverseEverything;\r\n\r\n    @Before public void setUp() {\r\n        lifeUniverseEverything = new QueryString();\r\n        lifeUniverseEverything.put(\"answer\", \"42\");\r\n    }\r\n\r\n    private static void assertSame(final String a, final String b) {\r\n        areSame(a, b, true);\r\n    }\r\n\r\n    private static void assertNotSame(final String a, final String b) {\r\n        areSame(a, b, false);\r\n    }\r\n\r\n    private static void areSame(final String a, final String b, final boolean expected) {\r\n        final URI uriA = a == null ? null : URI.create(a);\r\n        final URI uriB = b == null ? null : URI.create(b);\r\n        final String template = \"Expected '%s' and '%s' to be considered%s the same.\";\r\n        final String message = String.format(template, a, b, expected ? \"\" : \" NOT\");\r\n        Assert.assertEquals(message, expected, UriHelper.areSame(uriA, uriB));\r\n        Assert.assertEquals(message, expected, UriHelper.areSame(uriB, uriA));\r\n    }\r\n\r\n\r\n    @Test public void areSame_bothNull() throws Exception {\r\n        assertSame(null, null);\r\n    }\r\n\r\n    @Test public void areSame_sameInstance() throws Exception {\r\n        final URI uri = URI.create(\"http://one.example.com\");\r\n        Assert.assertTrue(UriHelper.areSame(uri, uri));\r\n    }\r\n\r\n    @Test public void areSame_identity() throws Exception {\r\n        assertSame(\"http://one.example.com\", \"http://one.example.com\");\r\n    }\r\n\r\n    @Test public void areSame_endsWithSlash() throws Exception {\r\n        assertSame(\"http://one.example.com/\", \"http://one.example.com\");\r\n    }\r\n\r\n    @Test public void areSame_schemeCase() throws Exception {\r\n        assertSame(\"http://one.example.com\", \"HTTP://one.example.com\");\r\n    }\r\n\r\n    @Test public void areSame_hostCase() throws Exception {\r\n        assertSame(\"http://ONE.example.com\", \"http://one.example.com\");\r\n    }\r\n\r\n    @Test public void areSame_implicitPort() throws Exception {\r\n        assertSame(\"http://one.example.com\", \"http://one.example.com:80\");\r\n    }\r\n\r\n    @Test public void areSame_withPathSlash() throws Exception {\r\n        assertSame(\"http://one.example.com/path/\", \"http://one.example.com/path/\");\r\n    }\r\n\r\n    @Test public void areSame_withPathWithoutSlash() throws Exception {\r\n        assertSame(\"http://one.example.com/path/\", \"http://one.example.com/path\");\r\n    }\r\n\r\n    @Test public void areSame_withPathQuery() throws Exception {\r\n        assertSame(\"http://one.example.com/search?q=example\", \"http://one.example.com/search?q=example\");\r\n    }\r\n\r\n    @Test public void areSame_withPathQueryFragment() throws Exception {\r\n        assertSame(\"http://one.example.com/search?q=example#top\", \"http://one.example.com/search?q=example#top\");\r\n    }\r\n\r\n\r\n    @Test public void areSame_oneNull() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path/\", null);\r\n    }\r\n\r\n    @Test public void areSame_differentScheme() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path/\", \"https://one.example.com/path/\");\r\n    }\r\n\r\n    @Test public void areSame_differentHost() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path/\", \"http://two.example.com/path/\");\r\n    }\r\n\r\n    @Test public void areSame_differentPort() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path/\", \"http://one.example.com:8080/path/\");\r\n    }\r\n\r\n    @Test public void areSame_differentPath() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path/\", \"http://one.example.com/\");\r\n    }\r\n\r\n    @Test public void areSame_differentQuery() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path?q=example\", \"http://one.example.com/path?q=different\");\r\n    }\r\n\r\n    @Test public void areSame_differentFragment() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path#top\", \"http://one.example.com/path#bottom\");\r\n    }\r\n\r\n    @Test public void areSame_differentFragmentAfterQuery() throws Exception {\r\n\r\n        assertNotSame(\"http://one.example.com/path?q=example#top\", \"http://one.example.com/path?q=example#bottom\");\r\n    }\r\n\r\n\r\n    private static void assertSameGitRepo(final String a, final String b) {\r\n        areSameGitRepo(a, b, true);\r\n    }\r\n\r\n    private static void assertNotSameGitRepo(final String a, final String b) {\r\n        areSameGitRepo(a, b, false);\r\n    }\r\n\r\n    private static void areSameGitRepo(final String a, final String b, final boolean expected) {\r\n        final URI uriA = a == null ? null : URI.create(a);\r\n        final URI uriB = b == null ? null : URI.create(b);\r\n        final String template = \"Expected '%s' and '%s' to be considered%s the same.\";\r\n        final String message = String.format(template, a, b, expected ? \"\" : \" NOT\");\r\n        Assert.assertEquals(message, expected, UriHelper.areSameGitRepo(uriA, uriB) );\r\n        Assert.assertEquals(message, expected, UriHelper.areSameGitRepo(uriB, uriA));\r\n    }\r\n\r\n    @Test public void areSameGitRepo_withoutDefaultCollection() throws Exception {\r\n        assertSameGitRepo(\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/project/_git/repo\",\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_withDefaultCollection() throws Exception {\r\n        assertSameGitRepo(\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/project/_git/repo\",\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_withMixedCaseDefaultCollection() throws Exception {\r\n        assertSameGitRepo(\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/Project/_git/Repo\",\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/defaultcollection/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_differentProject() throws Exception {\r\n        assertNotSameGitRepo(\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/myProject/_git/repo\",\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/othePproject/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_differentRepo() throws Exception {\r\n        assertNotSameGitRepo(\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/project/_git/myRepo\",\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/project/_git/otherRepo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_mixTeamServicesDefaultCollection() throws Exception {\r\n        assertSameGitRepo(\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/project/_git/repo\",\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_mixTfsDefaultCollection() throws Exception {\r\n        assertSameGitRepo(\r\n                \"http://tfs.example.com:8080/tfs/DefaultCollection/project/_git/repo\",\r\n                \"http://tfs.example.com:8080/tfs/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_differentPorts() throws Exception {\r\n        assertNotSameGitRepo(\r\n                \"http://tfs.example.com:8080/tfs/DefaultCollection/project/_git/repo\",\r\n                \"http://tfs.example.com:8081/tfs/DefaultCollection/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_teamServicesDifferentProtocols() throws Exception {\r\n        assertSameGitRepo(\r\n                \"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/project/_git/repo\",\r\n                \"ssh://fabrikam-fiber-inc@fabrikam-fiber-inc.visualstudio.com/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void areSameGitRepo_tfsDifferentProtocols() throws Exception {\r\n        assertSameGitRepo(\r\n                \"http://tfs.example.com:8081/tfs/DefaultCollection/project/_git/repo\",\r\n                \"ssh://tfs.example.com:22/tfs/project/_git/repo\"\r\n        );\r\n    }\r\n\r\n    @Test public void hasPath_hostOnly() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com\");\r\n\r\n        final boolean actual = UriHelper.hasPath(input);\r\n\r\n        Assert.assertEquals(false, actual);\r\n    }\r\n\r\n    @Test public void hasPath_hostSlash() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/\");\r\n\r\n        final boolean actual = UriHelper.hasPath(input);\r\n\r\n        Assert.assertEquals(false, actual);\r\n    }\r\n\r\n    @Test public void hasPath_path() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection\");\r\n\r\n        final boolean actual = UriHelper.hasPath(input);\r\n\r\n        Assert.assertEquals(true, actual);\r\n    }\r\n\r\n    @Test public void hasPath_pathSlash() throws Exception {\r\n        final URI input = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/\");\r\n\r\n        final boolean actual = UriHelper.hasPath(input);\r\n\r\n        Assert.assertEquals(true, actual);\r\n    }\r\n\r\n\r\n    @Test public void join_uriNoSlash_pathComponents() throws Exception {\r\n        final URI collectionUri = URI.create(\"https://fabrikam-fiber-inc.visualstudio.com\");\r\n\r\n        final URI actual = UriHelper.join(collectionUri, \"_home\", \"About\");\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_home/About\"), actual);\r\n    }\r\n\r\n    @Test public void join_noSlash_pathComponents() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com\";\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, \"_home\", \"About\");\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_home/About\"), actual);\r\n    }\r\n\r\n    @Test public void join_withSlash_pathComponents() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, \"_home\", \"About\");\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_home/About\"), actual);\r\n    }\r\n\r\n    @Test public void join_noSlash_queryString() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, lifeUniverseEverything);\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/?answer=42\"), actual);\r\n    }\r\n\r\n    @Test public void join_withSlash_queryString() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, lifeUniverseEverything);\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/?answer=42\"), actual);\r\n    }\r\n\r\n    @Test public void join_noSlash_pathAndQueryString() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, \"_home\", \"About\", lifeUniverseEverything);\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_home/About?answer=42\"), actual);\r\n    }\r\n\r\n    @Test public void join_withSlash_pathAndQueryString() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, \"_home\", \"About\", lifeUniverseEverything);\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_home/About?answer=42\"), actual);\r\n    }\r\n\r\n    @Test public void join_urlEncoding() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, \"_git\", \"Repo Name+With Spaces\");\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_git/Repo%20Name%2BWith%20Spaces\"), actual);\r\n    }\r\n\r\n    @Test public void join_sampleApiCall() throws Exception {\r\n        final String collectionUrl = \"https://fabrikam-fiber-inc.visualstudio.com/\";\r\n        final QueryString qs = new QueryString(\"api-version\", \"2.0\");\r\n\r\n        final URI actual = UriHelper.join(collectionUrl, \"_apis\", \"projects\", qs);\r\n\r\n        Assert.assertEquals(URI.create(\"https://fabrikam-fiber-inc.visualstudio.com/_apis/projects?api-version=2.0\"), actual);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/plugins/tfs/util/XmlHelperTest.java",
    "content": "package hudson.plugins.tfs.util;\r\n\r\nimport org.apache.commons.io.FileUtils;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.junit.Assert;\r\nimport org.junit.Test;\r\nimport org.w3c.dom.Document;\r\nimport org.w3c.dom.Element;\r\nimport org.w3c.dom.Node;\r\n\r\nimport javax.xml.parsers.DocumentBuilder;\r\nimport javax.xml.parsers.DocumentBuilderFactory;\r\nimport javax.xml.xpath.XPath;\r\nimport javax.xml.xpath.XPathConstants;\r\nimport javax.xml.xpath.XPathExpression;\r\nimport javax.xml.xpath.XPathFactory;\r\nimport java.io.BufferedReader;\r\nimport java.io.File;\r\nimport java.io.FileReader;\r\nimport java.io.IOException;\r\nimport java.io.InputStreamReader;\r\nimport java.net.URL;\r\n\r\npublic class XmlHelperTest {\r\n\r\n    @Test public void peekValue_Document() throws Exception {\r\n        final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r\n        final DocumentBuilder db = dbf.newDocumentBuilder();\r\n        final Document doc = db.newDocument();\r\n        // <build>\r\n        final Element root = doc.createElement(\"build\");\r\n            // <queueId>76</queueId>\r\n            final Element queueIdNode = doc.createElement(\"queueId\");\r\n            queueIdNode.appendChild(doc.createTextNode(\"76\"));\r\n            root.appendChild(queueIdNode);\r\n\r\n            // <timestamp>84</timestamp>\r\n            final Element timestampNode = doc.createElement(\"timestamp\");\r\n            timestampNode.appendChild(doc.createTextNode(\"84\"));\r\n            root.appendChild(timestampNode);\r\n        // </build>\r\n        doc.appendChild(root);\r\n\r\n        final String actualFound = XmlHelper.peekValue(doc, \"/build/timestamp\");\r\n\r\n        Assert.assertEquals(\"84\", actualFound);\r\n\r\n        final String actualNotFound = XmlHelper.peekValue(doc, \"/build/startTime\");\r\n\r\n        Assert.assertEquals(null, actualNotFound);\r\n    }\r\n\r\n    @Test public void peekValue_File() throws Exception {\r\n        final Class<? extends XmlHelperTest> clazz = this.getClass();\r\n        final String resourceBase = clazz.getSimpleName() + \"/peekValue_File/\";\r\n        final URL inputUrl = clazz.getResource(resourceBase + \"input.xml\");\r\n        File tmp = null;\r\n        try {\r\n            tmp = File.createTempFile(\"XmlHelperTest\", \"xml\");\r\n            FileUtils.copyURLToFile(inputUrl, tmp);\r\n\r\n            final String actual = XmlHelper.peekValue(tmp, \"/build/timestamp\");\r\n\r\n            Assert.assertEquals(\"1436542800239\", actual);\r\n        } finally {\r\n            FileUtils.deleteQuietly(tmp);\r\n        }\r\n    }\r\n\r\n    @Test public void pokeValue_Document() throws Exception {\r\n        final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r\n        final DocumentBuilder db = dbf.newDocumentBuilder();\r\n        final Document doc = db.newDocument();\r\n        // <build>\r\n        final Element root = doc.createElement(\"build\");\r\n            // <queueId>76</queueId>\r\n            final Element queueIdNode = doc.createElement(\"queueId\");\r\n            queueIdNode.appendChild(doc.createTextNode(\"76\"));\r\n            root.appendChild(queueIdNode);\r\n\r\n            // <timestamp>84</timestamp>\r\n            final Element timestampNode = doc.createElement(\"timestamp\");\r\n            timestampNode.appendChild(doc.createTextNode(\"84\"));\r\n            root.appendChild(timestampNode);\r\n        // </build>\r\n        doc.appendChild(root);\r\n\r\n        XmlHelper.pokeValue(doc, \"/build/timestamp\", \"42\");\r\n\r\n        final XPathFactory xpf = XPathFactory.newInstance();\r\n        final XPath xp = xpf.newXPath();\r\n        final XPathExpression expression = xp.compile(\"/build/timestamp\");\r\n        final Node node = (Node) expression.evaluate(doc, XPathConstants.NODE);\r\n        Assert.assertEquals(\"42\", node.getTextContent());\r\n    }\r\n\r\n    @Test public void pokeValue_File() throws Exception {\r\n        final Class<? extends XmlHelperTest> clazz = this.getClass();\r\n        final String resourceBase = clazz.getSimpleName() + \"/pokeValue_File/\";\r\n        final URL inputUrl = clazz.getResource(resourceBase + \"input.xml\");\r\n        File tmp = null;\r\n        BufferedReader expectedReader = null, actualReader = null;\r\n\r\n        try {\r\n            tmp = File.createTempFile(\"XmlHelperTest\", \"xml\");\r\n            FileUtils.copyURLToFile(inputUrl, tmp);\r\n\r\n            XmlHelper.pokeValue(tmp, \"/build/timestamp\", \"42\");\r\n\r\n            final URL expectedUrl = clazz.getResource(resourceBase + \"expected.xml\");\r\n            expectedReader = new BufferedReader(new InputStreamReader(expectedUrl.openStream()));\r\n            actualReader = new BufferedReader(new FileReader(tmp));\r\n            assertReaders(expectedReader, actualReader);\r\n        } finally {\r\n            FileUtils.deleteQuietly(tmp);\r\n            IOUtils.closeQuietly(expectedReader);\r\n            IOUtils.closeQuietly(actualReader);\r\n        }\r\n    }\r\n\r\n    /* Adapted from http://stackoverflow.com/a/466854/ */\r\n    public static void assertReaders(final BufferedReader expected, final BufferedReader actual)\r\n            throws IOException {\r\n        String expectedLine;\r\n        while ((expectedLine = expected.readLine()) != null) {\r\n            final String actualLine = actual.readLine();\r\n            Assert.assertNotNull(\"Expected had more lines than the actual.\", actualLine);\r\n            Assert.assertEquals(expectedLine, actualLine);\r\n        }\r\n        Assert.assertNull(\"Actual had more lines than the expected.\", actual.readLine());\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/hudson/util/SecretOverride.java",
    "content": "package hudson.util;\r\n\r\nimport jenkins.security.ConfidentialStore;\r\nimport jenkins.security.ConfidentialStoreOverride;\r\n\r\nimport java.io.Closeable;\r\nimport java.io.IOException;\r\n\r\n/**\r\n * Placed in the same package as {@link hudson.util.Secret} to be able to reach\r\n * its package-protected {@link hudson.util.Secret#SECRET} field, which allows\r\n * testing of encryption-using code without needing to launch all of Jenkins.\r\n */\r\npublic class SecretOverride implements Closeable {\r\n\r\n    private static ConfidentialStoreOverride confidentialStoreOverride = null;\r\n\r\n    public static void set(final String secretKey) {\r\n        Secret.SECRET = secretKey;\r\n        if (confidentialStoreOverride != null) {\r\n            try {\r\n                confidentialStoreOverride.close();\r\n            }\r\n            catch (final IOException ignored) {\r\n            }\r\n            confidentialStoreOverride = null;\r\n        }\r\n        if (secretKey != null) {\r\n            confidentialStoreOverride = new ConfidentialStoreOverride();\r\n        }\r\n    }\r\n\r\n    public SecretOverride() {\r\n        this(\"5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006\");\r\n    }\r\n\r\n    public SecretOverride(final String secretKey) {\r\n        set(secretKey);\r\n    }\r\n\r\n    public void close() throws IOException {\r\n        set(null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/java/jenkins/security/ConfidentialStoreOverride.java",
    "content": "package jenkins.security;\r\n\r\nimport hudson.Util;\r\n\r\nimport java.io.Closeable;\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.util.Random;\r\n\r\npublic class ConfidentialStoreOverride implements Closeable {\r\n\r\n    private static final File TEMP_FOLDER;\r\n    private static final ConfidentialStore TEST_CONFIDENTIAL_STORE;\r\n    private static final ThreadLocal<ConfidentialStore> TEST_THREAD_LOCAL;\r\n    private static final Random TEST_RANDOM_SOURCE = new Random(4 /* chosen by fair dice roll */);\r\n\r\n    static {\r\n        try {\r\n            TEMP_FOLDER = new File(Util.createTempDir(), \"jenkins\");\r\n            TEST_CONFIDENTIAL_STORE = new DefaultConfidentialStore(TEMP_FOLDER) {\r\n                public byte[] randomBytes(final int size) {\r\n                    byte[] random = new byte[size];\r\n                    TEST_RANDOM_SOURCE.nextBytes(random);\r\n                    return random;\r\n                }\r\n            };\r\n            TEST_THREAD_LOCAL = new ThreadLocal<ConfidentialStore>(){\r\n                protected ConfidentialStore initialValue() {\r\n                    return TEST_CONFIDENTIAL_STORE;\r\n                }\r\n            };\r\n        }\r\n        catch (final IOException e) {\r\n            throw new Error(e);\r\n        }\r\n        catch (final InterruptedException e) {\r\n            throw new Error(e);\r\n        }\r\n    }\r\n\r\n    public static void set(final ThreadLocal<ConfidentialStore> override) {\r\n        ConfidentialStore.TEST = override;\r\n    }\r\n\r\n    public ConfidentialStoreOverride() {\r\n        this(TEST_THREAD_LOCAL);\r\n    }\r\n\r\n    public ConfidentialStoreOverride(final ThreadLocal<ConfidentialStore> override) {\r\n        set(override);\r\n    }\r\n\r\n    public void close() throws IOException {\r\n        set(null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson>\n  <quietPeriod>360</quietPeriod>\n</hudson>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/hudson.plugins.tfs.TeamFoundationServerScm.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl plugin=\"tfs@3.2.0\">\n  <generation>2</generation>\n</hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/2015-07-15_20-37-42/build.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.model.Cause_-UserIdCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.1.1\">\n      <workspaceName>Hudson-upgradeEncodedPassword-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath></projectPath>\n      <serverUrl></serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n    <hudson.plugins.tfs.TFSRevisionState plugin=\"tfs@3.1.1\">\n      <changesetVersion></changesetVersion>\n      <projectPath></projectPath>\n    </hudson.plugins.tfs.TFSRevisionState>\n  </actions>\n  <timestamp>1437007062000</timestamp>\n  <result>SUCCESS</result>\n  <duration>8897</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn></builtOn>\n  <workspace>upgradeEncodedPassword/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.plugins.tfs.ChangeSetReader\" plugin=\"tfs@3.1.1\"/>\n</build>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/2015-07-15_20-37-42/changelog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<changelog>\r\n</changelog>\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/2015-07-15_20-37-42/log",
    "content": "Started by user \r\n(...)\r\nFinished: SUCCESS\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/lastFailedBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/lastStableBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/lastSuccessfulBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/lastUnstableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/lastUnsuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/builds/legacyIds",
    "content": ""
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<project>\n  <actions/>\n  <description></description>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n  <scm class=\"hudson.plugins.tfs.TeamFoundationServerScm\" plugin=\"tfs@3.2.0\">\n    <serverUrl></serverUrl>\n    <projectPath></projectPath>\n    <localPath>.</localPath>\n    <workspaceName>Hudson-${JOB_NAME}-${COMPUTERNAME}</workspaceName>\n    <password>pmJe5VYJg6gr2BdipI1sMGJScFwmT+pZbz7B2jISBrw=</password>\n    <userName>jenkins-tfs-plugin</userName>\n    <useUpdate>false</useUpdate>\n  </scm>\n  <assignedNode>agent</assignedNode>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <triggers>\n    <hudson.triggers.SCMTrigger>\n      <spec></spec>\n    </hudson.triggers.SCMTrigger>\n  </triggers>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers/>\n  <buildWrappers/>\n</project>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/jobs/agent/nextBuildNumber",
    "content": "1\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/agent/secret.key",
    "content": "5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson>\n  <quietPeriod>360</quietPeriod>\n</hudson>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/hudson.plugins.tfs.TeamFoundationServerScm.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl plugin=\"tfs@3.2.0\">\n  <generation>2</generation>\n</hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/2015-07-15_20-37-42/build.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.model.Cause_-UserIdCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.1.1\">\n      <workspaceName>Hudson-upgradeEncodedPassword-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath></projectPath>\n      <serverUrl></serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n    <hudson.plugins.tfs.TFSRevisionState plugin=\"tfs@3.1.1\">\n      <changesetVersion></changesetVersion>\n      <projectPath></projectPath>\n    </hudson.plugins.tfs.TFSRevisionState>\n  </actions>\n  <timestamp>1437007062000</timestamp>\n  <result>SUCCESS</result>\n  <duration>8897</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn></builtOn>\n  <workspace>upgradeEncodedPassword/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.plugins.tfs.ChangeSetReader\" plugin=\"tfs@3.1.1\"/>\n</build>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/2015-07-15_20-37-42/changelog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<changelog>\r\n</changelog>\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/2015-07-15_20-37-42/log",
    "content": "Started by user \r\n(...)\r\nFinished: SUCCESS\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/lastFailedBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/lastStableBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/lastSuccessfulBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/lastUnstableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/lastUnsuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/builds/legacyIds",
    "content": ""
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<project>\n  <actions/>\n  <description></description>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n  <scm class=\"hudson.plugins.tfs.TeamFoundationServerScm\" plugin=\"tfs@3.2.0\">\n    <serverUrl></serverUrl>\n    <projectPath></projectPath>\n    <localPath>.</localPath>\n    <workspaceName>Hudson-${JOB_NAME}-${COMPUTERNAME}</workspaceName>\n    <password>pmJe5VYJg6gr2BdipI1sMGJScFwmT+pZbz7B2jISBrw=</password>\n    <userName>jenkins-tfs-plugin</userName>\n    <cloakedPaths class=\"list\">\n      <string></string>\n      <string></string>\n    </cloakedPaths>\n    <useUpdate>false</useUpdate>\n  </scm>\n  <assignedNode>master</assignedNode>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <triggers>\n    <hudson.triggers.SCMTrigger>\n      <spec></spec>\n    </hudson.triggers.SCMTrigger>\n  </triggers>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers/>\n  <buildWrappers/>\n</project>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/jobs/cloakedPaths/nextBuildNumber",
    "content": "1\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/cloakedPaths/secret.key",
    "content": "5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson>\n  <quietPeriod>360</quietPeriod>\n</hudson>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/hudson.plugins.tfs.TeamFoundationServerScm.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl plugin=\"tfs@3.2.0\">\n  <generation>2</generation>\n</hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/2015-07-15_20-37-42/build.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.model.Cause_-UserIdCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.1.1\">\n      <workspaceName>Hudson-upgradeEncodedPassword-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath></projectPath>\n      <serverUrl></serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n    <hudson.plugins.tfs.TFSRevisionState plugin=\"tfs@3.1.1\">\n      <changesetVersion></changesetVersion>\n      <projectPath></projectPath>\n    </hudson.plugins.tfs.TFSRevisionState>\n  </actions>\n  <timestamp>1437007062000</timestamp>\n  <result>SUCCESS</result>\n  <duration>8897</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn></builtOn>\n  <workspace>upgradeEncodedPassword/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.plugins.tfs.ChangeSetReader\" plugin=\"tfs@3.1.1\"/>\n</build>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/2015-07-15_20-37-42/changelog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<changelog>\r\n</changelog>\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/2015-07-15_20-37-42/log",
    "content": "Started by user \r\n(...)\r\nFinished: SUCCESS\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/lastFailedBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/lastStableBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/lastSuccessfulBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/lastUnstableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/lastUnsuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/builds/legacyIds",
    "content": ""
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<project>\n  <actions/>\n  <description></description>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n\n  <scm class=\"hudson.plugins.tfs.TeamFoundationServerScm\" plugin=\"tfs@3.2.0\">\n    <serverUrl></serverUrl>\n    <projectPath></projectPath>\n    <localPath>.</localPath>\n    <workspaceName>Hudson-${JOB_NAME}-${COMPUTERNAME}</workspaceName>\n    <password>pmJe5VYJg6gr2BdipI1sMGJScFwmT+pZbz7B2jISBrw=</password>\n    <userName>jenkins-tfs-plugin</userName>\n    <useUpdate>false</useUpdate>\n  </scm>\n  <assignedNode>master</assignedNode>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <triggers/>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers>\n    <hudson.plugins.tfs.TFSLabeler plugin=\"tfs@3.2.0\">\n      <whenToLabel>success</whenToLabel>\n      <labelName></labelName>\n    </hudson.plugins.tfs.TFSLabeler>\n  </publishers>\n  <buildWrappers/>\n</project>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/jobs/createLabel/nextBuildNumber",
    "content": "1\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/createLabel/secret.key",
    "content": "5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson>\n  <quietPeriod>360</quietPeriod>\n</hudson>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/hudson.plugins.tfs.TeamFoundationServerScm.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl plugin=\"tfs@3.2.0\">\n  <generation>2</generation>\n</hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/builds/lastFailedBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/builds/lastStableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/builds/lastSuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/builds/lastUnstableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/builds/lastUnsuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/builds/legacyIds",
    "content": ""
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<project>\n  <actions/>\n  <description></description>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n  <scm class=\"hudson.plugins.tfs.TeamFoundationServerScm\" plugin=\"tfs@3.2.0\">\n    <serverUrl></serverUrl>\n    <projectPath></projectPath>\n    <localPath>.</localPath>\n    <workspaceName>Hudson-${JOB_NAME}-${COMPUTERNAME}</workspaceName>\n    <password>pmJe5VYJg6gr2BdipI1sMGJScFwmT+pZbz7B2jISBrw=</password>\n    <userName>jenkins-tfs-plugin</userName>\n    <useUpdate>false</useUpdate>\n  </scm>\n  <assignedNode>master</assignedNode>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <triggers>\n    <hudson.triggers.SCMTrigger>\n      <spec></spec>\n    </hudson.triggers.SCMTrigger>\n  </triggers>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers/>\n  <buildWrappers/>\n</project>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/jobs/newJob/nextBuildNumber",
    "content": "1\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/newJob/secret.key",
    "content": "5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson>\n  <disabledAdministrativeMonitors/>\n  <version>1.616</version>\n  <numExecutors>1</numExecutors>\n  <mode>EXCLUSIVE</mode>\n  <useSecurity>true</useSecurity>\n  <authorizationStrategy class=\"hudson.security.AuthorizationStrategy$Unsecured\"/>\n  <securityRealm class=\"hudson.security.SecurityRealm$None\"/>\n  <workspaceDir>${ITEM_ROOTDIR}/workspace</workspaceDir>\n  <buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>\n  <jdks/>\n  <viewsTabBar class=\"hudson.views.DefaultViewsTabBar\"/>\n  <myViewsTabBar class=\"hudson.views.DefaultMyViewsTabBar\"/>\n  <clouds/>\n  <quietPeriod>0</quietPeriod>\n  <scmCheckoutRetryCount>0</scmCheckoutRetryCount>\n  <views>\n    <hudson.model.AllView>\n      <owner class=\"hudson\" reference=\"../../..\"/>\n      <name>All</name>\n      <filterExecutors>false</filterExecutors>\n      <filterQueue>false</filterQueue>\n      <properties class=\"hudson.model.View$PropertyList\"/>\n    </hudson.model.AllView>\n  </views>\n  <primaryView>All</primaryView>\n  <slaveAgentPort>0</slaveAgentPort>\n  <label>windows</label>\n  <nodeProperties/>\n  <globalNodeProperties/>\n</hudson>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/2015-07-10_12-11-34/build.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.triggers.SCMTrigger_-SCMTriggerCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.triggers.SCMTrigger_-BuildAction/>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.2.0\">\n      <workspaceName>Hudson-oldPollingFallback-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath>$/FunctionalTests/TeamFoundationServerScmFunctionalTest/oldPollingFallback</projectPath>\n      <serverUrl>http://${tfs_server_name}:8080/tfs/jenkins-tfs-plugin</serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n  </actions>\n  <timestamp>1436542800239</timestamp>\n  <result>FAILURE</result>\n  <duration>134</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn></builtOn>\n  <workspace>oldPollingFallback/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.scm.NullChangeLogParser\"/>\n</build>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/2015-07-10_12-11-34/log",
    "content": "Started by an SCM change\r\n(bad stuff happens)\r\nFinished: FAILURE\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/2015-07-10_12-11-34/polling.log",
    "content": "Started on Jul 10, 2015 11:40:00 AM\r\nNo existing build. Scheduling a new one.\r\nDone. Took 1 ms\r\nChanges found\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/lastFailedBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/lastStableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/lastSuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/lastUnstableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/lastUnsuccessfulBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/builds/legacyIds",
    "content": ""
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<actions/>\n\t<description/>\n\t<keepDependencies>false</keepDependencies>\n\t<properties/>\n\t<scm class=\"hudson.plugins.tfs.TeamFoundationServerScm\" plugin=\"tfs@3.2.0\">\n\t\t<serverUrl></serverUrl>\n\t\t<projectPath></projectPath>\n\t\t<localPath>.</localPath>\n\t\t<workspaceName>Hudson-${JOB_NAME}-${COMPUTERNAME}</workspaceName>\n\t\t<password>pmJe5VYJg6gr2BdipI1sMGJScFwmT+pZbz7B2jISBrw=</password>\n\t\t<userName>jenkins-tfs-plugin</userName>\n\t\t<useUpdate>false</useUpdate>\n\t</scm>\n\t<assignedNode>master</assignedNode>\n\t<canRoam>false</canRoam>\n\t<disabled>false</disabled>\n\t<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n\t<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n\t<concurrentBuild>false</concurrentBuild>\n\t<builders/>\n\t<publishers/>\n\t<buildWrappers/>\n</project>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/jobs/oldPollingFallback/nextBuildNumber",
    "content": "2\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/oldPollingFallback/secret.key",
    "content": "5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson>\n</hudson>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/2015-07-15_20-37-42/build.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.model.Cause_-UserIdCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.1.1\">\n      <workspaceName>Hudson-upgradeEncodedPassword-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath></projectPath>\n      <serverUrl></serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n    <hudson.plugins.tfs.TFSRevisionState plugin=\"tfs@3.1.1\">\n      <changesetVersion></changesetVersion>\n      <projectPath></projectPath>\n    </hudson.plugins.tfs.TFSRevisionState>\n  </actions>\n  <timestamp>1436983436507</timestamp>\n  <result>SUCCESS</result>\n  <duration>8897</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn></builtOn>\n  <workspace>upgradeEncodedPassword/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.plugins.tfs.ChangeSetReader\" plugin=\"tfs@3.1.1\"/>\n</build>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/2015-07-15_20-37-42/changelog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<changelog>\r\n</changelog>\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/2015-07-15_20-37-42/log",
    "content": "Started by user \r\n(...)\r\nFinished: SUCCESS\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/lastFailedBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/lastStableBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/lastSuccessfulBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/lastUnstableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/lastUnsuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/builds/legacyIds",
    "content": ""
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<project>\n  <actions/>\n  <description></description>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n  <scm class=\"hudson.plugins.tfs.TeamFoundationServerScm\" plugin=\"tfs@3.1.1\">\n    <serverUrl></serverUrl>\n    <projectPath></projectPath>\n    <localPath>.</localPath>\n    <workspaceName>Hudson-${JOB_NAME}-${COMPUTERNAME}</workspaceName>\n    <userPassword>Zm9yLXRlc3Qtb25seQ==</userPassword>\n    <userName>jenkins-tfs-plugin</userName>\n    <useUpdate>false</useUpdate>\n  </scm>\n  <assignedNode>master</assignedNode>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers/>\n  <buildWrappers/>\n</project>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/jobs/upgradeEncodedPassword/nextBuildNumber",
    "content": "2\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/upgradeEncodedPassword/secret.key",
    "content": "5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson>\n  <quietPeriod>360</quietPeriod>\n</hudson>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/hudson.plugins.tfs.TeamFoundationServerScm.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl plugin=\"tfs@3.2.0\">\n  <generation>2</generation>\n</hudson.plugins.tfs.TeamFoundationServerScm_-DescriptorImpl>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/2015-07-15_20-37-42/build.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.model.Cause_-UserIdCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.1.1\">\n      <workspaceName>Hudson-useWebProxyServer-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath></projectPath>\n      <serverUrl></serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n    <hudson.plugins.tfs.TFSRevisionState plugin=\"tfs@3.1.1\">\n      <changesetVersion></changesetVersion>\n      <projectPath></projectPath>\n    </hudson.plugins.tfs.TFSRevisionState>\n  </actions>\n  <timestamp>1437007062000</timestamp>\n  <result>SUCCESS</result>\n  <duration>8897</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn></builtOn>\n  <workspace>useWebProxyServer/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.plugins.tfs.ChangeSetReader\" plugin=\"tfs@3.1.1\"/>\n</build>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/2015-07-15_20-37-42/changelog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<changelog>\r\n</changelog>\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/2015-07-15_20-37-42/log",
    "content": "Started by user \r\n(...)\r\nFinished: SUCCESS\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/lastFailedBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/lastStableBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/lastSuccessfulBuild",
    "content": "1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/lastUnstableBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/lastUnsuccessfulBuild",
    "content": "-1"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/builds/legacyIds",
    "content": ""
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/config.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<project>\n  <actions/>\n  <description></description>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n  <scm class=\"hudson.plugins.tfs.TeamFoundationServerScm\" plugin=\"tfs@3.2.0\">\n    <serverUrl></serverUrl>\n    <projectPath></projectPath>\n    <localPath>.</localPath>\n    <workspaceName>Hudson-${JOB_NAME}-${COMPUTERNAME}</workspaceName>\n    <password>pmJe5VYJg6gr2BdipI1sMGJScFwmT+pZbz7B2jISBrw=</password>\n    <userName>jenkins-tfs-plugin</userName>\n    <useUpdate>false</useUpdate>\n  </scm>\n  <assignedNode>master</assignedNode>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <triggers>\n    <hudson.triggers.SCMTrigger>\n      <spec></spec>\n    </hudson.triggers.SCMTrigger>\n  </triggers>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers/>\n  <buildWrappers/>\n</project>\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/jobs/useWebProxyServer/nextBuildNumber",
    "content": "1\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/proxy.xml",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<proxy>\n  <name></name>\n  <port></port>\n  <secretPassword>zTigAtPm/kPRVsuUZgIXnw==</secretPassword>\n</proxy>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/FunctionalTest/useWebProxyServer/secret.key",
    "content": "5e2422dc868f119d5033f4619a6f223d71d132a17f8a63f1056c9a1f57c65006"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/action/tf-changeset-1.log",
    "content": "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12472\r\nUser:      RNO\\_MCLWEB\r\nDate:      2008-jun-27 11:16:06\r\n\r\nComment:\r\n  Created team project folder $/tfsandbox via the Team Project Creation Wizard\r\n\r\nItems:\r\n  add $/tfsandbox\r\n\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/action/tf-changeset-2.log",
    "content": "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12492\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:11:15\r\n\r\nComment:\r\n  first file\r\n\r\nItems:\r\n  add $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12472\r\nUser:      RNO\\_MCLWEB\r\nDate:      2008-jun-10 11:16:06\r\n\r\nComment:\r\n  Created team project folder $/tfsandbox via the Team Project Creation Wizard\r\n\r\nItems:\r\n  add $/tfsandbox\r\n\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/action/tf-changeset-3.log",
    "content": "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12495\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:21:25\r\n\r\nComment:\r\n  changed and created one\r\n\r\nItems:\r\n  edit $/tfsandbox/readme.txt\r\n  add $/tfsandbox/readme2.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12493\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:19:41\r\n\r\nComment:\r\n  changed and created one\r\n\r\nItems:\r\n  edit $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12492\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:11:15\r\n\r\nComment:\r\n  first file\r\n\r\nItems:\r\n  add $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12472\r\nUser:      RNO\\_MCLWEB\r\nDate:      2008-jun-27 11:16:06\r\n\r\nComment:\r\n  Created team project folder $/tfsandbox via the Team Project Creation Wizard\r\n\r\nItems:\r\n  add $/tfsandbox\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/issue-3683.txt",
    "content": "-------------------------------------------------------------------------------\r\nChangeset: 19518\r\nUser: im21\r\nDate: 13 May 2009 22:38:55\r\n\r\nComment:\r\n  Uncommenting lines in IOC.cs\r\n\r\nItems:\r\n  edit $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework/IoC/IoC.cs\r\n\r\nCheck-in Notes:\r\n  Code Reviewer:\r\n  Performance Reviewer:\r\n  Security Reviewer:\r\n\r\n-------------------------------------------------------------------------------\r\nChangeset: 19517\r\nUser: im21\r\nDate: 13 May 2009 22:05:30\r\n\r\nComment:\r\n  Merging Framework Project file into r2 from MAIN\r\n\r\nItems:\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework/app.config;X4019\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework/Framework.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework/Framework.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework/WCF\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework/WCF/WCFProxyBase.cs\r\n\r\nCheck-in Notes:\r\n  Code Reviewer:\r\n  Performance Reviewer:\r\n  Security Reviewer:\r\n\r\n-------------------------------------------------------------------------------\r\nChangeset: 19516\r\nUser: im21\r\nDate: 13 May 2009 21:59:12\r\n\r\nComment:\r\n  Checking in framework changes\r\n\r\nItems:\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.CrossTalk\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.CrossTalk/Framework.CrossTalk.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.CrossTalk/Framework.CrossTalk.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.CrossTalk/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.CrossTalk/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.Security\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.Security/Framework.Security.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.Security/Framework.Security.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.Security/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Framework.Security/Properties/AssemblyInfo.cs;X4007\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/Properties/AssemblyInfo.cs;X3992\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SMO.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SQL.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SQL.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/Error.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/ErrorType.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/IPackageDetails.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageDetails.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageDetailsDTS.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageDetailsFILE.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageDetailsProvider.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageDetailsProviderResult.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageDetailsSQL.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageHelper.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Helpers/SQL/SSIS/PackageHelperResult.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/AccessControllerTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/AccessControlPolicyCacheTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/ApplicationsNavigatorTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/ContextDataExample.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/GroceryWeb.tesco.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/GroceryWeb.tesco\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/GuidBasedObjectIdentifierTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/Helpers/TestHelper.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/LoginContextHandlerTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/OperationsTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/PersistedIdentityHandlerTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/PolicyNavigatorTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/ReferenceMonitor.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/ReferenceMonitor.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/RefMonHttpModuleTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/Resources\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/Resources/TestData.Designer.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/Resources/TestData.resx\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/TokenHandlerTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/TypeBasedObjectIdentifierTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor.UnitTests/VSCodeGenAccessors.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/AccessController.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Entities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Entities/AccessControlDecisionEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/HttpContextKeys.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/IAccessController.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/AccessControlPolicyCache.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/ApplicationsNavigator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/AuthoriseEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/DataRepository.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/IAccessControlPolicyCache.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/ILoginContextHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/ITokenHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/LoggerEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/LoginContextHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/Operations.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/OperatorEnumerations.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/PolicyNavigator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/TokenHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Internal/Variable.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/IPersistedIdentityHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ITescoSecureHttpHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ObjectIdentifiers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ObjectIdentifiers/AbstractObjectIdentifier.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ObjectIdentifiers/GuidBasedObjectIdentifier.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ObjectIdentifiers/TypeBasedObjectIdentifier.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ObjectIdentifiers/WebButtonObjectIdentifier.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ObjectIdentifiers/WebUrlObjectIdentifier.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/PersistedIdentityHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Properties/AssemblyInfo.cs;X3999\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/Properties/AssemblyInfo.Internals..cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ReferenceMonitor.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/ReferenceMonitor.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/ReferenceMonitor/RefMonHttpModule.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/Configuration.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/Configuration.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/ConfigurationServiceReadTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/GroceryWebConfigTest.tesco.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/GroceryWebConfigTest.tesco\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/MockObjects.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/ConfigurationService.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/app.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/ClassDiagram1.cd\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/ILocatorService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/AddressEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/AddressesEntity.cs\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/AddressExceptionEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/AreaDetailsEntity.cs\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/Exception.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/Locator.Entities.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/Locator.Entities.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/PafAddressEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Locator.Entities/Properties/AssemblyInfo.cs;X4012\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorServiceFactory.cs\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorServiceOperations.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests/Locator.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests/Locator.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests/LocatorTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/Locator.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/LocatorWcfWebsite.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/LocatorWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/Properties/AssemblyInfo.cs;X3988\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/LocatorWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/IOperations.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/mssccprj.scc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/Operations.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/Properties/AssemblyInfo.cs;X3986\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/ResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/SensitiveDatabaseAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/SensitiveDatabaseAccess/SensitiveDatabaseAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/configuration.svcinfo\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/configuration91.svcinfo\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Locator.disco;X4009\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Locator.xsd;X4011\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Locator1.disco\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Locator1.xsd;X4010\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Locator2.xsd\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Locator21.xsd\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/LocatorSvcSDAOperations.wsdl;X4014\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/LocatorSvcSDAOperations1.wsdl\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Reference.cs\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Locator/Service References/LocatorSvcSDA/Reference.svcmap\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/app.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/EMailNotificationServiceProviderTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/EmailProvider.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/EmailProvider.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/EmailProviderTests/VSCodeGenAccessors.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/INotificationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/Notification.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/Notification.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/EmailEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/NotificationEntities.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/NotificationEntities.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/NotificationEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/NotificationMethodEnum.cs\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/NotificationTypeEnum.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationEntities/Properties/AssemblyInfo.cs;X3989\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/INotificationServiceProvider.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/NotificationProviderFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/NotificationProviders\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/NotificationProviders/EMailNotificationServiceProvider.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/NotificationService.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/NotificationService.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/NotificationServiceProvider.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationService/Properties/AssemblyInfo.cs;X3990\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests/Notification.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests/Notification.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests/NotificationServiceTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite/Notification.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite/NotificationWCFWebsite.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite/NotificationWCFWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite/Properties/AssemblyInfo.cs;X3993\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/NotificationWCFWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/Properties/AssemblyInfo.cs;X3997\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/Service References\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/Service References/NotificationWCFService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Notification/Service References/NotificationWCFService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/Auditing.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/Auditing.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/AuditingServiceTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/AuthenticationEventRequestTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/AuthorisationEventRequestTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/CryptographyEventRequestTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/Helpers/ObjectBuilderHelper.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/IdentificationEventRequestTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/SecurityEventRequestTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing.UnitTests/SecurityFailureEventRequestTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Auditing.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Auditing.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/AuditingService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/AuditingServiceFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/IAuditingService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Internal\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Internal/EventTypeInstruction.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Internal/EventTypeInstructions.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Internal/EventTypeInstructionsCache.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Internal/ResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Properties/AssemblyInfo.cs;X4015\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/AbstractEvent.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/AbstractSecurityEvent.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/AuthenticationEventRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/AuthorisationEventRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/AuthorisationManagementEventRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/CryptographyEventRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/IdentificationEventRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/SecurityEventRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/SecurityEventEntities/SecurityFailureEventRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Service References/AuditingSdaService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/Auditing/Service References/AuditingSdaService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/AuditingSensitiveDatabaseAccess.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/AuditingSensitiveDatabaseAccess.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/AuditingSensitiveDatabaseAccessTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/Helpers/TestHelper.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/AuditingSensitiveDatabaseAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/AuditingSensitiveDatabaseAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/AuditingSensitiveDatabaseAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/IAuditingSensitiveDatabaseAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/Properties/AssemblyInfo.cs;X4016\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingSensitiveDatabaseAccess/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests/AuditingService.IntegrationTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests/AuditingService.IntegrationTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests/IntegrationTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/AuditingService.IntegrationTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/SensitiveDataAccessWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/SensitiveDataAccessWcfWebsite/AuditingSensitiveDataAccess.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/SensitiveDataAccessWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/SensitiveDataAccessWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/SensitiveDataAccessWcfWebsite/SensitiveDataAccessWcfWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/SensitiveDataAccessWcfWebsite/SensitiveDataAccessWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Auditing/SensitiveDataAccessWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/app.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/Authentication.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/Authentication.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/AuthenticationMechanismFactoryMockTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/AuthenticationMechanismFactoryTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/AuthenticationServiceMockTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/AuthenticationServiceTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Authentication.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Authentication.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/AuthenticationChallenge.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/AuthenticationChallengeResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/AuthenticationChallengeResult.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/AuthenticationMechanismCache.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/AuthenticationResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/AuthenticationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Entities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Entities/MechanismDetails.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Entities/PasswordAuthenticationData.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/AbstractAuthenticationChallengeBuilder.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/AbstractAuthenticationChallengeResponseHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/AbstractAuthenticationManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/AbstractAuthenticationMechanismFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/AbstractAuthenticationResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/CaseInsensitivePasswordAuthenticationChallengeBuilder.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/CaseInsensitivePasswordAuthenticationChallengeResponseHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/CaseInsensitivePasswordAuthenticationManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/CaseInsensitivePasswordAuthenticationMechanismFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/PasswordAuthenticationChallengeBuilder.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/PasswordAuthenticationChallengeResponseHandler.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/PasswordAuthenticationManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/PasswordAuthenticationMechanismFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Factory/PasswordAuthenticationResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/IAuthenticationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/MechanismType.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Properties/AssemblyInfo.cs;X3995\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Service References/AuthenticationSdaService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Service References/AuthenticationSdaService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Service References/PasswordSdaService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/Authentication/Service References/PasswordSdaService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDataAccessWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDataAccessWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDataAccessWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDataAccessWcfWebsite/PasswordSensitiveDataAccess.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDataAccessWcfWebsite/PasswordSensitiveDataAccessWcfWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDataAccessWcfWebsite/PasswordSensitiveDataAccessWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDataAccessWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests/PasswordSensitiveDatabaseAccess.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests/PasswordSensitiveDatabaseAccess.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests/PasswordSensitiveDatabaseAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/DatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/IDatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/PasswordSensitiveDatabaseAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/PasswordSensitiveDatabaseAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/Properties/AssemblyInfo.cs;X3991\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/PasswordSensitiveDatabaseAccess/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDataAccessWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDataAccessWcfWebsite/AuthenticationSensitiveDataAccess.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDataAccessWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDataAccessWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDataAccessWcfWebsite/SensitiveDataAccessWcfWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDataAccessWcfWebsite/SensitiveDataAccessWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDataAccessWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests/PasswordSensitiveDatabaseAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests/SensitiveDatabaseAccess.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess.UnitTests/SensitiveDatabaseAccess.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/DatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/IDatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/Properties/AssemblyInfo.cs;X3994\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/SensitiveDatabaseAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authentication/SensitiveDatabaseAccess/SensitiveDatabaseAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AccessControlPolicyService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AccessControlPolicyServiceFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/AccessControlPolicyDataRequestTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/AccessControlPolicyManagementTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/AccessControlPolicyServiceFactoryTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/Authorisation.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/Authorisation.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/AuthorisationAuditingTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/AuthorisationServiceFactoryTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/AuthorisationTokenBuilderTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/Helpers/TestingHelpers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/ResourceAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/TestData.Designer.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/TestData.resx\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/UserAuthorisationTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Authorisation.UnitTests/UserPermissionBuilderTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/app.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/AccessControlPolicyManagementTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/ApplicationManagmentTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/AuthorisationManagement.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/AuthorisationManagement.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/AuthorisationManagementAuditingTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/AuthorisationManagementServiceTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/Helpers/TestingHelpers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/PermissionManagementTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/ResourceAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/UserGroupManagementTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/UserManagementTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagement.UnitTests/UserRoleManagementTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/AuthorisationManagementService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/ApplicationEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/ApplicationGroupEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/AuthorisationManagementRequestEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/IAuditableRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/PermissionContextEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/PermissionEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/UserEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/UserGroupEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Entities/UserRoleEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Helpers/ConversionHelpers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/IAuthorisationManagementService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/AccessControlPolicyManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/AccessControlPolicyGroupAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/AccessControlPolicyRoleAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/ApplicationEntityAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/ApplicationGroupEntityAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/BaseAccessControlPolicyUserAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/BaseUserEntityAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/PermissionEntityAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/UserGroupEntityAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Adapters/UserRoleEntityAdapter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/ApplicationManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/AuthorisationManagementAuditing.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IAccessControlPolicyManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IApplicationManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IAuthorisationManagementAuditing.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IPermissionManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IUserGroupManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IUserManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/IUserRoleManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/PermissionManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/ResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/UserGroupManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/UserManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/UserRoleManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Validators\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Validators/BaseUserValidator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Validators/UserGroupValidator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Internal/Validators/UserRoleValidator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Properties/AssemblyInfo.cs;X3987\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Service References/AuthorisationManagementSdaService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagement/Service References/AuthorisationManagementSdaService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/AuthorisationManagementSensitiveDatabaseAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/AuthorisationManagementSensitiveDatabaseAccessServiceFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/AuthorisationManagementSensitiveDBAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/AuthorisationManagementSensitiveDBAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/IAuthorisationManagementSensitiveDatabaseAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/Properties/AssemblyInfo.cs;X4000\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationManagementSensitiveDBAccess/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests/AuthorisationManagementSensitiveDatabaseAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests/AuthorisationMgtSensitiveDBAccess.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests/AuthorisationMgtSensitiveDBAccess.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationMgtSensitiveDBAccess.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDataAccessWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDataAccessWcfWebsite/AuthorisationSensitiveDataAccess.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDataAccessWcfWebsite/AuthorisationSensitiveDataAccessWcfWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDataAccessWcfWebsite/AuthorisationSensitiveDataAccessWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDataAccessWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDataAccessWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDataAccessWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/AuthorisationSensitiveDatabaseAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/AuthorisationSensitiveDatabaseAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/AuthorisationSensitiveDatabaseAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/IAuthorisationSensitiveDatabaseAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/Properties/AssemblyInfo.cs;X3996\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDatabaseAccess/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/AuthorisationSensitiveDatabaseAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/AuthorisationSensitiveDBAccess.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/AuthorisationSensitiveDBAccess.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/AuthorisationSerializers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/Helpers/TestingHelpers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/TestData.Designer.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationSensitiveDBAccess.UnitTests/TestData.resx\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationServicePublic.cd\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationWcfWebsite/Authorisation.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationWcfWebsite/AuthorisationWcfWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationWcfWebsite/AuthorisationWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/AuthorisationWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/AccessControlPolicy Source\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/AccessControlPolicy Source/AccessControlPolicy.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/AccessControlPolicy Source/AccessControlPolicy.xsd\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/AccessControlPolicy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/AccessControlPolicyCommonEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/AccessControlPolicyRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/IAuditableRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/PermissionContextDataEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/UserAuthorisationRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/UserPermissionEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/UserPermissionEntityComparer.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Entitities/UserPermissionsEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Helpers/AccessControlPolicyReader.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Helpers/StringHelpers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/IAccessControlPolicyService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/IAuthorisationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/AccessControlPolicyDataRequest.cs\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/AccessControlPolicyManagement.cs\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/AuthorisationAuditing.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/Builders\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/Builders/AuthorisationTokenBuilder.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/Builders/UserPermissionBuilder.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/IAccessControlPolicyManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/IAuthorisationAuditing.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/IAuthorisationDataRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/IResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/IUserAuthorisation.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/ObjectIdComparer.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/ResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Internal/UserAuthorisation.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/MgmtSensitiveDataAccessWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/MgmtSensitiveDataAccessWcfWebsite/AuthMgmtSensitiveDataAccess.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/MgmtSensitiveDataAccessWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/MgmtSensitiveDataAccessWcfWebsite/MgmtSensitiveDataAccessWcfWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/MgmtSensitiveDataAccessWcfWebsite/MgmtSensitiveDataAccessWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/MgmtSensitiveDataAccessWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/MgmtSensitiveDataAccessWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Properties/AssemblyInfo.cs;X3998\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Service References/AuthorisationSdaService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Authorisation/Service References/AuthorisationSdaService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/Helpers/TestingHelpers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/Identification.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/Identification.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/IdentificationAuditingTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/IdentificationServiceFactoryTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/IdentificationServiceTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entitities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entitities/GetIdentityResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entitities/GetUserLoginInfoResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entitities/IAuditableRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entitities/IdentityRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entitities/LogInState.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Entitities/UserIdentityRelationEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Identification.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Identification.csproj\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/IdentificationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/IdentificationServiceFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/IIdentificationService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Internal\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Internal/IdentificationAuditing.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Internal/IIdentificationAuditing.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Internal/IResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Internal/ResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Properties/AssemblyInfo.cs;X4005\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Service References/IdentificationSdaService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/Identification/Service References/IdentificationSdaService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/IdentificationSensitiveDatabaseAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/IdentificationSensitiveDatabaseAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/IdentificationSensitiveDatabaseAccesss.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/IdentificationSensitiveDatabaseAccessServiceFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/IIdentificationSensitiveDatabaseAccesss.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/Properties/AssemblyInfo.cs;X4006\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDatabaseAccess/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/Helpers\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/Helpers/TestingHelpers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/IdentificationSensitiveDBAccess.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/IdentificationSensitiveDBAccess.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/IdentificationsSensitiveDBAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/IdentificationSensitiveDBAccess.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/SensitiveDataAccessWcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/SensitiveDataAccessWcfWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/SensitiveDataAccessWcfWebsite/IdentificationSensitiveDataAccess.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/SensitiveDataAccessWcfWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/SensitiveDataAccessWcfWebsite/SensitiveDataAccessWcfWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/SensitiveDataAccessWcfWebsite/SensitiveDataAccessWcfWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/AccessControl/Identification/SensitiveDataAccessWcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/ImportLegacyMaterial.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/ImportLegacyMaterial.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/LegacyDataAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/Program.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/Properties/AssemblyInfo.cs;X4001\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/Service References/MaterialStoreService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/Service References/MaterialStoreService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/Service References/MaterialStoreServiceDataContractCtors.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/ImportLegacyMaterial/SetupLegacyKeys.cmd\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/MaterialStore.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/MaterialStore.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/MaterialStoreTest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/ResourceAccessFactoryMockTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/Service References/SensitiveDatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.UnitTests/Service References/SensitiveDatabaseAccessService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Cipher.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/CipherSettings.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/CryptographyType.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Entities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Entities/HashMaterialEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Entities/HashMaterialSetEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Entities/KeyMaterialEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Entities/KeyMaterialSetEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Entities/MaterialEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Entities/MaterialSetEntity.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/AbstractMaterialGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/AbstractMaterialStoreFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/AbstractMessageEntityGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/AbstractResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/BaseMaterialGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/CryptographicParameter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/HashMaterialGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/HashMaterialStoreFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/HashMessageEntityGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/HashParameter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/HashResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/LegacyMaterialGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/SymmetricMaterialGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/SymmetricMaterialStoreFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/SymmetricMessageEntityGenerator.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/SymmetricParameter.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Factory/SymmetricResourceAccess.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/HashAlgorithmType.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/IMaterialStore.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Internal\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Internal/Auditing\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Internal/Auditing/AuditMessage.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Internal/Auditing/MaterialStoreAuditor.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Internal/Auditing/MaterialStoreEventArgs.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Internal/Auditing/MaterialStoreEventHandlers.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Internal/MaterialStoreSettings.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MaterialStore.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MaterialStore.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MaterialStore.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MaterialStore.reg\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MaterialStoreSettings.tesco.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MaterialStoreSettings.tesco\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetHashMaterialRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetHashMaterialResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetHashMaterialSetRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetHashMaterialSetResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetKeyMaterialRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetKeyMaterialResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetKeyMaterialSetRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetKeyMaterialSetResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetMaterialRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetMaterialResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetMaterialSetRequest.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/MessageEntities/GetMaterialSetResponse.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Properties/AssemblyInfo.cs;X4017\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Properties/AssemblyInfo.Internals.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Service References/SensitiveDatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/Service References/SensitiveDatabaseAccessService.map\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStore/SymmetricAlgorithmType.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreAppPool.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreSensitiveDatabaseAccess.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreSensitiveDatabaseAccessAppPool.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreWCFWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreWCFWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreWCFWebsite/MaterialStore.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreWCFWebsite/MaterialStoreWCFWebsite.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreWCFWebsite/MaterialStoreWCFWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreWCFWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/MaterialStoreWCFWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests/SensitiveDatabaseAccess.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests/SensitiveDatabaseAccess.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess.UnitTests/SensitiveDatabaseAccessTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess/DatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess/IDatabaseAccessService.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess/Properties/AssemblyInfo.cs;X4004\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess/SensitiveDatabaseAccess.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccess/SensitiveDatabaseAccess.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/dummy.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/Properties/AssemblyInfo.cs;X4003\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/SensitiveDatabaseAccess.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/SensitiveDatabaseAccessWCFWebsite.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/SensitiveDatabaseAccessWCFWebsite.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/Security/KeyManagement/MaterialStore/SensitiveDatabaseAccessWCFWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc.Host.IIS\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc.Host.IIS/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc.Host.IIS/Properties/AssemblyInfo.cs;X4008\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc.Host.IIS/StateRegister.svc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc.Host.IIS/StateRegisterSvc.Host.IIS.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc.Host.IIS/StateRegisterSvc.Host.IIS.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc.Host.IIS/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc/app.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc/IStateRegisterSvc.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc/Properties/AssemblyInfo.cs;X4018\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc/StateRegisterSvc.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc/StateRegisterSvc.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Services/StateServices/StateRegisterSvc/StateRegisterSvc.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/app.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/IStateRegister.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Properties/AssemblyInfo.cs;X4013\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/RegisterItem.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/SecuredRegisterItem.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/SecureStateRegister.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/configuration.svcinfo\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/configuration91.svcinfo\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/Reference.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/Reference.svcmap\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegister.disco\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegister.xsd\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegister1.disco\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegister1.xsd\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegister2.xsd\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegister21.xsd\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegisterSvc.wsdl\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/Service References/StateRegisterSvc/StateRegisterSvc1.wsdl\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/State.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/State.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/StateRegister.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/State/StateRegistryFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/AutoIncrementingCredential.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Credential.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/CredentialCollection.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/CredentialName.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Internal\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Internal/IdentificationTokenBuilderFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Internal/ITokenBuilder.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Internal/TokenBuilder.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Internal/TokenValidationResult.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/ITokenFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/ITokenManagementProvider.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Properties\r\n  merge, delete $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Properties/AssemblyInfo.cs;X4002\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/SiteTokenManagement.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/TimerCredential.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/TokenFactory.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/TokenGroupValidationResult.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.csproj.vspscc\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/AuthorisationTokenTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/AutoIncrementingCredentialTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/CredentialCollectionTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/CredentialTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/ForgotMyPasswordTokenTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/IdentificationTokenTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/SecurityTokenTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/Tokens.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/Tokens.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/TokenTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens.UnitTests/TracerTokenTests.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/AuthorisationToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/BTCToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/ForgotMyPasswordToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/IAuthorisationToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/IBTCToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/IdentificationToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/IForgotMyPasswordToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/IIdentificationToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/ISecurityToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/IToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/ITracerToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/LegacyIdentificationToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/SecurityToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/Token.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/Tokens/TracerToken.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Tokens/wcfclientendpoints.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfClients\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfClients/readme.txt\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfClients/wcfclientendpoints.config\r\n  merge, branch $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfClients/wcfclientendpoints2.config\r\n  merge, edit   $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfClients/wcfstandardbinding.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/AppPool.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/ImportWcfWebsite.bat\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/keepalive.htm\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/readme.txt\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/RemoveWcfWebsite.bat\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/WcfWebsite.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/WcfWebsite_pre-refactor.xml\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/WcfWebsite/Web.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/App.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/AuthoringTests.txt\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/GroceryWeb.tesco.config\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/GroceryWeb.tesco\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/mssccprj.scc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/Properties\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/Properties/AssemblyInfo.cs\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/Workflow.UnitTests.csproj.vspscc\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/Workflow.UnitTests.csproj\r\n  merge         $/Tesco_Dotcom/Dev/r2/Tesco/Com/Framework/Workflow.UnitTests/WorkflowTest.cs\r\n\r\nCheck-in Notes:\r\n  Code Reviewer:\r\n  Performance Reviewer:\r\n  Security Reviewer:\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/issue-4184.txt",
    "content": "-------------------------------------------------------------------------------\r\nChangeset: 5516\r\nUser: Lo\r\nDate: Monday, 10 August 2009 5:17:36 p.m.\r\n\r\nComment:\r\n\r\nItems:\r\n  edit $/LD.Tracker/Common/LD.Tracker.Core/Entities/TrackerType.cs\r\n\r\nCheck-in Notes:\r\n  Code Reviewer:\r\n  Performance Reviewer:\r\n  Security Reviewer:\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/issue-4943.txt",
    "content": "-------------------------------------------------------------------------------\nChangeset: 45212\nUser: USERA\nChecked in by: USERB\nDate: Tuesday, November 24, 2009 10:59:13 AM\n\nComment:\n  Sample checkin with /author\n\nItems:\n  edit $/PROJECT/PATH/TO/FILE.txt\n\nPolicy Warnings:\n  Override Reason:\n    XXXX XXXXXXX XX XXXXX\n  Messages:\n    XXXXXXXX XXXXX XX XXXXXXXX XXXXXXX XXXX.\n    XXXXXXXX XXXXX XX XXXXXXXX XX XXXXXXX.\n\n-------------------------------------------------------------------------------\nChangeset: 15005\nUser: USERC\nDate: Monday, April 06, 2009 8:29:28 AM\n\nComment:\n  Sample normal checkin (without /author)\n\nItems:\n  edit $/PROJECT/PATH/TO/FILE.txt\n\nCheck-in Notes:\n  XXXXXXX XXXX:\n    XXXXXXX XXXXXX\n  XXXX XXXXXXXXXXX:\n    XXXXXX, XXXX;\n  XXXXXXX XXXXX XXX:\n    X\n  XXXXXXXX XXXXXXXXX:\n  XX XXXXXXXXX:\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/issue-6454.txt",
    "content": "Changeset: 146266\nUser: hschneider\nChecked in by: vsts-demon\nDate: Saturday, May 01, 2010 12:17:34 AM\n\nComment:\n  4/22/2010 3:56:15 PM: Recycling mode disabled; Test changed\n   (Updated by TFS to TFS Connector, server: 192.168.1.208:1666, id 521906. )\n\nItems:\n  edit $/source/Dev/playback/pb_playback/Olymp/LowLevelTests/FileScannerTest.cs\n  edit $/source/Dev/playback/pb_playback/Olymp/MainApplication/Panels/VirtualizingGroupingItemsPanel.cs\n\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/issue-6870-2.txt",
    "content": "Changeset: 24\nUser: GRP\\ObendorfH\nDate: 06.05.2010 13:29:24\n\nComment:\n  Initialer Check-In\n\nItems:\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base/.project\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base/.settings\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base/.tpignore\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base/pom.xml\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base/src\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base/.settings/org.maven.ide.eclipse.prefs\n  add $/TFSJavaBuild/Sources/Maven/DEV/com.haufelexware.project.base/src/site\n\nCheck-in Notes:\n  Code Reviewer:\n  Performance Reviewer:\n  Security Reviewer:\n\n-----------------------------------------------------------------------------------------------------------------------\nChangeset: 23\nUser: GRP\\ObendorfH\nDate: 06.05.2010 13:28:21\n\nComment:\n\n\nItems:\n  branch $/TFSJavaBuild/Sources/Maven/Current\n\nCheck-in Notes:\n  Code Reviewer:\n  Performance Reviewer:\n  Security Reviewer:\n "
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/issue-6870.txt",
    "content": "Changeset: 364235\nUser: GRP\\ObendorfH\nDate: 28.06.2010 17:25:40\n\nComment:\n  Versionierung fr EJB EAR\n\nItems:\n  edit $/Services/Server/DEV/SP/MavenDefs/pom.xml\n\nCheck-in Notes:\n  Code Reviewer: \n\n  Performance Reviewer: \n  Security Reviewer: \n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/tf-changeset-1.txt",
    "content": "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12472\r\nUser:      RNO\\_MCLWEB\r\nDate:      2008-jun-27 11:16:06\r\n\r\nComment:\r\n  Created team project folder $/tfsandbox via the Team Project Creation Wizard\r\n\r\nItems:\r\n  add $/tfsandbox\r\n\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/tf-changeset-2.txt",
    "content": "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12492\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:11:15\r\n\r\nComment:\r\n  first file\r\n\r\nItems:\r\n  add $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12472\r\nUser:      RNO\\_MCLWEB\r\nDate:      2008-jun-10 11:16:06\r\n\r\nComment:\r\n  Created team project folder $/tfsandbox via the Team Project Creation Wizard\r\n\r\nItems:\r\n  add $/tfsandbox\r\n\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/tf-changeset-3.txt",
    "content": "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12495\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:21:25\r\n\r\nComment:\r\n  changed and created one\r\n\r\nItems:\r\n  edit $/tfsandbox/readme.txt\r\n  add $/tfsandbox/readme2.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12493\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:19:41\r\n\r\nComment:\r\n  changed and created one\r\n\r\nItems:\r\n  edit $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12492\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:11:15\r\n\r\nComment:\r\n  first file\r\n\r\nItems:\r\n  add $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12472\r\nUser:      RNO\\_MCLWEB\r\nDate:      2008-jun-27 11:16:06\r\n\r\nComment:\r\n  Created team project folder $/tfsandbox via the Team Project Creation Wizard\r\n\r\nItems:\r\n  add $/tfsandbox\r\n\r\n  \r\n\r\n  \r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/tf-changeset-german-1.txt",
    "content": "-------------------------------------------------------------------------------\nChangeset: 302\nBenutzer: georg\nDatum: Freitag, 15. Juli 2011 16:24:59\nKommentar:\nElemente:\n  bearbeiten $/InvestInform/commons/Utils14/src/main/java/de/safir/api/types/ApiSafirBool.java\nEincheckhinweise:\n  Codebearbeiter:\n  Leistungsbearbeiter:\n  Sicherheitsbearbeiter:\n\n\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/commands/tf-workfold-list.txt",
    "content": "===========================================================================================================================================\r\nWorkspace: workspaceOne (username_cp)\r\nServer   : https://tfs09.codeplex.com\r\n $/tfshudsonplugin: C:\\tfshudsonplugin_2\\workfolder1\r\n $/tfshudsonplugin/folder: C:\\tfshudsonplugin_3\\workfolder1\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/git.push-sample.json",
    "content": "{\r\n  \"id\": \"03c164c2-8912-4d5e-8009-3707d5f83734\",\r\n  \"eventType\": \"git.push\",\r\n  \"publisherId\": \"tfs\",\r\n  \"scope\": \"all\",\r\n  \"message\": {\r\n    \"text\": \"Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.\",\r\n    \"html\": \"Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.\",\r\n    \"markdown\": \"Jamal Hartnett pushed updates to branch `master` of repository `Fabrikam-Fiber-Git`.\"\r\n  },\r\n  \"detailedMessage\": {\r\n    \"text\": \"Jamal Hartnett pushed 1 commit to branch master of repository Fabrikam-Fiber-Git.\\n - Fixed bug in web.config file 33b55f7c\",\r\n    \"html\": \"Jamal Hartnett pushed 1 commit to branch <a href=\\\"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/#version=GBmaster\\\">master</a> of repository <a href=\\\"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/\\\">Fabrikam-Fiber-Git</a>.\\n<ul>\\n<li>Fixed bug in web.config file <a href=\\\"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74\\\">33b55f7c</a>\\n</ul>\",\r\n    \"markdown\": \"Jamal Hartnett pushed 1 commit to branch [master](https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/#version=GBmaster) of repository [Fabrikam-Fiber-Git](https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/).\\n* Fixed bug in web.config file [33b55f7c](https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74)\"\r\n  },\r\n  \"resource\": {\r\n    \"commits\": [\r\n      {\r\n        \"commitId\": \"33b55f7cb7e7e245323987634f960cf4a6e6bc74\",\r\n        \"author\": {\r\n          \"name\": \"Jamal Hartnett\",\r\n          \"email\": \"fabrikamfiber4@hotmail.com\",\r\n          \"date\": \"2015-02-25T19:01:00Z\"\r\n        },\r\n        \"committer\": {\r\n          \"name\": \"Jamal Hartnett\",\r\n          \"email\": \"fabrikamfiber4@hotmail.com\",\r\n          \"date\": \"2015-02-25T19:01:00Z\"\r\n        },\r\n        \"comment\": \"Fixed bug in web.config file\",\r\n        \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74\"\r\n      }\r\n    ],\r\n    \"refUpdates\": [\r\n      {\r\n        \"name\": \"refs/heads/master\",\r\n        \"oldObjectId\": \"aad331d8d3b131fa9ae03cf5e53965b51942618a\",\r\n        \"newObjectId\": \"33b55f7cb7e7e245323987634f960cf4a6e6bc74\"\r\n      }\r\n    ],\r\n    \"repository\": {\r\n      \"id\": \"278d5cd2-584d-4b63-824a-2ba458937249\",\r\n      \"name\": \"Fabrikam-Fiber-Git\",\r\n      \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249\",\r\n      \"project\": {\r\n        \"id\": \"6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c\",\r\n        \"name\": \"Fabrikam-Fiber-Git\",\r\n        \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c\",\r\n        \"state\": \"wellFormed\"\r\n      },\r\n      \"defaultBranch\": \"refs/heads/master\",\r\n      \"remoteUrl\": \"https://fabrikam-fiber-inc.visualstudio.com/_git/Fabrikam-Fiber-Git\"\r\n    },\r\n    \"pushedBy\": {\r\n      \"id\": \"00067FFED5C7AF52@Live.com\",\r\n      \"displayName\": \"Jamal Hartnett\",\r\n      \"uniqueName\": \"Windows Live ID\\\\fabrikamfiber4@hotmail.com\"\r\n    },\r\n    \"pushId\": 14,\r\n    \"date\": \"2014-05-02T19:17:13.3309587Z\",\r\n    \"url\": \"https://fabrikam-fiber-inc.visualstudio.com/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/pushes/14\"\r\n  },\r\n  \"resourceVersion\": \"3.0-preview.1\",\r\n  \"resourceContainers\": {\r\n    \"collection\": {\r\n      \"id\": \"c12d0eb8-e382-443b-9f9c-c52cba5014c2\",\r\n      \"baseUrl\": \"https://fabrikam-fiber-inc.visualstudio.com/\"\r\n    },\r\n    \"account\": {\r\n      \"id\": \"f844ec47-a9db-4511-8281-8b63f4eaf94e\",\r\n      \"baseUrl\": \"https://fabrikam-fiber-inc.visualstudio.com/\"\r\n    },\r\n    \"project\": {\r\n      \"id\": \"be9b3917-87e6-42a4-a549-2bc06a7a878f\",\r\n      \"baseUrl\": \"https://fabrikam-fiber-inc.visualstudio.com/\"\r\n    }\r\n  },\r\n  \"createdDate\": \"2016-06-10T16:32:21.0569909Z\"\r\n}\r\n"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/util/XmlHelperTest/peekValue_File/input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.triggers.SCMTrigger_-SCMTriggerCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.triggers.SCMTrigger_-BuildAction/>\n    <org.jenkinsci.plugins.buildtriggerbadge.BuildTriggerBadgeAction plugin=\"buildtriggerbadge@2.0\">\n      <cause class=\"hudson.triggers.SCMTrigger$SCMTriggerCause\" reference=\"../../hudson.model.CauseAction/causes/hudson.triggers.SCMTrigger_-SCMTriggerCause\"/>\n    </org.jenkinsci.plugins.buildtriggerbadge.BuildTriggerBadgeAction>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.2.0\">\n      <workspaceName>Hudson-oldPollingFallback-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath>$/FunctionalTests/TeamFoundationServerScmFunctionalTest/oldPollingFallback</projectPath>\n      <serverUrl>http://${tfs_server_name}:8080/tfs/jenkins-tfs-plugin</serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n  </actions>\n  <queueId>76</queueId>\n  <timestamp>1436542800239</timestamp>\n  <startTime>1436542800244</startTime>\n  <result>FAILURE</result>\n  <duration>134</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn/>\n  <workspace>oldPollingFallback/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.scm.NullChangeLogParser\"/>\n</build>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/util/XmlHelperTest/pokeValue_File/expected.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><build>\r\n  <actions>\r\n    <hudson.model.CauseAction>\r\n      <causes>\r\n        <hudson.triggers.SCMTrigger_-SCMTriggerCause/>\r\n      </causes>\r\n    </hudson.model.CauseAction>\r\n    <hudson.triggers.SCMTrigger_-BuildAction/>\r\n    <org.jenkinsci.plugins.buildtriggerbadge.BuildTriggerBadgeAction plugin=\"buildtriggerbadge@2.0\">\r\n      <cause class=\"hudson.triggers.SCMTrigger$SCMTriggerCause\" reference=\"../../hudson.model.CauseAction/causes/hudson.triggers.SCMTrigger_-SCMTriggerCause\"/>\r\n    </org.jenkinsci.plugins.buildtriggerbadge.BuildTriggerBadgeAction>\r\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.2.0\">\r\n      <workspaceName>Hudson-oldPollingFallback-MASTER</workspaceName>\r\n      <workfolder>.</workfolder>\r\n      <projectPath>$/FunctionalTests/TeamFoundationServerScmFunctionalTest/oldPollingFallback</projectPath>\r\n      <serverUrl>http://${tfs_server_name}:8080/tfs/jenkins-tfs-plugin</serverUrl>\r\n      <workspaceExists>true</workspaceExists>\r\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\r\n  </actions>\r\n  <queueId>76</queueId>\r\n  <timestamp>42</timestamp>\r\n  <startTime>1436542800244</startTime>\r\n  <result>FAILURE</result>\r\n  <duration>134</duration>\r\n  <charset>windows-1252</charset>\r\n  <keepLog>false</keepLog>\r\n  <builtOn/>\r\n  <workspace>oldPollingFallback/workspace</workspace>\r\n  <hudsonVersion>1.448</hudsonVersion>\r\n  <scm class=\"hudson.scm.NullChangeLogParser\"/>\r\n</build>"
  },
  {
    "path": "tfs/src/test/resources/hudson/plugins/tfs/util/XmlHelperTest/pokeValue_File/input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><build>\n  <actions>\n    <hudson.model.CauseAction>\n      <causes>\n        <hudson.triggers.SCMTrigger_-SCMTriggerCause/>\n      </causes>\n    </hudson.model.CauseAction>\n    <hudson.triggers.SCMTrigger_-BuildAction/>\n    <org.jenkinsci.plugins.buildtriggerbadge.BuildTriggerBadgeAction plugin=\"buildtriggerbadge@2.0\">\n      <cause class=\"hudson.triggers.SCMTrigger$SCMTriggerCause\" reference=\"../../hudson.model.CauseAction/causes/hudson.triggers.SCMTrigger_-SCMTriggerCause\"/>\n    </org.jenkinsci.plugins.buildtriggerbadge.BuildTriggerBadgeAction>\n    <hudson.plugins.tfs.model.WorkspaceConfiguration plugin=\"tfs@3.2.0\">\n      <workspaceName>Hudson-oldPollingFallback-MASTER</workspaceName>\n      <workfolder>.</workfolder>\n      <projectPath>$/FunctionalTests/TeamFoundationServerScmFunctionalTest/oldPollingFallback</projectPath>\n      <serverUrl>http://${tfs_server_name}:8080/tfs/jenkins-tfs-plugin</serverUrl>\n      <workspaceExists>true</workspaceExists>\n    </hudson.plugins.tfs.model.WorkspaceConfiguration>\n  </actions>\n  <queueId>76</queueId>\n  <timestamp>1436542800239</timestamp>\n  <startTime>1436542800244</startTime>\n  <result>FAILURE</result>\n  <duration>134</duration>\n  <charset>windows-1252</charset>\n  <keepLog>false</keepLog>\n  <builtOn/>\n  <workspace>oldPollingFallback/workspace</workspace>\n  <hudsonVersion>1.448</hudsonVersion>\n  <scm class=\"hudson.scm.NullChangeLogParser\"/>\n</build>"
  },
  {
    "path": "tfs/src/test/resources/tf-get.log",
    "content": "C:\\Users\\Paulina\\Projects\\tfs\\tfsandbox2:\r\nGetting tfsandbox2\r\nGetting readme.txt\r\nGetting readme2.txt\r\n"
  },
  {
    "path": "tfs/src/test/resources/tf-history.log",
    "content": "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12495\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:21:25\r\n\r\nComment:\r\n  changed and created one WITH TWO\r\n\r\nItems:\r\n  edit $/tfsandbox/readme.txt\r\n  add $/tfsandbox/readme2.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12493\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:19:41\r\n\r\nComment:\r\n  changed and created one\r\n\r\nItems:\r\n  edit $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12492\r\nUser:      SND\\redsolo_cp\r\nDate:      2008-jun-27 13:11:15\r\n\r\nComment:\r\n  first file\r\n\r\nItems:\r\n  add $/tfsandbox/readme.txt\r\n\r\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nChangeset: 12472\r\nUser:      RNO\\_MCLWEB\r\nDate:      2008-jun-27 11:16:06\r\n\r\nComment:\r\n  Created team project folder $/tfsandbox via the Team Project Creation Wizard\r\n\r\nItems:\r\n  add $/tfsandbox\r\n"
  },
  {
    "path": "tfs/src/test/resources/tf-workfold.log",
    "content": "\r\n"
  },
  {
    "path": "tfs/src/test/resources/tf-workspace.log",
    "content": "Workspace 'asterix2' created.\r\n"
  },
  {
    "path": "tfs/src/test/resources/tf-workspaces.log",
    "content": "Server: https://tfs02.codeplex.com/\r\nWorkspace Owner          Computer Comment\r\n--------- -------------- -------- ----------------------------------------------------------------------------------------------------------\r\n\r\nasterix2  SND\\redsolo_cp ASTERIX\r\nastreix   SND\\redsolo_cp ASTERIX\r\n\r\n"
  },
  {
    "path": "tfs/src/test/resources/tf.bat",
    "content": "@ECHO OFF\r\n\r\nIF \"%1\" == \"\" GOTO HELP\r\n\r\nREM\r\nREM Determine what command to fake\r\nset command-output=\"%~dp0tf-%1.log\"\r\nset command=%1\r\n\r\nREM\r\nREM Find the last argument\r\nSETLOCAL\r\nSHIFT\r\n:LOOP\r\nIF {%1}=={} GOTO FOUND\r\nSET LAST=%1\r\nSHIFT\r\nGOTO :LOOP\r\n:FOUND\r\nENDLOCAL&SET LAST=%LAST%\r\n\r\nIF \"%command%\" == \"mkview\" GOTO MKVIEW\r\nIF \"%command%\" == \"setcs\" GOTO END\r\nGOTO PRINT-OUTPUT\r\n\r\n:MKVIEW\r\nmkdir %LAST%\r\n\r\n\r\n:PRINT-OUTPUT\r\nIF NOT EXIST %command-output% goto UNKNOWN-COMMAND\r\ntype %command-output%\r\nset errorlevel = 0\r\nGOTO END\r\n\r\n\r\n:UNKNOWN-COMMAND\r\nECHO Unknown command %1, %command-output%\r\nset errorlevel = 2\r\nGOTO END\r\n\r\n\r\n:HELP\r\necho Usage: tf [command] [ignored arguments]\r\nset errorlevel = 1\r\nGOTO END\r\n\r\n\r\n:END\r\nexit /b %errorlevel%"
  },
  {
    "path": "tfs/src/test/resources/tf.sh",
    "content": "#!/bin/sh\n#\n# This shell script will cat files named tf-[command].log to the stdout.\n# \n#\nif [ $# = 0 ]; then\n\techo 1>&2 Usage: tf [command] [ignored arguments]\n\texit 1\nfi\n\ncommandfile=`dirname $0`/tf-$1.log\n\ncase $1 in\n\tworkfold)\n#\t\teval last_arg=\\$$#\n\t\tmkdir $4\n\t\t;;\n\tsetcs)\n\t\texit 0\n\t\t;;\nesac\n\nif [ -r  $commandfile ] \nthen\n\tcat $commandfile\n\texit 0\nelse\n\techo Unknown command $1, $commandfile\n\texit 1\nfi\n"
  },
  {
    "path": "tfs-sdk/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.jenkins-ci.plugins</groupId>\n    <artifactId>tfs-parent</artifactId>\n    <version>5.157.1-SNAPSHOT</version>\n  </parent>\n\n  <artifactId>tfs-sdk</artifactId>\n  <name>TFS SDK installer</name>\n  <packaging>pom</packaging>\n\n  <!-- http://stackoverflow.com/a/31511080/98903 -->\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-install-plugin</artifactId>\n        <version>2.5.2</version>\n        <executions>\n          <execution>\n            <id>install.tfs.sdk.jar.locally</id>\n            <phase>validate</phase>\n            <goals>\n              <goal>install-file</goal>\n            </goals>\n            <configuration>\n              <file>src/com.microsoft.tfs.sdk-14.0.3.jar</file>\n              <groupId>com.microsoft.tfs.sdk</groupId>\n              <artifactId>com.microsoft.tfs.sdk</artifactId>\n              <version>14.0.3</version>\n              <packaging>jar</packaging>\n              <generatePom>true</generatePom>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  }
]