Skip to content

Commit ae82e9b

Browse files
author
Amna Akram
authored
Merge pull request #19 from buildkite-plugins/Sup-4697-adding-a-clean-checkout-option
[SUP-4697] Adding a clean checkout option
2 parents ed548d8 + b74e893 commit ae82e9b

4 files changed

Lines changed: 119 additions & 2 deletions

File tree

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,17 @@ Whether to pass `--no-cone` to `git sparse-checkout` so that the paths are consi
2424

2525
Whether to skip ssh-keyscan step. This will skip adding each ssh public key into the known-hosts file. Only use if ssh keys are already setup.
2626

27+
#### `clean_checkout` ('true' or 'false')
28+
29+
Whether to perform aggressive repository cleanup before checkout. This option handles scenarios where interrupted or cancelled jobs leave the git repository in a corrupted state with uncommitted changes that would prevent checkout. When enabled, it performs `git reset --hard HEAD` and `git sparse-checkout disable` in addition to the normal cleanup.
30+
31+
**⚠️ Warning:** This option will destroy ALL local changes and remove ALL untracked files. The `git clean -ffxdq` command with the `-x` flag will also remove ignored files (such as credentials, local configuration, or cache files). Only use this option when you're certain no important local data needs to be preserved.
32+
33+
Use this option for pipeline upload jobs that don't need to preserve local changes.
34+
2735
## Example
2836

29-
Below is an example for using sparse-checkout plugin.
37+
Below is an example of using sparse-checkout plugin.
3038

3139
```yaml
3240
steps:
@@ -38,6 +46,21 @@ steps:
3846
- .buildkite
3947
```
4048
49+
### Handling corrupted repository states
50+
51+
If your jobs are frequently cancelled during the git clone phase, you may encounter failures due to uncommitted changes left in the repository. Use the `clean_checkout` option to handle this:
52+
53+
```yaml
54+
steps:
55+
- label: "Pipeline upload with clean checkout"
56+
command: "buildkite-agent pipeline upload"
57+
plugins:
58+
- sparse-checkout#v1.1.0:
59+
paths:
60+
- .buildkite
61+
clean_checkout: true
62+
```
63+
4164
## ⚒ Developing
4265

