From: Luis Chamberlain <mcgrof@kernel.org>
To: Chuck Lever <cel@kernel.org>, Daniel Gomez <da.gomez@kruces.com>,
kdevops@lists.linux.dev
Cc: Luis Chamberlain <mcgrof@kernel.org>
Subject: [PATCH 5/8] bootlinux: add intelligent git repository detection and management
Date: Mon, 11 Aug 2025 15:43:04 -0700 [thread overview]
Message-ID: <20250811224307.2218478-6-mcgrof@kernel.org> (raw)
In-Reply-To: <20250811224307.2218478-1-mcgrof@kernel.org>
Add smart logic to infer when git clone is needed regardless of the
bootlinux_tree_set_by_cli setting. This solves the issue where directories
exist with files (like .config) but no .git repository, which previously
caused the git clone to be skipped.
The new logic:
1. Checks if the target directory exists
2. Checks if .git directory exists within it
3. Infers git clone is needed if directory exists but .git doesn't
4. Clones the repository even when bootlinux_tree_set_by_cli is true
5. Ensures the correct ref is checked out if git exists but on wrong ref
This handles the common case where:
- Directory is pre-created for 9p mount support
- Configuration files are copied before git clone
- bootlinux_tree_set_by_cli persists from previous runs
The implementation also:
- Fetches updates if the target ref doesn't exist locally
- Switches to the correct ref if repository exists but is on wrong branch
- Maintains backward compatibility with existing workflows
- Applies consistently across all build methods (9p, targets, builder)
This makes the system more robust and user-friendly by intelligently
handling partial setups and recovering from incomplete states.
Generated-by: Claude AI
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
playbooks/roles/bootlinux/tasks/build/9p.yml | 119 ++++++++++++++----
.../roles/bootlinux/tasks/build/builder.yml | 98 +++++++++++++--
.../roles/bootlinux/tasks/build/targets.yml | 98 +++++++++++++--
3 files changed, 273 insertions(+), 42 deletions(-)
diff --git a/playbooks/roles/bootlinux/tasks/build/9p.yml b/playbooks/roles/bootlinux/tasks/build/9p.yml
index 5c9489c3..d0ae61ad 100644
--- a/playbooks/roles/bootlinux/tasks/build/9p.yml
+++ b/playbooks/roles/bootlinux/tasks/build/9p.yml
@@ -26,23 +26,47 @@
run_once: true
delegate_to: localhost
-- name: Check if target directory exists when using 9p and Linux CLI was set
+- name: Check if target directory exists
stat:
path: "{{ bootlinux_9p_host_path }}"
register: target_directory_stat
run_once: true
delegate_to: localhost
+
+- name: Check if .git directory exists in target path
+ stat:
+ path: "{{ bootlinux_9p_host_path }}/.git"
+ register: git_directory_stat
+ run_once: true
+ delegate_to: localhost
when:
- - bootlinux_tree_set_by_cli|bool
+ - target_directory_stat.stat.exists
-- name: Fail if target directory does not exist when using 9p and Linux CLI was set
- fail:
- msg: "The target directory {{ bootlinux_9p_host_path }} does not exist."
+- name: Infer that git clone is needed when .git doesn't exist
+ set_fact:
+ needs_git_clone: true
+ when:
+ - target_directory_stat.stat.exists
+ - not git_directory_stat.stat.exists
run_once: true
delegate_to: localhost
+
+- name: Set needs_git_clone when directory doesn't exist
+ set_fact:
+ needs_git_clone: true
when:
- - bootlinux_tree_set_by_cli|bool
- not target_directory_stat.stat.exists
+ run_once: true
+ delegate_to: localhost
+
+- name: Set needs_git_clone to false when .git exists
+ set_fact:
+ needs_git_clone: false
+ when:
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ run_once: true
+ delegate_to: localhost
- name: Verify target git ref exists before cloning
command: "git ls-remote {{ target_linux_git }} {{ active_linux_ref | default(target_linux_ref) }}"
@@ -50,7 +74,7 @@
run_once: true
delegate_to: localhost
when:
- - not bootlinux_tree_set_by_cli|bool
+ - needs_git_clone|bool
tags: [ 'clone']
- name: Fail if git ref does not exist
@@ -68,20 +92,11 @@
- If using A/B testing with different refs, ensure shallow cloning is disabled
- The repository URL '{{ target_linux_git }}' is correct and accessible
when:
- - not bootlinux_tree_set_by_cli|bool
+ - needs_git_clone|bool
- ref_check.rc != 0
run_once: true
delegate_to: localhost
-- name: Check if target directory exists for dirty check
- stat:
- path: "{{ bootlinux_9p_host_path }}"
- register: git_dir_stat
- run_once: true
- delegate_to: localhost
- when:
- - not bootlinux_tree_set_by_cli|bool
-
- name: Check if git tree is dirty
command: "git -C {{ bootlinux_9p_host_path }} status --porcelain"
register: git_status
@@ -90,9 +105,9 @@
run_once: true
delegate_to: localhost
when:
- - not bootlinux_tree_set_by_cli|bool
- - git_dir_stat.stat.exists
- - git_dir_stat.stat.isdir
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
- name: Fail if git tree has local modifications
fail:
@@ -109,9 +124,9 @@
Modified files:
{{ git_status.stdout }}
when:
- - not bootlinux_tree_set_by_cli|bool
- - git_dir_stat.stat.exists
- - git_dir_stat.stat.isdir
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
- git_status.stdout | length > 0
run_once: true
delegate_to: localhost
@@ -129,9 +144,65 @@
until: not result.failed
tags: [ 'clone']
when:
- - not bootlinux_tree_set_by_cli|bool
+ - needs_git_clone|bool
+ run_once: true
+ delegate_to: localhost
+
+- name: Get current git ref when git exists but clone wasn't needed
+ command: "git -C {{ bootlinux_9p_host_path }} rev-parse HEAD"
+ register: current_ref
+ changed_when: false
+ run_once: true
+ delegate_to: localhost
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
+- name: Get target ref SHA
+ command: "git -C {{ bootlinux_9p_host_path }} rev-parse {{ active_linux_ref | default(target_linux_ref) }}"
+ register: target_ref_sha
+ changed_when: false
+ failed_when: false
run_once: true
delegate_to: localhost
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
+- name: Fetch updates if target ref doesn't exist locally
+ command: "git -C {{ bootlinux_9p_host_path }} fetch origin"
+ run_once: true
+ delegate_to: localhost
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - target_ref_sha.rc != 0
+
+- name: Get target ref SHA after fetch
+ command: "git -C {{ bootlinux_9p_host_path }} rev-parse {{ active_linux_ref | default(target_linux_ref) }}"
+ register: target_ref_sha_after_fetch
+ changed_when: false
+ run_once: true
+ delegate_to: localhost
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - target_ref_sha.rc != 0
+
+- name: Checkout target ref if not on correct ref
+ command: "git -C {{ bootlinux_9p_host_path }} checkout {{ active_linux_ref | default(target_linux_ref) }}"
+ run_once: true
+ delegate_to: localhost
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - (target_ref_sha.rc == 0 and current_ref.stdout != target_ref_sha.stdout) or
+ (target_ref_sha.rc != 0 and target_ref_sha_after_fetch is defined and target_ref_sha_after_fetch.rc == 0)
- name: Copy kernel delta if requested on the control node
template:
diff --git a/playbooks/roles/bootlinux/tasks/build/builder.yml b/playbooks/roles/bootlinux/tasks/build/builder.yml
index d36815ed..1213c56f 100644
--- a/playbooks/roles/bootlinux/tasks/build/builder.yml
+++ b/playbooks/roles/bootlinux/tasks/build/builder.yml
@@ -10,9 +10,43 @@
- target_linux_install_b4
- ansible_os_family == "Debian"
+- name: Check if target directory exists
+ stat:
+ path: "{{ target_linux_dir_path }}"
+ register: target_directory_stat
+
+- name: Check if .git directory exists in target path
+ stat:
+ path: "{{ target_linux_dir_path }}/.git"
+ register: git_directory_stat
+ when:
+ - target_directory_stat.stat.exists
+
+- name: Infer that git clone is needed when .git doesn't exist
+ set_fact:
+ needs_git_clone: true
+ when:
+ - target_directory_stat.stat.exists
+ - not git_directory_stat.stat.exists
+
+- name: Set needs_git_clone when directory doesn't exist
+ set_fact:
+ needs_git_clone: true
+ when:
+ - not target_directory_stat.stat.exists
+
+- name: Set needs_git_clone to false when .git exists
+ set_fact:
+ needs_git_clone: false
+ when:
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
- name: Verify target git ref exists before cloning
command: "git ls-remote {{ target_linux_git }} {{ target_linux_ref }}"
register: ref_check
+ when:
+ - needs_git_clone|bool
- name: Fail if git ref does not exist
fail:
@@ -29,21 +63,18 @@
- If using A/B testing with different refs, ensure shallow cloning is disabled
- The repository URL '{{ target_linux_git }}' is correct and accessible
when:
+ - needs_git_clone|bool
- ref_check.rc != 0
-- name: Check if target directory exists for dirty check
- stat:
- path: "{{ target_linux_dir_path }}"
- register: git_dir_stat
-
- name: Check if git tree is dirty
command: "git -C {{ target_linux_dir_path }} status --porcelain"
register: git_status
changed_when: false
failed_when: false
when:
- - git_dir_stat.stat.exists
- - git_dir_stat.stat.isdir
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
- name: Fail if git tree has local modifications
fail:
@@ -60,8 +91,9 @@
Modified files:
{{ git_status.stdout }}
when:
- - git_dir_stat.stat.exists
- - git_dir_stat.stat.isdir
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
- git_status.stdout | length > 0
- name: Clone {{ target_linux_tree }}
@@ -75,6 +107,54 @@
retries: 3
delay: 5
until: result is succeeded
+ when:
+ - needs_git_clone|bool
+
+- name: Get current git ref when git exists but clone wasn't needed
+ command: "git -C {{ target_linux_dir_path }} rev-parse HEAD"
+ register: current_ref
+ changed_when: false
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
+- name: Get target ref SHA
+ command: "git -C {{ target_linux_dir_path }} rev-parse {{ target_linux_ref }}"
+ register: target_ref_sha
+ changed_when: false
+ failed_when: false
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
+- name: Fetch updates if target ref doesn't exist locally
+ command: "git -C {{ target_linux_dir_path }} fetch origin"
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - target_ref_sha.rc != 0
+
+- name: Get target ref SHA after fetch
+ command: "git -C {{ target_linux_dir_path }} rev-parse {{ target_linux_ref }}"
+ register: target_ref_sha_after_fetch
+ changed_when: false
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - target_ref_sha.rc != 0
+
+- name: Checkout target ref if not on correct ref
+ command: "git -C {{ target_linux_dir_path }} checkout {{ target_linux_ref }}"
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - (target_ref_sha.rc == 0 and current_ref.stdout != target_ref_sha.stdout) or
+ (target_ref_sha.rc != 0 and target_ref_sha_after_fetch is defined and target_ref_sha_after_fetch.rc == 0)
- name: Copy the kernel delta to the builder
ansible.builtin.template:
diff --git a/playbooks/roles/bootlinux/tasks/build/targets.yml b/playbooks/roles/bootlinux/tasks/build/targets.yml
index 414602ab..87393c74 100644
--- a/playbooks/roles/bootlinux/tasks/build/targets.yml
+++ b/playbooks/roles/bootlinux/tasks/build/targets.yml
@@ -10,10 +10,44 @@
- target_linux_install_b4
- ansible_facts['os_family']|lower != 'debian'
+- name: Check if target directory exists
+ stat:
+ path: "{{ target_linux_dir_path }}"
+ register: target_directory_stat
+
+- name: Check if .git directory exists in target path
+ stat:
+ path: "{{ target_linux_dir_path }}/.git"
+ register: git_directory_stat
+ when:
+ - target_directory_stat.stat.exists
+
+- name: Infer that git clone is needed when .git doesn't exist
+ set_fact:
+ needs_git_clone: true
+ when:
+ - target_directory_stat.stat.exists
+ - not git_directory_stat.stat.exists
+
+- name: Set needs_git_clone when directory doesn't exist
+ set_fact:
+ needs_git_clone: true
+ when:
+ - not target_directory_stat.stat.exists
+
+- name: Set needs_git_clone to false when .git exists
+ set_fact:
+ needs_git_clone: false
+ when:
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
- name: Verify target git ref exists before cloning
command: "git ls-remote {{ target_linux_git }} {{ target_linux_ref }}"
register: ref_check
tags: [ 'clone']
+ when:
+ - needs_git_clone|bool
- name: Fail if git ref does not exist
fail:
@@ -30,21 +64,18 @@
- If using A/B testing with different refs, ensure shallow cloning is disabled
- The repository URL '{{ target_linux_git }}' is correct and accessible
when:
+ - needs_git_clone|bool
- ref_check.rc != 0
-- name: Check if target directory exists for dirty check
- stat:
- path: "{{ target_linux_dir_path }}"
- register: git_dir_stat
-
- name: Check if git tree is dirty
command: "git -C {{ target_linux_dir_path }} status --porcelain"
register: git_status
changed_when: false
failed_when: false
when:
- - git_dir_stat.stat.exists
- - git_dir_stat.stat.isdir
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
- name: Fail if git tree has local modifications
fail:
@@ -61,8 +92,9 @@
Modified files:
{{ git_status.stdout }}
when:
- - git_dir_stat.stat.exists
- - git_dir_stat.stat.isdir
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
- git_status.stdout | length > 0
- name: git clone {{ target_linux_tree }} on the target nodes
@@ -77,6 +109,54 @@
register: result
until: not result.failed
tags: [ 'clone']
+ when:
+ - needs_git_clone|bool
+
+- name: Get current git ref when git exists but clone wasn't needed
+ command: "git -C {{ target_linux_dir_path }} rev-parse HEAD"
+ register: current_ref
+ changed_when: false
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
+- name: Get target ref SHA
+ command: "git -C {{ target_linux_dir_path }} rev-parse {{ target_linux_ref }}"
+ register: target_ref_sha
+ changed_when: false
+ failed_when: false
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+
+- name: Fetch updates if target ref doesn't exist locally
+ command: "git -C {{ target_linux_dir_path }} fetch origin"
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - target_ref_sha.rc != 0
+
+- name: Get target ref SHA after fetch
+ command: "git -C {{ target_linux_dir_path }} rev-parse {{ target_linux_ref }}"
+ register: target_ref_sha_after_fetch
+ changed_when: false
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - target_ref_sha.rc != 0
+
+- name: Checkout target ref if not on correct ref
+ command: "git -C {{ target_linux_dir_path }} checkout {{ target_linux_ref }}"
+ when:
+ - not needs_git_clone|bool
+ - target_directory_stat.stat.exists
+ - git_directory_stat.stat.exists
+ - (target_ref_sha.rc == 0 and current_ref.stdout != target_ref_sha.stdout) or
+ (target_ref_sha.rc != 0 and target_ref_sha_after_fetch is defined and target_ref_sha_after_fetch.rc == 0)
- name: Copy kernel delta if requested on the target nodes
template:
--
2.47.2
next prev parent reply other threads:[~2025-08-11 22:43 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-11 22:42 [PATCH 0/8] linux-ab enhancements + monitor support Luis Chamberlain
2025-08-11 22:43 ` [PATCH 1/8] bootlinux: use different kernel for A/B testing by default Luis Chamberlain
2025-08-11 22:43 ` [PATCH 2/8] bootlinux: add support for custom refs on dev kernels on the CLI Luis Chamberlain
2025-08-11 22:43 ` [PATCH 3/8] bootlinux: add git ref verification before cloning Luis Chamberlain
2025-08-11 22:43 ` [PATCH 4/8] bootlinux: add git dirty check " Luis Chamberlain
2025-08-11 22:43 ` Luis Chamberlain [this message]
2025-08-11 22:43 ` [PATCH 6/8] bootlinux: enhance A/B testing and repository management Luis Chamberlain
2025-08-11 22:43 ` [PATCH 7/8] fstests: add make target for running tests on all hosts Luis Chamberlain
2025-08-11 22:43 ` [PATCH 8/8] monitoring: integrate monitoring collection into fstests workflow Luis Chamberlain
2025-08-11 22:46 ` Luis Chamberlain
2025-08-12 0:49 ` Luis Chamberlain
2025-08-14 0:59 ` Luis Chamberlain
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250811224307.2218478-6-mcgrof@kernel.org \
--to=mcgrof@kernel.org \
--cc=cel@kernel.org \
--cc=da.gomez@kruces.com \
--cc=kdevops@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox