fix(dsh): форс-рефспек тега при смене DSH_SUPERPOWERS_REPO (T3.5, #69)

This commit is contained in:
Andrey Epifancev 2026-10-25 00:26:00 +04:00
parent 914a54c3e4
commit 1a0c78cbc3
2 changed files with 34 additions and 4 deletions

View File

@ -414,10 +414,12 @@ ensure_pinned_clone() {
fi fi
# Online: refresh the pin. Fetching from $DSH_SUPERPOWERS_REPO (not from # Online: refresh the pin. Fetching from $DSH_SUPERPOWERS_REPO (not from
# the clone's origin) makes a repo change take effect on the next run # the clone's origin) makes a repo change take effect on the next run
# (T3.3); fetching the tag ref itself and checking out FETCH_HEAD handles # (T3.3); the force refspec updates the LOCAL tag as well as FETCH_HEAD, so
# a moved tag, which `git checkout <ref>` (resolving the stale local ref) # a later offline run still sees HEAD on the ref (T3.5), and checking out
# would miss. # FETCH_HEAD handles a moved tag, which `git checkout <ref>` (resolving the
if git -C "$dir" fetch -q --depth 1 "$DSH_SUPERPOWERS_REPO" "refs/tags/$ref" 2>/dev/null || # stale local ref) would miss. The plain "$ref" fallback covers non-tag
# refs (e.g. a branch pin).
if git -C "$dir" fetch -q --depth 1 "$DSH_SUPERPOWERS_REPO" "+refs/tags/$ref:refs/tags/$ref" 2>/dev/null ||
git -C "$dir" fetch -q --depth 1 "$DSH_SUPERPOWERS_REPO" "$ref" 2>/dev/null; then git -C "$dir" fetch -q --depth 1 "$DSH_SUPERPOWERS_REPO" "$ref" 2>/dev/null; then
if ! git -C "$dir" checkout -q FETCH_HEAD; then if ! git -C "$dir" checkout -q FETCH_HEAD; then
echo "FAIL: checkout of the fetched ref failed in $dir" >&2 echo "FAIL: checkout of the fetched ref failed in $dir" >&2

View File

@ -240,6 +240,34 @@ test('--skills updates an existing clone from DSH_SUPERPOWERS_REPO, not origin (
} }
}) })
test('after a repo switch, an offline run still reuses the clone on the ref (T3.5)', () => {
const work = tempDir()
try {
const home = join(work, 'home')
const repoA = makePinnedRepo(work, 'from-a', 'upstream-a')
const repoB = makePinnedRepo(work, 'from-b', 'upstream-b')
const installed = join(home, '.dsh', 'skills', 'using-superpowers', 'SKILL.md')
const first = runInstaller(home, ['--skills'], { DSH_SUPERPOWERS_REPO: `file://${repoA}` })
assert.equal(first.status, 0, first.stdout + first.stderr)
// Online switch: the clone moves to repoB's v7.0.1 (T3.3 behavior).
const second = runInstaller(home, ['--skills'], { DSH_SUPERPOWERS_REPO: `file://${repoB}` })
assert.equal(second.status, 0, second.stdout + second.stderr)
assert.match(readFileSync(installed, 'utf8'), /pin-marker: from-b/)
// Offline afterwards: the local tag must have moved with the fetch, so
// the on-ref reuse succeeds with a WARN instead of a hard FAIL.
const third = runInstaller(home, ['--skills'], { DSH_SUPERPOWERS_REPO: 'file:///nonexistent' })
const out = third.stdout + third.stderr
assert.equal(third.status, 0, out)
assert.match(out, /offline; reusing the existing clone/)
assert.match(readFileSync(installed, 'utf8'), /pin-marker: from-b/)
} finally {
cleanup(work)
}
})
test('--skills removes a half-cloned dir after a failed fresh clone (RF5)', () => { test('--skills removes a half-cloned dir after a failed fresh clone (RF5)', () => {
const home = tempDir() const home = tempDir()
try { try {