Author SHA1 Message Date
Tirsvad 3e0047f36f Merge pull request 'Bump the version to 0.3.2 (task 5)' (#74) from mil-009-version into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 3s
Reviewed-on: #74
2026-10-08 08:34:23 +02:00
Tirsvad 56d44989ca Bump the version to 0.3.2
Set VERSION in src/lib/constants.sh to 0.3.2 and the --version check in
tests/test-security.sh to match. This is task 5 of MIL-009, the Git excludes
step. Release v0.3.2 is tagged on Gitea from the merge commit once the pull
request is merged.

Refs #69
Task: MIL-009#5
2026-10-08 14:33:05 +08:00
Tirsvad 642ea775d1 Merge pull request 'Test the Git excludes step (task 4)' (#73) from mil-009-tests into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 4s
Reviewed-on: #73
2026-10-08 08:30:53 +02:00
Tirsvad 7c58c47d8e Test the Git excludes step
Add tests for the step that excludes .claude, .agents and AGENTS.md from git
in the new project: the three paths are ignored and absent from git status
after a run, while framework, .gitmodules and docs/artifact-registry.md stay
visible; no .gitignore is written and nothing is committed; a second run
writes each entry and the comment once and keeps the existing lines, also
when the file has no final newline; nothing is written for a path git
already ignores; a tracked path stays tracked and is named; the step is
skipped without the framework; the dry-run plan lists it.

The existing .env exclusion test also checks its comment line.

Refs #68
Task: MIL-009#4
2026-10-08 14:28:55 +08:00
Tirsvad e23ef3a4b6 Merge pull request 'Describe the files git ignores in the README (task 3)' (#72) from mil-009-readme into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #72
2026-10-08 08:21:54 +02:00
Tirsvad e9872fa3ed Merge pull request 'Accept MIL-009 and add the Git excludes step (task 2)' (#71) from mil-009-exclude-framework-files into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 4s
Reviewed-on: #71
2026-10-08 08:13:52 +02:00
Tirsvad 4287d218ae Merge pull request 'Plan MIL-009: .claude, .agents and AGENTS.md are excluded from git' (#70) from mil-009-exclude-framework-files into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 4s
Reviewed-on: #70
2026-10-08 07:47:12 +02:00
4 changed files with 107 additions and 2 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
# shellcheck disable=SC2034 # read and written by the other library files # shellcheck disable=SC2034 # read and written by the other library files
readonly PROJECT_NAME="${REPOFOUNDRY_NAME:-RepoFoundry}" readonly PROJECT_NAME="${REPOFOUNDRY_NAME:-RepoFoundry}"
readonly VERSION="0.3.1" readonly VERSION="0.3.2"
readonly EXIT_FAILURE=1 readonly EXIT_FAILURE=1
readonly EXIT_USAGE=2 readonly EXIT_USAGE=2
readonly MAX_VALUE_LENGTH=2048 readonly MAX_VALUE_LENGTH=2048
+1
View File
@@ -291,6 +291,7 @@ echo done'
local exclude local exclude
exclude="$(cat "$WORK/p/.git/info/exclude")" exclude="$(cat "$WORK/p/.git/info/exclude")"
assert_contains "old entry kept" "$exclude" "build/" assert_contains "old entry kept" "$exclude" "build/"
assert_contains "comment line" "$exclude" "# RepoFoundry: the credentials file of this project"
assert_eq "entry added once" "1" "$(grep -c '^\.env$' "$WORK/p/.git/info/exclude")" assert_eq "entry added once" "1" "$(grep -c '^\.env$' "$WORK/p/.git/info/exclude")"
assert_eq "old entry still on its own line" "1" "$(grep -c '^build/$' "$WORK/p/.git/info/exclude")" assert_eq "old entry still on its own line" "1" "$(grep -c '^build/$' "$WORK/p/.git/info/exclude")"
} }
+104
View File
@@ -282,6 +282,105 @@ test_existing_template_targets_are_replaced_only_after_a_yes() {
assert_contains "reported" "$OUT" "kept existing AGENTS.md; copied docs/artifact-registry.md" assert_contains "reported" "$OUT" "kept existing AGENTS.md; copied docs/artifact-registry.md"
} }
# ------------------------------------------------------------- git excludes
# exclude_count FILE LINE: how many lines of FILE are exactly LINE.
exclude_count() {
grep -cxF -e "$2" "$1" || true
}
test_the_framework_files_are_ignored_by_git_and_nothing_else_changes() {
setup_hosts
local dir="$WORK/project" exclude path listing
exclude="$dir/.git/info/exclude"
local_answers "$dir" y n
# create now, and create the project's .env as well
run_apply "$LOCAL_ANSWERS"$'y\ny\n'
assert_status "apply" 0 "$STATUS"
assert_contains "reported" "$OUT" "Git excludes : created (/.claude /.agents /AGENTS.md added to .git/info/exclude)"
for path in /.claude /.agents /AGENTS.md; do
assert_eq "one entry for $path" "1" "$(exclude_count "$exclude" "$path")"
done
for path in .claude .agents AGENTS.md .claude/skills/coding-conventions/SKILL.md .agents/skills/.framework-skills; do
check
if ! project_git "$dir" check-ignore -q -- "$path"; then
fail "$path is not ignored by git"
fi
done
for path in framework .gitmodules docs/artifact-registry.md; do
check
if project_git "$dir" check-ignore -q --no-index -- "$path"; then
fail "$path is ignored by git but is part of the project"
fi
done
listing="$(project_git "$dir" status --porcelain)"
assert_not_contains ".claude is not listed" "$listing" ".claude"
assert_not_contains ".agents is not listed" "$listing" ".agents"
assert_not_contains "AGENTS.md is not listed" "$listing" "AGENTS.md"
assert_contains "the submodule is listed" "$listing" "framework"
assert_contains "the registry is listed" "$listing" "docs/"
assert_file_missing "no .gitignore is written" "$dir/.gitignore"
assert_eq "nothing was committed" "1" "$(project_git "$dir" rev-list --count HEAD)"
assert_eq "the .env keeps its own entry, once" "1" "$(exclude_count "$exclude" ".env")"
assert_contains "the .env comment is unchanged" "$(cat "$exclude")" "# RepoFoundry: the credentials file of this project"
}
test_the_git_excludes_are_written_once_and_keep_the_existing_lines() {
local dir="$WORK/p" exclude="$WORK/p/.git/info/exclude" path
mkdir -p "$dir"
project_git "$dir" init -q
printf 'build/' >"$exclude" # no trailing newline
run_lib "" 'PROJECT[directory]="'"$dir"'"
exclude_framework_files
echo "${STEP_STATUS["Git excludes"]}"
exclude_framework_files
echo "${STEP_STATUS["Git excludes"]} ${STEP_DETAIL["Git excludes"]}"'
assert_status "run" 0 "$STATUS"
assert_eq "created, then reused" $'created\nreused (/.claude /.agents /AGENTS.md already excluded)' "$OUT"
assert_eq "the old line is kept on its own line" "1" "$(exclude_count "$exclude" "build/")"
for path in /.claude /.agents /AGENTS.md; do
assert_eq "entry for $path written once" "1" "$(exclude_count "$exclude" "$path")"
done
assert_eq "one comment line" "1" "$(exclude_count "$exclude" "# RepoFoundry: the files installed from the framework")"
}
test_nothing_is_written_for_paths_git_already_ignores() {
local dir="$WORK/p" exclude="$WORK/p/.git/info/exclude"
mkdir -p "$dir"
project_git "$dir" init -q
printf '.claude\n.agents\nAGENTS.md\n' >"$dir/.gitignore"
run_lib "" 'PROJECT[directory]="'"$dir"'"
exclude_framework_files
echo "${STEP_STATUS["Git excludes"]}"'
assert_status "run" 0 "$STATUS"
assert_eq "reused" "reused" "$OUT"
assert_eq "no entry written" "0" "$(grep -c '^/' "$exclude" || true)"
assert_eq "no comment written" "0" "$(exclude_count "$exclude" "# RepoFoundry: the files installed from the framework")"
}
test_a_tracked_framework_file_stays_tracked_and_is_named() {
local dir="$WORK/p"
mkdir -p "$dir/.agents" "$dir/.claude"
project_git "$dir" init -q
printf 'mine\n' >"$dir/AGENTS.md"
printf 'x\n' >"$dir/.agents/keep"
printf 'y\n' >"$dir/.claude/new" # not tracked
project_git "$dir" add AGENTS.md .agents/keep
project_git "$dir" commit -q -m seed
run_lib "" 'PROJECT[directory]="'"$dir"'"
exclude_framework_files
echo "${STEP_STATUS["Git excludes"]} ${STEP_DETAIL["Git excludes"]}"'
assert_status "run" 0 "$STATUS"
assert_contains "names the tracked paths" "$OUT" "git tracks .agents AGENTS.md, so it is not ignored"
assert_eq "both are still tracked" $'.agents/keep\nAGENTS.md' "$(project_git "$dir" ls-files)"
assert_eq "the content is unchanged" "mine" "$(cat "$dir/AGENTS.md")"
assert_eq "nothing is staged or modified" "" "$(project_git "$dir" status --porcelain)"
check
if ! project_git "$dir" check-ignore -q -- .claude; then
fail ".claude, which git does not track, is not ignored"
fi
}
# ----------------------------------------------------------- SSH and errors # ----------------------------------------------------------- SSH and errors
test_without_ssh_the_run_stops_unless_the_framework_is_skipped() { test_without_ssh_the_run_stops_unless_the_framework_is_skipped() {
@@ -311,6 +410,9 @@ test_without_ssh_the_framework_steps_are_skipped_after_a_yes() {
assert_contains "framework skipped" "$OUT" "Framework : skipped (no SSH access to Gitea)" assert_contains "framework skipped" "$OUT" "Framework : skipped (no SSH access to Gitea)"
assert_contains "skills and hooks skipped" "$OUT" "Skills and hooks : skipped (no SSH access to Gitea)" assert_contains "skills and hooks skipped" "$OUT" "Skills and hooks : skipped (no SSH access to Gitea)"
assert_contains "templates skipped" "$OUT" "Templates : skipped (no SSH access to Gitea)" assert_contains "templates skipped" "$OUT" "Templates : skipped (no SSH access to Gitea)"
assert_contains "git excludes skipped" "$OUT" "Git excludes : skipped (no SSH access to Gitea)"
assert_not_contains "nothing excluded: .claude" "$(cat "$dir/.git/info/exclude")" "/.claude"
assert_not_contains "nothing excluded: AGENTS.md" "$(cat "$dir/.git/info/exclude")" "/AGENTS.md"
assert_file_missing "no submodule" "$dir/.gitmodules" assert_file_missing "no submodule" "$dir/.gitmodules"
assert_file_missing "no AGENTS.md" "$dir/AGENTS.md" assert_file_missing "no AGENTS.md" "$dir/AGENTS.md"
} }
@@ -365,6 +467,7 @@ test_the_dry_run_plan_describes_the_local_steps_and_creates_nothing() {
assert_contains "framework" "$OUT" "Framework : add $SSH_FRAMEWORK_URL as a submodule" assert_contains "framework" "$OUT" "Framework : add $SSH_FRAMEWORK_URL as a submodule"
assert_contains "skills and hooks" "$OUT" "Skills and hooks : install once; plan gate yes" assert_contains "skills and hooks" "$OUT" "Skills and hooks : install once; plan gate yes"
assert_contains "templates" "$OUT" "Templates : AGENTS.md and docs/artifact-registry.md (you are asked before a file is replaced)" assert_contains "templates" "$OUT" "Templates : AGENTS.md and docs/artifact-registry.md (you are asked before a file is replaced)"
assert_contains "git excludes" "$OUT" "Git excludes : /.claude /.agents /AGENTS.md go into .git/info/exclude (no tracked file changes)"
assert_file_missing "nothing created" "$dir" assert_file_missing "nothing created" "$dir"
} }
@@ -378,6 +481,7 @@ test_the_plan_marks_an_existing_directory_and_missing_ssh() {
run_dry "$LOCAL_ANSWERS" run_dry "$LOCAL_ANSWERS"
assert_contains "existing directory" "$OUT" "use the existing directory $dir, which has files (you will be asked)" assert_contains "existing directory" "$OUT" "use the existing directory $dir, which has files (you will be asked)"
assert_contains "no SSH" "$OUT" "NOT possible without SSH to Gitea; you will be asked whether to go on without it" assert_contains "no SSH" "$OUT" "NOT possible without SSH to Gitea; you will be asked whether to go on without it"
assert_not_contains "no git excludes without the framework" "$OUT" "Git excludes"
assert_contains "HTTPS origin" "$OUT" "will use HTTPS (SSH test: failed" assert_contains "HTTPS origin" "$OUT" "will use HTTPS (SSH test: failed"
} }
+1 -1
View File
@@ -103,7 +103,7 @@ test_usage_errors() {
assert_contains "help shows exit codes" "$OUT" "Exit codes" assert_contains "help shows exit codes" "$OUT" "Exit codes"
run_cli "" --version run_cli "" --version
assert_status "version" 0 "$STATUS" assert_status "version" 0 "$STATUS"
assert_contains "version output" "$OUT" "RepoFoundry 0.3.1" assert_contains "version output" "$OUT" "RepoFoundry 0.3.2"
} }
test_warns_when_env_is_not_ignored_by_git() { test_warns_when_env_is_not_ignored_by_git() {