def test_default(): filename = "config/buildorama.yml" logger, konf = sh.setup_config(filename) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] jenk_conf = konf.topLevel('Jenkins') job_name = 'troglodyte' assert jenk_conf['Jobs'][0]['Job'] == job_name
def test_namesake_projects(): # have a config that mentions m-e-p Project for the AgileCentral_Project # inhale the config # mock up a build for the 'australopithicus' Job which will trigger the necessity of creating an AC BuildDefinition record for it filename = "config/platypus.yml" logger, konf = sh.setup_config(filename, jenkins_structure=PLATYPUS_JENKINS_STRUCTURE, services=PLATYPUS_SERVICES) bc = bsh.BLDConnector(konf, logger) agiconn = bc.agicen_conn # use agiconn.agicen to clear out any Builds/BuildDefinition that match our intended actions jobs_projs = {'centaur-mordant': agiconn.agicen.getProject('Jenkins // Salamandra').oid, 'australopithicus': agiconn.agicen.getProject('Jenkins // Corral // Salamandra').oid, } for job, project_oid in jobs_projs.items(): criteria = ['BuildDefinition.Name = "%s"' % job, 'BuildDefinition.Project.ObjectID = %d' % project_oid] response = agiconn.agicen.get('Build', fetch="ObjectID,Name", query=criteria) for build in response: agiconn.agicen.delete('Build', build) criteria = ['Name = "%s"' % job, 'Project.ObjectID = %d' % project_oid] response = agiconn.agicen.get('BuildDefinition', fetch="ObjectID,Name", query=criteria) for buildef in response: agiconn.agicen.delete('BuildDefinition', buildef) assert 'Jenkins' in agiconn._project_cache.keys() assert 'Jenkins // Salamandra' in agiconn._project_cache.keys() assert 'Jenkins // Corral // Salamandra' in agiconn._project_cache.keys() target_project = "Jenkins // Corral // Salamandra" tp = agiconn.agicen.getProject(target_project) assert target_project in bc.target_projects # create some mock builds for associated with the mep Projects # throw those against #builds = createMockBuilds(['centaur-mordant', 'australopithicus']) job_name = 'australopithicus' build_start = int((datetime.datetime.now() - datetime.timedelta(minutes=60)).timestamp()) build_number, status = 532, 'SUCCESS' started, duration = build_start, 231 commits = [] build = bsh.MockJenkinsBuild(job_name, build_number, status, started, duration, commits) build.changeSets = [] build.url = "http://jenkey.dfsa.com:8080/job/bashfulmonkies/532" build_data = build.as_tuple_data() info = OrderedDict(build_data) assert 'Project' not in info build_job_uri = "/".join(build.url.split('/')[:-2]) build_defn = agiconn.ensureBuildDefinitionExists(job_name, 'Jenkins // Corral // Salamandra', build_job_uri) assert build_defn.Name == job_name assert build_defn.Project.ObjectID == tp.oid if agiconn.buildExists(build_defn, build.number): agiconn.log.debug('Build #{0} for {1} already recorded, skipping...'.format(build.number, job_name)) # pull out any build.changeSets commit IDs and see if they match up with AgileCentral Changeset items Revision attribute # if so, get all such commit IDs and their associated Changeset ObjectID, then # add that "collection" as the Build's Changesets collection agicen_build, status = bc.postBuildToAgileCentral(build_defn, build, [], job_name) assert agicen_build.BuildDefinition.ref == build_defn.ref
def test_jenkins_struct_with_bad_projects(): of = sh.OutputFile('test.log') filename = "config/wallace_gf.yml" jenkins_struct = { 'Jobs': [{ 'Job': 'Wendolene Ramsbottom', 'AgileCentral_Project': 'Close Shave' }, { 'Job': 'Lady Tottington', 'AgileCentral_Project': 'The Curse of the Were-Rabbit' }, { 'Job': 'Piella Bakewell', 'AgileCentral_Project': 'A Matter of Loaf and Death' }] } logger, konf = sh.setup_config(filename, jenkins_struct) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] expectedErrPattern = "These projects mentioned in the config were not located in AgileCentral Workspace %s" % konf.topLevel( 'AgileCentral')['Workspace'] with pytest.raises(Exception) as excinfo: sh.BLDConnector(konf, logger) assert excinfo.typename == 'ConfigurationError' log_output = of.readlines() error_line = [line for line in log_output if 'ERROR' in line][0] assert re.search(expectedErrPattern, error_line) is not None
def test_services_non_default(): filename = "config/wallace_gf.yml" service_struct = { 'Preview': False, 'LogLevel': 'INFO', 'ShowVCSData': False } logger, konf = sh.setup_config(filename, 'DEFAULT_JENKINS_STRUCTURE', service_struct) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] service_conf = konf.topLevel('Service') assert service_conf['Preview'] == False
def test_bad_services_config(): filename = "config/wallace_gf.yml" service_struct = { 'Purview': False, 'LogChains': 'INFO', 'VenusRising': False } expectedErrPattern = 'Supplied services .* contain bogus items' with pytest.raises(Exception) as excinfo: logger, konf = sh.setup_config(filename, 'DEFAULT_JENKINS_STRUCTURE', service_struct) actualErrVerbiage = excinfo.value.args[0] assert re.match(expectedErrPattern, actualErrVerbiage) is not None
def test_validate_projects(): of = sh.OutputFile('test.log') filename = "config/wallace_gf.yml" logger, konf = sh.setup_config(filename) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] expectedErrPattern = "projects mentioned in the config were not located in AgileCentral Workspace" with pytest.raises(Exception) as excinfo: sh.BLDConnector(konf, logger) assert excinfo.typename == 'ConfigurationError' log_output = of.readlines() error_line = [line for line in log_output if 'ERROR' in line][0] assert re.search(expectedErrPattern, error_line) is not None
def test_bad_containers(): filename = "config/wallace_gf.yml" jenkin_struct = { 'Vistas': [{'Vista': 'Wendolene Ramsbottom', 'Allergies': 'Cheese'}, {'View': 'Lady Tottington'}, {'Job': 'Piella Bakewell'}] } expectedErrPattern = "Missing 'Vista'" with pytest.raises(Exception) as excinfo: logger, konf = sh.setup_config(filename, jenkin_struct) actualErrVerbiage = excinfo.value.args[0] assert expectedErrPattern in actualErrVerbiage
def test_default_config_spoke_validation(): filename = "config/wallace_gf.yml" logger, konf = sh.setup_config(filename) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] ac_conf = konf.topLevel('AgileCentral') ac_workspace = ac_conf['Workspace'] jenk_conf = konf.topLevel('Jenkins') expectedErrPattern = "Validation failed" with pytest.raises(Exception) as excinfo: build_connector = sh.BLDConnector(konf, logger) actualErrVerbiage = excinfo.value.args[0] assert re.search(expectedErrPattern, actualErrVerbiage) is not None assert excinfo.typename == 'ConfigurationError'
def test_structure_non_default(): filename = "config/wallace_gf.yml" jenkin_struct = { 'Jobs': [{'Job': 'Wendolene Ramsbottom', 'AgileCentral_Project': 'Close Shave'}, {'Job': 'Lady Tottington', 'AgileCentral_Project': 'The Curse of the Were-Rabbit'}, {'Job': 'Piella Bakewell', 'AgileCentral_Project': 'A Matter of Loaf and Death'}] } logger, konf = sh.setup_config(filename, jenkin_struct, 'DEFAULT_SERVICES') assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] jenk_conf = konf.topLevel('Jenkins') project_name = 'A Matter of Loaf and Death' assert jenk_conf['Jobs'][1]['Job'] == 'Lady Tottington' assert jenk_conf['Jobs'][2]['AgileCentral_Project'] == project_name
def test_bad_workspace_with_default_config(): filename = "config/wallace_gf.yml" logger, konf = sh.setup_config(filename) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] ac_conf = konf.topLevel('AgileCentral') ac_workspace = ac_conf['Workspace'] wrong_ac_workspace = "Dunderhead" ac_conf['Workspace'] = wrong_ac_workspace jenk_conf = konf.topLevel('Jenkins') expectedErrPattern = "Specified workspace of '.*' either does not exist or the user does not have permission to access that workspace" with pytest.raises(Exception) as excinfo: sh.BLDConnector(konf, logger) actualErrVerbiage = excinfo.value.args[0] assert re.search(expectedErrPattern, actualErrVerbiage) is not None
def test_jenkins_struct_with_bad_projects(): of = sh.OutputFile('test.log') filename = "config/wallace_gf.yml" jenkins_struct = { 'Jobs': [{'Job': 'Wendolene Ramsbottom', 'AgileCentral_Project': 'Close Shave'}, {'Job': 'Lady Tottington', 'AgileCentral_Project': 'The Curse of the Were-Rabbit'}, {'Job': 'Piella Bakewell', 'AgileCentral_Project': 'A Matter of Loaf and Death'}] } logger, konf = sh.setup_config(filename, jenkins_struct) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] expectedErrPattern = "These projects mentioned in the config were not located in AgileCentral Workspace %s" % konf.topLevel('AgileCentral')['Workspace'] with pytest.raises(Exception) as excinfo: sh.BLDConnector(konf, logger) assert excinfo.typename == 'ConfigurationError' log_output = of.readlines() error_line = [line for line in log_output if 'ERROR' in line][0] assert re.search(expectedErrPattern, error_line) is not None
def test_create_build_with_no_commits(): filename = "config/buildorama.yml" logger, konf = sh.setup_config(filename) konf.topLevel('AgileCentral')['Project'] = 'Jenkins' agicen = bsh.AgileCentralConnection(konf.topLevel('AgileCentral'), logger) agicen.other_name = 'Jenkins' agicen.connect() agicen.validateProjects(['Jenkins']) build_start = int((datetime.now() - timedelta(minutes=60)).timestamp()) build_name = 'Willy Wonka stirs the chocolate' job_name, build_number, status = '%s' % build_name, 532, 'SUCCESS' started, duration = build_start, 231 commits = [] build = bsh.MockJenkinsBuild(job_name, build_number, status, started, duration, commits) build.url = "http://jenkey.dfsa.com:8080/job/bashfulmonkies/532" build_job_uri = "/".join(build.url.split('/')[:-2]) build_defn = agicen.ensureBuildDefinitionExists(job_name, 'Jenkins', build_job_uri) assert build_defn is not None changesets = agicen.matchToChangesets(commits) assert len(changesets) == 0 binfo = OrderedDict(build.as_tuple_data()) binfo['BuildDefinition'] = build_defn agicen_build = agicen.createBuild(binfo) assert agicen_build is not None assert int(agicen_build.Number) == 532 query = 'BuildDefinition.Name = "%s"' % build_name workspace = konf.topLevel('AgileCentral')['Workspace'] response = agicen.agicen.get('Build', fetch='ObjectID,Name,BuildDefinition,Number', query=query, workspace=workspace, project=None) assert response.resultCount > 0 a_build = response.next() assert a_build.BuildDefinition.Name == build_name assert int(a_build.Number) == 532
def test_project_validation_queries(): """ we expect someting like this: ((((Name = "AC Engineering") OR (Name = "Alligator Tiers")) OR (Name = "O.U.T.S")) OR (Name = "2016 Q4")) returns 5 because there are two projects with Name = "2016 Q4" """ filename = "config/wallace_gf.yml" logger, konf = sh.setup_config(filename) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] ac_conf = konf.topLevel('AgileCentral') acc = sh.AgileCentralConnection(ac_conf, logger) figmentary_projects = ['Ambition', 'Epsilorg', 'Philo', 'Zebra'] cranky = acc._construct_ored_Name_query(figmentary_projects) assert cranky.count(' OR ') == 3 assert cranky.count('(') == cranky.count(")") noneski_projects = [] cranky = acc._construct_ored_Name_query(noneski_projects) assert len(cranky) == 0 assert cranky.count(' OR ') == 0
def jenkins_job_lifecycle(job_name, config, view="All", folder=None): """ Given a job name and a config dictionary, create a Job for the job name, simulate a build, run the part of the bldeif connector that will detect the job and then delete the job. """ logger, konf = sh.setup_config(config) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] jenk_conf = konf.topLevel('Jenkins') jenkins_url = jsh.construct_jenkins_url(jenk_conf) r1 = jsh.create_job(jenk_conf, jenkins_url, job_name, view, folder) assert r1.status_code in [200, 201] r2 = jsh.build(jenk_conf, jenkins_url, job_name, folder=folder) assert r2.status_code in [200, 201] r3 = jsh.delete_job(jenk_conf, jenkins_url, job_name, folder=folder) assert r3.status_code == 200 return True
def test_non_default_services(): filename = "config/wallace_gf.yml" jenkin_struct = { 'Jobs': [{'Job': 'Wendolene Ramsbottom', 'AgileCentral_Project': 'Close Shave'}, {'Job': 'Lady Tottington', 'AgileCentral_Project': 'The Curse of the Were-Rabbit'}, {'Job': 'Piella Bakewell', 'AgileCentral_Project': 'A Matter of Loaf and Death'}] } service_struct = { 'Preview': False, 'LogLevel': 'INFO', 'ShowVCSData': False } logger, konf = sh.setup_config(filename, jenkin_struct, service_struct) assert konf.topLevels() == ['AgileCentral', 'Jenkins', 'Service'] jenk_conf = konf.topLevel('Jenkins') project_name = 'Close Shave' assert jenk_conf['Jobs'][0]['Job'] == 'Wendolene Ramsbottom' assert jenk_conf['Jobs'][0]['AgileCentral_Project'] == project_name service_conf = konf.topLevel('Service') assert service_conf['Preview'] == False jenkins_jobs = jenk_conf['Jobs'] assert len(jenkins_jobs) == 3
def test_create_build_with_no_commits(): filename = "config/buildorama.yml" logger, konf = sh.setup_config(filename) konf.topLevel('AgileCentral')['Project'] = 'Jenkins' agicen = bsh.AgileCentralConnection(konf.topLevel('AgileCentral'), logger) agicen.other_name = 'Jenkins' agicen.connect() agicen.validateProjects(['Jenkins']) build_start = int((datetime.now() - timedelta(minutes=60)).timestamp()) build_name = 'Willy Wonka stirs the chocolate' job_name, build_number, status = '%s' %build_name, 532, 'SUCCESS' started, duration = build_start, 231 commits = [] build = bsh.MockJenkinsBuild(job_name, build_number, status, started, duration, commits) build.url = "http://jenkey.dfsa.com:8080/job/bashfulmonkies/532" build_job_uri = "/".join(build.url.split('/')[:-2]) build_defn = agicen.ensureBuildDefinitionExists(job_name, 'Jenkins', build_job_uri) assert build_defn is not None changesets = agicen.matchToChangesets(commits) assert len(changesets) == 0 binfo = OrderedDict(build.as_tuple_data()) binfo['BuildDefinition'] = build_defn agicen_build = agicen.createBuild(binfo) assert agicen_build is not None assert int(agicen_build.Number) == 532 query = 'BuildDefinition.Name = "%s"' % build_name workspace = konf.topLevel('AgileCentral')['Workspace'] response = agicen.agicen.get('Build', fetch='ObjectID,Name,BuildDefinition,Number', query=query, workspace=workspace, project=None) assert response.resultCount > 0 a_build = response.next() assert a_build.BuildDefinition.Name == build_name assert int(a_build.Number) == 532
def test_create_build_having_commits(): ref_time = datetime.now().utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") # get a konf and a logger, filename = "config/buildorama.yml" logger, konf = sh.setup_config(filename) konf.topLevel('AgileCentral')['Project'] = 'Jenkins' # get an AgileCentralConnection agicen = bsh.AgileCentralConnection(konf.topLevel('AgileCentral'), logger) agicen.other_name = 'Jenkins' agicen.connect() agicen.validateProjects(['Jenkins']) # mock up a Build build_start = int((datetime.now() - timedelta(minutes=60)).timestamp()) build_name = 'Hungry kids devour our tasty product' job_name, build_number, status = '%s' % build_name, 74, 'SUCCESS' started, duration = build_start, 43 # use some SHA values corresponding to some actual Agile Central Changeset items in our target Workspace commits = ['CHOCOLATE', 'MORE CHOCOLATE'] # these are actual shas random_scm_repo_name = "Velocirat" random_scm_type = "abacus" #scm_repo = create_scm_repo(agicen, random_scm_repo_name, random_scm_type) scm_repo = agicen.ensureSCMRepositoryExists(random_scm_repo_name, random_scm_type) for sha in commits: changeset_payload = { 'SCMRepository': scm_repo.ref, 'Revision': sha, 'CommitTimestamp': '2016-12-31' } try: changeset = agicen.agicen.create('Changeset', changeset_payload) except Exception as msg: raise Exception("Could not create Changeset %s" % msg) build = bsh.MockJenkinsBuild(job_name, build_number, status, started, duration, commits) build.url = "http://jenkey.dfsa.com:8080/job/hugrycats/%s" % build_number build_job_uri = "/".join(build.url.split('/')[:-2]) # run the same code as above to matchToChangesets # assert that some were found build_defn = agicen.ensureBuildDefinitionExists(job_name, 'Jenkins', build_job_uri) assert build_defn is not None changesets = agicen.matchToChangesets(commits) assert len(changesets) == 2 # confabulate a build_info dict with Changesets = list of matching AgileCentral Changesets # call agicen.createBuild(build_info) binfo = OrderedDict(build.as_tuple_data()) binfo['BuildDefinition'] = build_defn binfo['Changesets'] = changesets agicen_build = agicen.createBuild(binfo) # assert that the Build was created assert agicen_build is not None # assert that the build number is correct assert int(agicen_build.Number) == build_number # use agicen.agicen.get('Build',...) to find the newly created Build item query = ['BuildDefinition.Name = "%s"' % build_name] query.append('Number = "%s"' % build_number) query.append('CreationDate >= %s' % ref_time) workspace = konf.topLevel('AgileCentral')['Workspace'] response = agicen.agicen.get( 'Build', fetch='ObjectID,Name,BuildDefinition,Number,Changesets', query=query, workspace=workspace, project=None) # assert that the build has a Changesets attribute value that has a collection attribute assert response.resultCount > 0 a_build = response.next() assert a_build.BuildDefinition.Name == build_name assert int(a_build.Number) == build_number # assert that the Changesets returned are indeed the target Changesets (no more, no less) changesets = [cs for cs in a_build.Changesets] assert len(changesets) >= 2 assert ('MORE CHOCOLATE' in [cs.Revision for cs in changesets]) == True print("loons are crazy %s" % len(changesets))
def test_create_build_having_commits(): ref_time = datetime.now().utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") # get a konf and a logger, filename = "config/buildorama.yml" logger, konf = sh.setup_config(filename) konf.topLevel('AgileCentral')['Project'] = 'Jenkins' # get an AgileCentralConnection agicen = bsh.AgileCentralConnection(konf.topLevel('AgileCentral'), logger) agicen.other_name = 'Jenkins' agicen.connect() agicen.validateProjects(['Jenkins']) # mock up a Build build_start = int((datetime.now() - timedelta(minutes=60)).timestamp()) build_name = 'Hungry kids devour our tasty product' job_name, build_number, status = '%s' %build_name, 74, 'SUCCESS' started, duration = build_start, 43 # use some SHA values corresponding to some actual Agile Central Changeset items in our target Workspace commits = ['CHOCOLATE', 'MORE CHOCOLATE'] # these are actual shas random_scm_repo_name = "Velocirat" random_scm_type = "abacus" #scm_repo = create_scm_repo(agicen, random_scm_repo_name, random_scm_type) scm_repo = agicen.ensureSCMRepositoryExists(random_scm_repo_name, random_scm_type) for sha in commits: changeset_payload = { 'SCMRepository': scm_repo.ref, 'Revision': sha, 'CommitTimestamp': '2016-12-31' } try: changeset = agicen.agicen.create('Changeset', changeset_payload) except Exception as msg: raise Exception("Could not create Changeset %s" % msg) build = bsh.MockJenkinsBuild(job_name, build_number, status, started, duration, commits) build.url = "http://jenkey.dfsa.com:8080/job/hugrycats/%s" % build_number build_job_uri = "/".join(build.url.split('/')[:-2]) # run the same code as above to matchToChangesets # assert that some were found build_defn = agicen.ensureBuildDefinitionExists(job_name, 'Jenkins', build_job_uri) assert build_defn is not None changesets = agicen.matchToChangesets(commits) assert len(changesets) == 2 # confabulate a build_info dict with Changesets = list of matching AgileCentral Changesets # call agicen.createBuild(build_info) binfo = OrderedDict(build.as_tuple_data()) binfo['BuildDefinition'] = build_defn binfo['Changesets'] = changesets agicen_build = agicen.createBuild(binfo) # assert that the Build was created assert agicen_build is not None # assert that the build number is correct assert int(agicen_build.Number) == build_number # use agicen.agicen.get('Build',...) to find the newly created Build item query = ['BuildDefinition.Name = "%s"' % build_name] query.append('Number = "%s"' % build_number) query.append('CreationDate >= %s' % ref_time) workspace = konf.topLevel('AgileCentral')['Workspace'] response = agicen.agicen.get('Build', fetch='ObjectID,Name,BuildDefinition,Number,Changesets', query=query, workspace=workspace, project=None) # assert that the build has a Changesets attribute value that has a collection attribute assert response.resultCount > 0 a_build = response.next() assert a_build.BuildDefinition.Name == build_name assert int(a_build.Number) == build_number # assert that the Changesets returned are indeed the target Changesets (no more, no less) changesets = [cs for cs in a_build.Changesets] assert len(changesets) >= 2 assert ('MORE CHOCOLATE' in [cs.Revision for cs in changesets]) == True print("loons are crazy %s" % len(changesets))
def test_namesake_projects(): # have a config that mentions m-e-p Project for the AgileCentral_Project # inhale the config # mock up a build for the 'australopithicus' Job which will trigger the necessity of creating an AC BuildDefinition record for it filename = "config/platypus.yml" logger, konf = sh.setup_config( filename, jenkins_structure=PLATYPUS_JENKINS_STRUCTURE, services=PLATYPUS_SERVICES) bc = bsh.BLDConnector(konf, logger) agiconn = bc.agicen_conn # use agiconn.agicen to clear out any Builds/BuildDefinition that match our intended actions jobs_projs = { 'centaur-mordant': agiconn.agicen.getProject('Jenkins // Salamandra').oid, 'australopithicus': agiconn.agicen.getProject('Jenkins // Corral // Salamandra').oid, } for job, project_oid in jobs_projs.items(): criteria = [ 'BuildDefinition.Name = "%s"' % job, 'BuildDefinition.Project.ObjectID = %d' % project_oid ] response = agiconn.agicen.get('Build', fetch="ObjectID,Name", query=criteria) for build in response: agiconn.agicen.delete('Build', build) criteria = ['Name = "%s"' % job, 'Project.ObjectID = %d' % project_oid] response = agiconn.agicen.get('BuildDefinition', fetch="ObjectID,Name", query=criteria) for buildef in response: agiconn.agicen.delete('BuildDefinition', buildef) assert 'Jenkins' in agiconn._project_cache.keys() assert 'Jenkins // Salamandra' in agiconn._project_cache.keys() assert 'Jenkins // Corral // Salamandra' in agiconn._project_cache.keys() target_project = "Jenkins // Corral // Salamandra" tp = agiconn.agicen.getProject(target_project) assert target_project in bc.target_projects # create some mock builds for associated with the mep Projects # throw those against #builds = createMockBuilds(['centaur-mordant', 'australopithicus']) job_name = 'australopithicus' build_start = int( (datetime.datetime.now() - datetime.timedelta(minutes=60)).timestamp()) build_number, status = 532, 'SUCCESS' started, duration = build_start, 231 commits = [] build = bsh.MockJenkinsBuild(job_name, build_number, status, started, duration, commits) build.changeSets = [] build.url = "http://jenkey.dfsa.com:8080/job/bashfulmonkies/532" build_data = build.as_tuple_data() info = OrderedDict(build_data) assert 'Project' not in info build_job_uri = "/".join(build.url.split('/')[:-2]) build_defn = agiconn.ensureBuildDefinitionExists( job_name, 'Jenkins // Corral // Salamandra', build_job_uri) assert build_defn.Name == job_name assert build_defn.Project.ObjectID == tp.oid if agiconn.buildExists(build_defn, build.number): agiconn.log.debug( 'Build #{0} for {1} already recorded, skipping...'.format( build.number, job_name)) # pull out any build.changeSets commit IDs and see if they match up with AgileCentral Changeset items Revision attribute # if so, get all such commit IDs and their associated Changeset ObjectID, then # add that "collection" as the Build's Changesets collection agicen_build, status = bc.postBuildToAgileCentral(build_defn, build, [], job_name) assert agicen_build.BuildDefinition.ref == build_defn.ref