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
14 changes: 8 additions & 6 deletions internal/server/handlers_wiki_browse.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,15 +277,17 @@ func unsyncedWikiFiles(ctx context.Context, vaultPath string) map[string]bool {
if vaultPath == "" {
return out
}
// `git diff --name-only origin/HEAD HEAD` returns paths that differ
// in either direction. We don't restrict to a subdir — both
// entries/ and entities/ paths flow through here so the same set
// can be queried from multiple call sites.
res, err := runGitCapture(ctx, vaultPath, "diff", "--name-only", "origin/HEAD", "HEAD")
// `git diff --name-only --relative origin/HEAD HEAD` returns paths
// that differ in either direction, relative to vaultPath. --relative
// is required when vaultPath is a subdirectory of the repo root
// (e.g. a wiki_path like "wikis/"): without it git outputs paths
// relative to the repo root (e.g. "wikis/entries/foo.md") while
// callers look up vault-relative keys (e.g. "entries/foo.md").
res, err := runGitCapture(ctx, vaultPath, "diff", "--name-only", "--relative", "origin/HEAD", "HEAD")
if err != nil {
// Some repos don't expose origin/HEAD as a symbolic ref; try
// origin/main as a fallback before giving up.
res, err = runGitCapture(ctx, vaultPath, "diff", "--name-only", "origin/main", "HEAD")
res, err = runGitCapture(ctx, vaultPath, "diff", "--name-only", "--relative", "origin/main", "HEAD")
if err != nil {
return out
}
Expand Down
38 changes: 38 additions & 0 deletions internal/server/handlers_wiki_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package server

import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -288,3 +289,40 @@ References [[service-x]] (already on origin) and [[service-new]] (local-only).
assert.Equal(t, []string{"entities/services/service-new.md"}, got,
"auto-include must pick up the unsynced stub and ignore the already-synced one")
}

// TestUnsyncedWikiFiles_SubdirVaultPath verifies that unsyncedWikiFiles
// returns paths relative to vaultPath even when vaultPath is a
// subdirectory of the git repo root (e.g. wiki_path: "wikis/"). Without
// --relative, git diff emits paths like "wikis/entries/foo.md" while
// callers look up vault-relative keys like "entries/foo.md" — causing
// every newly committed entry to appear synced and disabling the push
// button.
func TestUnsyncedWikiFiles_SubdirVaultPath(t *testing.T) {
t.Parallel()

repoRoot := t.TempDir()
gitInit(t, repoRoot)

// Write a seed file at the repo root so the initial commit is non-empty.
require.NoError(t, os.WriteFile(filepath.Join(repoRoot, "README.md"), []byte("wiki\n"), 0o600))
gitCommitAll(t, repoRoot, "init")
gitSetupOriginWithMain(t, repoRoot)

// Create the wikis/ subdir that mirrors a profile with wiki_path: "wikis".
vaultPath := filepath.Join(repoRoot, "wikis")
require.NoError(t, os.MkdirAll(filepath.Join(vaultPath, "entries"), 0o700))

// Commit a new entry locally (not yet pushed to origin).
entryPath := filepath.Join(vaultPath, "entries", "inv-test.md")
require.NoError(t, os.WriteFile(entryPath, []byte("# test\n"), 0o600))
gitCommitAll(t, repoRoot, "wiki: inv-test")

got := unsyncedWikiFiles(context.Background(), vaultPath)

// The key must be vault-relative ("entries/inv-test.md"), not
// repo-root-relative ("wikis/entries/inv-test.md").
assert.True(t, got["entries/inv-test.md"],
"entry committed under wikis/ subdir must appear as vault-relative key in unsynced set; got keys: %v", got)
assert.False(t, got["wikis/entries/inv-test.md"],
"repo-root-relative key must not appear; got keys: %v", got)
}
Loading