4366
To run testing, shellchecks and plugin linting use `bk run` with the [Buildkite CLI](https://github.com/buildkite/cli).

hooks/checkout

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ else
1919
fi
2020

2121
SKIP_SSH_KEYSCAN_OPTION="$(plugin_read_config SKIP_SSH_KEYSCAN "false")"
22+
CLEAN_CHECKOUT_OPTION="$(plugin_read_config CLEAN_CHECKOUT "false")"
23+
24+
if [[ "${CLEAN_CHECKOUT_OPTION}" = "true" ]]; then
25+
echo "⚠️ WARNING: clean_checkout is enabled - this will destroy any local changes and reset the repository state"
26+
fi
2227

2328
if [[ -n "${BUILDKITE_REPO_SSH_HOST:-}" ]] && [[ "${SKIP_SSH_KEYSCAN_OPTION}" = "false" ]] ; then
2429
echo "Scanning SSH keys for remote git repository"
@@ -41,7 +46,26 @@ if [[ ! -d .git ]]; then
4146
"${BUILDKITE_REPO}" .
4247
fi
4348

44-
git clean -ffxdq
49+
# Enable clean checkout option to deal with corrupted repository states
50+
if [[ "${CLEAN_CHECKOUT_OPTION}" = "true" ]]; then
51+
echo "Clean checkout enabled - resetting repository state"
52+
# Remove index lock files
53+
find .git -name "*.lock" -delete 2>/dev/null || true
54+
# Reset index if corrupted
55+
if ! git status >/dev/null 2>&1; then
56+
rm -f .git/index 2>/dev/null || true
57+
fi
58+
# Disable sparse-checkout
59+
git sparse-checkout disable 2>/dev/null || true
60+
# Clean and reset
61+
git clean -ffxdq
62+
63+
if git rev-parse --verify HEAD >/dev/null 2>&1; then
64+
git reset --hard HEAD
65+
fi
66+
else
67+
git clean -ffxdq
68+
fi
4569

4670
FETCH_FLAGS=()
4771
if [[ -n "${BUILDKITE_GIT_FETCH_FLAGS:-}" ]]; then

plugin.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ configuration:
1313
skip_ssh_keyscan:
1414
type: boolean
1515
default: false
16+
clean_checkout:
17+
type: boolean
18+
default: false
1619
required:
1720
- paths
1821
additionalProperties: false

tests/checkout.bats

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,70 @@ setup() {
100100
unstub ssh-keyscan
101101
unstub git
102102
}
103+
104+
@test "Clean checkout disabled - uses normal git clean" {
105+
export BUILDKITE_PLUGIN_SPARSE_CHECKOUT_CLEAN_CHECKOUT="false"
106+
107+
stub ssh-keyscan "* : echo 'keyscan'"
108+
stub git "clean -ffxdq : echo 'git clean normal'"
109+
stub git "fetch --depth 1 origin * : echo 'git fetch'"
110+
stub git "sparse-checkout set * * : echo 'git sparse-checkout'"
111+
stub git "checkout * : echo 'checkout'"
112+
113+
run "$PWD"/hooks/checkout
114+
115+
assert_success
116+
assert_output --partial 'git clean normal'
117+
refute_output --partial 'Clean checkout enabled'
118+
119+
unstub ssh-keyscan
120+
unstub git
121+
}
122+
123+
@test "Clean checkout enabled performs aggressive cleanup" {
124+
export BUILDKITE_PLUGIN_SPARSE_CHECKOUT_CLEAN_CHECKOUT="true"
125+
126+
stub ssh-keyscan "* : echo 'keyscan'"
127+
stub git "status : echo 'status ok'"
128+
stub git "sparse-checkout disable : echo 'git sparse-checkout disable'"
129+
stub git "clean -ffxdq : echo 'git clean aggressive'"
130+
stub git "rev-parse --verify HEAD : echo 'HEAD'"
131+
stub git "reset --hard HEAD : echo 'git reset hard'"
132+
stub git "fetch --depth 1 origin * : echo 'git fetch'"
133+
stub git "sparse-checkout set * * : echo 'git sparse-checkout'"
134+
stub git "checkout * : echo 'checkout'"
135+
136+
run "$PWD"/hooks/checkout
137+
138+
assert_success
139+
assert_output --partial 'Clean checkout enabled - resetting repository state'
140+
assert_output --partial 'git reset hard'
141+
assert_output --partial 'git clean aggressive'
142+
assert_output --partial 'git sparse-checkout disable'
143+
144+
unstub ssh-keyscan
145+
unstub git
146+
}
147+
148+
@test "Clean checkout handles repository without HEAD gracefully" {
149+
export BUILDKITE_PLUGIN_SPARSE_CHECKOUT_CLEAN_CHECKOUT="true"
150+
151+
stub ssh-keyscan "* : echo 'keyscan'"
152+
stub git "status : echo 'status ok'"
153+
stub git "sparse-checkout disable : echo 'sparse-checkout disable'"
154+
stub git "clean -ffxdq : echo 'git clean'"
155+
stub git "rev-parse --verify HEAD : exit 1"
156+
stub git "fetch --depth 1 origin * : echo 'git fetch'"
157+
stub git "sparse-checkout set * * : echo 'git sparse-checkout'"
158+
stub git "checkout * : echo 'checkout'"
159+
160+
run "$PWD"/hooks/checkout
161+
162+
assert_success
163+
assert_output --partial 'Clean checkout enabled - resetting repository state'
164+
assert_output --partial 'git clean'
165+
assert_output --partial 'sparse-checkout disable'
166+
167+
unstub ssh-keyscan
168+
unstub git
169+
}

0 commit comments

Comments
 (0)