Skip to content

Commit d22bd75

Browse files
Refactor git probe helpers (#765)
* refactor: centralize git probe helpers * fix: satisfy git probe lint --------- Co-authored-by: homeboy-ci[bot] <266378653+homeboy-ci[bot]@users.noreply.github.com>
1 parent d002d9b commit d22bd75

4 files changed

Lines changed: 77 additions & 34 deletions

File tree

inc/Support/GitRunner.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,63 @@ public static function run( string $path, string $args, int $timeout_seconds = 0
134134
'output' => $result['output'],
135135
);
136136
}
137+
138+
/**
139+
* Run a read-only git probe and return trimmed output, or null on failure.
140+
*/
141+
public static function probe_output( string $path, string $args ): ?string {
142+
$result = self::run($path, $args);
143+
if ( is_wp_error($result) ) {
144+
return null;
145+
}
146+
147+
$output = trim( (string) ( $result['output'] ?? '' ));
148+
return '' !== $output ? $output : null;
149+
}
150+
151+
/**
152+
* Get the current branch for a repository.
153+
*/
154+
public static function current_branch( string $path ): ?string {
155+
return self::probe_output($path, 'rev-parse --abbrev-ref HEAD');
156+
}
157+
158+
/**
159+
* Get a configured remote URL for a repository.
160+
*/
161+
public static function remote_url( string $path, string $remote_name = 'origin' ): ?string {
162+
$remote_name = preg_replace('/[^A-Za-z0-9._-]/', '', $remote_name);
163+
if ( '' === $remote_name ) {
164+
return null;
165+
}
166+
167+
return self::probe_output($path, 'config --get ' . escapeshellarg('remote.' . $remote_name . '.url'));
168+
}
169+
170+
/**
171+
* Get the latest commit summary for a repository.
172+
*/
173+
public static function latest_commit_summary( string $path ): ?string {
174+
return self::probe_output($path, 'log -1 --format="%h %s"');
175+
}
176+
177+
/**
178+
* Count dirty status lines for a repository.
179+
*/
180+
public static function dirty_count( string $path ): int {
181+
$output = self::probe_output($path, 'status --porcelain');
182+
if ( null === $output ) {
183+
return 0;
184+
}
185+
186+
return count(array_filter(array_map('trim', explode("\n", $output))));
187+
}
188+
189+
/**
190+
* Check whether an exact ref exists.
191+
*/
192+
public static function ref_exists( string $path, string $ref ): bool {
193+
$result = self::run($path, 'show-ref --verify --quiet ' . escapeshellarg($ref));
194+
return ! is_wp_error($result);
195+
}
137196
}

inc/Workspace/WorkspaceGitOperations.php

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace DataMachineCode\Workspace;
99

1010
use DataMachineCode\Support\GitHubRemote;
11+
use DataMachineCode\Support\GitRunner;
1112
use DataMachineCode\Support\PathSecurity;
1213
use DataMachineCode\Support\ProcessRunner;
1314

@@ -41,10 +42,6 @@ public function git_status( string $handle ): array|\WP_Error {
4142
return $policy_attestation;
4243
}
4344

44-
$branch_result = $this->run_git($repo_path, 'rev-parse --abbrev-ref HEAD');
45-
$remote_result = $this->run_git($repo_path, 'config --get remote.origin.url');
46-
$latest_result = $this->run_git($repo_path, 'log -1 --format="%h %s"');
47-
4845
$files = array_filter(array_map('trim', explode("\n", $status_result['output'] ?? '')));
4946

