From 64042ac8a6df87a517c58e0e2652522878b7f915 Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 07:15:44 +0000 Subject: [PATCH] feat(gitea): generalise mirror creation Co-Authored-By: Virgil --- gitea/repos.go | 20 +++++++++++++------- gitea/repos_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/gitea/repos.go b/gitea/repos.go index 356e47d..efd0bfe 100644 --- a/gitea/repos.go +++ b/gitea/repos.go @@ -123,16 +123,14 @@ func (c *Client) GetRepo(owner, name string) (*gitea.Repository, error) { return repo, nil } -// CreateMirror creates a mirror repository on Gitea from a GitHub clone URL. -// This uses the Gitea migration API to set up a pull mirror. -// If authToken is provided, it is used to authenticate against the source (e.g. for private GitHub repos). -// Usage: CreateMirror(...) -func (c *Client) CreateMirror(owner, name, cloneURL, authToken string) (*gitea.Repository, error) { +// CreateMirrorFromService creates a mirror repository from an arbitrary git service. +// Usage: CreateMirrorFromService(...) +func (c *Client) CreateMirrorFromService(owner, name, cloneURL string, service gitea.GitServiceType, authToken string) (*gitea.Repository, error) { opts := gitea.MigrateRepoOption{ RepoName: name, RepoOwner: owner, CloneAddr: cloneURL, - Service: gitea.GitServiceGithub, + Service: service, Mirror: true, Description: "Mirror of " + cloneURL, } @@ -143,12 +141,20 @@ func (c *Client) CreateMirror(owner, name, cloneURL, authToken string) (*gitea.R repo, _, err := c.api.MigrateRepo(opts) if err != nil { - return nil, log.E("gitea.CreateMirror", "failed to create mirror", err) + return nil, log.E("gitea.CreateMirrorFromService", "failed to create mirror", err) } return repo, nil } +// CreateMirror creates a mirror repository on Gitea from a GitHub clone URL. +// This uses the Gitea migration API to set up a pull mirror. +// If authToken is provided, it is used to authenticate against the source (e.g. for private GitHub repos). +// Usage: CreateMirror(...) +func (c *Client) CreateMirror(owner, name, cloneURL, authToken string) (*gitea.Repository, error) { + return c.CreateMirrorFromService(owner, name, cloneURL, gitea.GitServiceGithub, authToken) +} + // DeleteRepo deletes a repository from Gitea. // Usage: DeleteRepo(...) func (c *Client) DeleteRepo(owner, name string) error { diff --git a/gitea/repos_test.go b/gitea/repos_test.go index 4ae97ba..61f1081 100644 --- a/gitea/repos_test.go +++ b/gitea/repos_test.go @@ -3,6 +3,9 @@ package gitea import ( + "encoding/json" + "net/http" + "net/http/httptest" "testing" giteaSDK "code.gitea.io/sdk/gitea" @@ -97,6 +100,38 @@ func TestClient_CreateMirror_Bad_ServerError_Good(t *testing.T) { assert.Contains(t, err.Error(), "failed to create mirror") } +func TestClient_CreateMirrorFromService_Good_Gitea_Good(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/api/v1/version", func(w http.ResponseWriter, r *http.Request) { + jsonResponse(w, map[string]string{"version": "1.21.0"}) + }) + mux.HandleFunc("/api/v1/repos/migrate", func(w http.ResponseWriter, r *http.Request) { + var opts map[string]any + require.NoError(t, json.NewDecoder(r.Body).Decode(&opts)) + assert.Equal(t, "gitea", opts["service"]) + assert.Equal(t, true, opts["mirror"]) + assert.Equal(t, "https://forge.example.org/core/go-scm.git", opts["clone_addr"]) + assert.Equal(t, "secret-token", opts["auth_token"]) + w.WriteHeader(http.StatusCreated) + jsonResponse(w, map[string]any{ + "id": 40, "name": "public-mirror", "full_name": "test-org/public-mirror", + "owner": map[string]any{"login": "test-org"}, + "mirror": true, + }) + }) + + srv := httptest.NewServer(mux) + defer srv.Close() + + client, err := New(srv.URL, "test-token") + require.NoError(t, err) + + repo, err := client.CreateMirrorFromService("test-org", "public-mirror", "https://forge.example.org/core/go-scm.git", giteaSDK.GitServiceGitea, "secret-token") + require.NoError(t, err) + require.NotNil(t, repo) + assert.Equal(t, "public-mirror", repo.Name) +} + func TestClient_DeleteRepo_Good(t *testing.T) { client, srv := newTestClient(t) defer srv.Close()