A great article on a few intermediate-level tidbits of knowledge:
Month: July 2016
Setting Environment Variables From PowerShell Tasks Under TFS 2015
This is less than intuitive, but you can hotwire some underlying functionality to set your own environment variables that will persist from task to task. Here, we take a value from the environment and set another value derived from it.
Write-Host "##vso[task.setvariable variable=ACTIONSFOLDER;]$env:BUILD_DROPFOLDER\Scripts\Steps"
Sorting All Files in Tree by Modified-Time (in OS X)
This command had to be modified to run under OS X as it, and its heritage, don’t support the “-printf” parameter:
$ find . -print0 | xargs -0 stat -f '%m %N' | sort -k 1,1 -n
Tail of output in my situation:
1469286497 ./dev_import/data/160609_103423/.160609_103423.processing/style-color 1469286497 ./dev_import/data/160609_103423/.160609_103423.processing/upc 1469286541 ./bip/config/log.py 1469286566 ./dev/run_dev.sh 1469286597 ./dev_import/data/160609_103423/events.log.20160723-110946 1469286624 ./dev_import/data/160609_103423/.160609_103423.processing 1469286626 ./dev_import/data/160609_103423 1469286626 ./dev_import/data/160609_103423/events.log.20160723-111026
Using NuGet.Core to Get the Latest Version of a Package
Add the NuGet.Core package from NuGet and you’ll be in business. We use a NuGet config-file to get the one or more repositories that you might be using and hit them one at a time.
using NuGet; using System; using System.Collections.Generic; using System.Linq; using System.Xml.XPath; namespace LatestVersion { class PackageNotFoundException : Exception { public string PackageName { get; private set; } public PackageNotFoundException(string packageName) : base(String.Format("Package [{0}] not found.", packageName)) { PackageName = packageName; } } class NuGet { string nugetConfigFilepath; public NuGet(string nugetConfigFilepath) { this.nugetConfigFilepath = nugetConfigFilepath; } public IEnumerable<Tuple> GetSources() { XPathNavigator nav; XPathDocument docNav; string xPath; docNav = new XPathDocument(nugetConfigFilepath); nav = docNav.CreateNavigator(); xPath = "/configuration/packageSources/add"; foreach (XPathNavigator xpn in nav.Select(xPath)) { string name = xpn.GetAttribute("key", ""); string uri = xpn.GetAttribute("value", ""); yield return new Tuple(name, uri); } } public SemanticVersion GetLatestVersion(string packageName) { foreach (Tuple source in GetSources()) { string name = source.Item1; string uri = source.Item2; IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository(uri); // Passing NULL for `versionSpec` will return the latest version. IEnumerable packagesRaw = repo.FindPackages(packageName, null, false, false); IList packages = packagesRaw.ToList(); if (packages.Count == 0) { continue; } return packages[0].Version; } throw new PackageNotFoundException(packageName); } } }
Best Argument-Processing for .NET/C#
After trying NDesk.Options and Fluent, I am nothing but impressed with CLAP (“Command-Line Auto-Parser”). It completely relies on reflection and parameter attributes (usually just one or two) to automatically marshal your values, assign defaults, enforce requiredness, and provide command-line documentation. It’s beautiful and, so far, flawless. Well done.
using CLAP; namespace MyNamespace { class Program { [Verb(IsDefault = true, Description = "Print the current version of the given package and, optionally, increment it.")] public void Version( [Description("Project path")] [Required] string projectPath, [Description("Package name")] [Required] string packageName, [Description("Base version to increment from (if lower than current, else use current)")] string baseVersion = null, [Description("Increment the version before returning")] bool increment = false ) { // ... } } }
If you don’t decorate with the “Required” attribute and don’t provide a default value the parameter will default to null
. I explicitly set baseVersion
to a default of null
because I prefer being explicit.
Converting TFS 2015 Build Definition Names to Their Directory IDs
A TFS 2015 agent maintains a directory of build-space directories, where each corresponds to a single build definition. Each of these has a source-directory (“s”; usually automatically checked-out), binaries-directory (“b”; for intermediate binaries prior to publish-oriented cherry-picking), and artifact-staging directory (“a”; for artifacts to be published).
Not only is each of the build-space directories an integer with no clear mapping to the build-definition but this integer is different from one agent to the next. It turns out that there is a meta-information directory whose children are collection GUIDs. Furthermore, the children of those directories are additional directories with integer names. Each of these has a JSON file that contains build-definition information.
I quickly wrote a Python script to search for a given build definition and print the ID. The basic functionality is split into succinct, easily-callable methods for whatever other tasks you might have.
import logging import os.path import json _LOGGER = logging.getLogger(__name__) class Tfs(object): def __init__(self, agent_path): self.__agent_path = agent_path self.__srm_path = \ os.path.join( self.__agent_path, '_work', 'SourceRootMapping') _LOGGER.debug("Agent SRM path: [%s]", self.__srm_path) def collection_gen(self): for filename in os.listdir(self.__srm_path): filepath = os.path.join(self.__srm_path, filename) if os.path.isdir(filepath) is False: continue _LOGGER.debug("Collection GUID: [%s]", filename) yield filename, filepath def definition_gen(self, collection_path): for srm_id_raw in os.listdir(collection_path): _LOGGER.debug("SRM ID: [%s]", srm_id_raw) definition_info_filepath = \ os.path.join( collection_path, srm_id_raw, 'SourceFolder.json') with open(definition_info_filepath) as f: yield json.load(f) def lookup_definition(self, definition_name): for collection_guid, collection_path in self.collection_gen(): for definition in self.definition_gen(collection_path): current_definition_name = definition['definitionName'] _LOGGER.debug("Definition: [%s]", current_definition_name) if current_definition_name != definition_name: continue return definition raise ValueError("Could not find definition: {}".format( definition_name)) def _configure_logging(): sh = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s [%(name)s %(levelname)s] %(message)s') sh.setFormatter(formatter) _LOGGER.addHandler(sh) _LOGGER.setLevel(logging.DEBUG) if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument( 'agent_path', help="Agent path") parser.add_argument( 'definition_name', help="Build-definition name") args = parser.parse_args() _configure_logging() t = Tfs(args.agent_path) definition = t.lookup_definition(args.definition_name) print(definition['agent_builddirectory'])
Output:
D:\development\python>python tfs.py c:\tfs_build_agent ConsoleProject.Dev 2016-07-07 23:32:02,756 [__main__ DEBUG] Agent SRM path: [c:\tfs_build_agent\_work\SourceRootMapping] 2016-07-07 23:32:02,756 [__main__ DEBUG] Collection GUID: [2cf8d3cb-b8d4-49e1-bbdb-2aacf02f48c4] 2016-07-07 23:32:02,757 [__main__ DEBUG] SRM ID: [1] 2016-07-07 23:32:02,757 [__main__ DEBUG] Definition: [ConsoleProject.Dev] 1
Important Notes
-
The child directories of the SourceRootMapping directory will not exactly reflect the current build definitions. Some of them may represent build definitions that no longer exist.
-
One of the current work directories may be using an ID used by an old build-definition at some point in the past. So, if you are building a dictionary of work-directory IDs to build-definitions, you will have to use the build-definition’s ID or one of the timestamps described in the its JSON file to reconcile the latest build-definition to use that directory.
Searching for Specific Packages in NuGet
Package searches in NuGet hit the query API and the query API, by default, does a substring search. This obviously might get annoying when a simple string that you’re searching for might appear within any of the searchable characteristics of many different packages.
However, since this is the standard query interface, and you can pass more than just flat strings, you can also modify the query to do an exact search using the “PackageId” modifier:
C:\>nuget list zebus Zebus 1.4.6 Zebus.Directory 1.2.10 Zebus.Directory.Cassandra 1.2.10 Zebus.Directory.Standalone 1.2.10 Zebus.Persistence 1.0.2 Zebus.Persistence.CQL 1.0.2 Zebus.Persistence.CQL.Testing 1.0.2 Zebus.Testing 1.4.6 C:\>nuget list PackageId:zebus Zebus 1.4.6
TFS 2015 Database Structure Investigation
A TFS 2015 build agent maintains a list of directories where builds occur. Each of these directories is assigned a monotonically-incrementing number and has three children: “s” (“source” directory where your files are, usually, automatically checked-out for you), “b” (“binaries” directory where you can choose to stash files that aren’t automatically cleaned-up), and “a” (“artifact-staging” directory where you push files/directories that will be published). Each agent assigns its own IDs for each build definition.
I sought to figure out 1) how to lookup the mapping between the build-definitions and these agent-ID pairs, and 2) how to lookup the paths when you publish a build to be stored by the TFS server (rather than a fileshare). Every so often I wander into the TFS database to chip away at its elusive topology. I’ll briefly document my observations here for the benefit of myself and others. I’ll add on new information as I might encounter it in the future. I’m only currently concerned with build-definitions but any information that can be provided for release-definitions would also be welcomes.
There is a main database (e.g. “Tfs_Configuration”) and subordinate collection-specific database (e.e. “Tfs_DefaultCollection”).
[Build].[tbl_Build]
Information on individual builds including build numbers (e.g. 20160512.1) and “definition ID”.
SELECT looks like:
SELECT TOP 1000 [PartitionId] ,[DataspaceId] ,[BuildId] ,[DefinitionId] ,[DefinitionVersion] ,[BuildNumber] ,[BuildNumberRevision] ,[RepositoryId] ,[BranchId] ,[SourceVersion] ,[Parameters] ,[Status] ,[QueueId] ,[QueueTime] ,[Priority] ,[StartTime] ,[FinishTime] ,[Reason] ,[Result] ,[RequestedFor] ,[RequestedBy] ,[ChangedOn] ,[ChangedBy] ,[OrchestrationId] ,[Deleted] ,[ValidationIssues] ,[QueueOptions] ,[KeepForever] ,[ChangesCalculated] ,[DeletedOn] FROM [Tfs_DefaultCollection].[Build].[tbl_Build]
Record looks like:
PartitionId DataspaceId BuildId DefinitionId DefinitionVersion BuildNumber BuildNumberRevision RepositoryId BranchId SourceVersion Parameters Status QueueId QueueTime Priority StartTime FinishTime Reason Result RequestedFor RequestedBy ChangedOn ChangedBy OrchestrationId Deleted ValidationIssues QueueOptions KeepForever ChangesCalculated DeletedOn 1 22 168 1 58 20160701.1 1 1 2 C31 {"system.debug":"false","BuildConfiguration":"release","BuildPlatform":"any cpu"} 2 1 2016-07-01 16:11:01.2247845 3 2016-07-01 16:11:03.5025120 2016-07-01 16:11:23.2632483 1 2 FD456772-708D-496C-9259-32596770CD73 FD456772-708D-496C-9259-32596770CD73 2016-07-01 16:11:23.450 02442124-655A-49B2-A6FB-20269EDEBEF6 E6ABEC05-179C-4406-91CB-E96B9B6CFD7C 0 NULL NULL 0 1 NULL
[Build].[tbl_Definition]
Describes individual build-definitions, presumably. Includes “definition ID”, “definition version” (probably a pointer to the head version), “definition name”.
SELECT looks like:
SELECT TOP 1000 [PartitionId] ,[DataspaceId] ,[DefinitionId] ,[DefinitionVersion] ,[DefinitionName] ,[Quality] ,[QueueId] ,[QueueStatus] ,[RepositoryId] ,[DefaultBranchId] ,[TriggerTypes] ,[Description] ,[BuildNumberFormat] ,[JobAuthorizationScope] ,[JobTimeout] ,[Comment] ,[Author] ,[CreatedOn] ,[ParentDefinitionId] ,[Options] ,[Repository] ,[Triggers] ,[Steps] ,[Variables] ,[Demands] ,[RetentionPolicy] ,[BadgeEnabled] ,[Deleted] FROM [Tfs_DefaultCollection].[Build].[tbl_Definition]
Record looks like:
PartitionId DataspaceId DefinitionId DefinitionVersion DefinitionName Quality QueueId QueueStatus RepositoryId DefaultBranchId TriggerTypes Description BuildNumberFormat JobAuthorizationScope JobTimeout Comment Author CreatedOn ParentDefinitionId Options Repository Triggers Steps Variables Demands RetentionPolicy BadgeEnabled Deleted 1 22 1 58 ConsoleProject.Dev 1 1 0 1 1 1 NULL $(date:yyyyMMdd)$(rev:.r) 1 60 Added publish-to-server step. FD456772-708D-496C-9259-32596770CD73 2016-07-01 16:10:57.070 NULL [{"enabled":false,"definition":{"id":"7c555368-ca64-4199-add6-9ebaf0b0137d"},"inputs":{"multipliers":"[]","parallel":"false","continueOnError":"true","additionalFields":"{}"}},{"enabled":false,"definition":{"id":"a9db38f9-9fdc-478c-b0f9-464221e58316"},"inputs":{"workItemType":"1","assignToRequestor":"true","additionalFields":"{}"}},{"enabled":false,"definition":{"id":"57578776-4c22-4526-aeb0-86b6da17ee9c"},"inputs":{"additionalFields":"{}"}}] {"properties":{"labelSources":"0","tfvcMapping":"{\"mappings\":[{\"serverPath\":\"$/d67f9d95-2f6c-43f0-aa2f-6f7804fde7db\",\"mappingType\":\"map\",\"localPath\":\"\\\\\"},{\"serverPath\":\"$/d67f9d95-2f6c-43f0-aa2f-6f7804fde7db/Drops\",\"mappingType\":\"cloak\",\"localPath\":\"\\\\\"}]}"},"id":"$/","type":"TfsVersionControl","name":"d67f9d95-2f6c-43f0-aa2f-6f7804fde7db","url":"http://dustin-pc:8181/tfs/DefaultCollection/","defaultBranch":"$/d67f9d95-2f6c-43f0-aa2f-6f7804fde7db","rootFolder":"$/d67f9d95-2f6c-43f0-aa2f-6f7804fde7db","clean":"false","checkoutSubmodules":false} NULL [{"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build solution $/TestProject/TestConsoleApplication.sln","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"*"},"inputs":{"solution":"$/d67f9d95-2f6c-43f0-aa2f-6f7804fde7db/TestConsoleApplication.sln","msbuildArgs":"/target:publish /p:ApplicationVersion=1.0.2.2 /p:InstallUrl=\\\\localhost\\clickonce\\consoletestfrombuild\\ /p:UpdateUrl=\\\\localhost\\clickonce\\consoletestfrombuild\\ /p:PublishUrl=\\\\localhost\\clickonce\\consoletestfrombuild\\ /p:UpdateEnabled=true /p:UpdateMode=Foreground /p:ProductName=TestConsoleApplication /p:IsWebBootstrapper=false","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","clean":"true","restoreNugetPackages":"true","vsVersion":"14.0","msbuildArchitecture":"x86","logProjectEvents":"true"}},{"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build solution $/TestProject/TestDatabase.sln","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"*"},"inputs":{"solution":"$/d67f9d95-2f6c-43f0-aa2f-6f7804fde7db/TestDatabase.sln","msbuildArgs":"","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","clean":"true","restoreNugetPackages":"true","vsVersion":"14.0","msbuildArchitecture":"x86","logProjectEvents":"true"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Run script $/TestProject/TestScripts/TestEcho.cmd","task":{"id":"bfc8bf76-e7ac-4a8c-9a55-a944a9f632fd","versionSpec":"*"},"inputs":{"filename":"$/d67f9d95-2f6c-43f0-aa2f-6f7804fde7db/TestScripts/TestEcho.cmd","arguments":"","modifyEnvironment":"false","workingFolder":"","failOnStandardError":"false"}},{"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Copy Files to: $(Build.ArtifactStagingDirectory)","task":{"id":"5bfb729a-a7c8-4a78-a7c3-8d717bb7c13c","versionSpec":"*"},"inputs":{"SourceFolder":"$(Build.SourcesDirectory)\\TestConsoleApplication\\bin\\Release","Contents":"**\\*","TargetFolder":"$(Build.ArtifactStagingDirectory)","CleanTargetFolder":"true","OverWrite":"false"}},{"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Copy Files to: $(Build.ArtifactStagingDirectory)\\deployment\\Release\\Utility","task":{"id":"5bfb729a-a7c8-4a78-a7c3-8d717bb7c13c","versionSpec":"*"},"inputs":{"SourceFolder":"$(Build.SourcesDirectory)\\Release\\Utility","Contents":"**\\*","TargetFolder":"$(Build.ArtifactStagingDirectory)\\deployment\\Release\\Utility","CleanTargetFolder":"false","OverWrite":"false"}},{"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Copy Files to: $(Build.ArtifactStagingDirectory)/TestDatabase1","task":{"id":"5bfb729a-a7c8-4a78-a7c3-8d717bb7c13c","versionSpec":"*"},"inputs":{"SourceFolder":"$(Build.SourcesDirectory)\\TestDatabase1\\bin\\Release","Contents":"TestDatabase1.dacpac","TargetFolder":"$(Build.ArtifactStagingDirectory)/TestDatabase1","CleanTargetFolder":"false","OverWrite":"false"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Publish Artifact: drop","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"*"},"inputs":{"PathtoPublish":"$(build.artifactstagingdirectory)","ArtifactName":"drop","ArtifactType":"FilePath","TargetPath":"\\\\localhost\\build_publish\\$(Build.DefinitionName)\\$(Build.BuildNumber)"}},{"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Publish Artifact: Published_$(Build.BuildNumber)","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"*"},"inputs":{"PathtoPublish":"$(build.artifactstagingdirectory)","ArtifactName":"Published_$(Build.BuildNumber)","ArtifactType":"Container","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)"}}] {"system.debug":{"value":"false","allowOverride":true},"BuildConfiguration":{"value":"release","allowOverride":true},"BuildPlatform":{"value":"any cpu","allowOverride":true},"DUSTINPASSWORD":{"value":null,"allowOverride":true,"isSecret":true}} NULL [{"branches":["+refs/heads/*"],"artifacts":["build.SourceLabel"],"daysToKeep":10,"minimumToKeep":1,"deleteBuildRecord":true,"deleteTestResults":true}] 0 0
[Build].[tbl_DefinitionHistory]
Describes the history of changes to the definition. Includes “definition ID”, “definition version”, “definition name”, and several JSON blocks.
Note that the record I provided is the most recent available (in my local sandbox environment). Though I had just made a change to a definition, it was, curiously, not represented in this table (though many other, previous, changes ones were).
SELECT looks like:
SELECT TOP 1000 [PartitionId] ,[DataspaceId] ,[DefinitionId] ,[DefinitionVersion] ,[DefinitionName] ,[QueueId] ,[QueueStatus] ,[RepositoryId] ,[DefaultBranchId] ,[Description] ,[BuildNumberFormat] ,[JobAuthorizationScope] ,[JobTimeout] ,[Comment] ,[Author] ,[CreatedOn] ,[Options] ,[Repository] ,[Triggers] ,[Steps] ,[Variables] ,[Demands] ,[RetentionPolicy] ,[BadgeEnabled] ,[Deleted] FROM [Tfs_DefaultCollection].[Build].[tbl_DefinitionHistory]
Record looks like:
PartitionId DataspaceId DefinitionId DefinitionVersion DefinitionName QueueId QueueStatus RepositoryId DefaultBranchId Description BuildNumberFormat JobAuthorizationScope JobTimeout Comment Author CreatedOn Options Repository Triggers Steps Variables Demands RetentionPolicy BadgeEnabled Deleted 1 32 12 18 PWC Audit360 Simulation Build 1 0 2 9 NULL $(date:yyyyMMdd)$(rev:.r) 1 60 NULL FD456772-708D-496C-9259-32596770CD73 2016-05-27 18:45:03.117 [{"enabled":false,"definition":{"id":"7c555368-ca64-4199-add6-9ebaf0b0137d"},"inputs":{"multipliers":"[]","parallel":"false","continueOnError":"true","additionalFields":"{}"}},{"enabled":false,"definition":{"id":"a9db38f9-9fdc-478c-b0f9-464221e58316"},"inputs":{"workItemType":"16","assignToRequestor":"true","additionalFields":"{}"}},{"enabled":false,"definition":{"id":"57578776-4c22-4526-aeb0-86b6da17ee9c"},"inputs":{"additionalFields":"{}"}}] {"properties":{"labelSources":"0","tfvcMapping":"{\"mappings\":[{\"serverPath\":\"$/d0942daa-ac39-462f-8115-fada54d8f780\",\"mappingType\":\"map\",\"localPath\":\"\\\\\"},{\"serverPath\":\"$/d0942daa-ac39-462f-8115-fada54d8f780/Drops\",\"mappingType\":\"cloak\",\"localPath\":\"\\\\\"}]}"},"id":"$/","type":"TfsVersionControl","name":"d0942daa-ac39-462f-8115-fada54d8f780","url":"http://dustin-pc:8181/tfs/DefaultCollection/","defaultBranch":"$/d0942daa-ac39-462f-8115-fada54d8f780","rootFolder":"$/d0942daa-ac39-462f-8115-fada54d8f780","clean":"false","checkoutSubmodules":false} NULL [{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"NuGet restore Audit360.Server.sln","task":{"id":"333b11bd-d341-40d9-afcf-b32d5ce6f23b","versionSpec":"*"},"inputs":{"solution":"Audit360.Server.sln","nugetConfigPath":"$/d0942daa-ac39-462f-8115-fada54d8f780/nuget.config","noCache":"false","nuGetRestoreArgs":"","nuGetPath":""}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"NuGet restore Audit360.SilverlightBuild.sln","task":{"id":"333b11bd-d341-40d9-afcf-b32d5ce6f23b","versionSpec":"*"},"inputs":{"solution":"Audit360.SilverlightBuild.sln","nugetConfigPath":"","noCache":"false","nuGetRestoreArgs":"","nuGetPath":""}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"NuGet restore Audit360.Database.sln","task":{"id":"333b11bd-d341-40d9-afcf-b32d5ce6f23b","versionSpec":"*"},"inputs":{"solution":"Audit360.Database.sln","nugetConfigPath":"","noCache":"false","nuGetRestoreArgs":"","nuGetPath":""}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"NuGet restore Audit360.Queue.sln","task":{"id":"333b11bd-d341-40d9-afcf-b32d5ce6f23b","versionSpec":"*"},"inputs":{"solution":"Audit360.Queue.sln","nugetConfigPath":"","noCache":"false","nuGetRestoreArgs":"","nuGetPath":""}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"NuGet restore MarketData.Database.sln","task":{"id":"333b11bd-d341-40d9-afcf-b32d5ce6f23b","versionSpec":"*"},"inputs":{"solution":"MarketData.Database.sln","nugetConfigPath":"","noCache":"false","nuGetRestoreArgs":"","nuGetPath":""}},{"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build solution Audit360.Server.sln","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"*"},"inputs":{"solution":"Audit360.Server.sln","msbuildArgs":"/t:build;publish /p:DeployOnBuild=True /m:1 /p:DeployPrefix=F1","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","clean":"true","restoreNugetPackages":"true","vsVersion":"14.0","msbuildArchitecture":"x86","logProjectEvents":"true"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Build solution Audit360.SilverlightBuild.sln","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"*"},"inputs":{"solution":"Audit360.SilverlightBuild.sln","msbuildArgs":"","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","clean":"true","restoreNugetPackages":"true","vsVersion":"14.0","msbuildArchitecture":"x86","logProjectEvents":"true"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Build solution Audit360.Database.sln","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"*"},"inputs":{"solution":"Audit360.Database.sln","msbuildArgs":"","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","clean":"true","restoreNugetPackages":"true","vsVersion":"14.0","msbuildArchitecture":"x86","logProjectEvents":"true"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Build solution Audit360.Queue.sln","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"*"},"inputs":{"solution":"Audit360.Queue.sln","msbuildArgs":"","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","clean":"true","restoreNugetPackages":"true","vsVersion":"14.0","msbuildArchitecture":"x86","logProjectEvents":"true"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Build solution MarketData.Database.sln","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"*"},"inputs":{"solution":"MarketData.Database.sln","msbuildArgs":"","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","clean":"true","restoreNugetPackages":"true","vsVersion":"14.0","msbuildArchitecture":"x86","logProjectEvents":"true"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Test Assemblies **\\$(BuildConfiguration)\\*test*.dll;-:**\\obj\\**","task":{"id":"ef087383-ee5e-42c7-9a53-ab56c98420f9","versionSpec":"*"},"inputs":{"testAssembly":"**\\$(BuildConfiguration)\\*test*.dll;-:**\\obj\\**","testFiltercriteria":"","runSettingsFile":"","overrideTestrunParameters":"","codeCoverageEnabled":"false","runInParallel":"false","vsTestVersion":"14.0","pathtoCustomTestAdapters":"","otherConsoleOptions":"","testRunTitle":"","platform":"$(BuildPlatform)","configuration":"$(BuildConfiguration)","publishRunAttachments":"true"}},{"enabled":false,"continueOnError":true,"alwaysRun":false,"displayName":"Publish symbols path: ","task":{"id":"0675668a-7bba-4ccb-901d-5ad6554ca653","versionSpec":"*"},"inputs":{"SymbolsPath":"","SearchPattern":"**\\bin\\**\\*.pdb","SymbolsFolder":"","SkipIndexing":"false","TreatNotIndexedAsWarning":"false","SymbolsMaximumWaitTime":"","SymbolsProduct":"","SymbolsVersion":"","SymbolsArtifactName":"Symbols_$(BuildConfiguration)"}},{"enabled":false,"continueOnError":false,"alwaysRun":true,"displayName":"Copy Files to: $(build.artifactstagingdirectory)","task":{"id":"5bfb729a-a7c8-4a78-a7c3-8d717bb7c13c","versionSpec":"*"},"inputs":{"SourceFolder":"$(build.sourcesdirectory)","Contents":"**\\bin\\$(BuildConfiguration)\\**","TargetFolder":"$(build.artifactstagingdirectory)","CleanTargetFolder":"false","OverWrite":"false"}},{"enabled":false,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact: drop","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"*"},"inputs":{"PathtoPublish":"$(build.artifactstagingdirectory)","ArtifactName":"drop","ArtifactType":"Container","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)"}},{"enabled":false,"continueOnError":false,"alwaysRun":false,"displayName":"Run script $/PwcSimulation/Build/RMPostBuild.cmd","task":{"id":"bfc8bf76-e7ac-4a8c-9a55-a944a9f632fd","versionSpec":"*"},"inputs":{"filename":"$/d0942daa-ac39-462f-8115-fada54d8f780/Build/RMPostBuild.cmd","arguments":"/C:FB /E:F1","modifyEnvironment":"false","workingFolder":"","failOnStandardError":"false"}}] {"system.debug":{"value":"false","allowOverride":true},"BuildConfiguration":{"value":"FB","allowOverride":true},"BuildPlatform":{"value":"any cpu","allowOverride":true}} NULL [{"branches":["+refs/heads/*"],"artifacts":["build.SourceLabel"],"daysToKeep":10,"minimumToKeep":1,"deleteBuildRecord":true,"deleteTestResults":true}] 0 0
[dbo].[tbl_Workspace]
Appears to describe the workspaces that are currently defined for users, builds, etc..
SELECT looks like:
SELECT TOP 1000 [PartitionId] ,[WorkspaceId] ,[OwnerId] ,[WorkspaceName] ,[WorkspaceVersion] ,[Type] ,[Comment] ,[CreationDate] ,[Computer] ,[PolicyOverrideComment] ,[LastAccessDate] ,[CheckInNoteId] ,[RefreshRecursive] ,[HasDeletedChanges] ,[SequentialId] ,[IsLocal] ,[PendingChangeSig] ,[FileTime] ,[LastMappingsUpdate] ,[ProjectNotificationId] ,[ItemIdCounter] ,[VersionStamp] FROM [Tfs_DefaultCollection].[dbo].[tbl_Workspace]
Record looks like :
PartitionId WorkspaceId OwnerId WorkspaceName WorkspaceVersion Type Comment CreationDate Computer PolicyOverrideComment LastAccessDate CheckInNoteId RefreshRecursive HasDeletedChanges SequentialId IsLocal PendingChangeSig FileTime LastMappingsUpdate ProjectNotificationId ItemIdCounter VersionStamp 1 420000001 65CED833-E406-4B14-BDB2-51590FE7569C ws_5_1 1 0 Created by Distributed Task - getCode 2016-06-29 03:47:10.363 DUSTIN-PC NULL 2016-06-29 03:47:10.363 NULL 0 0 22 1 B2140B25-F70A-4B4D-BFB1-184703037010 0 2016-06-29 03:47:10.370 37 -1025 2.00
[dbo].[tbl_WorkingFolder]
This use of this table is unclear. It describes the paths on the disk where the build-processes for each definition are hosted, but they also include a “workspace ID”. This would make sense for individual builds but not for latent build-definitions (workspaces for builds are ephemeral, unless the build fails, and are only created once the build starts). This seems promising for where the mappings for the build directories are stored, except that there appears to be potentially many records for the same build-definitions.
SELECT looks like:
SELECT TOP 1000 [PartitionId] ,[WorkspaceId] ,[ItemDataspaceId] ,[ProjectName] ,[ServerItem] ,[LocalItem] ,[MappingType] ,[CreationDate] ,[Depth] FROM [Tfs_DefaultCollection].[dbo].[tbl_WorkingFolder]
Record looks like:
PartitionId WorkspaceId ItemDataspaceId ProjectName ServerItem LocalItem MappingType CreationDate Depth 1 320000001 21 TestProject $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\ C:\tfs>build>agent\>work\1\s\ 1 2016-07-01 16:11:07.500 120 1 320000001 21 TestProject $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\Drops\ NULL 0 2016-07-01 16:11:07.500 120 1 360000001 21 TestProject $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\ C:\tfs>build>agent\>work\3\s\ 1 2016-05-24 18:22:09.760 120 1 360000001 21 TestProject $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\Drops\ NULL 0 2016-05-24 18:22:09.760 120 1 420000001 21 TestProject $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\ C:\tfs>build>agent\>work\5\s\ 1 2016-06-29 03:47:10.363 120 1 420000001 21 TestProject $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\Drops\ NULL 0 2016-06-29 03:47:10.363 120
[dbo].[tbl_WorkingFolderHistory]
The purpose of this table is completely unclear, though it includes build location paths (just like WorkingFolder).
SELECT looks like:
SELECT TOP 1000 [PartitionId] ,[WorkspaceId] ,[ItemDataspaceId] ,[ServerItem] ,[LocalItem] ,[Active] FROM [Tfs_DefaultCollection].[dbo].[tbl_WorkingFolderHistory]
Record looks like:
PartitionId WorkspaceId ItemDataspaceId ServerItem LocalItem Active 1 320000001 21 $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\ C:\tfs>build>agent\>work\1\s\ 1 1 320000001 21 $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\Drops\ C:\tfs>build>agent\>work\1\s\Drops\ 0 1 360000001 21 $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\ C:\tfs>build>agent\>work\3\s\ 1 1 400000001 31 $\d0942daa"ac39"462f"8115"fada54d8f780\ C:\tfs>build>agent\>work\7\s\ 0 1 400000001 31 $\d0942daa"ac39"462f"8115"fada54d8f780\Drops\ C:\tfs>build>agent\>work\7\s\Drops\ 0 1 420000001 21 $\d67f9d95"2f6c"43f0"aa2f"6f7804fde7db\ C:\tfs>build>agent\>work\5\s\ 1