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.
You must be logged in to post a comment.