5047
$response = array(
@@ -53,9 +50,9 @@ public function git_status( string $handle ): array|\WP_Error {
5350
'repo' => $parsed['repo'],
5451
'is_worktree' => $parsed['is_worktree'],
5552
'path' => $repo_path,
56-
'branch' => ! is_wp_error($branch_result) ? trim( (string) $branch_result['output']) : null,
57-
'remote' => ! is_wp_error($remote_result) ? trim( (string) $remote_result['output']) : null,
58-
'commit' => ! is_wp_error($latest_result) ? trim( (string) $latest_result['output']) : null,
53+
'branch' => GitRunner::current_branch($repo_path),
54+
'remote' => GitRunner::remote_url($repo_path),
55+
'commit' => GitRunner::latest_commit_summary($repo_path),
5956
'dirty' => count($files),
6057
'files' => array_values($files),
6158
);
@@ -1709,14 +1706,7 @@ private function get_workspace_git_policies(): array {
17091706
* @return string|null Remote URL or null.
17101707
*/
17111708
private function git_get_remote( string $repo_path, string $remote_name = 'origin' ): ?string {
1712-
$escaped = escapeshellarg($repo_path);
1713-
$remote_name = preg_replace('/[^A-Za-z0-9._-]/', '', $remote_name);
1714-
if ( '' === $remote_name ) {
1715-
return null;
1716-
}
1717-
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec
1718-
$remote = exec(sprintf('git -C %s config --get %s 2>/dev/null', $escaped, escapeshellarg('remote.' . $remote_name . '.url')));
1719-
return ( '' !== $remote ) ? $remote : null;
1709+
return GitRunner::remote_url($repo_path, $remote_name);
17201710
}
17211711

17221712
/**
@@ -1726,9 +1716,6 @@ private function git_get_remote( string $repo_path, string $remote_name = 'origi
17261716
* @return string|null Branch name or null.
17271717
*/
17281718
private function git_get_branch( string $repo_path ): ?string {
1729-
$escaped = escapeshellarg($repo_path);
1730-
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec
1731-
$branch = exec(sprintf('git -C %s rev-parse --abbrev-ref HEAD 2>/dev/null', $escaped));
1732-
return ( '' !== $branch ) ? $branch : null;
1719+
return GitRunner::current_branch($repo_path);
17331720
}
17341721
}

inc/Workspace/WorkspaceRepositoryLifecycle.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -688,14 +688,10 @@ public function show_repo( string $handle ): array|\WP_Error {
688688
return new \WP_Error('repo_not_found', sprintf('Workspace handle "%s" not found.', $parsed['dir_name']), array( 'status' => 404 ));
689689
}
690690

691-
$escaped = escapeshellarg($repo_path);
692-
693-
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec
694-
$branch = trim( (string) exec(sprintf('git -C %s rev-parse --abbrev-ref HEAD 2>/dev/null', $escaped)));
695-
$remote = trim( (string) exec(sprintf('git -C %s config --get remote.origin.url 2>/dev/null', $escaped)));
696-
$commit = trim( (string) exec(sprintf('git -C %s log -1 --format="%%h %%s" 2>/dev/null', $escaped)));
697-
$status = trim( (string) exec(sprintf('git -C %s status --porcelain 2>/dev/null | wc -l', $escaped)));
698-
// phpcs:enable
691+
$branch = GitRunner::current_branch($repo_path);
692+
$remote = GitRunner::remote_url($repo_path);
693+
$commit = GitRunner::latest_commit_summary($repo_path);
694+
$status = GitRunner::dirty_count($repo_path);
699695

700696
$result = array(
701697
'success' => true,
@@ -704,10 +700,10 @@ public function show_repo( string $handle ): array|\WP_Error {
704700
'is_worktree' => $parsed['is_worktree'],
705701
'is_context' => null !== $context_policy,
706702
'path' => $repo_path,
707-
'branch' => $branch ? $branch : null,
708-
'remote' => $remote ? $remote : null,
709-
'commit' => $commit ? $commit : null,
710-
'dirty' => (int) $status,
703+
'branch' => $branch,
704+
'remote' => $remote,
705+
'commit' => $commit,
706+
'dirty' => $status,
711707
'primary_freshness' => ! $parsed['is_worktree'] ? $this->build_primary_freshness_report($repo_path, $parsed['dir_name']) : null,
712708
);
713709
if ( null !== $context_policy ) {

inc/Workspace/WorkspaceWorktreeLifecycle.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
namespace DataMachineCode\Workspace;
99

10+
use DataMachineCode\Support\GitRunner;
11+
1012
defined('ABSPATH') || exit;
1113

1214
trait WorkspaceWorktreeLifecycle {
@@ -256,12 +258,11 @@ private function worktree_add_locked(
256258
}
257259

258260
// Does the branch already exist locally?
259-
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec
260-
exec(sprintf('git -C %s show-ref --verify --quiet %s 2>&1', escapeshellarg($primary_path), escapeshellarg('refs/heads/' . $branch)), $_unused, $exists_local);
261+
$exists_local = GitRunner::ref_exists($primary_path, 'refs/heads/' . $branch);
261262
$created_branch = false;
262263
$resolved_base = null;
263264

264-
if ( 0 === $exists_local ) {
265+
if ( $exists_local ) {
265266
if ( ! $allow_stale && ! $rebase_base && ! $fetch_failed ) {
266267
$default_guard = $this->assert_ref_current_with_default_branch($primary_path, $branch, $repo, $branch, 'branch');
267268
if ( is_wp_error($default_guard) ) {

0 commit comments

Comments
 (0)