mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
feat(repo): sync forks on the server, wire forks into clones, validate set-default
repo sync OWNER/REPO, run where no Git remote points to the repository,
now updates it on the server: a fork's branch fast-forwards to its
parent's through merge-upstream, and a pull mirror fetches its source.
repo fork reports an existing fork ("! bob/x already exists") instead of
a raw HTTP 409, refuses to fork a repository into its own owner, and
gains --fork-name, --clone (Git flags after --) and --remote, which adds
the fork as origin and renames the old origin to upstream.
repo clone passes Git flags after --, and takes --upstream-remote-name
and --no-upstream for forks. Clones report what they set up.
repo set-default checks that the repository exists before saving it,
prints the saved repository with --view, removes it with --unset, and
reports the change.
Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
13 files changed
+599
-98
No files matched your search
@@ -62,6 +62,62 @@ func TestRepoSyncFastForwardsWithoutSwitchingBranches(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoSyncUpdatesAForkOrMirrorOnTheServer(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name, repo, feedback string
|
||||
requests []string
|
||||
json string
|
||||
}{
|
||||
{
|
||||
name: "fork", repo: `{"full_name":"bob/project","fork":true,"default_branch":"main","parent":{"full_name":"alice/project"}}`,
|
||||
requests: []string{"GET /api/v1/repos/bob/project", "GET /api/v1/repos/bob/project/branches/main", "POST /api/v1/repos/bob/project/merge-upstream", "GET /api/v1/repos/bob/project/branches/main"},
|
||||
feedback: "✓ Synced bob/project main from alice/project (fast-forward 1111111..2222222)\n",
|
||||
json: `{"branch":"main","commit":"2222222bbbb","previous":"1111111aaaa","remote":"alice/project"}`,
|
||||
},
|
||||
{
|
||||
name: "mirror", repo: `{"full_name":"bob/project","mirror":true,"original_url":"https://example.test/source.git"}`,
|
||||
requests: []string{"GET /api/v1/repos/bob/project", "POST /api/v1/repos/bob/project/mirror-sync"},
|
||||
feedback: "✓ Started updating the mirror bob/project from its source\n",
|
||||
json: `{"branch":"","commit":"","previous":"","remote":"https://example.test/source.git"}`,
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var requests []string
|
||||
synced := false
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requests = append(requests, r.Method+" "+r.URL.Path)
|
||||
switch r.URL.Path {
|
||||
case "/api/v1/repos/bob/project":
|
||||
_, _ = w.Write([]byte(test.repo))
|
||||
case "/api/v1/repos/bob/project/branches/main":
|
||||
commit := "1111111aaaa"
|
||||
if synced {
|
||||
commit = "2222222bbbb"
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"name":"main","commit":{"id":"` + commit + `"}}`))
|
||||
case "/api/v1/repos/bob/project/merge-upstream":
|
||||
requirePayload(t, `{"branch":"main","ff_only":true}`, r.Body)
|
||||
synced = true
|
||||
_, _ = w.Write([]byte(`{"merge_type":"fast-forward"}`))
|
||||
default:
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
deps, out, diagnostics := repoTTYDeps(t, server.URL)
|
||||
deps.Git = &syncGit{}
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "sync", "bob/project"}))
|
||||
require.Equal(t, test.requests, requests)
|
||||
require.Equal(t, test.feedback, diagnostics.String())
|
||||
require.Empty(t, out.String())
|
||||
deps, out, _ = serverDeps(t, server.URL)
|
||||
deps.Git, synced, requests = &syncGit{}, false, nil
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "sync", "bob/project", "--json"}))
|
||||
require.JSONEq(t, test.json, out.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoSyncOutsideACloneExplainsWhatItNeeds(t *testing.T) {
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Errorf("unexpected request %s %s", r.Method, r.URL.Path)
|
||||
@@ -71,5 +127,5 @@ func TestRepoSyncOutsideACloneExplainsWhatItNeeds(t *testing.T) {
|
||||
deps.Git = &syncGit{}
|
||||
err := Execute(context.Background(), deps, []string{"repo", "sync", "-R", "alice/project", "-b", "main"})
|
||||
require.Equal(t, clierr.Usage, clierr.ExitCode(err), "%v", err)
|
||||
require.ErrorContains(t, err, "repo sync must run inside a Git clone of alice/project")
|
||||
require.ErrorContains(t, err, "repo sync needs a Git clone of alice/project; run it inside one, or pass a fork to update it on the server")
|
||||
}
|
||||
Reference in new issue
Block a user