Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,30 @@ jobs:
- name: Setup Bazelisk
run: go install github.com/bazelbuild/bazelisk@latest && export PATH=$PATH:$(go env GOPATH)/bin
- uses: actions/checkout@v4
- name: Free disk space on Ubuntu
if: runner.os == 'Linux'
run: |
# //cli:E2ETest plus coverage can exhaust the default ubuntu-latest image.
# Reclaim space from preinstalled toolchains this job does not use.
# Keep /usr/local/lib/android: rules_android resolves ANDROID_HOME there.
sudo rm -rf /usr/share/dotnet /opt/ghc
sudo docker image prune --all --force || true
# /mnt has more headroom than / on hosted runners; keep Bazel outputs off root.
if [ -d /mnt ]; then
sudo mkdir -p /mnt/bazel-output
sudo chown "$USER" /mnt/bazel-output
echo "BAZEL_OUTPUT_USER_ROOT=/mnt/bazel-output" >> "$GITHUB_ENV"
fi
df -h / /mnt 2>/dev/null || df -h /
- name: Run bazel-diff tests
env:
USE_BAZEL_VERSION: ${{ matrix.bazel }}
run: ~/go/bin/bazelisk coverage --combined_report=lcov //cli/... //tools:coverage_check_test //tools/go/... --enable_bzlmod=true --enable_workspace=false
run: |
BAZEL_STARTUP=()
if [ -n "${BAZEL_OUTPUT_USER_ROOT:-}" ]; then
BAZEL_STARTUP=(--output_user_root="${BAZEL_OUTPUT_USER_ROOT}")
fi
~/go/bin/bazelisk "${BAZEL_STARTUP[@]}" coverage --combined_report=lcov //cli/... //tools:coverage_check_test //tools/go/... --enable_bzlmod=true --enable_workspace=false
- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
Expand All @@ -54,7 +74,12 @@ jobs:
# (seen flaking on macos-latest x bazel 9.x).
USE_BAZEL_VERSION: ${{ matrix.bazel }}
COVERAGE_THRESHOLD: '90'
run: ~/go/bin/bazelisk run //tools:coverage-check -- --badge-json coverage.json bazel-out/_coverage/_coverage_report.dat
run: |
BAZEL_STARTUP=()
if [ -n "${BAZEL_OUTPUT_USER_ROOT:-}" ]; then
BAZEL_STARTUP=(--output_user_root="${BAZEL_OUTPUT_USER_ROOT}")
fi
~/go/bin/bazelisk "${BAZEL_STARTUP[@]}" run //tools:coverage-check -- --badge-json coverage.json bazel-out/_coverage/_coverage_report.dat
- name: Enforce Go coverage threshold (>= 90% line coverage under tools/go/)
env:
# Must match the `Run bazel-diff tests` step above; see the note on the
Expand All @@ -63,7 +88,12 @@ jobs:
# Gate Go independently of the Kotlin overall so thin Go coverage can't hide
# behind well-covered Kotlin (and vice versa). --include scopes the report to
# Go production source only (tools/go/, which excludes tools/coverage_check.py).
run: ~/go/bin/bazelisk run //tools:coverage-check -- --include tools/go/ --threshold 90 bazel-out/_coverage/_coverage_report.dat
run: |
BAZEL_STARTUP=()
if [ -n "${BAZEL_OUTPUT_USER_ROOT:-}" ]; then
BAZEL_STARTUP=(--output_user_root="${BAZEL_OUTPUT_USER_ROOT}")
fi
~/go/bin/bazelisk "${BAZEL_STARTUP[@]}" run //tools:coverage-check -- --include tools/go/ --threshold 90 bazel-out/_coverage/_coverage_report.dat
- name: Upload test logs
uses: actions/upload-artifact@v4
if: always()
Expand Down
27 changes: 21 additions & 6 deletions cli/src/main/kotlin/com/bazel_diff/server/GitClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ interface GitClient {
fun checkout(revision: String)
}

/** A full 40-char lowercase hex commit SHA as printed by `git rev-parse`. */
private val COMMIT_SHA = Regex("^[0-9a-f]{40}$")

/** [GitClient] backed by the `git` binary at [gitPath], run inside [workspacePath]. */
class ProcessGitClient(
private val workspacePath: Path,
Expand Down Expand Up @@ -121,10 +124,17 @@ class ProcessGitClient(
} catch (e: GitClientException) {
throw MissingRevisionException(revision, e)
}
return output.firstOrNull()?.trim()?.takeIf { it.isNotEmpty() }
?: throw MissingRevisionException(revision)
return parseCommitShaOutput(output) ?: throw MissingRevisionException(revision)
}

/**
* Picks the commit SHA out of `git rev-parse` stdout. Git may concurrently write informational
* messages to stderr (e.g. "Auto packing the repository in background for optimum performance.");
* [run] captures stdout only, but matching the SHA shape is an extra guard.
*/
private fun parseCommitShaOutput(output: List<String>): String? =
output.asSequence().map { it.trim() }.firstOrNull { COMMIT_SHA.matches(it) }

override fun checkout(revision: String) {
logger.i { "git checkout $revision in $workspacePath" }
run("checkout", "--force", revision)
Expand All @@ -136,17 +146,22 @@ class ProcessGitClient(
val result = runBlocking {
process(
*cmd.toTypedArray(),
// Merge stdout+stderr so a failure's diagnostics are captured in one place.
// Capture stdout only: git writes informational messages (e.g. background auto-pack) to
// stderr that must not be parsed as command output. Failures still surface on stderr via
// PRINT so they appear in the service logs.
stdout = Redirect.CAPTURE,
stderr = Redirect.CAPTURE,
stderr = Redirect.PRINT,
workingDirectory = workspacePath.toFile(),
destroyForcibly = true,
)
}
if (result.resultCode != 0) {
val stdout = result.output.joinToString("\n").trim()
throw GitClientException(
"git ${args.joinToString(" ")} failed (exit ${result.resultCode}): " +
result.output.joinToString("\n"))
buildString {
append("git ${args.joinToString(" ")} failed (exit ${result.resultCode})")
if (stdout.isNotEmpty()) append(": ").append(stdout)
})
}
return result.output
}
Expand Down
Loading