Reduce the number of loops in prepare-workspace-git

Our prepare-workspace-git role was trying to express a few related steps
as ansible tasks. The problem is that each one of these steps had to
iterate through the entire project list incurring the ansible startup
time for each task of each loop iteration. We can speed things up a bit
if we use a single loop and a slightly more complicated shell task that
checks if things like directories exist before cloning/initing git
repos.

Note this is still slower than if we removed the Ansible task loop
entirely and move this logic into an ansible module that can run a loop
internally. However, making a change like that is significantly more
involved as we'd likely end up exec'ing git with python and need to
manage logging, errors, and so on. The shell module already handles that
for us in a nice way.

Change-Id: Ic87eb182cc4ca4bd0acdd1aa46c2d72dc1165e90
This commit is contained in:
Clark Boylan 2022-09-22 10:23:22 -07:00
parent 8fed1dfaa6
commit 4f02e92e70

View File

@ -1,59 +1,27 @@
- name: Find locally cached git repos
stat:
path: "{{ cached_repos_root }}/{{ zj_project.canonical_name }}"
with_items: "{{ zuul.projects.values() | list }}"
loop_control:
loop_var: zj_project
register: cached_repos
# We do a bare clone here first so that we skip creating a working copy that
# will be overwritten later anyway.
- name: Clone cached repo to workspace
# Do all the steps in a single shell script. This reduces the number of times
# ansible must loop over the list of projects which reduces the amount of
# task startup time we incur.
- name: Set initial repo states in workspace
shell: |
set -e
git clone --bare {{ cached_repos_root }}/{{ zj_project.0.canonical_name }} {{ ansible_user_dir }}/{{ zj_project.0.src_dir }}/.git
cd {{ ansible_user_dir }}/{{ zj_project.0.src_dir }}
set -ex
if [ -d "{{ cached_repos_root }}/{{ zj_project.canonical_name }}" ] ; then
# We do a bare clone here first so that we skip creating a working
# copy that will be overwritten later anyway.
git clone --bare {{ cached_repos_root }}/{{ zj_project.canonical_name }} {{ ansible_user_dir }}/{{ zj_project.src_dir }}/.git
else
git init {{ ansible_user_dir }}/{{ zj_project.src_dir }}
fi
cd {{ ansible_user_dir }}/{{ zj_project.src_dir }}
git config --local --bool core.bare false
args:
creates: "{{ ansible_user_dir }}/{{ zj_project.0.src_dir }}"
when: zj_project.1.stat.exists
with_together:
- "{{ zuul.projects.values() | list }}"
- "{{ cached_repos.results }}"
loop_control:
loop_var: zj_project
# ANSIBLE0006: If we use the git module, we get warning
# ANSIBLE0004 since we do not give an explicit version
tags:
- skip_ansible_lint
- name: Initialize non-cached repos
command: "git init {{ ansible_user_dir }}/{{ zj_project.0.src_dir }}"
args:
creates: "{{ ansible_user_dir }}/{{ zj_project.0.src_dir }}"
when: not zj_project.1.stat.exists
with_together:
- "{{ zuul.projects.values() | list }}"
- "{{ cached_repos.results }}"
loop_control:
loop_var: zj_project
# ANSIBLE0006: If we use the git module, we get warning
# ANSIBLE0004 since we do not give an explicit version
tags:
- skip_ansible_lint
- name: Remove origin from local git repos and replace it by the zuul fake origin
# To be idempotent, remove origin only if it's found in the local list.
shell: |
set -e
git remote -v | grep origin && git remote rm origin || true
git remote add origin file:///dev/null
args:
chdir: "{{ ansible_user_dir }}/{{ zj_project.src_dir }}"
creates: "{{ ansible_user_dir }}/{{ zj_project.src_dir }}"
with_items: "{{ zuul.projects.values() | list }}"
loop_control:
loop_var: zj_project
# ANSIBLE0006: git remote is not supported by ansible module
# We're using git in a shell script because it is faster and the module
# doesn't support features we need.
tags:
- skip_ansible_lint