diff --git a/cmd/f3.go b/cmd/f3.go deleted file mode 100644 index d977867a74..0000000000 --- a/cmd/f3.go +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-License-Identifier: MIT - -package cmd - -import ( - "context" - "fmt" - - auth_model "code.gitea.io/gitea/models/auth" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/services/f3/util" - - "github.com/urfave/cli/v2" - f3_types "lab.forgefriends.org/friendlyforgeformat/gof3/config/types" - f3_common "lab.forgefriends.org/friendlyforgeformat/gof3/forges/common" - f3_format "lab.forgefriends.org/friendlyforgeformat/gof3/format" -) - -var CmdF3 = &cli.Command{ - Name: "f3", - Usage: "Friendly Forge Format (F3) format export/import.", - Description: "Import or export a repository from or to the Friendly Forge Format (F3) format.", - Action: runF3, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "directory", - Value: "./f3", - Usage: "Path of the directory where the F3 dump is stored", - }, - &cli.StringFlag{ - Name: "user", - Value: "", - Usage: "The name of the user who owns the repository", - }, - &cli.StringFlag{ - Name: "repository", - Value: "", - Usage: "The name of the repository", - }, - &cli.StringFlag{ - Name: "authentication-source", - Value: "", - Usage: "The name of the authentication source matching the forge of origin", - }, - &cli.BoolFlag{ - Name: "no-pull-request", - Usage: "Do not dump pull requests", - }, - &cli.BoolFlag{ - Name: "import", - Usage: "Import from the directory", - }, - &cli.BoolFlag{ - Name: "export", - Usage: "Export to the directory", - }, - }, -} - -func runF3(ctx *cli.Context) error { - stdCtx, cancel := installSignals() - defer cancel() - - if err := initDB(stdCtx); err != nil { - return err - } - - if err := git.InitSimple(stdCtx); err != nil { - return err - } - - return RunF3(stdCtx, ctx) -} - -func getAuthenticationSource(ctx context.Context, authenticationSource string) (*auth_model.Source, error) { - source, err := auth_model.GetSourceByName(ctx, authenticationSource) - if err != nil { - if auth_model.IsErrSourceNotExist(err) { - return nil, nil - } - return nil, err - } - return source, nil -} - -func RunF3(stdCtx context.Context, ctx *cli.Context) error { - doer, err := user_model.GetAdminUser(stdCtx) - if err != nil { - return err - } - - features := f3_types.AllFeatures - if ctx.Bool("no-pull-request") { - features.PullRequests = false - } - - var sourceID int64 - sourceName := ctx.String("authentication-source") - source, err := getAuthenticationSource(stdCtx, sourceName) - if err != nil { - return fmt.Errorf("error retrieving the authentication-source %s %v", sourceName, err) - } - if source != nil { - sourceID = source.ID - } - - forgejo := util.ForgejoForgeRoot(features, doer, sourceID) - f3 := util.F3ForgeRoot(features, ctx.String("directory")) - - if ctx.Bool("export") { - forgejo.Forge.Users.List(stdCtx) - user := forgejo.Forge.Users.GetFromFormat(stdCtx, &f3_format.User{UserName: ctx.String("user")}) - if user.IsNil() { - return fmt.Errorf("%s is not a known user", ctx.String("user")) - } - - user.Projects.List(stdCtx) - project := user.Projects.GetFromFormat(stdCtx, &f3_format.Project{Name: ctx.String("repository")}) - if project.IsNil() { - return fmt.Errorf("%s/%s is not a known repository", ctx.String("user"), ctx.String("repository")) - } - - options := f3_common.NewMirrorOptionsRecurse(user, project) - f3.Forge.Mirror(stdCtx, forgejo.Forge, options) - fmt.Println("exported") - } else if ctx.Bool("import") { - options := f3_common.NewMirrorOptionsRecurse() - forgejo.Forge.Mirror(stdCtx, f3.Forge, options) - fmt.Println("imported") - } else { - return fmt.Errorf("either --import or --export must be specified") - } - - return nil -} diff --git a/cmd/forgejo/actions.go b/cmd/forgejo/actions.go index 4949dfcba5..5227e8ab37 100644 --- a/cmd/forgejo/actions.go +++ b/cmd/forgejo/actions.go @@ -132,8 +132,8 @@ func validateSecret(secret string) error { } func RunRegister(ctx context.Context, cliCtx *cli.Context) error { + var cancel context.CancelFunc if !ContextGetNoInit(ctx) { - var cancel context.CancelFunc ctx, cancel = installSignals(ctx) defer cancel() diff --git a/cmd/forgejo/f3.go b/cmd/forgejo/f3.go new file mode 100644 index 0000000000..cbe1a1590c --- /dev/null +++ b/cmd/forgejo/f3.go @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT + +package forgejo + +import ( + "context" + "fmt" + + auth_model "code.gitea.io/gitea/models/auth" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/services/f3/util" + + "github.com/urfave/cli/v2" + f3_types "lab.forgefriends.org/friendlyforgeformat/gof3/config/types" + f3_common "lab.forgefriends.org/friendlyforgeformat/gof3/forges/common" + f3_format "lab.forgefriends.org/friendlyforgeformat/gof3/format" +) + +func CmdF3(ctx context.Context) *cli.Command { + return &cli.Command{ + Name: "f3", + Usage: "Friendly Forge Format (F3) format export/import.", + Description: "Import or export a repository from or to the Friendly Forge Format (F3) format.", + Action: prepareWorkPathAndCustomConf(ctx, func(cliCtx *cli.Context) error { return RunF3(ctx, cliCtx) }), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "directory", + Value: "./f3", + Usage: "Path of the directory where the F3 dump is stored", + }, + &cli.StringFlag{ + Name: "user", + Value: "", + Usage: "The name of the user who owns the repository", + }, + &cli.StringFlag{ + Name: "repository", + Value: "", + Usage: "The name of the repository", + }, + &cli.StringFlag{ + Name: "authentication-source", + Value: "", + Usage: "The name of the authentication source matching the forge of origin", + }, + &cli.BoolFlag{ + Name: "no-pull-request", + Usage: "Do not dump pull requests", + }, + &cli.BoolFlag{ + Name: "import", + Usage: "Import from the directory", + }, + &cli.BoolFlag{ + Name: "export", + Usage: "Export to the directory", + }, + }, + } +} + +func getAuthenticationSource(ctx context.Context, authenticationSource string) (*auth_model.Source, error) { + source, err := auth_model.GetSourceByName(ctx, authenticationSource) + if err != nil { + if auth_model.IsErrSourceNotExist(err) { + return nil, nil + } + return nil, err + } + return source, nil +} + +func RunF3(ctx context.Context, cliCtx *cli.Context) error { + var cancel context.CancelFunc + if !ContextGetNoInit(ctx) { + ctx, cancel = installSignals(ctx) + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + + if err := git.InitSimple(ctx); err != nil { + return err + } + } + + doer, err := user_model.GetAdminUser(ctx) + if err != nil { + return err + } + + features := f3_types.AllFeatures + if cliCtx.Bool("no-pull-request") { + features.PullRequests = false + } + + var sourceID int64 + sourceName := cliCtx.String("authentication-source") + source, err := getAuthenticationSource(ctx, sourceName) + if err != nil { + return fmt.Errorf("error retrieving the authentication-source %s %v", sourceName, err) + } + if source != nil { + sourceID = source.ID + } + + forgejo := util.ForgejoForgeRoot(features, doer, sourceID) + f3 := util.F3ForgeRoot(features, cliCtx.String("directory")) + + if cliCtx.Bool("export") { + forgejo.Forge.Users.List(ctx) + user := forgejo.Forge.Users.GetFromFormat(ctx, &f3_format.User{UserName: cliCtx.String("user")}) + if user.IsNil() { + return fmt.Errorf("%s is not a known user", cliCtx.String("user")) + } + + user.Projects.List(ctx) + project := user.Projects.GetFromFormat(ctx, &f3_format.Project{Name: cliCtx.String("repository")}) + if project.IsNil() { + return fmt.Errorf("%s/%s is not a known repository", cliCtx.String("user"), cliCtx.String("repository")) + } + + options := f3_common.NewMirrorOptionsRecurse(user, project) + f3.Forge.Mirror(ctx, forgejo.Forge, options) + fmt.Fprintln(ContextGetStdout(ctx), "exported") + } else if cliCtx.Bool("import") { + options := f3_common.NewMirrorOptionsRecurse() + forgejo.Forge.Mirror(ctx, f3.Forge, options) + fmt.Fprintln(ContextGetStdout(ctx), "imported") + } else { + return fmt.Errorf("either --import or --export must be specified") + } + + return nil +} diff --git a/cmd/forgejo/forgejo.go b/cmd/forgejo/forgejo.go index affb39157a..bf6da2282b 100644 --- a/cmd/forgejo/forgejo.go +++ b/cmd/forgejo/forgejo.go @@ -36,6 +36,7 @@ func CmdForgejo(ctx context.Context) *cli.Command { Flags: []cli.Flag{}, Subcommands: []*cli.Command{ CmdActions(ctx), + CmdF3(ctx), }, } } diff --git a/cmd/main.go b/cmd/main.go index 46fb933212..2a49cafe3a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -200,7 +200,6 @@ func newMainApp(subCmds ...*cli.Command) *cli.App { CmdMigrate, CmdKeys, CmdDoctor, - CmdF3, CmdManager, CmdEmbedded, CmdMigrateStorage, diff --git a/tests/integration/cmd_f3_test.go b/tests/integration/cmd_forgejo_f3_test.go similarity index 51% rename from tests/integration/cmd_f3_test.go rename to tests/integration/cmd_forgejo_f3_test.go index 82bbe4febe..bfc0572582 100644 --- a/tests/integration/cmd_f3_test.go +++ b/tests/integration/cmd_forgejo_f3_test.go @@ -3,38 +3,28 @@ package integration import ( - "bytes" "context" - "io" "net/url" - "os" "testing" - "code.gitea.io/gitea/cmd" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/services/migrations" "github.com/stretchr/testify/assert" - "github.com/urfave/cli/v2" f3_forges "lab.forgefriends.org/friendlyforgeformat/gof3/forges" f3_util "lab.forgefriends.org/friendlyforgeformat/gof3/util" ) func Test_CmdF3(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { - AllowLocalNetworks := setting.Migrations.AllowLocalNetworks - setting.F3.Enabled = true - setting.Migrations.AllowLocalNetworks = true + defer test.MockVariable(&setting.F3.Enabled, true)() + defer test.MockVariable(&setting.Migrations.AllowLocalNetworks, true)() + // Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string. + defer test.MockVariable(&setting.AppVer, "1.16.0") // without migrations.Init() AllowLocalNetworks = true is not effective and // a http call fails with "...migration can only call allowed HTTP servers..." migrations.Init() - AppVer := setting.AppVer - // Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string. - setting.AppVer = "1.16.0" - defer func() { - setting.Migrations.AllowLocalNetworks = AllowLocalNetworks - setting.AppVer = AppVer - }() // // Step 1: create a fixture @@ -54,24 +44,10 @@ func Test_CmdF3(t *testing.T) { // // Step 2: import the fixture into Gitea // - cmd.CmdF3.Action = func(ctx *cli.Context) error { return cmd.RunF3(context.Background(), ctx) } { - realStdout := os.Stdout // Backup Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - app := cli.NewApp() - app.Writer = w - app.ErrWriter = w - app.Commands = []*cli.Command{cmd.CmdF3} - assert.NoError(t, app.Run([]string{"forgejo", "f3", "--import", "--directory", fixture.ForgeRoot.GetDirectory()})) - - w.Close() - var buf bytes.Buffer - io.Copy(&buf, r) - commandOutput := buf.String() - assert.EqualValues(t, "imported\n", commandOutput) - os.Stdout = realStdout + output, err := cmdForgejoCaptureOutput(t, []string{"forgejo", "forgejo-cli", "f3", "--import", "--directory", fixture.ForgeRoot.GetDirectory()}) + assert.NoError(t, err) + assert.EqualValues(t, "imported\n", output) } // @@ -79,23 +55,9 @@ func Test_CmdF3(t *testing.T) { // directory := t.TempDir() { - realStdout := os.Stdout // Backup Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - app := cli.NewApp() - app.Writer = w - app.ErrWriter = w - app.Commands = []*cli.Command{cmd.CmdF3} - assert.NoError(t, app.Run([]string{"forgejo", "f3", "--export", "--no-pull-request", "--user", fixture.UserFormat.UserName, "--repository", fixture.ProjectFormat.Name, "--directory", directory})) - - w.Close() - var buf bytes.Buffer - io.Copy(&buf, r) - commandOutput := buf.String() - assert.EqualValues(t, "exported\n", commandOutput) - os.Stdout = realStdout - + output, err := cmdForgejoCaptureOutput(t, []string{"forgejo", "forgejo-cli", "f3", "--export", "--no-pull-request", "--user", fixture.UserFormat.UserName, "--repository", fixture.ProjectFormat.Name, "--directory", directory}) + assert.NoError(t, err) + assert.EqualValues(t, "exported\n", output) } //