Store a repo state file in the log directory
This adds a file named workspace-repos.json to the workspace build log directory. It contains the repo state and git commands needed to reconstruct the repo state used for the job. A later change may add a tool to translate the structured data in this file to a shell script. Other uses of the file may involve reading the repo state directly to determine the last "real" commit in the tree before Zuul started creating its speculative vision of the future. Change-Id: Ifc5ee03fdc41a82f481ac57b8992ba7bd5f9b6c0 Co-Authored-By: Tobias Henkel <tobias.henkel@bmw.de>
This commit is contained in:
parent
c2dc705147
commit
598c362db8
@ -490,6 +490,50 @@ class TestExecutorRepos(ZuulTestCase, ExecutorReposMixin):
|
||||
]
|
||||
self.assertBuildStates(states, projects)
|
||||
|
||||
def test_repo_state_file(self):
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
|
||||
A.addApproval('Code-Review', 2)
|
||||
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
|
||||
self.waitUntilSettled()
|
||||
|
||||
build = self.getBuildByName('project-merge')
|
||||
path = os.path.join(build.jobdir.log_root, 'workspace-repos.json')
|
||||
with open(path, 'r') as f:
|
||||
data = json.load(f)
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
|
||||
# Don't check the timestamp, but verify it exists
|
||||
self.assertIsNotNone(data['merge_ops'][2].pop('timestamp', None))
|
||||
self.assertEqual(
|
||||
data['merge_ops'],
|
||||
[{'cmd': ['git', 'checkout', 'master'],
|
||||
'path': 'review.example.com/org/project1'},
|
||||
{'cmd': ['git', 'fetch', 'origin', 'refs/changes/01/1/1'],
|
||||
'path': 'review.example.com/org/project1'},
|
||||
{'cmd': ['git',
|
||||
'merge',
|
||||
'-m',
|
||||
"Merge 'refs/changes/01/1/1'",
|
||||
'-s',
|
||||
'resolve',
|
||||
'FETCH_HEAD'],
|
||||
'path': 'review.example.com/org/project1'},
|
||||
{'cmd': ['git', 'checkout', 'master'],
|
||||
'path': 'review.example.com/org/project1'}])
|
||||
self.assertEqual(
|
||||
set(data['repo_state']['review.example.com/org/project1'].keys()),
|
||||
{'refs/heads/master', 'refs/remotes/origin/master',
|
||||
'refs/tags/init'})
|
||||
self.assertEqual(
|
||||
"zuul@example.com",
|
||||
data['merge_email'])
|
||||
self.assertEqual(
|
||||
"zuul",
|
||||
data['merge_name'])
|
||||
|
||||
|
||||
class TestExecutorRepoRoles(ZuulTestCase, ExecutorReposMixin):
|
||||
tenant_config_file = 'config/executor-repos/main.yaml'
|
||||
|
@ -1570,6 +1570,7 @@ class AnsibleJob(object):
|
||||
zuul_resources = self.prepareNodes(args) # set self.host_list
|
||||
self.prepareVars(args, zuul_resources) # set self.original_hostvars
|
||||
self.writeDebugInventory()
|
||||
self.writeRepoStateFile(repos)
|
||||
|
||||
# Early abort if abort requested
|
||||
if self.aborted:
|
||||
@ -1612,6 +1613,37 @@ class AnsibleJob(object):
|
||||
self.log.debug("Sending result: %s", result_data)
|
||||
self.executor_server.completeBuild(self.build_request, result_data)
|
||||
|
||||
def writeRepoStateFile(self, repos):
|
||||
# Write out the git operation performed up to this point
|
||||
repo_state_file = os.path.join(self.jobdir.log_root,
|
||||
'workspace-repos.json')
|
||||
# First make a connection+project_name -> path mapping
|
||||
workspace_paths = {}
|
||||
for project in self.arguments['projects']:
|
||||
repo = repos.get(project['canonical_name'])
|
||||
if repo:
|
||||
workspace_paths[(project['connection'], project['name'])] =\
|
||||
repo.workspace_project_path
|
||||
repo_state = {}
|
||||
for connection_name, connection_value in self.repo_state.items():
|
||||
for project_name, project_value in connection_value.items():
|
||||
# We may have data in self.repo_state for repos that
|
||||
# are not present in the work dir (ie, they are used
|
||||
# for roles). To keep things simple for now, we will
|
||||
# omit that, but we could add them later.
|
||||
workspace_project_path = workspace_paths.get(
|
||||
(connection_name, project_name))
|
||||
if workspace_project_path:
|
||||
repo_state[workspace_project_path] = project_value
|
||||
repo_state_data = dict(
|
||||
repo_state=repo_state,
|
||||
merge_ops=[o.toDict() for o in self.merge_ops],
|
||||
merge_name=self.executor_server.merge_name,
|
||||
merge_email=self.executor_server.merge_email,
|
||||
)
|
||||
with open(repo_state_file, 'w') as f:
|
||||
json.dump(repo_state_data, f, sort_keys=True, indent=2)
|
||||
|
||||
def getResultData(self):
|
||||
data = {}
|
||||
secret_data = {}
|
||||
|
Loading…
Reference in New Issue
Block a user