diff --git a/api/tangled/repoblob.go b/api/tangled/repoblob.go --- a/api/tangled/repoblob.go +++ b/api/tangled/repoblob.go @@ -72,7 +72,7 @@ // // path: Path to the file within the repository // raw: Return raw file content instead of JSON response // ref: Git reference (branch, tag, or commit SHA) -// repo: Repository identifier in format 'did:plc:.../repoName' +// repo: DID of the repository func RepoBlob(ctx context.Context, c util.LexClient, path string, raw bool, ref string, repo string) (*RepoBlob_Output, error) { var out RepoBlob_Output diff --git a/api/tangled/tempanalyzeMerge.go b/api/tangled/tempanalyzeMerge.go --- a/api/tangled/tempanalyzeMerge.go +++ b/api/tangled/tempanalyzeMerge.go @@ -34,7 +34,7 @@ // GitTempAnalyzeMerge calls the XRPC method "sh.tangled.git.temp.analyzeMerge". // // branch: Target branch to merge into // patch: Patch or pull request to check for merge conflicts -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempAnalyzeMerge(ctx context.Context, c util.LexClient, branch string, patch string, repo string) (*GitTempAnalyzeMerge_Output, error) { var out GitTempAnalyzeMerge_Output diff --git a/api/tangled/tempgetArchive.go b/api/tangled/tempgetArchive.go --- a/api/tangled/tempgetArchive.go +++ b/api/tangled/tempgetArchive.go @@ -20,7 +20,7 @@ // // format: Archive format // prefix: Prefix for files in the archive // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetArchive(ctx context.Context, c util.LexClient, format string, prefix string, ref string, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/tempgetBlob.go b/api/tangled/tempgetBlob.go --- a/api/tangled/tempgetBlob.go +++ b/api/tangled/tempgetBlob.go @@ -19,7 +19,7 @@ // GitTempGetBlob calls the XRPC method "sh.tangled.git.temp.getBlob". // // path: Path within the repository tree // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetBlob(ctx context.Context, c util.LexClient, path string, ref string, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/tempgetBranch.go b/api/tangled/tempgetBranch.go --- a/api/tangled/tempgetBranch.go +++ b/api/tangled/tempgetBranch.go @@ -30,7 +30,7 @@ // GitTempGetBranch calls the XRPC method "sh.tangled.git.temp.getBranch". // // name: Branch name to get information for -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetBranch(ctx context.Context, c util.LexClient, name string, repo string) (*GitTempGetBranch_Output, error) { var out GitTempGetBranch_Output diff --git a/api/tangled/tempgetCommit.go b/api/tangled/tempgetCommit.go --- a/api/tangled/tempgetCommit.go +++ b/api/tangled/tempgetCommit.go @@ -17,7 +17,7 @@ // GitTempGetCommit calls the XRPC method "sh.tangled.git.temp.getCommit". // // ref: reference name to resolve -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetCommit(ctx context.Context, c util.LexClient, ref string, repo string) (*GitTempDefs_Commit, error) { var out GitTempDefs_Commit diff --git a/api/tangled/tempgetDiff.go b/api/tangled/tempgetDiff.go --- a/api/tangled/tempgetDiff.go +++ b/api/tangled/tempgetDiff.go @@ -17,7 +17,7 @@ ) // GitTempGetDiff calls the XRPC method "sh.tangled.git.temp.getDiff". // -// repo: AT-URI of the repository +// repo: DID of the repository // rev1: First revision (commit, branch, or tag) // rev2: Second revision (commit, branch, or tag) func GitTempGetDiff(ctx context.Context, c util.LexClient, repo string, rev1 string, rev2 string) ([]byte, error) { diff --git a/api/tangled/tempgetEntity.go b/api/tangled/tempgetEntity.go --- a/api/tangled/tempgetEntity.go +++ b/api/tangled/tempgetEntity.go @@ -18,7 +18,7 @@ // GitTempGetEntity calls the XRPC method "sh.tangled.git.temp.getEntity". // // path: path of the entity // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetEntity(ctx context.Context, c util.LexClient, path string, ref string, repo string) (*GitTempDefs_Blob, error) { var out GitTempDefs_Blob diff --git a/api/tangled/tempgetHead.go b/api/tangled/tempgetHead.go --- a/api/tangled/tempgetHead.go +++ b/api/tangled/tempgetHead.go @@ -16,7 +16,7 @@ ) // GitTempGetHead calls the XRPC method "sh.tangled.git.temp.getHead". // -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetHead(ctx context.Context, c util.LexClient, repo string) (*GitTempDefs_Branch, error) { var out GitTempDefs_Branch diff --git a/api/tangled/tempgetTag.go b/api/tangled/tempgetTag.go --- a/api/tangled/tempgetTag.go +++ b/api/tangled/tempgetTag.go @@ -17,7 +17,7 @@ ) // GitTempGetTag calls the XRPC method "sh.tangled.git.temp.getTag". // -// repo: AT-URI of the repository +// repo: DID of the repository // tag: Name of tag, such as v1.3.0 func GitTempGetTag(ctx context.Context, c util.LexClient, repo string, tag string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/tempgetTree.go b/api/tangled/tempgetTree.go --- a/api/tangled/tempgetTree.go +++ b/api/tangled/tempgetTree.go @@ -72,7 +72,7 @@ // GitTempGetTree calls the XRPC method "sh.tangled.git.temp.getTree". // // path: Path within the repository tree // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetTree(ctx context.Context, c util.LexClient, path string, ref string, repo string) (*GitTempGetTree_Output, error) { var out GitTempGetTree_Output diff --git a/api/tangled/templistBranches.go b/api/tangled/templistBranches.go --- a/api/tangled/templistBranches.go +++ b/api/tangled/templistBranches.go @@ -19,7 +19,7 @@ // GitTempListBranches calls the XRPC method "sh.tangled.git.temp.listBranches". // // cursor: Pagination cursor // limit: Maximum number of branches to return -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListBranches(ctx context.Context, c util.LexClient, cursor string, limit int64, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/templistCommits.go b/api/tangled/templistCommits.go --- a/api/tangled/templistCommits.go +++ b/api/tangled/templistCommits.go @@ -20,7 +20,7 @@ // // cursor: Pagination cursor (commit SHA) // limit: Maximum number of commits to return // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListCommits(ctx context.Context, c util.LexClient, cursor string, limit int64, ref string, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/templistLanguages.go b/api/tangled/templistLanguages.go --- a/api/tangled/templistLanguages.go +++ b/api/tangled/templistLanguages.go @@ -44,7 +44,7 @@ // GitTempListLanguages calls the XRPC method "sh.tangled.git.temp.listLanguages". // // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListLanguages(ctx context.Context, c util.LexClient, ref string, repo string) (*GitTempListLanguages_Output, error) { var out GitTempListLanguages_Output diff --git a/api/tangled/templistTags.go b/api/tangled/templistTags.go --- a/api/tangled/templistTags.go +++ b/api/tangled/templistTags.go @@ -19,7 +19,7 @@ // GitTempListTags calls the XRPC method "sh.tangled.git.temp.listTags". // // cursor: Pagination cursor // limit: Maximum number of tags to return -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListTags(ctx context.Context, c util.LexClient, cursor string, limit int64, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/appview/pulls/compose.go b/appview/pulls/compose.go --- a/appview/pulls/compose.go +++ b/appview/pulls/compose.go @@ -334,7 +334,7 @@ } func (s *Pulls) listBranches(ctx context.Context, repo *models.Repo) ([]types.Branch, error) { xrpcc := &indigoxrpc.Client{Host: s.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoDid) if err != nil { return nil, err } diff --git a/appview/pulls/resubmit_check_test.go b/appview/pulls/resubmit_check_test.go new file mode 100644 --- /dev/null +++ b/appview/pulls/resubmit_check_test.go @@ -0,0 +1,166 @@ +package pulls + +import ( + "context" + "encoding/json" + "io" + "log/slog" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/bluesky-social/indigo/atproto/syntax" + "tangled.org/core/api/tangled" + "tangled.org/core/appview/config" + "tangled.org/core/appview/models" + "tangled.org/core/appview/pages" +) + +const ( + resubmitTestOwnerDID = "did:plc:boltless" + resubmitTestRepoDID = "did:plc:akshay" + resubmitTestBranch = "feature" + resubmitTestSourceRev = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +) + +func newKnotmirrorStub(t *testing.T, hash string) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/xrpc/"+tangled.GitTempGetBranchNSID { + t.Errorf("unexpected path %q", r.URL.Path) + http.Error(w, "wrong path", http.StatusNotFound) + return + } + repoQuery := r.URL.Query().Get("repo") + if _, err := syntax.ParseDID(repoQuery); err != nil { + t.Errorf("repo param %q is not a DID: %v", repoQuery, err) + http.Error(w, "repo must be a DID", http.StatusBadRequest) + return + } + if got := r.URL.Query().Get("name"); got != resubmitTestBranch { + t.Errorf("name param = %q, want %q", got, resubmitTestBranch) + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(tangled.GitTempGetBranch_Output{ + Name: resubmitTestBranch, + Hash: hash, + When: time.Now().UTC().Format(time.RFC3339), + }) + })) +} + +func newPullsFromKnotURL(url string) *Pulls { + return &Pulls{ + logger: slog.New(slog.NewTextHandler(io.Discard, nil)), + config: &config.Config{ + KnotMirror: config.KnotMirrorConfig{Url: url}, + }, + } +} + +func newForkPull(state models.PullState) (*models.Pull, *models.Repo, models.Stack) { + sourceRepoDid := syntax.DID(resubmitTestRepoDID) + pull := &models.Pull{ + State: state, + OwnerDid: resubmitTestOwnerDID, + TargetBranch: "main", + Submissions: []*models.PullSubmission{ + {SourceRev: resubmitTestSourceRev}, + }, + PullSource: &models.PullSource{ + Branch: resubmitTestBranch, + RepoDid: &sourceRepoDid, + }, + } + repo := &models.Repo{RepoDid: resubmitTestRepoDID} + stack := models.Stack{pull} + return pull, repo, stack +} + +func TestResubmitCheck_BranchAdvanced(t *testing.T) { + srv := newKnotmirrorStub(t, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + defer srv.Close() + + s := newPullsFromKnotURL(srv.URL) + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullOpen) + + got := s.resubmitCheck(req, repo, pull, stack) + if got != pages.ShouldResubmit { + t.Errorf("resubmitCheck() = %v, want ShouldResubmit", got) + } +} + +func TestResubmitCheck_BranchUpToDate(t *testing.T) { + srv := newKnotmirrorStub(t, resubmitTestSourceRev) + defer srv.Close() + + s := newPullsFromKnotURL(srv.URL) + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullOpen) + + got := s.resubmitCheck(req, repo, pull, stack) + if got != pages.ShouldNotResubmit { + t.Errorf("resubmitCheck() = %v, want ShouldNotResubmit", got) + } +} + +func TestResubmitCheck_MergedReturnsUnknown(t *testing.T) { + s := newPullsFromKnotURL("http://unused") + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullMerged) + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.Unknown { + t.Errorf("resubmitCheck() = %v, want Unknown for merged pull", got) + } +} + +func TestResubmitCheck_PatchBasedReturnsUnknown(t *testing.T) { + s := newPullsFromKnotURL("http://unused") + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullOpen) + pull.PullSource = nil + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.Unknown { + t.Errorf("resubmitCheck() = %v, want Unknown for patch-based pull", got) + } +} + +func TestResubmitCheck_KnotUnreachableReturnsUnknown(t *testing.T) { + s := newPullsFromKnotURL("http://127.0.0.1:1") + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + req := httptest.NewRequest(http.MethodGet, "/", nil).WithContext(ctx) + pull, repo, stack := newForkPull(models.PullOpen) + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.Unknown { + t.Errorf("resubmitCheck() = %v, want Unknown when knot unreachable", got) + } +} + +func TestResubmitCheck_NonForkUsesRepoDid(t *testing.T) { + const targetRepoDID = "did:plc:scallop" + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if got := r.URL.Query().Get("repo"); got != targetRepoDID { + t.Errorf("repo param = %q, want %q for non-fork pull", got, targetRepoDID) + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(tangled.GitTempGetBranch_Output{ + Name: resubmitTestBranch, + Hash: resubmitTestSourceRev, + When: time.Now().UTC().Format(time.RFC3339), + }) + })) + defer srv.Close() + + s := newPullsFromKnotURL(srv.URL) + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, _, stack := newForkPull(models.PullOpen) + pull.PullSource.RepoDid = nil + repo := &models.Repo{RepoDid: targetRepoDID} + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.ShouldNotResubmit { + t.Errorf("resubmitCheck() = %v, want ShouldNotResubmit", got) + } +} diff --git a/appview/pulls/single.go b/appview/pulls/single.go --- a/appview/pulls/single.go +++ b/appview/pulls/single.go @@ -350,7 +350,7 @@ return nil } xrpcc := &indigoxrpc.Client{Host: s.config.KnotMirror.Url} - resp, err := tangled.GitTempGetBranch(r.Context(), xrpcc, branch, repo.RepoAt().String()) + resp, err := tangled.GitTempGetBranch(r.Context(), xrpcc, branch, repo.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { s.logger.Error("failed to get branch", "xrpcerr", xrpcerr, "err", err) return nil diff --git a/appview/repo/archive.go b/appview/repo/archive.go --- a/appview/repo/archive.go +++ b/appview/repo/archive.go @@ -24,7 +24,7 @@ } // build the xrpc url query := url.Values{} - query.Set("repo", f.RepoAt().String()) + query.Set("repo", f.RepoDid) query.Set("ref", ref) query.Set("format", "tar.gz") query.Set("prefix", r.URL.Query().Get("prefix")) diff --git a/appview/repo/artifact.go b/appview/repo/artifact.go --- a/appview/repo/artifact.go +++ b/appview/repo/artifact.go @@ -310,7 +310,7 @@ } xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, f.RepoDid) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tags", "xrpcerr", xrpcerr, "err", err) diff --git a/appview/repo/blob.go b/appview/repo/blob.go --- a/appview/repo/blob.go +++ b/appview/repo/blob.go @@ -52,7 +52,7 @@ filePath := chi.URLParam(r, "*") filePath, _ = url.PathUnescape(filePath) xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, f.RepoAt().String()) + resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.blob", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) @@ -272,7 +272,7 @@ } func generateBlobURL(config *config.Config, repo *models.Repo, ref, filePath string) string { query := url.Values{} - query.Set("repo", string(repo.RepoAt())) + query.Set("repo", repo.RepoDid) query.Set("ref", ref) query.Set("path", filePath) query.Set("raw", "true") diff --git a/appview/repo/branches.go b/appview/repo/branches.go --- a/appview/repo/branches.go +++ b/appview/repo/branches.go @@ -23,7 +23,7 @@ return } xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.branches", "err", err) rp.pages.Error503(w) diff --git a/appview/repo/compare.go b/appview/repo/compare.go --- a/appview/repo/compare.go +++ b/appview/repo/compare.go @@ -32,7 +32,7 @@ } xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.branches", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) @@ -69,7 +69,7 @@ if queryHead != "" { head = queryHead } - tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tags", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) diff --git a/appview/repo/feed.go b/appview/repo/feed.go --- a/appview/repo/feed.go +++ b/appview/repo/feed.go @@ -209,7 +209,7 @@ func (rp *Repo) createCommitItems(ctx context.Context, repo *models.Repo, ownerSlashRepo string) ([]*feeds.Item, error) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 100, "", repo.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 100, "", repo.RepoDid) if err != nil { return nil, fmt.Errorf("failed to call XRPC repo.log: %w", err) } @@ -248,7 +248,7 @@ func (rp *Repo) createTagItems(ctx context.Context, repo *models.Repo, ownerSlashRepo string) ([]*feeds.Item, error) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - tagBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 100, repo.RepoAt().String()) + tagBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 100, repo.RepoDid) if err != nil { return nil, fmt.Errorf("failed to call XRPC repo.tags: %w", err) } diff --git a/appview/repo/index.go b/appview/repo/index.go --- a/appview/repo/index.go +++ b/appview/repo/index.go @@ -171,7 +171,7 @@ xrpcc := &indigoxrpc.Client{ Host: rp.config.KnotMirror.Url, Client: http.DefaultClient, } - ls, err := tangled.GitTempListLanguages(ctx, xrpcc, currentRef, repo.RepoAt().String()) + ls, err := tangled.GitTempListLanguages(ctx, xrpcc, currentRef, repo.RepoDid) if err != nil { return nil, fmt.Errorf("calling knotmirror git.listLanguages: %w", err) } @@ -254,7 +254,7 @@ // buildIndexResponse creates a RepoIndexResponse by combining multiple xrpc calls in parallel func (rp *Repo) buildIndexResponse(ctx context.Context, repo *models.Repo, ref string) (*types.RepoIndexResponse, error) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - branchesBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoAt().String()) + branchesBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoDid) if err != nil { return nil, fmt.Errorf("calling knotmirror git.listBranches: %w", err) } @@ -296,7 +296,7 @@ ) // tags wg.Go(func() { - tagsBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, repo.RepoAt().String()) + tagsBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, repo.RepoDid) if err != nil { errs = errors.Join(errs, fmt.Errorf("failed to call git.ListTags: %w", err)) return @@ -309,7 +309,7 @@ }) // tree/files wg.Go(func() { - resp, err := tangled.GitTempGetTree(ctx, xrpcc, "", ref, repo.RepoAt().String()) + resp, err := tangled.GitTempGetTree(ctx, xrpcc, "", ref, repo.RepoDid) if err != nil { errs = errors.Join(errs, fmt.Errorf("failed to call git.GetTree: %w", err)) return @@ -319,7 +319,7 @@ }) // commits wg.Go(func() { - logBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 50, ref, repo.RepoAt().String()) + logBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 50, ref, repo.RepoDid) if err != nil { errs = errors.Join(errs, fmt.Errorf("failed to call git.ListCommits: %w", err)) return diff --git a/appview/repo/log.go b/appview/repo/log.go --- a/appview/repo/log.go +++ b/appview/repo/log.go @@ -111,7 +111,7 @@ offset := (page - 1) * int(limit) cursor = strconv.Itoa(offset) } - xrpcBytes, err := tangled.GitTempListCommits(r.Context(), xrpcc, cursor, limit, ref, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListCommits(r.Context(), xrpcc, cursor, limit, ref, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.log", "err", err) rp.pages.Error503(w) @@ -125,7 +125,7 @@ rp.pages.Error503(w) return } - tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.tags", "err", err) rp.pages.Error503(w) @@ -146,7 +146,7 @@ } } } - branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.branches", "err", err) rp.pages.Error503(w) diff --git a/appview/repo/settings.go b/appview/repo/settings.go --- a/appview/repo/settings.go +++ b/appview/repo/settings.go @@ -381,7 +381,7 @@ user := rp.oauth.GetMultiAccountUser(r) xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) var result types.RepoBranchesResponse if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC git.listBranches", "xrpcerr", xrpcerr, "err", err) diff --git a/appview/repo/tags.go b/appview/repo/tags.go --- a/appview/repo/tags.go +++ b/appview/repo/tags.go @@ -28,7 +28,7 @@ l.Error("failed to get repo and knot", "err", err) return } xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.tags", "err", err) rp.pages.Error503(w) @@ -86,13 +86,13 @@ tag := chi.URLParam(r, "tag") xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempGetTag(r.Context(), xrpcc, f.RepoAt().String(), tag) + xrpcBytes, err := tangled.GitTempGetTag(r.Context(), xrpcc, f.RepoDid, tag) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { // if we don't match an existing tag, and the tag we're trying // to match is "latest", resolve to the most recent tag l.Info("failed to call XRPC git.getTag", "xrpcerr", xrpcerr, "err", err, "tag", tag) if tag == "latest" { - tagsBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 1, f.RepoAt().String()) + tagsBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 1, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC git.ListTags for latest", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) diff --git a/appview/repo/tree.go b/appview/repo/tree.go --- a/appview/repo/tree.go +++ b/appview/repo/tree.go @@ -35,7 +35,7 @@ treePath, _ = url.PathUnescape(treePath) treePath = strings.TrimSuffix(treePath, "/") xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcResp, err := tangled.GitTempGetTree(r.Context(), xrpcc, treePath, ref, f.RepoAt().String()) + xrpcResp, err := tangled.GitTempGetTree(r.Context(), xrpcc, treePath, ref, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tree", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) diff --git a/knotmirror/git.go b/knotmirror/git.go --- a/knotmirror/git.go +++ b/knotmirror/git.go @@ -25,6 +25,7 @@ // Fetch fetches the repository Fetch(ctx context.Context, repo *models.Repo) error // Sync mirrors the repository. It will clone the repository if repository doesn't exist. Sync(ctx context.Context, repo *models.Repo) error + Delete(repo *models.Repo) error } type CliGitMirrorManager struct { @@ -114,6 +115,10 @@ return fmt.Errorf("fetching repo: %w", err) } } return nil +} + +func (c *CliGitMirrorManager) Delete(repo *models.Repo) error { + return os.RemoveAll(c.makeRepoPath(repo)) } var ( @@ -249,6 +254,10 @@ return fmt.Errorf("fetching repo: %w", err) } } return nil +} + +func (c *GoGitMirrorManager) Delete(repo *models.Repo) error { + return os.RemoveAll(c.makeRepoPath(repo)) } func makeRepoRemoteUrl(knot, repoIdentifier string, knotUseSSL bool) (string, error) { diff --git a/knotmirror/tapclient.go b/knotmirror/tapclient.go --- a/knotmirror/tapclient.go +++ b/knotmirror/tapclient.go @@ -133,6 +133,16 @@ } } case tapc.RecordDeleteAction: + aturi := syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", evt.Did, tangled.RepoNSID, evt.Rkey)) + repo, err := db.GetRepoByAtUri(ctx, t.db, aturi) + if err != nil { + return fmt.Errorf("looking up repo before delete: %w", err) + } + if repo != nil { + if err := t.gitm.Delete(repo); err != nil { + return fmt.Errorf("removing mirror dir: %w", err) + } + } if err := db.DeleteRepo(ctx, t.db, evt.Did, evt.Rkey); err != nil { return fmt.Errorf("deleting repo from db: %w", err) } diff --git a/knotmirror/xrpc/git_get_archive.go b/knotmirror/xrpc/git_get_archive.go --- a/knotmirror/xrpc/git_get_archive.go +++ b/knotmirror/xrpc/git_get_archive.go @@ -23,8 +23,8 @@ format = r.URL.Query().Get("format") prefix = r.URL.Query().Get("prefix") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -61,7 +61,7 @@ return } repoName, err := func() (string, error) { - r, err := db.GetRepoByAtUri(ctx, x.db, repo) + r, err := db.GetRepoByRepoDid(ctx, x.db, repo) if err != nil { return "", err } diff --git a/knotmirror/xrpc/git_get_blob.go b/knotmirror/xrpc/git_get_blob.go --- a/knotmirror/xrpc/git_get_blob.go +++ b/knotmirror/xrpc/git_get_blob.go @@ -24,8 +24,8 @@ ref = r.URL.Query().Get("ref") // ref can be empty (git.Open handles this) path = r.URL.Query().Get("path") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -111,10 +111,10 @@ } w.Write(contents) } -func (x *Xrpc) getFile(ctx context.Context, repo syntax.ATURI, ref, path string) (*object.File, error) { +func (x *Xrpc) getFile(ctx context.Context, repo syntax.DID, ref, path string) (*object.File, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_get_branch.go b/knotmirror/xrpc/git_get_branch.go --- a/knotmirror/xrpc/git_get_branch.go +++ b/knotmirror/xrpc/git_get_branch.go @@ -21,8 +21,8 @@ repoQuery = r.URL.Query().Get("repo") nameQuery = r.URL.Query().Get("name") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -45,10 +45,10 @@ } writeJson(w, http.StatusOK, out) } -func (x *Xrpc) getBranch(ctx context.Context, repo syntax.ATURI, branchName string) (*tangled.GitTempGetBranch_Output, error) { +func (x *Xrpc) getBranch(ctx context.Context, repo syntax.DID, branchName string) (*tangled.GitTempGetBranch_Output, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.PlainOpen(repoPath) diff --git a/knotmirror/xrpc/git_get_tag.go b/knotmirror/xrpc/git_get_tag.go --- a/knotmirror/xrpc/git_get_tag.go +++ b/knotmirror/xrpc/git_get_tag.go @@ -19,8 +19,8 @@ repoQuery = r.URL.Query().Get("repo") tagName = r.URL.Query().Get("tag") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -42,10 +42,10 @@ } writeJson(w, http.StatusOK, out) } -func (x *Xrpc) getTag(ctx context.Context, repo syntax.ATURI, tagName string) (*types.RepoTagResponse, error) { +func (x *Xrpc) getTag(ctx context.Context, repo syntax.DID, tagName string) (*types.RepoTagResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.PlainOpen(repoPath) diff --git a/knotmirror/xrpc/git_get_tree.go b/knotmirror/xrpc/git_get_tree.go --- a/knotmirror/xrpc/git_get_tree.go +++ b/knotmirror/xrpc/git_get_tree.go @@ -26,8 +26,8 @@ ) l := x.logger.With("method", "git.getTree", "repo", repoQuery, "ref", ref) l.Debug("request") - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -47,10 +47,10 @@ } writeJson(w, http.StatusOK, out) } -func (x *Xrpc) getTree(ctx context.Context, repo syntax.ATURI, ref, path string) (*tangled.GitTempGetTree_Output, error) { +func (x *Xrpc) getTree(ctx context.Context, repo syntax.DID, ref, path string) (*tangled.GitTempGetTree_Output, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_list_branches.go b/knotmirror/xrpc/git_list_branches.go --- a/knotmirror/xrpc/git_list_branches.go +++ b/knotmirror/xrpc/git_list_branches.go @@ -4,12 +4,12 @@ import ( "context" "fmt" "net/http" + "os" "path/filepath" "strconv" "github.com/bluesky-social/indigo/atproto/atclient" "github.com/bluesky-social/indigo/atproto/syntax" - "tangled.org/core/knotmirror/db" "tangled.org/core/knotserver/git" "tangled.org/core/types" ) @@ -21,8 +21,8 @@ limitQuery = r.URL.Query().Get("limit") cursorQuery = r.URL.Query().Get("cursor") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -57,10 +57,10 @@ } writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listBranches(ctx context.Context, repo syntax.ATURI, limit int, cursor int64) (*types.RepoBranchesResponse, error) { +func (x *Xrpc) listBranches(ctx context.Context, repo syntax.DID, limit int, cursor int64) (*types.RepoBranchesResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.PlainOpen(repoPath) @@ -82,16 +82,10 @@ Branches: branches, }, nil } -func (x *Xrpc) makeRepoPath(ctx context.Context, repo syntax.ATURI) (string, error) { - r, err := db.GetRepoByAtUri(ctx, x.db, repo) - if err != nil { - return "", fmt.Errorf("looking up repo: %w", err) +func (x *Xrpc) makeRepoPath(ctx context.Context, repoDid syntax.DID) (string, error) { + path := filepath.Join(x.cfg.GitRepoBasePath, repoDid.String()) + if _, err := os.Stat(path); err != nil { + return "", fmt.Errorf("repo %s not mirrored locally: %w", repoDid, err) } - if r == nil { - return "", fmt.Errorf("repo not found: %s", repo) - } - if r.RepoDid == "" { - return "", fmt.Errorf("repo missing repo_did: %s", repo) - } - return filepath.Join(x.cfg.GitRepoBasePath, r.RepoDid.String()), nil + return path, nil } diff --git a/knotmirror/xrpc/git_list_commits.go b/knotmirror/xrpc/git_list_commits.go --- a/knotmirror/xrpc/git_list_commits.go +++ b/knotmirror/xrpc/git_list_commits.go @@ -20,8 +20,8 @@ limitQuery = r.URL.Query().Get("limit") cursorQuery = r.URL.Query().Get("cursor") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -56,10 +56,10 @@ } writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listCommits(ctx context.Context, repo syntax.ATURI, ref string, limit int, cursor int64) (*types.RepoLogResponse, error) { +func (x *Xrpc) listCommits(ctx context.Context, repo syntax.DID, ref string, limit int, cursor int64) (*types.RepoLogResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_list_languages.go b/knotmirror/xrpc/git_list_languages.go --- a/knotmirror/xrpc/git_list_languages.go +++ b/knotmirror/xrpc/git_list_languages.go @@ -28,9 +28,9 @@ ) l := x.logger.With("method", "git.listLanguages", "repo", repoQuery, "ref", ref) l.Debug("request") - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { - l.Error("invalid repo at-uri", "err", err) + repo, err := syntax.ParseDID(repoQuery) + if err != nil { + l.Error("invalid repo did", "err", err) writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -64,10 +64,10 @@ writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listLanguages(ctx context.Context, repo syntax.ATURI, ref string) (*tangled.GitTempListLanguages_Output, error) { +func (x *Xrpc) listLanguages(ctx context.Context, repo syntax.DID, ref string) (*tangled.GitTempListLanguages_Output, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_list_tags.go b/knotmirror/xrpc/git_list_tags.go --- a/knotmirror/xrpc/git_list_tags.go +++ b/knotmirror/xrpc/git_list_tags.go @@ -21,8 +21,8 @@ limitQuery = r.URL.Query().Get("limit") cursorQuery = r.URL.Query().Get("cursor") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -57,10 +57,10 @@ } writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listTags(ctx context.Context, repo syntax.ATURI, limit int, cursor int64) (*types.RepoTagsResponse, error) { +func (x *Xrpc) listTags(ctx context.Context, repo syntax.DID, limit int, cursor int64) (*types.RepoTagsResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.PlainOpen(repoPath) diff --git a/knotmirror/xrpc/proxy.go b/knotmirror/xrpc/proxy.go --- a/knotmirror/xrpc/proxy.go +++ b/knotmirror/xrpc/proxy.go @@ -9,7 +9,6 @@ "net/http" "net/url" "strings" - "github.com/bluesky-social/indigo/api/atproto" "github.com/bluesky-social/indigo/atproto/syntax" indigoxrpc "github.com/bluesky-social/indigo/xrpc" "tangled.org/core/api/tangled" @@ -70,9 +69,8 @@ // Strip trailing slash for consistent formatting return strings.TrimRight(u.String(), "/"), nil } -func (x *Xrpc) resolveKnot(ctx context.Context, repoAt syntax.ATURI) (*knotInfo, error) { - repo, err := db.GetRepoByAtUri(ctx, x.db, repoAt) - if err == nil && repo != nil { +func (x *Xrpc) resolveKnot(ctx context.Context, repoDid syntax.DID) (*knotInfo, error) { + if repo, err := db.GetRepoByRepoDid(ctx, x.db, repoDid); err == nil && repo != nil { knotURL := repo.KnotDomain if !strings.Contains(repo.KnotDomain, "://") { if host, _ := db.GetHost(ctx, x.db, repo.KnotDomain); host != nil { @@ -93,73 +91,60 @@ } return &knotInfo{baseURL: knotURL, repoIdentifier: repo.RepoIdentifier()}, nil } - owner, err := x.resolver.ResolveIdent(ctx, repoAt.Authority().String()) + ident, err := x.resolver.ResolveIdent(ctx, repoDid.String()) if err != nil { - return nil, fmt.Errorf("resolving repo owner: %w", err) + return nil, fmt.Errorf("resolving repoDid %s: %w", repoDid, err) } - - xrpcc := indigoxrpc.Client{Host: owner.PDSEndpoint()} - out, err := atproto.RepoGetRecord(ctx, &xrpcc, "", tangled.RepoNSID, repoAt.Authority().String(), repoAt.RecordKey().String()) + knotURL, err := validateKnotURL(ident.GetServiceEndpoint("atproto_pds")) if err != nil { - return nil, fmt.Errorf("fetching repo record from PDS: %w", err) + return nil, fmt.Errorf("repoDid %s: %w", repoDid, err) } - record := out.Value.Val.(*tangled.Repo) - if record.RepoDid == nil || *record.RepoDid == "" { - return nil, fmt.Errorf("repo record has no repo_did") + xrpcc := &indigoxrpc.Client{Host: knotURL, Client: x.httpClient} + out, err := tangled.RepoDescribeRepo(ctx, xrpcc, repoDid.String()) + if err != nil { + x.logger.Warn("describeRepo failed; serving without metadata upsert", "knot", knotURL, "repo", repoDid, "err", err) + return &knotInfo{baseURL: knotURL, repoIdentifier: repoDid.String()}, nil } - knotURL := record.Knot - if !strings.Contains(record.Knot, "://") { - if host, _ := db.GetHost(ctx, x.db, record.Knot); host != nil { - knotURL = host.URL() - } else { - x.logger.Warn("repo is from unknown knot") - if x.cfg.KnotUseSSL { - knotURL = "https://" + knotURL - } else { - knotURL = "http://" + knotURL - } - } + if out.RepoDid != repoDid.String() { + return nil, fmt.Errorf("knot %s returned mismatched repoDid: got %q, want %q", knotURL, out.RepoDid, repoDid) + } + ownerDid, err := syntax.ParseDID(out.OwnerDid) + if err != nil { + return nil, fmt.Errorf("describeRepo on %s returned invalid ownerDid %q: %w", knotURL, out.OwnerDid, err) + } + rkey, err := syntax.ParseRecordKey(out.Rkey) + if err != nil { + return nil, fmt.Errorf("describeRepo on %s returned invalid rkey %q: %w", knotURL, out.Rkey, err) } - rkey := repoAt.RecordKey().String() - repoDid := syntax.DID(*record.RepoDid) go func() { - bgCtx := context.Background() pending := &models.Repo{ - Did: owner.DID, - Rkey: repoAt.RecordKey(), - Cid: (*syntax.CID)(out.Cid), - Name: rkey, + Did: ownerDid, + Rkey: rkey, + Name: string(rkey), KnotDomain: knotURL, RepoDid: repoDid, State: models.RepoStatePending, } - if upsertErr := db.UpsertRepo(bgCtx, x.db, pending); upsertErr != nil { - x.logger.Error("failed to upsert repo after proxy resolution", "err", upsertErr) + if err := db.UpsertRepo(context.Background(), x.db, pending); err != nil { + x.logger.Error("failed to upsert repo after directory resolution", "err", err) } }() - knotURL, err = validateKnotURL(knotURL) - if err != nil { - return nil, err - } - return &knotInfo{ - baseURL: knotURL, - repoIdentifier: repoDid.String(), - }, nil + return &knotInfo{baseURL: knotURL, repoIdentifier: repoDid.String()}, nil } -func (x *Xrpc) proxyToKnot(w http.ResponseWriter, r *http.Request, repoAt syntax.ATURI) bool { +func (x *Xrpc) proxyToKnot(w http.ResponseWriter, r *http.Request, repoDid syntax.DID) bool { mirrorNSID := strings.TrimPrefix(r.URL.Path, "/xrpc/") knotNSID, ok := mirrorToKnotNSID[mirrorNSID] if !ok { return false } - knot, err := x.resolveKnot(r.Context(), repoAt) + knot, err := x.resolveKnot(r.Context(), repoDid) if err != nil { - x.logger.Warn("proxy: failed to resolve knot", "repo", repoAt, "err", err) + x.logger.Warn("proxy: failed to resolve knot", "repo", repoDid, "err", err) return false } @@ -197,6 +182,6 @@ if _, err := io.Copy(w, resp.Body); err != nil { x.logger.Warn("proxy: response copy interrupted", "target", target, "err", err) } - x.logger.Info("proxy: served from knot", "repo", repoAt, "knot", knot.baseURL, "status", resp.StatusCode) + x.logger.Info("proxy: served from knot", "repo", repoDid, "knot", knot.baseURL, "status", resp.StatusCode) return true } diff --git a/knotmirror/xrpc/repo_blob.go b/knotmirror/xrpc/repo_blob.go --- a/knotmirror/xrpc/repo_blob.go +++ b/knotmirror/xrpc/repo_blob.go @@ -24,8 +24,8 @@ ref = r.URL.Query().Get("ref") // ref can be empty (git.Open handles this) path = r.URL.Query().Get("path") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -155,10 +155,10 @@ writeJson(w, http.StatusOK, response) } -func (x *Xrpc) getRepo(ctx context.Context, repo syntax.ATURI, ref string) (*git.GitRepo, error) { +func (x *Xrpc) getRepo(ctx context.Context, repo syntax.DID, ref string) (*git.GitRepo, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/lexicons/git/temp/analyzeMerge.json b/lexicons/git/temp/analyzeMerge.json --- a/lexicons/git/temp/analyzeMerge.json +++ b/lexicons/git/temp/analyzeMerge.json @@ -11,8 +11,8 @@ "required": ["repo", "patch", "branch"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "patch": { "type": "string", diff --git a/lexicons/git/temp/getArchive.json b/lexicons/git/temp/getArchive.json --- a/lexicons/git/temp/getArchive.json +++ b/lexicons/git/temp/getArchive.json @@ -10,8 +10,8 @@ "required": ["repo", "ref"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getBlob.json b/lexicons/git/temp/getBlob.json --- a/lexicons/git/temp/getBlob.json +++ b/lexicons/git/temp/getBlob.json @@ -10,8 +10,8 @@ "required": ["repo", "path"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getBranch.json b/lexicons/git/temp/getBranch.json --- a/lexicons/git/temp/getBranch.json +++ b/lexicons/git/temp/getBranch.json @@ -10,8 +10,8 @@ "required": ["repo", "name"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "name": { "type": "string", diff --git a/lexicons/git/temp/getCommit.json b/lexicons/git/temp/getCommit.json --- a/lexicons/git/temp/getCommit.json +++ b/lexicons/git/temp/getCommit.json @@ -11,8 +11,8 @@ "required": ["repo", "ref"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getDiff.json b/lexicons/git/temp/getDiff.json --- a/lexicons/git/temp/getDiff.json +++ b/lexicons/git/temp/getDiff.json @@ -10,8 +10,8 @@ "required": ["repo", "rev1", "rev2"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "rev1": { "type": "string", diff --git a/lexicons/git/temp/getEntity.json b/lexicons/git/temp/getEntity.json --- a/lexicons/git/temp/getEntity.json +++ b/lexicons/git/temp/getEntity.json @@ -11,8 +11,8 @@ "required": ["repo", "path"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getHead.json b/lexicons/git/temp/getHead.json --- a/lexicons/git/temp/getHead.json +++ b/lexicons/git/temp/getHead.json @@ -10,8 +10,8 @@ "required": ["repo"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" } } }, diff --git a/lexicons/git/temp/getTag.json b/lexicons/git/temp/getTag.json --- a/lexicons/git/temp/getTag.json +++ b/lexicons/git/temp/getTag.json @@ -13,8 +13,8 @@ ], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "tag": { "type": "string", diff --git a/lexicons/git/temp/getTree.json b/lexicons/git/temp/getTree.json --- a/lexicons/git/temp/getTree.json +++ b/lexicons/git/temp/getTree.json @@ -13,8 +13,8 @@ ], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/listBranches.json b/lexicons/git/temp/listBranches.json --- a/lexicons/git/temp/listBranches.json +++ b/lexicons/git/temp/listBranches.json @@ -10,8 +10,8 @@ "required": ["repo"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "limit": { "type": "integer", diff --git a/lexicons/git/temp/listCommits.json b/lexicons/git/temp/listCommits.json --- a/lexicons/git/temp/listCommits.json +++ b/lexicons/git/temp/listCommits.json @@ -10,8 +10,8 @@ "required": ["repo"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/listLanguages.json b/lexicons/git/temp/listLanguages.json --- a/lexicons/git/temp/listLanguages.json +++ b/lexicons/git/temp/listLanguages.json @@ -10,8 +10,8 @@ "required": ["repo"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/listTags.json b/lexicons/git/temp/listTags.json --- a/lexicons/git/temp/listTags.json +++ b/lexicons/git/temp/listTags.json @@ -10,8 +10,8 @@ "required": ["repo"], "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "limit": { "type": "integer", diff --git a/lexicons/repo/blob.json b/lexicons/repo/blob.json --- a/lexicons/repo/blob.json +++ b/lexicons/repo/blob.json @@ -14,7 +14,8 @@ ], "properties": { "repo": { "type": "string", - "description": "Repository identifier in format 'did:plc:.../repoName'" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string",