mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-06-07 23:27:41 +00:00
chore(upgrade): urfave/cli from v2 to v3 (#8035)
Some checks failed
/ release (push) Waiting to run
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
Integration tests for the release process / release-simulation (push) Has been cancelled
Some checks failed
/ release (push) Waiting to run
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
Integration tests for the release process / release-simulation (push) Has been cancelled
urfave/cli v2 will eventually become unmaintained, switch over to v3 which is the latest supported version. Note: the `docs` command would be a lot of work to restore with v3 ([the package is still in alpha](https://github.com/urfave/cli-docs)) An alternative to avoid a breaking change would be to not upgrade from v2 to v3 for that reason alone. Note: these commits were cherry-picked from https://code.forgejo.org/forgefriends/forgefriends Note: it is best reviewed side by side with no display of whitespace changes (there are a lot of those when converting vars to func). - a few functional changes were necessary and are noted in context in the file changes tab - https://cli.urfave.org/migrate-v2-to-v3/ upgrade instructions were followed in the most minimal way possible - upgrade gof3 to v3.10.8 which includes and upgrade from urfave/cli v2 to urfave/cli v3 - upgrade gitlab.com/gitlab-org/api/client-go v0.129.0 because it is an indirect dependency of gof3 and requires a change because of a deprecated field that otherwise triggers a lint error but nothing else otherwise - verified that the [script](https://codeberg.org/forgejo/docs/src/branch/next/scripts/cli-docs.sh) that generates the [CLI documentation](https://codeberg.org/forgejo/docs/src/branch/next/scripts/cli-docs.sh) still works. There are cosmetic differences and the **help** subcommand is no longer advertised (although it is still supported) but the `--help` option is advertised as expected so it is fine. - end-to-end tests [passed](https://code.forgejo.org/forgejo/end-to-end/pulls/667) (they use the Forgejo CLI to some extent) ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests - I added test coverage for Go changes... - [ ] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] I do not want this change to show in the release notes. - [ ] I want the title to show in the release notes with a link to this pull request. - [x] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title. <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Breaking features - [PR](https://codeberg.org/forgejo/forgejo/pulls/8035): <!--number 8035 --><!--line 0 --><!--description VGhlIGBmb3JnZWpvIGRvY3NgIGNvbW1hbmQgaXMgZGVwcmVjYXRlZCBhbmQgQ0xJIGVycm9ycyBhcmUgbm93IGRpc3BsYXllZCBvbiBzdGRlcnIgaW5zdGVhZCBvZiBzdGRvdXQuIFRoZXNlIGJyZWFraW5nIGNoYW5nZXMgaGFwcGVuZWQgYmVjYXVzZSB0aGUgcGFja2FnZSB1c2VkIHRvIHBhcnNlIHRoZSBjb21tYW5kIGxpbmUgYXJndW1lbnRzIHdhcyBbdXBncmFkZWQgZnJvbSB2MiB0byB2M10oaHR0cHM6Ly9jbGkudXJmYXZlLm9yZy9taWdyYXRlLXYyLXRvLXYzLykuIEEgW3NlcGFyYXRlIHByb2plY3Qgd2FzIGluaXRpYXRlZF0oaHR0cHM6Ly9naXRodWIuY29tL3VyZmF2ZS9jbGktZG9jcykgdG8gcmUtaW1wbGVtZW50IHRoZSBgZG9jc2AgY29tbWFuZCwgYnV0IGl0IGlzIG5vdCB5ZXQgcHJvZHVjdGlvbiByZWFkeS4=-->The `forgejo docs` command is deprecated and CLI errors are now displayed on stderr instead of stdout. These breaking changes happened because the package used to parse the command line arguments was [upgraded from v2 to v3](https://cli.urfave.org/migrate-v2-to-v3/). A [separate project was initiated](https://github.com/urfave/cli-docs) to re-implement the `docs` command, but it is not yet production ready.<!--description--> <!--end release-notes-assistant--> Co-authored-by: limiting-factor <limiting-factor@posteo.com> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8035 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
parent
dec17ba704
commit
55d8910255
53 changed files with 1219 additions and 1119 deletions
2
Makefile
2
Makefile
|
@ -557,7 +557,7 @@ test-check:
|
||||||
|
|
||||||
.PHONY: test\#%
|
.PHONY: test\#%
|
||||||
test\#%:
|
test\#%:
|
||||||
@echo "Running go test with -tags '$(TEST_TAGS)'..."
|
@echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
|
||||||
@$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
|
@$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
|
|
5
assets/go-licenses.json
generated
5
assets/go-licenses.json
generated
|
@ -934,6 +934,11 @@
|
||||||
"path": "github.com/urfave/cli/v2/LICENSE",
|
"path": "github.com/urfave/cli/v2/LICENSE",
|
||||||
"licenseText": "MIT License\n\nCopyright (c) 2022 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
|
"licenseText": "MIT License\n\nCopyright (c) 2022 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "github.com/urfave/cli/v3",
|
||||||
|
"path": "github.com/urfave/cli/v3/LICENSE",
|
||||||
|
"licenseText": "MIT License\n\nCopyright (c) 2023 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "github.com/valyala/fastjson",
|
"name": "github.com/valyala/fastjson",
|
||||||
"path": "github.com/valyala/fastjson/LICENSE",
|
"path": "github.com/valyala/fastjson/LICENSE",
|
||||||
|
|
|
@ -4,25 +4,28 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// CmdActions represents the available actions sub-commands.
|
||||||
// CmdActions represents the available actions sub-commands.
|
func cmdActions() *cli.Command {
|
||||||
CmdActions = &cli.Command{
|
return &cli.Command{
|
||||||
Name: "actions",
|
Name: "actions",
|
||||||
Usage: "Manage Forgejo Actions",
|
Usage: "Manage Forgejo Actions",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdActionsGenRunnerToken,
|
subcmdActionsGenRunnerToken(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdActionsGenRunnerToken = &cli.Command{
|
func subcmdActionsGenRunnerToken() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "generate-runner-token",
|
Name: "generate-runner-token",
|
||||||
Usage: "Generate a new token for a runner to use to register with the server",
|
Usage: "Generate a new token for a runner to use to register with the server",
|
||||||
Action: runGenerateActionsRunnerToken,
|
Action: runGenerateActionsRunnerToken,
|
||||||
|
@ -36,10 +39,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runGenerateActionsRunnerToken(c *cli.Context) error {
|
func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
70
cmd/admin.go
70
cmd/admin.go
|
@ -15,56 +15,64 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
repo_module "forgejo.org/modules/repository"
|
repo_module "forgejo.org/modules/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// CmdAdmin represents the available admin sub-command.
|
||||||
// CmdAdmin represents the available admin sub-command.
|
func cmdAdmin() *cli.Command {
|
||||||
CmdAdmin = &cli.Command{
|
return &cli.Command{
|
||||||
Name: "admin",
|
Name: "admin",
|
||||||
Usage: "Perform common administrative operations",
|
Usage: "Perform common administrative operations",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdUser,
|
subcmdUser(),
|
||||||
subcmdRepoSyncReleases,
|
subcmdRepoSyncReleases(),
|
||||||
subcmdRegenerate,
|
subcmdRegenerate(),
|
||||||
subcmdAuth,
|
subcmdAuth(),
|
||||||
subcmdSendMail,
|
subcmdSendMail(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdRepoSyncReleases = &cli.Command{
|
func subcmdRepoSyncReleases() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "repo-sync-releases",
|
Name: "repo-sync-releases",
|
||||||
Usage: "Synchronize repository releases with tags",
|
Usage: "Synchronize repository releases with tags",
|
||||||
Action: runRepoSyncReleases,
|
Action: runRepoSyncReleases,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdRegenerate = &cli.Command{
|
func subcmdRegenerate() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "regenerate",
|
Name: "regenerate",
|
||||||
Usage: "Regenerate specific files",
|
Usage: "Regenerate specific files",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
microcmdRegenHooks,
|
microcmdRegenHooks,
|
||||||
microcmdRegenKeys,
|
microcmdRegenKeys,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdAuth = &cli.Command{
|
func subcmdAuth() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "auth",
|
Name: "auth",
|
||||||
Usage: "Modify external auth providers",
|
Usage: "Modify external auth providers",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
microcmdAuthAddOauth,
|
microcmdAuthAddOauth(),
|
||||||
microcmdAuthUpdateOauth,
|
microcmdAuthUpdateOauth(),
|
||||||
microcmdAuthAddLdapBindDn,
|
microcmdAuthAddLdapBindDn(),
|
||||||
microcmdAuthUpdateLdapBindDn,
|
microcmdAuthUpdateLdapBindDn(),
|
||||||
microcmdAuthAddLdapSimpleAuth,
|
microcmdAuthAddLdapSimpleAuth(),
|
||||||
microcmdAuthUpdateLdapSimpleAuth,
|
microcmdAuthUpdateLdapSimpleAuth(),
|
||||||
microcmdAuthAddSMTP,
|
microcmdAuthAddSMTP(),
|
||||||
microcmdAuthUpdateSMTP,
|
microcmdAuthUpdateSMTP(),
|
||||||
microcmdAuthList,
|
microcmdAuthList(),
|
||||||
microcmdAuthDelete,
|
microcmdAuthDelete(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdSendMail = &cli.Command{
|
func subcmdSendMail() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "sendmail",
|
Name: "sendmail",
|
||||||
Usage: "Send a message to all users",
|
Usage: "Send a message to all users",
|
||||||
Action: runSendMail,
|
Action: runSendMail,
|
||||||
|
@ -86,15 +94,17 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
idFlag = &cli.Int64Flag{
|
func idFlag() *cli.Int64Flag {
|
||||||
|
return &cli.Int64Flag{
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Usage: "ID of authentication source",
|
Usage: "ID of authentication source",
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runRepoSyncReleases(_ *cli.Context) error {
|
func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -13,17 +14,20 @@ import (
|
||||||
"forgejo.org/models/db"
|
"forgejo.org/models/db"
|
||||||
auth_service "forgejo.org/services/auth"
|
auth_service "forgejo.org/services/auth"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func microcmdAuthDelete() *cli.Command {
|
||||||
microcmdAuthDelete = &cli.Command{
|
return &cli.Command{
|
||||||
Name: "delete",
|
Name: "delete",
|
||||||
Usage: "Delete specific auth source",
|
Usage: "Delete specific auth source",
|
||||||
Flags: []cli.Flag{idFlag},
|
Flags: []cli.Flag{idFlag()},
|
||||||
Action: runDeleteAuth,
|
Action: runDeleteAuth,
|
||||||
}
|
}
|
||||||
microcmdAuthList = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func microcmdAuthList() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List auth sources",
|
Usage: "List auth sources",
|
||||||
Action: runListAuth,
|
Action: runListAuth,
|
||||||
|
@ -54,10 +58,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runListAuth(c *cli.Context) error {
|
func runListAuth(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -90,12 +94,12 @@ func runListAuth(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDeleteAuth(c *cli.Context) error {
|
func runDeleteAuth(ctx context.Context, c *cli.Command) error {
|
||||||
if !c.IsSet("id") {
|
if !c.IsSet("id") {
|
||||||
return errors.New("--id flag is missing")
|
return errors.New("--id flag is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"forgejo.org/models/auth"
|
"forgejo.org/models/auth"
|
||||||
"forgejo.org/services/auth/source/ldap"
|
"forgejo.org/services/auth/source/ldap"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -23,8 +23,8 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func commonLdapCLIFlags() []cli.Flag {
|
||||||
commonLdapCLIFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Usage: "Authentication name.",
|
Usage: "Authentication name.",
|
||||||
|
@ -102,8 +102,10 @@ var (
|
||||||
Usage: "The attribute of the user’s LDAP record containing the user’s avatar.",
|
Usage: "The attribute of the user’s LDAP record containing the user’s avatar.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ldapBindDnCLIFlags = append(commonLdapCLIFlags,
|
func ldapBindDnCLIFlags() []cli.Flag {
|
||||||
|
return append(commonLdapCLIFlags(),
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "bind-dn",
|
Name: "bind-dn",
|
||||||
Usage: "The DN to bind to the LDAP server with when searching for the user.",
|
Usage: "The DN to bind to the LDAP server with when searching for the user.",
|
||||||
|
@ -128,49 +130,59 @@ var (
|
||||||
Name: "page-size",
|
Name: "page-size",
|
||||||
Usage: "Search page size.",
|
Usage: "Search page size.",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
|
func ldapSimpleAuthCLIFlags() []cli.Flag {
|
||||||
|
return append(commonLdapCLIFlags(),
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "user-dn",
|
Name: "user-dn",
|
||||||
Usage: "The user's DN.",
|
Usage: "The user's DN.",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddLdapBindDn = &cli.Command{
|
func microcmdAuthAddLdapBindDn() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "add-ldap",
|
Name: "add-ldap",
|
||||||
Usage: "Add new LDAP (via Bind DN) authentication source",
|
Usage: "Add new LDAP (via Bind DN) authentication source",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().addLdapBindDn(c)
|
return newAuthService().addLdapBindDn(ctx, cli)
|
||||||
},
|
},
|
||||||
Flags: ldapBindDnCLIFlags,
|
Flags: ldapBindDnCLIFlags(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateLdapBindDn = &cli.Command{
|
func microcmdAuthUpdateLdapBindDn() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "update-ldap",
|
Name: "update-ldap",
|
||||||
Usage: "Update existing LDAP (via Bind DN) authentication source",
|
Usage: "Update existing LDAP (via Bind DN) authentication source",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().updateLdapBindDn(c)
|
return newAuthService().updateLdapBindDn(ctx, cli)
|
||||||
},
|
},
|
||||||
Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...),
|
Flags: append([]cli.Flag{idFlag()}, ldapBindDnCLIFlags()...),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddLdapSimpleAuth = &cli.Command{
|
func microcmdAuthAddLdapSimpleAuth() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "add-ldap-simple",
|
Name: "add-ldap-simple",
|
||||||
Usage: "Add new LDAP (simple auth) authentication source",
|
Usage: "Add new LDAP (simple auth) authentication source",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().addLdapSimpleAuth(c)
|
return newAuthService().addLdapSimpleAuth(ctx, cli)
|
||||||
},
|
},
|
||||||
Flags: ldapSimpleAuthCLIFlags,
|
Flags: ldapSimpleAuthCLIFlags(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateLdapSimpleAuth = &cli.Command{
|
func microcmdAuthUpdateLdapSimpleAuth() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "update-ldap-simple",
|
Name: "update-ldap-simple",
|
||||||
Usage: "Update existing LDAP (simple auth) authentication source",
|
Usage: "Update existing LDAP (simple auth) authentication source",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().updateLdapSimpleAuth(c)
|
return newAuthService().updateLdapSimpleAuth(ctx, cli)
|
||||||
},
|
},
|
||||||
Flags: append([]cli.Flag{idFlag}, ldapSimpleAuthCLIFlags...),
|
Flags: append([]cli.Flag{idFlag()}, ldapSimpleAuthCLIFlags()...),
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
// newAuthService creates a service with default functions.
|
// newAuthService creates a service with default functions.
|
||||||
func newAuthService() *authService {
|
func newAuthService() *authService {
|
||||||
|
@ -183,7 +195,7 @@ func newAuthService() *authService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseAuthSource assigns values on authSource according to command line flags.
|
// parseAuthSource assigns values on authSource according to command line flags.
|
||||||
func parseAuthSource(c *cli.Context, authSource *auth.Source) {
|
func parseAuthSource(c *cli.Command, authSource *auth.Source) {
|
||||||
if c.IsSet("name") {
|
if c.IsSet("name") {
|
||||||
authSource.Name = c.String("name")
|
authSource.Name = c.String("name")
|
||||||
}
|
}
|
||||||
|
@ -202,7 +214,7 @@ func parseAuthSource(c *cli.Context, authSource *auth.Source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseLdapConfig assigns values on config according to command line flags.
|
// parseLdapConfig assigns values on config according to command line flags.
|
||||||
func parseLdapConfig(c *cli.Context, config *ldap.Source) error {
|
func parseLdapConfig(c *cli.Command, config *ldap.Source) error {
|
||||||
if c.IsSet("name") {
|
if c.IsSet("name") {
|
||||||
config.Name = c.String("name")
|
config.Name = c.String("name")
|
||||||
}
|
}
|
||||||
|
@ -289,7 +301,7 @@ func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) {
|
||||||
|
|
||||||
// getAuthSource gets the login source by its id defined in the command line flags.
|
// getAuthSource gets the login source by its id defined in the command line flags.
|
||||||
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
|
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
|
||||||
func (a *authService) getAuthSource(ctx context.Context, c *cli.Context, authType auth.Type) (*auth.Source, error) {
|
func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authType auth.Type) (*auth.Source, error) {
|
||||||
if err := argsSet(c, "id"); err != nil {
|
if err := argsSet(c, "id"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -307,12 +319,12 @@ func (a *authService) getAuthSource(ctx context.Context, c *cli.Context, authTyp
|
||||||
}
|
}
|
||||||
|
|
||||||
// addLdapBindDn adds a new LDAP via Bind DN authentication source.
|
// addLdapBindDn adds a new LDAP via Bind DN authentication source.
|
||||||
func (a *authService) addLdapBindDn(c *cli.Context) error {
|
func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error {
|
||||||
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil {
|
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -336,8 +348,8 @@ func (a *authService) addLdapBindDn(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateLdapBindDn updates a new LDAP via Bind DN authentication source.
|
// updateLdapBindDn updates a new LDAP via Bind DN authentication source.
|
||||||
func (a *authService) updateLdapBindDn(c *cli.Context) error {
|
func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -358,12 +370,12 @@ func (a *authService) updateLdapBindDn(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
|
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
|
||||||
func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
|
func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) error {
|
||||||
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-dn", "user-filter", "email-attribute"); err != nil {
|
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-dn", "user-filter", "email-attribute"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -387,8 +399,8 @@ func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source.
|
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source.
|
||||||
func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
|
func (a *authService) updateLdapSimpleAuth(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAddLdapBindDn(t *testing.T) {
|
func TestAddLdapBindDn(t *testing.T) {
|
||||||
|
@ -225,12 +225,12 @@ func TestAddLdapBindDn(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthAddLdapBindDn.Flags
|
app.Flags = microcmdAuthAddLdapBindDn().Flags
|
||||||
app.Action = service.addLdapBindDn
|
app.Action = service.addLdapBindDn
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
|
@ -454,12 +454,12 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
|
app.Flags = microcmdAuthAddLdapSimpleAuth().Flags
|
||||||
app.Action = service.addLdapSimpleAuth
|
app.Action = service.addLdapSimpleAuth
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
|
@ -915,12 +915,12 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthUpdateLdapBindDn.Flags
|
app.Flags = microcmdAuthUpdateLdapBindDn().Flags
|
||||||
app.Action = service.updateLdapBindDn
|
app.Action = service.updateLdapBindDn
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1303,12 +1303,12 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
|
app.Flags = microcmdAuthUpdateLdapSimpleAuth().Flags
|
||||||
app.Action = service.updateLdapSimpleAuth
|
app.Action = service.updateLdapSimpleAuth
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -11,11 +12,11 @@ import (
|
||||||
auth_model "forgejo.org/models/auth"
|
auth_model "forgejo.org/models/auth"
|
||||||
"forgejo.org/services/auth/source/oauth2"
|
"forgejo.org/services/auth/source/oauth2"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func oauthCLIFlags() []cli.Flag {
|
||||||
oauthCLIFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Value: "",
|
Value: "",
|
||||||
|
@ -120,23 +121,27 @@ var (
|
||||||
Usage: "Activate automatic team membership removal depending on groups",
|
Usage: "Activate automatic team membership removal depending on groups",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddOauth = &cli.Command{
|
func microcmdAuthAddOauth() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "add-oauth",
|
Name: "add-oauth",
|
||||||
Usage: "Add new Oauth authentication source",
|
Usage: "Add new Oauth authentication source",
|
||||||
Action: runAddOauth,
|
Action: runAddOauth,
|
||||||
Flags: oauthCLIFlags,
|
Flags: oauthCLIFlags(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateOauth = &cli.Command{
|
func microcmdAuthUpdateOauth() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "update-oauth",
|
Name: "update-oauth",
|
||||||
Usage: "Update existing Oauth authentication source",
|
Usage: "Update existing Oauth authentication source",
|
||||||
Action: runUpdateOauth,
|
Action: runUpdateOauth,
|
||||||
Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
|
Flags: append(oauthCLIFlags()[:1], append([]cli.Flag{idFlag()}, oauthCLIFlags()[1:]...)...),
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
func parseOAuth2Config(_ context.Context, c *cli.Command) *oauth2.Source {
|
||||||
var customURLMapping *oauth2.CustomURLMapping
|
var customURLMapping *oauth2.CustomURLMapping
|
||||||
if c.IsSet("use-custom-urls") {
|
if c.IsSet("use-custom-urls") {
|
||||||
customURLMapping = &oauth2.CustomURLMapping{
|
customURLMapping = &oauth2.CustomURLMapping{
|
||||||
|
@ -168,15 +173,15 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddOauth(c *cli.Context) error {
|
func runAddOauth(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := parseOAuth2Config(c)
|
config := parseOAuth2Config(ctx, c)
|
||||||
if config.Provider == "openidConnect" {
|
if config.Provider == "openidConnect" {
|
||||||
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
||||||
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
||||||
|
@ -192,12 +197,12 @@ func runAddOauth(c *cli.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUpdateOauth(c *cli.Context) error {
|
func runUpdateOauth(ctx context.Context, c *cli.Command) error {
|
||||||
if !c.IsSet("id") {
|
if !c.IsSet("id") {
|
||||||
return errors.New("--id flag is missing")
|
return errors.New("--id flag is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -11,11 +12,11 @@ import (
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/modules/util"
|
||||||
"forgejo.org/services/auth/source/smtp"
|
"forgejo.org/services/auth/source/smtp"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func smtpCLIFlags() []cli.Flag {
|
||||||
smtpCLIFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Value: "",
|
Value: "",
|
||||||
|
@ -71,23 +72,27 @@ var (
|
||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddSMTP = &cli.Command{
|
func microcmdAuthAddSMTP() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "add-smtp",
|
Name: "add-smtp",
|
||||||
Usage: "Add new SMTP authentication source",
|
Usage: "Add new SMTP authentication source",
|
||||||
Action: runAddSMTP,
|
Action: runAddSMTP,
|
||||||
Flags: smtpCLIFlags,
|
Flags: smtpCLIFlags(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateSMTP = &cli.Command{
|
func microcmdAuthUpdateSMTP() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "update-smtp",
|
Name: "update-smtp",
|
||||||
Usage: "Update existing SMTP authentication source",
|
Usage: "Update existing SMTP authentication source",
|
||||||
Action: runUpdateSMTP,
|
Action: runUpdateSMTP,
|
||||||
Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...),
|
Flags: append(smtpCLIFlags()[:1], append([]cli.Flag{idFlag()}, smtpCLIFlags()[1:]...)...),
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
func parseSMTPConfig(c *cli.Command, conf *smtp.Source) error {
|
||||||
if c.IsSet("auth-type") {
|
if c.IsSet("auth-type") {
|
||||||
conf.Auth = c.String("auth-type")
|
conf.Auth = c.String("auth-type")
|
||||||
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
|
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
|
||||||
|
@ -123,8 +128,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddSMTP(c *cli.Context) error {
|
func runAddSMTP(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -163,12 +168,12 @@ func runAddSMTP(c *cli.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUpdateSMTP(c *cli.Context) error {
|
func runUpdateSMTP(ctx context.Context, c *cli.Command) error {
|
||||||
if !c.IsSet("id") {
|
if !c.IsSet("id") {
|
||||||
return errors.New("--id flag is missing")
|
return errors.New("--id flag is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
asymkey_model "forgejo.org/models/asymkey"
|
asymkey_model "forgejo.org/models/asymkey"
|
||||||
"forgejo.org/modules/graceful"
|
"forgejo.org/modules/graceful"
|
||||||
repo_service "forgejo.org/services/repository"
|
repo_service "forgejo.org/services/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -25,8 +27,8 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runRegenerateHooks(_ *cli.Context) error {
|
func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -35,8 +37,8 @@ func runRegenerateHooks(_ *cli.Context) error {
|
||||||
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRegenerateKeys(_ *cli.Context) error {
|
func runRegenerateKeys(ctx context.Context, _ *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,18 +4,20 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var subcmdUser = &cli.Command{
|
func subcmdUser() *cli.Command {
|
||||||
Name: "user",
|
return &cli.Command{
|
||||||
Usage: "Modify users",
|
Name: "user",
|
||||||
Subcommands: []*cli.Command{
|
Usage: "Modify users",
|
||||||
microcmdUserCreate,
|
Commands: []*cli.Command{
|
||||||
microcmdUserList,
|
microcmdUserCreate(),
|
||||||
microcmdUserChangePassword,
|
microcmdUserList(),
|
||||||
microcmdUserDelete,
|
microcmdUserChangePassword(),
|
||||||
microcmdUserGenerateAccessToken,
|
microcmdUserDelete(),
|
||||||
microcmdUserMustChangePassword,
|
microcmdUserGenerateAccessToken(),
|
||||||
},
|
microcmdUserMustChangePassword(),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
@ -13,40 +14,42 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
user_service "forgejo.org/services/user"
|
user_service "forgejo.org/services/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserChangePassword = &cli.Command{
|
func microcmdUserChangePassword() *cli.Command {
|
||||||
Name: "change-password",
|
return &cli.Command{
|
||||||
Usage: "Change a user's password",
|
Name: "change-password",
|
||||||
Action: runChangePassword,
|
Usage: "Change a user's password",
|
||||||
Flags: []cli.Flag{
|
Action: runChangePassword,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "username",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"u"},
|
Name: "username",
|
||||||
Value: "",
|
Aliases: []string{"u"},
|
||||||
Usage: "The user to change password for",
|
Value: "",
|
||||||
|
Usage: "The user to change password for",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "New password to set for user",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "must-change-password",
|
||||||
|
Usage: "User must change password",
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "password",
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "New password to set for user",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "must-change-password",
|
|
||||||
Usage: "User must change password",
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runChangePassword(c *cli.Context) error {
|
func runChangePassword(ctx context.Context, c *cli.Command) error {
|
||||||
if err := argsSet(c, "username", "password"); err != nil {
|
if err := argsSet(c, "username", "password"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -15,75 +16,76 @@ import (
|
||||||
"forgejo.org/modules/optional"
|
"forgejo.org/modules/optional"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserCreate = &cli.Command{
|
func microcmdUserCreate() *cli.Command {
|
||||||
Name: "create",
|
return &cli.Command{
|
||||||
Usage: "Create a new user in database",
|
Name: "create",
|
||||||
Action: runCreateUser,
|
Usage: "Create a new user in database",
|
||||||
Flags: []cli.Flag{
|
Action: runCreateUser,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "name",
|
&cli.StringFlag{
|
||||||
Usage: "Username. DEPRECATED: use username instead",
|
Name: "name",
|
||||||
|
Usage: "Username. DEPRECATED: use username instead",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Usage: "Username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "User password",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "email",
|
||||||
|
Usage: "User email address",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "admin",
|
||||||
|
Usage: "User is an admin",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "random-password",
|
||||||
|
Usage: "Generate a random password for the user",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "must-change-password",
|
||||||
|
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "random-password-length",
|
||||||
|
Usage: "Length of the random password to be generated",
|
||||||
|
Value: 12,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "access-token",
|
||||||
|
Usage: "Generate access token for the user",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "access-token-name",
|
||||||
|
Usage: `Name of the generated access token`,
|
||||||
|
Value: "gitea-admin",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "access-token-scopes",
|
||||||
|
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
||||||
|
Value: "all",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "restricted",
|
||||||
|
Usage: "Make a restricted user account",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "fullname",
|
||||||
|
Usage: `The full, human-readable name of the user`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "username",
|
|
||||||
Usage: "Username",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "password",
|
|
||||||
Usage: "User password",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "email",
|
|
||||||
Usage: "User email address",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "admin",
|
|
||||||
Usage: "User is an admin",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "random-password",
|
|
||||||
Usage: "Generate a random password for the user",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "must-change-password",
|
|
||||||
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
|
|
||||||
Value: true,
|
|
||||||
DisableDefaultText: true,
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "random-password-length",
|
|
||||||
Usage: "Length of the random password to be generated",
|
|
||||||
Value: 12,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "access-token",
|
|
||||||
Usage: "Generate access token for the user",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "access-token-name",
|
|
||||||
Usage: `Name of the generated access token`,
|
|
||||||
Value: "gitea-admin",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "access-token-scopes",
|
|
||||||
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
|
||||||
Value: "all",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "restricted",
|
|
||||||
Usage: "Make a restricted user account",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "fullname",
|
|
||||||
Usage: `The full, human-readable name of the user`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCreateUser(c *cli.Context) error {
|
func runCreateUser(ctx context.Context, c *cli.Command) error {
|
||||||
// this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first
|
// this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first
|
||||||
// duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future.
|
// duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future.
|
||||||
setting.LoadSettings()
|
setting.LoadSettings()
|
||||||
|
@ -108,10 +110,10 @@ func runCreateUser(c *cli.Context) error {
|
||||||
username = c.String("username")
|
username = c.String("username")
|
||||||
} else {
|
} else {
|
||||||
username = c.String("name")
|
username = c.String("name")
|
||||||
_, _ = fmt.Fprint(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
_, _ = fmt.Fprint(c.Root().ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -12,41 +13,43 @@ import (
|
||||||
"forgejo.org/modules/storage"
|
"forgejo.org/modules/storage"
|
||||||
user_service "forgejo.org/services/user"
|
user_service "forgejo.org/services/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserDelete = &cli.Command{
|
func microcmdUserDelete() *cli.Command {
|
||||||
Name: "delete",
|
return &cli.Command{
|
||||||
Usage: "Delete specific user by id, name or email",
|
Name: "delete",
|
||||||
Flags: []cli.Flag{
|
Usage: "Delete specific user by id, name or email",
|
||||||
&cli.Int64Flag{
|
Flags: []cli.Flag{
|
||||||
Name: "id",
|
&cli.Int64Flag{
|
||||||
Usage: "ID of user of the user to delete",
|
Name: "id",
|
||||||
|
Usage: "ID of user of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Aliases: []string{"u"},
|
||||||
|
Usage: "Username of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "email",
|
||||||
|
Aliases: []string{"e"},
|
||||||
|
Usage: "Email of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "purge",
|
||||||
|
Usage: "Purge user, all their repositories, organizations and comments",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
Action: runDeleteUser,
|
||||||
Name: "username",
|
}
|
||||||
Aliases: []string{"u"},
|
|
||||||
Usage: "Username of the user to delete",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "email",
|
|
||||||
Aliases: []string{"e"},
|
|
||||||
Usage: "Email of the user to delete",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "purge",
|
|
||||||
Usage: "Purge user, all their repositories, organizations and comments",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: runDeleteUser,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDeleteUser(c *cli.Context) error {
|
func runDeleteUser(ctx context.Context, c *cli.Command) error {
|
||||||
if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") {
|
if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") {
|
||||||
return errors.New("You must provide the id, username or email of a user to delete")
|
return errors.New("You must provide the id, username or email of a user to delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,49 +4,52 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
auth_model "forgejo.org/models/auth"
|
auth_model "forgejo.org/models/auth"
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserGenerateAccessToken = &cli.Command{
|
func microcmdUserGenerateAccessToken() *cli.Command {
|
||||||
Name: "generate-access-token",
|
return &cli.Command{
|
||||||
Usage: "Generate an access token for a specific user",
|
Name: "generate-access-token",
|
||||||
Flags: []cli.Flag{
|
Usage: "Generate an access token for a specific user",
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "username",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"u"},
|
Name: "username",
|
||||||
Usage: "Username",
|
Aliases: []string{"u"},
|
||||||
|
Usage: "Username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "token-name",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "Token name",
|
||||||
|
Value: "gitea-admin",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "raw",
|
||||||
|
Usage: "Display only the token value",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "scopes",
|
||||||
|
Value: "all",
|
||||||
|
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
Action: runGenerateAccessToken,
|
||||||
Name: "token-name",
|
}
|
||||||
Aliases: []string{"t"},
|
|
||||||
Usage: "Token name",
|
|
||||||
Value: "gitea-admin",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "raw",
|
|
||||||
Usage: "Display only the token value",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "scopes",
|
|
||||||
Value: "all",
|
|
||||||
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: runGenerateAccessToken,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateAccessToken(c *cli.Context) error {
|
func runGenerateAccessToken(ctx context.Context, c *cli.Command) error {
|
||||||
if !c.IsSet("username") {
|
if !c.IsSet("username") {
|
||||||
return errors.New("you must provide a username to generate a token for")
|
return errors.New("you must provide a username to generate a token for")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,29 +4,32 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserList = &cli.Command{
|
func microcmdUserList() *cli.Command {
|
||||||
Name: "list",
|
return &cli.Command{
|
||||||
Usage: "List users",
|
Name: "list",
|
||||||
Action: runListUsers,
|
Usage: "List users",
|
||||||
Flags: []cli.Flag{
|
Action: runListUsers,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "admin",
|
&cli.BoolFlag{
|
||||||
Usage: "List only admin users",
|
Name: "admin",
|
||||||
|
Usage: "List only admin users",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runListUsers(c *cli.Context) error {
|
func runListUsers(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,38 +4,41 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserMustChangePassword = &cli.Command{
|
func microcmdUserMustChangePassword() *cli.Command {
|
||||||
Name: "must-change-password",
|
return &cli.Command{
|
||||||
Usage: "Set the must change password flag for the provided users or all users",
|
Name: "must-change-password",
|
||||||
Action: runMustChangePassword,
|
Usage: "Set the must change password flag for the provided users or all users",
|
||||||
Flags: []cli.Flag{
|
Action: runMustChangePassword,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "all",
|
&cli.BoolFlag{
|
||||||
Aliases: []string{"A"},
|
Name: "all",
|
||||||
Usage: "All users must change password, except those explicitly excluded with --exclude",
|
Aliases: []string{"A"},
|
||||||
|
Usage: "All users must change password, except those explicitly excluded with --exclude",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "exclude",
|
||||||
|
Aliases: []string{"e"},
|
||||||
|
Usage: "Do not change the must-change-password flag for these users",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "unset",
|
||||||
|
Usage: "Instead of setting the must-change-password flag, unset it",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
}
|
||||||
Name: "exclude",
|
|
||||||
Aliases: []string{"e"},
|
|
||||||
Usage: "Do not change the must-change-password flag for these users",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "unset",
|
|
||||||
Usage: "Instead of setting the must-change-password flag, unset it",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMustChangePassword(c *cli.Context) error {
|
func runMustChangePassword(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if c.NArg() == 0 && !c.IsSet("all") {
|
if c.NArg() == 0 && !c.IsSet("all") {
|
||||||
|
|
77
cmd/cert.go
77
cmd/cert.go
|
@ -6,6 +6,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
@ -20,47 +21,49 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdCert represents the available cert sub-command.
|
// CmdCert represents the available cert sub-command.
|
||||||
var CmdCert = &cli.Command{
|
func cmdCert() *cli.Command {
|
||||||
Name: "cert",
|
return &cli.Command{
|
||||||
Usage: "Generate self-signed certificate",
|
Name: "cert",
|
||||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
Usage: "Generate self-signed certificate",
|
||||||
|
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||||
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||||
Action: runCert,
|
Action: runCert,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "host",
|
Name: "host",
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
|
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "ecdsa-curve",
|
||||||
|
Value: "",
|
||||||
|
Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "rsa-bits",
|
||||||
|
Value: 3072,
|
||||||
|
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "start-date",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Creation date formatted as Jan 1 15:04:05 2011",
|
||||||
|
},
|
||||||
|
&cli.DurationFlag{
|
||||||
|
Name: "duration",
|
||||||
|
Value: 365 * 24 * time.Hour,
|
||||||
|
Usage: "Duration that certificate is valid for",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "ca",
|
||||||
|
Usage: "whether this cert should be its own Certificate Authority",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "ecdsa-curve",
|
|
||||||
Value: "",
|
|
||||||
Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "rsa-bits",
|
|
||||||
Value: 3072,
|
|
||||||
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "start-date",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Creation date formatted as Jan 1 15:04:05 2011",
|
|
||||||
},
|
|
||||||
&cli.DurationFlag{
|
|
||||||
Name: "duration",
|
|
||||||
Value: 365 * 24 * time.Hour,
|
|
||||||
Usage: "Duration that certificate is valid for",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "ca",
|
|
||||||
Usage: "whether this cert should be its own Certificate Authority",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func publicKey(priv any) any {
|
func publicKey(priv any) any {
|
||||||
|
@ -89,7 +92,7 @@ func pemBlockForKey(priv any) *pem.Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCert(c *cli.Context) error {
|
func runCert(ctx context.Context, c *cli.Command) error {
|
||||||
if err := argsSet(c, "host"); err != nil {
|
if err := argsSet(c, "host"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
26
cmd/cmd.go
26
cmd/cmd.go
|
@ -20,19 +20,21 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/modules/util"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// argsSet checks that all the required arguments are set. args is a list of
|
// argsSet checks that all the required arguments are set. args is a list of
|
||||||
// arguments that must be set in the passed Context.
|
// arguments that must be set in the passed Context.
|
||||||
func argsSet(c *cli.Context, args ...string) error {
|
func argsSet(c *cli.Command, args ...string) error {
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
if !c.IsSet(a) {
|
if !c.IsSet(a) {
|
||||||
return errors.New(a + " is not set")
|
return errors.New(a + " is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if util.IsEmptyString(c.String(a)) {
|
if s, ok := c.Value(a).(string); ok {
|
||||||
return errors.New(a + " is required")
|
if util.IsEmptyString(s) {
|
||||||
|
return errors.New(a + " is required")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -73,8 +75,8 @@ If this is the intended configuration file complete the [database] section.`, se
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func installSignals() (context.Context, context.CancelFunc) {
|
func installSignals(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
go func() {
|
go func() {
|
||||||
// install notify
|
// install notify
|
||||||
signalChannel := make(chan os.Signal, 1)
|
signalChannel := make(chan os.Signal, 1)
|
||||||
|
@ -109,7 +111,7 @@ func setupConsoleLogger(level log.Level, colorize bool, out io.Writer) {
|
||||||
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func globalBool(c *cli.Context, name string) bool {
|
func globalBool(c *cli.Command, name string) bool {
|
||||||
for _, ctx := range c.Lineage() {
|
for _, ctx := range c.Lineage() {
|
||||||
if ctx.Bool(name) {
|
if ctx.Bool(name) {
|
||||||
return true
|
return true
|
||||||
|
@ -120,16 +122,16 @@ func globalBool(c *cli.Context, name string) bool {
|
||||||
|
|
||||||
// PrepareConsoleLoggerLevel by default, use INFO level for console logger, but some sub-commands (for git/ssh protocol) shouldn't output any log to stdout.
|
// PrepareConsoleLoggerLevel by default, use INFO level for console logger, but some sub-commands (for git/ssh protocol) shouldn't output any log to stdout.
|
||||||
// Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever.
|
// Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever.
|
||||||
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(*cli.Context) error {
|
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||||
return func(c *cli.Context) error {
|
return func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||||
level := defaultLevel
|
level := defaultLevel
|
||||||
if globalBool(c, "quiet") {
|
if globalBool(cli, "quiet") {
|
||||||
level = log.FATAL
|
level = log.FATAL
|
||||||
}
|
}
|
||||||
if globalBool(c, "debug") || globalBool(c, "verbose") {
|
if globalBool(cli, "debug") || globalBool(cli, "verbose") {
|
||||||
level = log.TRACE
|
level = log.TRACE
|
||||||
}
|
}
|
||||||
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
||||||
return nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
cmd/docs.go
65
cmd/docs.go
|
@ -1,65 +0,0 @@
|
||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CmdDocs represents the available docs sub-command.
|
|
||||||
var CmdDocs = &cli.Command{
|
|
||||||
Name: "docs",
|
|
||||||
Usage: "Output CLI documentation",
|
|
||||||
Description: "A command to output Forgejo's CLI documentation, optionally to a file.",
|
|
||||||
Action: runDocs,
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "man",
|
|
||||||
Usage: "Output man pages instead",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "output",
|
|
||||||
Aliases: []string{"o"},
|
|
||||||
Usage: "Path to output to instead of stdout (will overwrite if exists)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func runDocs(ctx *cli.Context) error {
|
|
||||||
docs, err := ctx.App.ToMarkdown()
|
|
||||||
if ctx.Bool("man") {
|
|
||||||
docs, err = ctx.App.ToMan()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ctx.Bool("man") {
|
|
||||||
// Clean up markdown. The following bug was fixed in v2, but is present in v1.
|
|
||||||
// It affects markdown output (even though the issue is referring to man pages)
|
|
||||||
// https://github.com/urfave/cli/issues/1040
|
|
||||||
firstHashtagIndex := strings.Index(docs, "#")
|
|
||||||
|
|
||||||
if firstHashtagIndex > 0 {
|
|
||||||
docs = docs[firstHashtagIndex:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out := os.Stdout
|
|
||||||
if ctx.String("output") != "" {
|
|
||||||
fi, err := os.Create(ctx.String("output"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer fi.Close()
|
|
||||||
out = fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = fmt.Fprintln(out, docs)
|
|
||||||
return err
|
|
||||||
}
|
|
129
cmd/doctor.go
129
cmd/doctor.go
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
golog "log"
|
golog "log"
|
||||||
"os"
|
"os"
|
||||||
|
@ -19,80 +20,86 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/services/doctor"
|
"forgejo.org/services/doctor"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDoctor represents the available doctor sub-command.
|
// CmdDoctor represents the available doctor sub-command.
|
||||||
var CmdDoctor = &cli.Command{
|
func cmdDoctor() *cli.Command {
|
||||||
Name: "doctor",
|
return &cli.Command{
|
||||||
Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
|
Name: "doctor",
|
||||||
Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
|
||||||
|
Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
||||||
|
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
cmdDoctorCheck,
|
cmdDoctorCheck(),
|
||||||
cmdRecreateTable,
|
cmdRecreateTable(),
|
||||||
cmdDoctorConvert,
|
cmdDoctorConvert(),
|
||||||
},
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdDoctorCheck = &cli.Command{
|
func cmdDoctorCheck() *cli.Command {
|
||||||
Name: "check",
|
return &cli.Command{
|
||||||
Usage: "Diagnose and optionally fix problems",
|
Name: "check",
|
||||||
Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
Usage: "Diagnose and optionally fix problems",
|
||||||
Action: runDoctorCheck,
|
Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
||||||
Flags: []cli.Flag{
|
Action: runDoctorCheck,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "list",
|
&cli.BoolFlag{
|
||||||
Usage: "List the available checks",
|
Name: "list",
|
||||||
|
Usage: "List the available checks",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "default",
|
||||||
|
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "run",
|
||||||
|
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "all",
|
||||||
|
Usage: "Run all the available checks",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "fix",
|
||||||
|
Usage: "Automatically fix what we can",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "log-file",
|
||||||
|
Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "color",
|
||||||
|
Aliases: []string{"H"},
|
||||||
|
Usage: "Use color for outputted information",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "default",
|
|
||||||
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
|
|
||||||
},
|
|
||||||
&cli.StringSliceFlag{
|
|
||||||
Name: "run",
|
|
||||||
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "all",
|
|
||||||
Usage: "Run all the available checks",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "fix",
|
|
||||||
Usage: "Automatically fix what we can",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "log-file",
|
|
||||||
Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "color",
|
|
||||||
Aliases: []string{"H"},
|
|
||||||
Usage: "Use color for outputted information",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdRecreateTable = &cli.Command{
|
func cmdRecreateTable() *cli.Command {
|
||||||
Name: "recreate-table",
|
return &cli.Command{
|
||||||
Usage: "Recreate tables from XORM definitions and copy the data.",
|
Name: "recreate-table",
|
||||||
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
Usage: "Recreate tables from XORM definitions and copy the data.",
|
||||||
Flags: []cli.Flag{
|
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "debug",
|
&cli.BoolFlag{
|
||||||
Usage: "Print SQL commands sent",
|
Name: "debug",
|
||||||
|
Usage: "Print SQL commands sent",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
Description: `The database definitions Forgejo uses change across versions, sometimes changing default values and leaving old unused columns.
|
||||||
Description: `The database definitions Forgejo uses change across versions, sometimes changing default values and leaving old unused columns.
|
|
||||||
|
|
||||||
This command will cause Xorm to recreate tables, copying over the data and deleting the old table.
|
This command will cause Xorm to recreate tables, copying over the data and deleting the old table.
|
||||||
|
|
||||||
You should back-up your database before doing this and ensure that your database is up-to-date first.`,
|
You should back-up your database before doing this and ensure that your database is up-to-date first.`,
|
||||||
Action: runRecreateTable,
|
Action: runRecreateTable,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRecreateTable(ctx *cli.Context) error {
|
func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Redirect the default golog to here
|
// Redirect the default golog to here
|
||||||
|
@ -143,7 +150,7 @@ func runRecreateTable(ctx *cli.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
func setupDoctorDefaultLogger(ctx *cli.Command, colorize bool) {
|
||||||
// Silence the default loggers
|
// Silence the default loggers
|
||||||
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
||||||
|
|
||||||
|
@ -165,8 +172,8 @@ func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoctorCheck(ctx *cli.Context) error {
|
func runDoctorCheck(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
colorize := log.CanColorStdout
|
colorize := log.CanColorStdout
|
||||||
|
|
|
@ -4,25 +4,28 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forgejo.org/models/db"
|
"forgejo.org/models/db"
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdDoctorConvert represents the available convert sub-command.
|
// cmdDoctorConvert represents the available convert sub-command.
|
||||||
var cmdDoctorConvert = &cli.Command{
|
func cmdDoctorConvert() *cli.Command {
|
||||||
Name: "convert",
|
return &cli.Command{
|
||||||
Usage: "Convert the database",
|
Name: "convert",
|
||||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
Usage: "Convert the database",
|
||||||
Action: runDoctorConvert,
|
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||||
|
Action: runDoctorConvert,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoctorConvert(ctx *cli.Context) error {
|
func runDoctorConvert(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"forgejo.org/services/doctor"
|
"forgejo.org/services/doctor"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDoctorRun(t *testing.T) {
|
func TestDoctorRun(t *testing.T) {
|
||||||
|
@ -22,12 +22,12 @@ func TestDoctorRun(t *testing.T) {
|
||||||
|
|
||||||
SkipDatabaseInitialization: true,
|
SkipDatabaseInitialization: true,
|
||||||
})
|
})
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Commands = []*cli.Command{cmdDoctorCheck}
|
app.Commands = []*cli.Command{cmdDoctorCheck()}
|
||||||
err := app.Run([]string{"./gitea", "check", "--run", "test-check"})
|
err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = app.Run([]string{"./gitea", "check", "--run", "no-such"})
|
err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "no-such"})
|
||||||
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
err = app.Run([]string{"./gitea", "check", "--run", "test-check,no-such"})
|
err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check,no-such"})
|
||||||
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
}
|
}
|
||||||
|
|
155
cmd/dump.go
155
cmd/dump.go
|
@ -5,6 +5,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -23,7 +24,7 @@ import (
|
||||||
|
|
||||||
"code.forgejo.org/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
"github.com/mholt/archiver/v3"
|
"github.com/mholt/archiver/v3"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error {
|
func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error {
|
||||||
|
@ -84,6 +85,10 @@ func (o *outputType) Set(value string) error {
|
||||||
return fmt.Errorf("allowed values are %s", o.Join())
|
return fmt.Errorf("allowed values are %s", o.Join())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *outputType) Get() any {
|
||||||
|
return o.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (o outputType) String() string {
|
func (o outputType) String() string {
|
||||||
if o.selected == "" {
|
if o.selected == "" {
|
||||||
return o.Default
|
return o.Default
|
||||||
|
@ -97,79 +102,81 @@ var outputTypeEnum = &outputType{
|
||||||
}
|
}
|
||||||
|
|
||||||
// CmdDump represents the available dump sub-command.
|
// CmdDump represents the available dump sub-command.
|
||||||
var CmdDump = &cli.Command{
|
func cmdDump() *cli.Command {
|
||||||
Name: "dump",
|
return &cli.Command{
|
||||||
Usage: "Dump Forgejo files and database",
|
Name: "dump",
|
||||||
Description: `Dump compresses all related files and database into zip file.
|
Usage: "Dump Forgejo files and database",
|
||||||
|
Description: `Dump compresses all related files and database into zip file.
|
||||||
It can be used for backup and capture Forgejo server image to send to maintainer`,
|
It can be used for backup and capture Forgejo server image to send to maintainer`,
|
||||||
Action: runDump,
|
Action: runDump,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"f"},
|
||||||
Value: fmt.Sprintf("forgejo-dump-%d.zip", time.Now().Unix()),
|
Value: fmt.Sprintf("forgejo-dump-%d.zip", time.Now().Unix()),
|
||||||
Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.",
|
Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "verbose",
|
||||||
|
Aliases: []string{"V"},
|
||||||
|
Usage: "Show process details",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "quiet",
|
||||||
|
Aliases: []string{"q"},
|
||||||
|
Usage: "Only display warnings and errors",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "tempdir",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "Temporary dir path",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "database",
|
||||||
|
Aliases: []string{"d"},
|
||||||
|
Usage: "Specify the database SQL syntax: sqlite3, mysql, postgres",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-repository",
|
||||||
|
Aliases: []string{"R"},
|
||||||
|
Usage: "Skip repositories",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-log",
|
||||||
|
Aliases: []string{"L"},
|
||||||
|
Usage: "Skip logs",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-custom-dir",
|
||||||
|
Usage: "Skip custom directory",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-lfs-data",
|
||||||
|
Usage: "Skip LFS data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-attachment-data",
|
||||||
|
Usage: "Skip attachment data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-package-data",
|
||||||
|
Usage: "Skip package data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-index",
|
||||||
|
Usage: "Skip bleve index data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-repo-archives",
|
||||||
|
Usage: "Skip repository archives",
|
||||||
|
},
|
||||||
|
&cli.GenericFlag{
|
||||||
|
Name: "type",
|
||||||
|
Value: outputTypeEnum,
|
||||||
|
Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "verbose",
|
|
||||||
Aliases: []string{"V"},
|
|
||||||
Usage: "Show process details",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "quiet",
|
|
||||||
Aliases: []string{"q"},
|
|
||||||
Usage: "Only display warnings and errors",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "tempdir",
|
|
||||||
Aliases: []string{"t"},
|
|
||||||
Usage: "Temporary dir path",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "database",
|
|
||||||
Aliases: []string{"d"},
|
|
||||||
Usage: "Specify the database SQL syntax: sqlite3, mysql, postgres",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-repository",
|
|
||||||
Aliases: []string{"R"},
|
|
||||||
Usage: "Skip repositories",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-log",
|
|
||||||
Aliases: []string{"L"},
|
|
||||||
Usage: "Skip logs",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-custom-dir",
|
|
||||||
Usage: "Skip custom directory",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-lfs-data",
|
|
||||||
Usage: "Skip LFS data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-attachment-data",
|
|
||||||
Usage: "Skip attachment data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-package-data",
|
|
||||||
Usage: "Skip package data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-index",
|
|
||||||
Usage: "Skip bleve index data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-repo-archives",
|
|
||||||
Usage: "Skip repository archives",
|
|
||||||
},
|
|
||||||
&cli.GenericFlag{
|
|
||||||
Name: "type",
|
|
||||||
Value: outputTypeEnum,
|
|
||||||
Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fatal(format string, args ...any) {
|
func fatal(format string, args ...any) {
|
||||||
|
@ -177,7 +184,7 @@ func fatal(format string, args ...any) {
|
||||||
log.Fatal(format, args...)
|
log.Fatal(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDump(ctx *cli.Context) error {
|
func runDump(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
var file *os.File
|
var file *os.File
|
||||||
fileName := ctx.String("file")
|
fileName := ctx.String("file")
|
||||||
outType := ctx.String("type")
|
outType := ctx.String("type")
|
||||||
|
@ -222,7 +229,7 @@ func runDump(ctx *cli.Context) error {
|
||||||
return errors.New("--quiet and --verbose cannot both be set")
|
return errors.New("--quiet and --verbose cannot both be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
err := db.InitEngine(stdCtx)
|
err := db.InitEngine(stdCtx)
|
||||||
|
|
112
cmd/dump_repo.go
112
cmd/dump_repo.go
|
@ -19,68 +19,70 @@ import (
|
||||||
"forgejo.org/services/convert"
|
"forgejo.org/services/convert"
|
||||||
"forgejo.org/services/migrations"
|
"forgejo.org/services/migrations"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDumpRepository represents the available dump repository sub-command.
|
// CmdDumpRepository represents the available dump repository sub-command.
|
||||||
var CmdDumpRepository = &cli.Command{
|
func cmdDumpRepository() *cli.Command {
|
||||||
Name: "dump-repo",
|
return &cli.Command{
|
||||||
Usage: "Dump the repository from git/github/gitea/gitlab",
|
Name: "dump-repo",
|
||||||
Description: "This is a command for dumping the repository data.",
|
Usage: "Dump the repository from git/github/gitea/gitlab",
|
||||||
Action: runDumpRepository,
|
Description: "This is a command for dumping the repository data.",
|
||||||
Flags: []cli.Flag{
|
Action: runDumpRepository,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "git_service",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "git_service",
|
||||||
Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
|
Value: "",
|
||||||
},
|
Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "repo_dir",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"r"},
|
Name: "repo_dir",
|
||||||
Value: "./data",
|
Aliases: []string{"r"},
|
||||||
Usage: "Repository dir path to store the data",
|
Value: "./data",
|
||||||
},
|
Usage: "Repository dir path to store the data",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "clone_addr",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "clone_addr",
|
||||||
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
|
Value: "",
|
||||||
},
|
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "auth_username",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "auth_username",
|
||||||
Usage: "The username to visit the clone_addr",
|
Value: "",
|
||||||
},
|
Usage: "The username to visit the clone_addr",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "auth_password",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "auth_password",
|
||||||
Usage: "The password to visit the clone_addr",
|
Value: "",
|
||||||
},
|
Usage: "The password to visit the clone_addr",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "auth_token",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "auth_token",
|
||||||
Usage: "The personal token to visit the clone_addr",
|
Value: "",
|
||||||
},
|
Usage: "The personal token to visit the clone_addr",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "owner_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "owner_name",
|
||||||
Usage: "The data will be stored on a directory with owner name if not empty",
|
Value: "",
|
||||||
},
|
Usage: "The data will be stored on a directory with owner name if not empty",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "repo_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "repo_name",
|
||||||
Usage: "The data will be stored on a directory with repository name if not empty",
|
Value: "",
|
||||||
},
|
Usage: "The data will be stored on a directory with repository name if not empty",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "units",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "units",
|
||||||
Usage: `Which items will be migrated, one or more units should be separated as comma.
|
Value: "",
|
||||||
|
Usage: `Which items will be migrated, one or more units should be separated as comma.
|
||||||
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDumpRepository(ctx *cli.Context) error {
|
func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -19,23 +20,25 @@ import (
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/modules/util"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdEmbedded represents the available extract sub-command.
|
// CmdEmbedded represents the available extract sub-command.
|
||||||
var (
|
func cmdEmbedded() *cli.Command {
|
||||||
CmdEmbedded = &cli.Command{
|
return &cli.Command{
|
||||||
Name: "embedded",
|
Name: "embedded",
|
||||||
Usage: "Extract embedded resources",
|
Usage: "Extract embedded resources",
|
||||||
Description: "A command for extracting embedded resources, like templates and images",
|
Description: "A command for extracting embedded resources, like templates and images",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdList,
|
subcmdList(),
|
||||||
subcmdView,
|
subcmdView(),
|
||||||
subcmdExtract,
|
subcmdExtract(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdList = &cli.Command{
|
func subcmdList() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List files matching the given pattern",
|
Usage: "List files matching the given pattern",
|
||||||
Action: runList,
|
Action: runList,
|
||||||
|
@ -47,8 +50,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdView = &cli.Command{
|
func subcmdView() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "view",
|
Name: "view",
|
||||||
Usage: "View a file matching the given pattern",
|
Usage: "View a file matching the given pattern",
|
||||||
Action: runView,
|
Action: runView,
|
||||||
|
@ -60,8 +65,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdExtract = &cli.Command{
|
func subcmdExtract() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "extract",
|
Name: "extract",
|
||||||
Usage: "Extract resources",
|
Usage: "Extract resources",
|
||||||
Action: runExtract,
|
Action: runExtract,
|
||||||
|
@ -90,9 +97,9 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
matchedAssetFiles []assetFile
|
var matchedAssetFiles []assetFile
|
||||||
)
|
|
||||||
|
|
||||||
type assetFile struct {
|
type assetFile struct {
|
||||||
fs *assetfs.LayeredFS
|
fs *assetfs.LayeredFS
|
||||||
|
@ -100,7 +107,7 @@ type assetFile struct {
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func initEmbeddedExtractor(c *cli.Context) error {
|
func initEmbeddedExtractor(_ context.Context, c *cli.Command) error {
|
||||||
setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr)
|
setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr)
|
||||||
|
|
||||||
patterns, err := compileCollectPatterns(c.Args().Slice())
|
patterns, err := compileCollectPatterns(c.Args().Slice())
|
||||||
|
@ -115,32 +122,32 @@ func initEmbeddedExtractor(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runList(c *cli.Context) error {
|
func runList(ctx context.Context, c *cli.Command) error {
|
||||||
if err := runListDo(c); err != nil {
|
if err := runListDo(ctx, c); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runView(c *cli.Context) error {
|
func runView(ctx context.Context, c *cli.Command) error {
|
||||||
if err := runViewDo(c); err != nil {
|
if err := runViewDo(ctx, c); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExtract(c *cli.Context) error {
|
func runExtract(ctx context.Context, c *cli.Command) error {
|
||||||
if err := runExtractDo(c); err != nil {
|
if err := runExtractDo(ctx, c); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runListDo(c *cli.Context) error {
|
func runListDo(ctx context.Context, c *cli.Command) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,8 +158,8 @@ func runListDo(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runViewDo(c *cli.Context) error {
|
func runViewDo(ctx context.Context, c *cli.Command) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,8 +181,8 @@ func runViewDo(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExtractDo(c *cli.Context) error {
|
func runExtractDo(ctx context.Context, c *cli.Command) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +278,7 @@ func extractAsset(d string, a assetFile, overwrite, rename bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectAssetFilesByPattern(c *cli.Context, globs []glob.Glob, path string, layer *assetfs.Layer) {
|
func collectAssetFilesByPattern(c *cli.Command, globs []glob.Glob, path string, layer *assetfs.Layer) {
|
||||||
fs := assetfs.Layered(layer)
|
fs := assetfs.Layered(layer)
|
||||||
files, err := fs.ListAllFiles(".", true)
|
files, err := fs.ListAllFiles(".", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -17,14 +17,14 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
private_routers "forgejo.org/routers/private"
|
private_routers "forgejo.org/routers/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CmdActions(ctx context.Context) *cli.Command {
|
func CmdActions(ctx context.Context) *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "actions",
|
Name: "actions",
|
||||||
Usage: "Commands for managing Forgejo Actions",
|
Usage: "Commands for managing Forgejo Actions",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
SubcmdActionsGenerateRunnerToken(ctx),
|
SubcmdActionsGenerateRunnerToken(ctx),
|
||||||
SubcmdActionsGenerateRunnerSecret(ctx),
|
SubcmdActionsGenerateRunnerSecret(ctx),
|
||||||
SubcmdActionsRegister(ctx),
|
SubcmdActionsRegister(ctx),
|
||||||
|
@ -37,7 +37,7 @@ func SubcmdActionsGenerateRunnerToken(ctx context.Context) *cli.Command {
|
||||||
Name: "generate-runner-token",
|
Name: "generate-runner-token",
|
||||||
Usage: "Generate a new token for a runner to use to register with the server",
|
Usage: "Generate a new token for a runner to use to register with the server",
|
||||||
Before: prepareWorkPathAndCustomConf(ctx),
|
Before: prepareWorkPathAndCustomConf(ctx),
|
||||||
Action: func(cliCtx *cli.Context) error { return RunGenerateActionsRunnerToken(ctx, cliCtx) },
|
Action: RunGenerateActionsRunnerToken,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "scope",
|
Name: "scope",
|
||||||
|
@ -53,7 +53,7 @@ func SubcmdActionsGenerateRunnerSecret(ctx context.Context) *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "generate-secret",
|
Name: "generate-secret",
|
||||||
Usage: "Generate a secret suitable for input to the register subcommand",
|
Usage: "Generate a secret suitable for input to the register subcommand",
|
||||||
Action: func(cliCtx *cli.Context) error { return RunGenerateSecret(ctx, cliCtx) },
|
Action: RunGenerateSecret,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
||||||
Name: "register",
|
Name: "register",
|
||||||
Usage: "Idempotent registration of a runner using a shared secret",
|
Usage: "Idempotent registration of a runner using a shared secret",
|
||||||
Before: prepareWorkPathAndCustomConf(ctx),
|
Before: prepareWorkPathAndCustomConf(ctx),
|
||||||
Action: func(cliCtx *cli.Context) error { return RunRegister(ctx, cliCtx) },
|
Action: RunRegister,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
|
@ -106,19 +106,19 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSecret(ctx context.Context, cliCtx *cli.Context) (string, error) {
|
func readSecret(ctx context.Context, cli *cli.Command) (string, error) {
|
||||||
if cliCtx.IsSet("secret") {
|
if cli.IsSet("secret") {
|
||||||
return cliCtx.String("secret"), nil
|
return cli.String("secret"), nil
|
||||||
}
|
}
|
||||||
if cliCtx.IsSet("secret-stdin") {
|
if cli.IsSet("secret-stdin") {
|
||||||
buf, err := io.ReadAll(ContextGetStdin(ctx))
|
buf, err := io.ReadAll(ContextGetStdin(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(buf), nil
|
return string(buf), nil
|
||||||
}
|
}
|
||||||
if cliCtx.IsSet("secret-file") {
|
if cli.IsSet("secret-file") {
|
||||||
path := cliCtx.String("secret-file")
|
path := cli.String("secret-file")
|
||||||
buf, err := os.ReadFile(path)
|
buf, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -139,18 +139,18 @@ func validateSecret(secret string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLabels(cliCtx *cli.Context) (*[]string, error) {
|
func getLabels(cli *cli.Command) (*[]string, error) {
|
||||||
if !cliCtx.Bool("keep-labels") {
|
if !cli.Bool("keep-labels") {
|
||||||
lblValue := strings.Split(cliCtx.String("labels"), ",")
|
lblValue := strings.Split(cli.String("labels"), ",")
|
||||||
return &lblValue, nil
|
return &lblValue, nil
|
||||||
}
|
}
|
||||||
if cliCtx.String("labels") != "" {
|
if cli.String("labels") != "" {
|
||||||
return nil, errors.New("--labels and --keep-labels should not be used together")
|
return nil, errors.New("--labels and --keep-labels should not be used together")
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
func RunRegister(ctx context.Context, cli *cli.Command) error {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
ctx, cancel = installSignals(ctx)
|
ctx, cancel = installSignals(ctx)
|
||||||
|
@ -162,17 +162,17 @@ func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
}
|
}
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
secret, err := readSecret(ctx, cliCtx)
|
secret, err := readSecret(ctx, cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := validateSecret(secret); err != nil {
|
if err := validateSecret(secret); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
scope := cliCtx.String("scope")
|
scope := cli.String("scope")
|
||||||
name := cliCtx.String("name")
|
name := cli.String("name")
|
||||||
version := cliCtx.String("version")
|
version := cli.String("version")
|
||||||
labels, err := getLabels(cliCtx)
|
labels, err := getLabels(cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
func RunGenerateSecret(ctx context.Context, cli *cli.Command) error {
|
||||||
runner := actions_model.ActionRunner{}
|
runner := actions_model.ActionRunner{}
|
||||||
if err := runner.GenerateToken(); err != nil {
|
if err := runner.GenerateToken(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -221,7 +221,7 @@ func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) error {
|
func RunGenerateActionsRunnerToken(ctx context.Context, cli *cli.Command) error {
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
ctx, cancel = installSignals(ctx)
|
ctx, cancel = installSignals(ctx)
|
||||||
|
@ -230,7 +230,7 @@ func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) err
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
scope := cliCtx.String("scope")
|
scope := cli.String("scope")
|
||||||
|
|
||||||
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
||||||
if extra.HasError() {
|
if extra.HasError() {
|
||||||
|
|
|
@ -4,14 +4,13 @@
|
||||||
package forgejo
|
package forgejo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"forgejo.org/services/context"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestActions_getLabels(t *testing.T) {
|
func TestActions_getLabels(t *testing.T) {
|
||||||
|
@ -54,21 +53,21 @@ func TestActions_getLabels(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := SubcmdActionsRegister(context.Context{}).Flags
|
flags := SubcmdActionsRegister(t.Context()).Flags
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(fmt.Sprintf("args: %v", c.args), func(t *testing.T) {
|
t.Run(fmt.Sprintf("args: %v", c.args), func(t *testing.T) {
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
var result *resultType
|
var result *resultType
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = flags
|
app.Flags = flags
|
||||||
app.Action = func(ctx *cli.Context) error {
|
app.Action = func(_ context.Context, ctx *cli.Command) error {
|
||||||
labels, err := getLabels(ctx)
|
labels, err := getLabels(ctx)
|
||||||
result = &resultType{labels, err}
|
result = &resultType{labels, err}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
_ = app.Run(c.args)
|
_ = app.Run(t.Context(), c.args)
|
||||||
|
|
||||||
// Test the results
|
// Test the results
|
||||||
require.NotNil(t, result)
|
require.NotNil(t, result)
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
f3_cmd "code.forgejo.org/f3/gof3/v3/cmd"
|
f3_cmd "code.forgejo.org/f3/gof3/v3/cmd"
|
||||||
f3_logger "code.forgejo.org/f3/gof3/v3/logger"
|
f3_logger "code.forgejo.org/f3/gof3/v3/logger"
|
||||||
f3_util "code.forgejo.org/f3/gof3/v3/util"
|
f3_util "code.forgejo.org/f3/gof3/v3/util"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CmdF3(ctx context.Context) *cli.Command {
|
func CmdF3(ctx context.Context) *cli.Command {
|
||||||
|
@ -28,21 +28,21 @@ func CmdF3(ctx context.Context) *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "f3",
|
Name: "f3",
|
||||||
Usage: "F3",
|
Usage: "F3",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
SubcmdF3Mirror(ctx),
|
SubcmdF3Mirror(ctx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubcmdF3Mirror(ctx context.Context) *cli.Command {
|
func SubcmdF3Mirror(ctx context.Context) *cli.Command {
|
||||||
mirrorCmd := f3_cmd.CreateCmdMirror(ctx)
|
mirrorCmd := f3_cmd.CreateCmdMirror()
|
||||||
mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx)
|
mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx)
|
||||||
f3Action := mirrorCmd.Action
|
f3Action := mirrorCmd.Action
|
||||||
mirrorCmd.Action = func(c *cli.Context) error { return runMirror(ctx, c, f3Action) }
|
mirrorCmd.Action = func(ctx context.Context, cli *cli.Command) error { return runMirror(ctx, cli, f3Action) }
|
||||||
return mirrorCmd
|
return mirrorCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMirror(ctx context.Context, c *cli.Context, action cli.ActionFunc) error {
|
func runMirror(ctx context.Context, c *cli.Command, action cli.ActionFunc) error {
|
||||||
setting.LoadF3Setting()
|
setting.LoadF3Setting()
|
||||||
if !setting.F3.Enabled {
|
if !setting.F3.Enabled {
|
||||||
return errors.New("F3 is disabled, it is not ready to be used and is only present for development purposes")
|
return errors.New("F3 is disabled, it is not ready to be used and is only present for development purposes")
|
||||||
|
@ -69,7 +69,7 @@ func runMirror(ctx context.Context, c *cli.Context, action cli.ActionFunc) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := action(c)
|
err := action(ctx, c)
|
||||||
if panicError, ok := err.(f3_util.PanicError); ok {
|
if panicError, ok := err.(f3_util.PanicError); ok {
|
||||||
log.Debug("F3 Stack trace\n%s", panicError.Stack())
|
log.Debug("F3 Stack trace\n%s", panicError.Stack())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type key int
|
type key int
|
||||||
|
@ -34,7 +34,7 @@ func CmdForgejo(ctx context.Context) *cli.Command {
|
||||||
Name: "forgejo-cli",
|
Name: "forgejo-cli",
|
||||||
Usage: "Forgejo CLI",
|
Usage: "Forgejo CLI",
|
||||||
Flags: []cli.Flag{},
|
Flags: []cli.Flag{},
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
CmdActions(ctx),
|
CmdActions(ctx),
|
||||||
CmdF3(ctx),
|
CmdF3(ctx),
|
||||||
},
|
},
|
||||||
|
@ -147,12 +147,12 @@ func handleCliResponseExtra(ctx context.Context, extra private.ResponseExtra) er
|
||||||
return cli.Exit(extra.Error, 1)
|
return cli.Exit(extra.Error, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareWorkPathAndCustomConf(ctx context.Context) func(c *cli.Context) error {
|
func prepareWorkPathAndCustomConf(ctx context.Context) func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||||
return func(c *cli.Context) error {
|
return func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
var args setting.ArgWorkPathAndCustomConf
|
var args setting.ArgWorkPathAndCustomConf
|
||||||
// from children to parent, check the global flags
|
// from children to parent, check the global flags
|
||||||
for _, curCtx := range c.Lineage() {
|
for _, curCtx := range cli.Lineage() {
|
||||||
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
||||||
args.WorkPath = curCtx.String("work-path")
|
args.WorkPath = curCtx.String("work-path")
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,6 @@ func prepareWorkPathAndCustomConf(ctx context.Context) func(c *cli.Context) erro
|
||||||
}
|
}
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
}
|
}
|
||||||
return nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,56 +5,65 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"forgejo.org/modules/generate"
|
"forgejo.org/modules/generate"
|
||||||
|
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// CmdGenerate represents the available generate sub-command.
|
||||||
// CmdGenerate represents the available generate sub-command.
|
func cmdGenerate() *cli.Command {
|
||||||
CmdGenerate = &cli.Command{
|
return &cli.Command{
|
||||||
Name: "generate",
|
Name: "generate",
|
||||||
Usage: "Generate Gitea's secrets/keys/tokens",
|
Usage: "Generate Gitea's secrets/keys/tokens",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdSecret,
|
subcmdSecret(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdSecret = &cli.Command{
|
func subcmdSecret() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
Usage: "Generate a secret token",
|
Usage: "Generate a secret token",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
microcmdGenerateInternalToken,
|
microcmdGenerateInternalToken(),
|
||||||
microcmdGenerateLfsJwtSecret,
|
microcmdGenerateLfsJwtSecret(),
|
||||||
microcmdGenerateSecretKey,
|
microcmdGenerateSecretKey(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdGenerateInternalToken = &cli.Command{
|
func microcmdGenerateInternalToken() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "INTERNAL_TOKEN",
|
Name: "INTERNAL_TOKEN",
|
||||||
Usage: "Generate a new INTERNAL_TOKEN",
|
Usage: "Generate a new INTERNAL_TOKEN",
|
||||||
Action: runGenerateInternalToken,
|
Action: runGenerateInternalToken,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdGenerateLfsJwtSecret = &cli.Command{
|
func microcmdGenerateLfsJwtSecret() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "JWT_SECRET",
|
Name: "JWT_SECRET",
|
||||||
Aliases: []string{"LFS_JWT_SECRET"},
|
Aliases: []string{"LFS_JWT_SECRET"},
|
||||||
Usage: "Generate a new JWT_SECRET",
|
Usage: "Generate a new JWT_SECRET",
|
||||||
Action: runGenerateLfsJwtSecret,
|
Action: runGenerateLfsJwtSecret,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdGenerateSecretKey = &cli.Command{
|
func microcmdGenerateSecretKey() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "SECRET_KEY",
|
Name: "SECRET_KEY",
|
||||||
Usage: "Generate a new SECRET_KEY",
|
Usage: "Generate a new SECRET_KEY",
|
||||||
Action: runGenerateSecretKey,
|
Action: runGenerateSecretKey,
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runGenerateInternalToken(c *cli.Context) error {
|
func runGenerateInternalToken(ctx context.Context, c *cli.Command) error {
|
||||||
internalToken, err := generate.NewInternalToken()
|
internalToken, err := generate.NewInternalToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -69,7 +78,7 @@ func runGenerateInternalToken(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateLfsJwtSecret(c *cli.Context) error {
|
func runGenerateLfsJwtSecret(ctx context.Context, c *cli.Command) error {
|
||||||
_, jwtSecretBase64 := generate.NewJwtSecret()
|
_, jwtSecretBase64 := generate.NewJwtSecret()
|
||||||
|
|
||||||
fmt.Printf("%s", jwtSecretBase64)
|
fmt.Printf("%s", jwtSecretBase64)
|
||||||
|
@ -81,7 +90,7 @@ func runGenerateLfsJwtSecret(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateSecretKey(c *cli.Context) error {
|
func runGenerateSecretKey(ctx context.Context, c *cli.Command) error {
|
||||||
secretKey, err := generate.NewSecretKey()
|
secretKey, err := generate.NewSecretKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
57
cmd/hook.go
57
cmd/hook.go
|
@ -21,29 +21,31 @@ import (
|
||||||
repo_module "forgejo.org/modules/repository"
|
repo_module "forgejo.org/modules/repository"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
hookBatchSize = 30
|
hookBatchSize = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// CmdHook represents the available hooks sub-command.
|
||||||
// CmdHook represents the available hooks sub-command.
|
func cmdHook() *cli.Command {
|
||||||
CmdHook = &cli.Command{
|
return &cli.Command{
|
||||||
Name: "hook",
|
Name: "hook",
|
||||||
Usage: "(internal) Should only be called by Git",
|
Usage: "(internal) Should only be called by Git",
|
||||||
Description: "Delegate commands to corresponding Git hooks",
|
Description: "Delegate commands to corresponding Git hooks",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdHookPreReceive,
|
subcmdHookPreReceive(),
|
||||||
subcmdHookUpdate,
|
subcmdHookUpdate(),
|
||||||
subcmdHookPostReceive,
|
subcmdHookPostReceive(),
|
||||||
subcmdHookProcReceive,
|
subcmdHookProcReceive(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdHookPreReceive = &cli.Command{
|
func subcmdHookPreReceive() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "pre-receive",
|
Name: "pre-receive",
|
||||||
Usage: "Delegate pre-receive Git hook",
|
Usage: "Delegate pre-receive Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -54,7 +56,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
subcmdHookUpdate = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func subcmdHookUpdate() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "update",
|
Name: "update",
|
||||||
Usage: "Delegate update Git hook",
|
Usage: "Delegate update Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -65,7 +70,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
subcmdHookPostReceive = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func subcmdHookPostReceive() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "post-receive",
|
Name: "post-receive",
|
||||||
Usage: "Delegate post-receive Git hook",
|
Usage: "Delegate post-receive Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -76,8 +84,11 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Note: new hook since git 2.29
|
}
|
||||||
subcmdHookProcReceive = &cli.Command{
|
|
||||||
|
// Note: new hook since git 2.29
|
||||||
|
func subcmdHookProcReceive() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "proc-receive",
|
Name: "proc-receive",
|
||||||
Usage: "Delegate proc-receive Git hook",
|
Usage: "Delegate proc-receive Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -88,7 +99,7 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
type delayWriter struct {
|
type delayWriter struct {
|
||||||
internal io.Writer
|
internal io.Writer
|
||||||
|
@ -161,11 +172,11 @@ func (n *nilWriter) WriteString(s string) (int, error) {
|
||||||
return len(s), nil
|
return len(s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookPreReceive(c *cli.Context) error {
|
func runHookPreReceive(ctx context.Context, c *cli.Command) error {
|
||||||
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
@ -291,13 +302,13 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// runHookUpdate process the update hook: https://git-scm.com/docs/githooks#update
|
// runHookUpdate process the update hook: https://git-scm.com/docs/githooks#update
|
||||||
func runHookUpdate(c *cli.Context) error {
|
func runHookUpdate(ctx context.Context, c *cli.Command) error {
|
||||||
// Now if we're an internal don't do anything else
|
// Now if we're an internal don't do anything else
|
||||||
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if c.NArg() != 3 {
|
if c.NArg() != 3 {
|
||||||
|
@ -323,8 +334,8 @@ func runHookUpdate(c *cli.Context) error {
|
||||||
return fail(ctx, fmt.Sprintf("The modification of %s is skipped as it's an internal reference.", refFullName), "")
|
return fail(ctx, fmt.Sprintf("The modification of %s is skipped as it's an internal reference.", refFullName), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookPostReceive(c *cli.Context) error {
|
func runHookPostReceive(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
@ -487,8 +498,8 @@ func hookPrintResults(results []private.HookPostReceiveBranchResult) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookProcReceive(c *cli.Context) error {
|
func runHookProcReceive(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Capture what's being written into a standard file descriptor.
|
// Capture what's being written into a standard file descriptor.
|
||||||
|
@ -134,14 +134,14 @@ func TestDelayWriter(t *testing.T) {
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")()
|
defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")()
|
||||||
|
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Commands = []*cli.Command{subcmdHookPreReceive}
|
app.Commands = []*cli.Command{subcmdHookPreReceive()}
|
||||||
|
|
||||||
t.Run("Should delay", func(t *testing.T) {
|
t.Run("Should delay", func(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)()
|
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)()
|
||||||
finish := captureOutput(t, os.Stdout)
|
finish := captureOutput(t, os.Stdout)
|
||||||
|
|
||||||
err = app.Run([]string{"./forgejo", "pre-receive"})
|
err = app.Run(t.Context(), []string{"./forgejo", "pre-receive"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
out := finish()
|
out := finish()
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ func TestDelayWriter(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)()
|
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)()
|
||||||
finish := captureOutput(t, os.Stdout)
|
finish := captureOutput(t, os.Stdout)
|
||||||
|
|
||||||
err = app.Run([]string{"./forgejo", "pre-receive"})
|
err = app.Run(t.Context(), []string{"./forgejo", "pre-receive"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
out := finish()
|
out := finish()
|
||||||
|
|
||||||
|
@ -163,15 +163,15 @@ func TestDelayWriter(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunHookUpdate(t *testing.T) {
|
func TestRunHookUpdate(t *testing.T) {
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Commands = []*cli.Command{subcmdHookUpdate}
|
app.Commands = []*cli.Command{subcmdHookUpdate()}
|
||||||
|
|
||||||
t.Run("Removal of internal reference", func(t *testing.T) {
|
t.Run("Removal of internal reference", func(t *testing.T) {
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||||
defer test.MockVariableValue(&setting.IsProd, false)()
|
defer test.MockVariableValue(&setting.IsProd, false)()
|
||||||
finish := captureOutput(t, os.Stderr)
|
finish := captureOutput(t, os.Stderr)
|
||||||
|
|
||||||
err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
||||||
out := finish()
|
out := finish()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ func TestRunHookUpdate(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.IsProd, false)()
|
defer test.MockVariableValue(&setting.IsProd, false)()
|
||||||
finish := captureOutput(t, os.Stderr)
|
finish := captureOutput(t, os.Stderr)
|
||||||
|
|
||||||
err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"})
|
err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"})
|
||||||
out := finish()
|
out := finish()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
|
@ -191,12 +191,12 @@ func TestRunHookUpdate(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Removal of branch", func(t *testing.T) {
|
t.Run("Removal of branch", func(t *testing.T) {
|
||||||
err := app.Run([]string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Not enough arguments", func(t *testing.T) {
|
t.Run("Not enough arguments", func(t *testing.T) {
|
||||||
err := app.Run([]string{"./forgejo", "update"})
|
err := app.Run(t.Context(), []string{"./forgejo", "update"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
73
cmd/keys.go
73
cmd/keys.go
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -11,45 +12,47 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdKeys represents the available keys sub-command
|
// CmdKeys represents the available keys sub-command
|
||||||
var CmdKeys = &cli.Command{
|
func cmdKeys() *cli.Command {
|
||||||
Name: "keys",
|
return &cli.Command{
|
||||||
Usage: "(internal) Should only be called by SSH server",
|
Name: "keys",
|
||||||
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
Usage: "(internal) Should only be called by SSH server",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
||||||
Action: runKeys,
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Flags: []cli.Flag{
|
Action: runKeys,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "expected",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"e"},
|
Name: "expected",
|
||||||
Value: "git",
|
Aliases: []string{"e"},
|
||||||
Usage: "Expected user for whom provide key commands",
|
Value: "git",
|
||||||
|
Usage: "Expected user for whom provide key commands",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Aliases: []string{"u"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "Username trying to log in by SSH",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "type",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "content",
|
||||||
|
Aliases: []string{"k"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "username",
|
|
||||||
Aliases: []string{"u"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "Username trying to log in by SSH",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "type",
|
|
||||||
Aliases: []string{"t"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "content",
|
|
||||||
Aliases: []string{"k"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runKeys(c *cli.Context) error {
|
func runKeys(ctx context.Context, c *cli.Command) error {
|
||||||
if !c.IsSet("username") {
|
if !c.IsSet("username") {
|
||||||
return errors.New("No username provided")
|
return errors.New("No username provided")
|
||||||
}
|
}
|
||||||
|
@ -68,7 +71,7 @@ func runKeys(c *cli.Context) error {
|
||||||
return errors.New("No key type and content provided")
|
return errors.New("No key type and content provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
@ -78,6 +81,6 @@ func runKeys(c *cli.Context) error {
|
||||||
if extra.Error != nil {
|
if extra.Error != nil {
|
||||||
return extra.Error
|
return extra.Error
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString.Text))
|
_, _ = fmt.Fprintln(c.Root().Writer, strings.TrimSpace(authorizedString.Text))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,17 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runSendMail(c *cli.Context) error {
|
func runSendMail(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
113
cmd/main.go
113
cmd/main.go
|
@ -14,7 +14,7 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdHelp is our own help subcommand with more information
|
// cmdHelp is our own help subcommand with more information
|
||||||
|
@ -25,18 +25,18 @@ func cmdHelp() *cli.Command {
|
||||||
Aliases: []string{"h"},
|
Aliases: []string{"h"},
|
||||||
Usage: "Shows a list of commands or help for one command",
|
Usage: "Shows a list of commands or help for one command",
|
||||||
ArgsUsage: "[command]",
|
ArgsUsage: "[command]",
|
||||||
Action: func(c *cli.Context) (err error) {
|
Action: func(ctx context.Context, c *cli.Command) (err error) {
|
||||||
lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea, {Command:nil}
|
lineage := c.Lineage() // The order is from child to parent: help, doctor, Forgejo
|
||||||
targetCmdIdx := 0
|
targetCmdIdx := 0
|
||||||
if c.Command.Name == "help" {
|
if c.Name == "help" {
|
||||||
targetCmdIdx = 1
|
targetCmdIdx = 1
|
||||||
}
|
}
|
||||||
if lineage[targetCmdIdx+1].Command != nil {
|
if targetCmdIdx+1 < len(lineage) {
|
||||||
err = cli.ShowCommandHelp(lineage[targetCmdIdx+1], lineage[targetCmdIdx].Command.Name)
|
err = cli.ShowCommandHelp(ctx, lineage[targetCmdIdx+1], lineage[targetCmdIdx].Name)
|
||||||
} else {
|
} else {
|
||||||
err = cli.ShowAppHelp(c)
|
err = cli.ShowAppHelp(c)
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(c.App.Writer, `
|
_, _ = fmt.Fprintf(c.Root().Writer, `
|
||||||
DEFAULT CONFIGURATION:
|
DEFAULT CONFIGURATION:
|
||||||
AppPath: %s
|
AppPath: %s
|
||||||
WorkPath: %s
|
WorkPath: %s
|
||||||
|
@ -77,25 +77,25 @@ func appGlobalFlags() []cli.Flag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareSubcommandWithConfig(command *cli.Command, globalFlags []cli.Flag) {
|
func prepareSubcommandWithConfig(command *cli.Command, globalFlags func() []cli.Flag) {
|
||||||
command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...)
|
command.Flags = append(globalFlags(), command.Flags...)
|
||||||
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
||||||
command.HideHelp = true
|
command.HideHelp = true
|
||||||
if command.Name != "help" {
|
if command.Name != "help" {
|
||||||
command.Subcommands = append(command.Subcommands, cmdHelp())
|
command.Commands = append(command.Commands, cmdHelp())
|
||||||
}
|
}
|
||||||
for i := range command.Subcommands {
|
for i := range command.Commands {
|
||||||
prepareSubcommandWithConfig(command.Subcommands[i], globalFlags)
|
prepareSubcommandWithConfig(command.Commands[i], globalFlags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
|
// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
|
||||||
// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times
|
// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times
|
||||||
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) error {
|
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(_ context.Context, _ *cli.Command) error {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx context.Context, cli *cli.Command) error {
|
||||||
var args setting.ArgWorkPathAndCustomConf
|
var args setting.ArgWorkPathAndCustomConf
|
||||||
// from children to parent, check the global flags
|
// from children to parent, check the global flags
|
||||||
for _, curCtx := range ctx.Lineage() {
|
for _, curCtx := range cli.Lineage() {
|
||||||
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
||||||
args.WorkPath = curCtx.String("work-path")
|
args.WorkPath = curCtx.String("work-path")
|
||||||
}
|
}
|
||||||
|
@ -107,15 +107,15 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
if ctx.Bool("help") || action == nil {
|
if cli.Bool("help") || action == nil {
|
||||||
// the default behavior of "urfave/cli": "nil action" means "show help"
|
// the default behavior of "urfave/cli": "nil action" means "show help"
|
||||||
return cmdHelp().Action(ctx)
|
return cmdHelp().Action(ctx, cli)
|
||||||
}
|
}
|
||||||
return action(ctx)
|
return action(ctx, cli)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainApp(version, versionExtra string) *cli.App {
|
func NewMainApp(version, versionExtra string) *cli.Command {
|
||||||
path, err := os.Executable()
|
path, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -124,7 +124,7 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
|
|
||||||
subCmdsStandalone := make([]*cli.Command, 0, 10)
|
subCmdsStandalone := make([]*cli.Command, 0, 10)
|
||||||
subCmdWithConfig := make([]*cli.Command, 0, 10)
|
subCmdWithConfig := make([]*cli.Command, 0, 10)
|
||||||
globalFlags := make([]cli.Flag, 0, 10)
|
globalFlags := func() []cli.Flag { return []cli.Flag{} }
|
||||||
|
|
||||||
//
|
//
|
||||||
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
||||||
|
@ -133,14 +133,16 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
if executable == "forgejo-cli" {
|
if executable == "forgejo-cli" {
|
||||||
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdActions(context.Background()))
|
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdActions(context.Background()))
|
||||||
subCmdWithConfig = append(subCmdWithConfig, forgejo.CmdF3(context.Background()))
|
subCmdWithConfig = append(subCmdWithConfig, forgejo.CmdF3(context.Background()))
|
||||||
globalFlags = append(globalFlags, []cli.Flag{
|
globalFlags = func() []cli.Flag {
|
||||||
&cli.BoolFlag{
|
return []cli.Flag{
|
||||||
Name: "quiet",
|
&cli.BoolFlag{
|
||||||
},
|
Name: "quiet",
|
||||||
&cli.BoolFlag{
|
},
|
||||||
Name: "verbose",
|
&cli.BoolFlag{
|
||||||
},
|
Name: "verbose",
|
||||||
}...)
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
||||||
|
@ -149,55 +151,54 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
// binary and rename it to forgejo if they want.
|
// binary and rename it to forgejo if they want.
|
||||||
//
|
//
|
||||||
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdForgejo(context.Background()))
|
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdForgejo(context.Background()))
|
||||||
subCmdWithConfig = append(subCmdWithConfig, CmdActions)
|
subCmdWithConfig = append(subCmdWithConfig, cmdActions())
|
||||||
}
|
}
|
||||||
|
|
||||||
return innerNewMainApp(version, versionExtra, subCmdsStandalone, subCmdWithConfig, globalFlags)
|
return innerNewMainApp(version, versionExtra, subCmdsStandalone, subCmdWithConfig, globalFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs []cli.Flag) *cli.App {
|
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs func() []cli.Flag) *cli.Command {
|
||||||
app := cli.NewApp()
|
app := &cli.Command{}
|
||||||
app.HelpName = "forgejo"
|
|
||||||
app.Name = "Forgejo"
|
app.Name = "Forgejo"
|
||||||
app.Usage = "Beyond coding. We forge."
|
app.Usage = "Beyond coding. We forge."
|
||||||
app.Description = `By default, forgejo will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".`
|
app.Description = `By default, forgejo will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".`
|
||||||
app.Version = version + versionExtra
|
app.Version = version + versionExtra
|
||||||
app.EnableBashCompletion = true
|
app.EnableShellCompletion = true
|
||||||
|
|
||||||
// these sub-commands need to use config file
|
// these sub-commands need to use config file
|
||||||
subCmdWithConfig := []*cli.Command{
|
subCmdWithConfig := []*cli.Command{
|
||||||
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
||||||
CmdWeb,
|
cmdWeb(),
|
||||||
CmdServ,
|
cmdServ(),
|
||||||
CmdHook,
|
cmdHook(),
|
||||||
CmdKeys,
|
cmdKeys(),
|
||||||
CmdDump,
|
cmdDump(),
|
||||||
CmdAdmin,
|
cmdAdmin(),
|
||||||
CmdMigrate,
|
cmdMigrate(),
|
||||||
CmdDoctor,
|
cmdDoctor(),
|
||||||
CmdManager,
|
cmdManager(),
|
||||||
CmdEmbedded,
|
cmdEmbedded(),
|
||||||
CmdMigrateStorage,
|
cmdMigrateStorage(),
|
||||||
CmdDumpRepository,
|
cmdDumpRepository(),
|
||||||
CmdRestoreRepository,
|
cmdRestoreRepository(),
|
||||||
}
|
}
|
||||||
|
|
||||||
subCmdWithConfig = append(subCmdWithConfig, subCmdWithConfigArgs...)
|
subCmdWithConfig = append(subCmdWithConfig, subCmdWithConfigArgs...)
|
||||||
|
|
||||||
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
||||||
subCmdStandalone := []*cli.Command{
|
subCmdStandalone := []*cli.Command{
|
||||||
CmdCert,
|
cmdCert(),
|
||||||
CmdGenerate,
|
cmdGenerate(),
|
||||||
CmdDocs,
|
|
||||||
}
|
}
|
||||||
subCmdStandalone = append(subCmdStandalone, subCmdsStandaloneArgs...)
|
subCmdStandalone = append(subCmdStandalone, subCmdsStandaloneArgs...)
|
||||||
|
|
||||||
app.DefaultCommand = CmdWeb.Name
|
app.DefaultCommand = cmdWeb().Name
|
||||||
|
|
||||||
globalFlags := appGlobalFlags()
|
globalFlags := func() []cli.Flag {
|
||||||
globalFlags = append(globalFlags, globalFlagsArgs...)
|
return append(appGlobalFlags(), globalFlagsArgs()...)
|
||||||
|
}
|
||||||
app.Flags = append(app.Flags, cli.VersionFlag)
|
app.Flags = append(app.Flags, cli.VersionFlag)
|
||||||
app.Flags = append(app.Flags, globalFlags...)
|
app.Flags = append(app.Flags, globalFlags()...)
|
||||||
app.HideHelp = true // use our own help action to show helps (with more information like default config)
|
app.HideHelp = true // use our own help action to show helps (with more information like default config)
|
||||||
app.Before = PrepareConsoleLoggerLevel(log.INFO)
|
app.Before = PrepareConsoleLoggerLevel(log.INFO)
|
||||||
for i := range subCmdWithConfig {
|
for i := range subCmdWithConfig {
|
||||||
|
@ -210,8 +211,8 @@ func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmd
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMainApp(app *cli.App, args ...string) error {
|
func RunMainApp(app *cli.Command, args ...string) error {
|
||||||
err := app.Run(args)
|
err := app.Run(context.Background(), args)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -220,7 +221,7 @@ func RunMainApp(app *cli.App, args ...string) error {
|
||||||
cli.OsExiter(1)
|
cli.OsExiter(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
_, _ = fmt.Fprintf(app.Root().ErrWriter, "Command error: %v\n", err)
|
||||||
cli.OsExiter(1)
|
cli.OsExiter(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -17,7 +18,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -28,10 +29,10 @@ func makePathOutput(workPath, customPath, customConf string) string {
|
||||||
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
|
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
|
func newTestApp(testCmdAction func(_ context.Context, ctx *cli.Command) error) *cli.Command {
|
||||||
app := NewMainApp("version", "version-extra")
|
app := NewMainApp("version", "version-extra")
|
||||||
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
|
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
|
||||||
prepareSubcommandWithConfig(testCmd, appGlobalFlags())
|
prepareSubcommandWithConfig(testCmd, appGlobalFlags)
|
||||||
app.Commands = append(app.Commands, testCmd)
|
app.Commands = append(app.Commands, testCmd)
|
||||||
app.DefaultCommand = testCmd.Name
|
app.DefaultCommand = testCmd.Name
|
||||||
return app
|
return app
|
||||||
|
@ -43,7 +44,7 @@ type runResult struct {
|
||||||
ExitCode int
|
ExitCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestApp(app *cli.App, args ...string) (runResult, error) {
|
func runTestApp(app *cli.Command, args ...string) (runResult, error) {
|
||||||
outBuf := new(strings.Builder)
|
outBuf := new(strings.Builder)
|
||||||
errBuf := new(strings.Builder)
|
errBuf := new(strings.Builder)
|
||||||
app.Writer = outBuf
|
app.Writer = outBuf
|
||||||
|
@ -66,7 +67,6 @@ func TestCliCmd(t *testing.T) {
|
||||||
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
|
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
|
||||||
|
|
||||||
cli.CommandHelpTemplate = "(command help template)"
|
cli.CommandHelpTemplate = "(command help template)"
|
||||||
cli.AppHelpTemplate = "(app help template)"
|
|
||||||
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
@ -110,12 +110,17 @@ func TestCliCmd(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
app := newTestApp(func(ctx *cli.Context) error {
|
|
||||||
_, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.cmd, func(t *testing.T) {
|
t.Run(c.cmd, func(t *testing.T) {
|
||||||
|
defer test.MockProtect(&setting.AppWorkPath)()
|
||||||
|
defer test.MockProtect(&setting.CustomPath)()
|
||||||
|
defer test.MockProtect(&setting.CustomConf)()
|
||||||
|
|
||||||
|
app := newTestApp(func(_ context.Context, ctx *cli.Command) error {
|
||||||
|
_, _ = fmt.Fprint(ctx.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
for k, v := range c.env {
|
for k, v := range c.env {
|
||||||
t.Setenv(k, v)
|
t.Setenv(k, v)
|
||||||
}
|
}
|
||||||
|
@ -123,34 +128,34 @@ func TestCliCmd(t *testing.T) {
|
||||||
r, err := runTestApp(app, args...)
|
r, err := runTestApp(app, args...)
|
||||||
require.NoError(t, err, c.cmd)
|
require.NoError(t, err, c.cmd)
|
||||||
assert.NotEmpty(t, c.exp, c.cmd)
|
assert.NotEmpty(t, c.exp, c.cmd)
|
||||||
assert.Contains(t, r.Stdout, c.exp, c.cmd)
|
assert.Contains(t, r.Stdout, c.exp, c.cmd+"\n"+r.Stdout)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCliCmdError(t *testing.T) {
|
func TestCliCmdError(t *testing.T) {
|
||||||
app := newTestApp(func(ctx *cli.Context) error { return errors.New("normal error") })
|
app := newTestApp(func(_ context.Context, ctx *cli.Command) error { return errors.New("normal error") })
|
||||||
r, err := runTestApp(app, "./gitea", "test-cmd")
|
r, err := runTestApp(app, "./gitea", "test-cmd")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Empty(t, r.Stdout)
|
||||||
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return cli.Exit("exit error", 2) })
|
app = newTestApp(func(_ context.Context, ctx *cli.Command) error { return cli.Exit("exit error", 2) })
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Equal(t, 2, r.ExitCode)
|
assert.Equal(t, 2, r.ExitCode)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Empty(t, r.Stdout)
|
||||||
assert.Equal(t, "exit error\n", r.Stderr)
|
assert.Equal(t, "exit error\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
app = newTestApp(func(_ context.Context, ctx *cli.Command) error { return nil })
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout)
|
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
||||||
assert.Empty(t, r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
|
assert.Empty(t, r.Stdout)
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
app = newTestApp(func(_ context.Context, ctx *cli.Command) error { return nil })
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
||||||
|
|
|
@ -4,30 +4,34 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// CmdManager represents the manager command
|
||||||
// CmdManager represents the manager command
|
func cmdManager() *cli.Command {
|
||||||
CmdManager = &cli.Command{
|
return &cli.Command{
|
||||||
Name: "manager",
|
Name: "manager",
|
||||||
Usage: "Manage the running forgejo process",
|
Usage: "Manage the running forgejo process",
|
||||||
Description: "This is a command for managing the running forgejo process",
|
Description: "This is a command for managing the running forgejo process",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdShutdown,
|
subcmdShutdown(),
|
||||||
subcmdRestart,
|
subcmdRestart(),
|
||||||
subcmdReloadTemplates,
|
subcmdReloadTemplates(),
|
||||||
subcmdFlushQueues,
|
subcmdFlushQueues(),
|
||||||
subcmdLogging,
|
subcmdLogging(),
|
||||||
subCmdProcesses,
|
subCmdProcesses(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
subcmdShutdown = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func subcmdShutdown() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "shutdown",
|
Name: "shutdown",
|
||||||
Usage: "Gracefully shutdown the running process",
|
Usage: "Gracefully shutdown the running process",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -37,7 +41,10 @@ var (
|
||||||
},
|
},
|
||||||
Action: runShutdown,
|
Action: runShutdown,
|
||||||
}
|
}
|
||||||
subcmdRestart = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func subcmdRestart() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "restart",
|
Name: "restart",
|
||||||
Usage: "Gracefully restart the running process - (not implemented for windows servers)",
|
Usage: "Gracefully restart the running process - (not implemented for windows servers)",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -47,7 +54,10 @@ var (
|
||||||
},
|
},
|
||||||
Action: runRestart,
|
Action: runRestart,
|
||||||
}
|
}
|
||||||
subcmdReloadTemplates = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func subcmdReloadTemplates() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "reload-templates",
|
Name: "reload-templates",
|
||||||
Usage: "Reload template files in the running process",
|
Usage: "Reload template files in the running process",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -57,7 +67,10 @@ var (
|
||||||
},
|
},
|
||||||
Action: runReloadTemplates,
|
Action: runReloadTemplates,
|
||||||
}
|
}
|
||||||
subcmdFlushQueues = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func subcmdFlushQueues() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "flush-queues",
|
Name: "flush-queues",
|
||||||
Usage: "Flush queues in the running process",
|
Usage: "Flush queues in the running process",
|
||||||
Action: runFlushQueues,
|
Action: runFlushQueues,
|
||||||
|
@ -76,7 +89,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
subCmdProcesses = &cli.Command{
|
}
|
||||||
|
|
||||||
|
func subCmdProcesses() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "processes",
|
Name: "processes",
|
||||||
Usage: "Display running processes within the current process",
|
Usage: "Display running processes within the current process",
|
||||||
Action: runProcesses,
|
Action: runProcesses,
|
||||||
|
@ -106,10 +122,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runShutdown(c *cli.Context) error {
|
func runShutdown(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -117,8 +133,8 @@ func runShutdown(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestart(c *cli.Context) error {
|
func runRestart(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -126,8 +142,8 @@ func runRestart(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runReloadTemplates(c *cli.Context) error {
|
func runReloadTemplates(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -135,8 +151,8 @@ func runReloadTemplates(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFlushQueues(c *cli.Context) error {
|
func runFlushQueues(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -144,8 +160,8 @@ func runFlushQueues(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runProcesses(c *cli.Context) error {
|
func runProcesses(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -11,11 +12,11 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func defaultLoggingFlags() []cli.Flag {
|
||||||
defaultLoggingFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "logger",
|
Name: "logger",
|
||||||
Usage: `Logger name - will default to "default"`,
|
Usage: `Logger name - will default to "default"`,
|
||||||
|
@ -56,11 +57,13 @@ var (
|
||||||
Name: "debug",
|
Name: "debug",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdLogging = &cli.Command{
|
func subcmdLogging() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "logging",
|
Name: "logging",
|
||||||
Usage: "Adjust logging commands",
|
Usage: "Adjust logging commands",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "pause",
|
Name: "pause",
|
||||||
Usage: "Pause logging (Forgejo will buffer logs up to a certain point and will drop them after that point)",
|
Usage: "Pause logging (Forgejo will buffer logs up to a certain point and will drop them after that point)",
|
||||||
|
@ -104,11 +107,11 @@ var (
|
||||||
}, {
|
}, {
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "Add a logger",
|
Usage: "Add a logger",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Usage: "Add a file logger",
|
Usage: "Add a file logger",
|
||||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
Flags: append(defaultLoggingFlags(), []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "filename",
|
Name: "filename",
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"f"},
|
||||||
|
@ -152,7 +155,7 @@ var (
|
||||||
}, {
|
}, {
|
||||||
Name: "conn",
|
Name: "conn",
|
||||||
Usage: "Add a net conn logger",
|
Usage: "Add a net conn logger",
|
||||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
Flags: append(defaultLoggingFlags(), []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "reconnect-on-message",
|
Name: "reconnect-on-message",
|
||||||
Aliases: []string{"R"},
|
Aliases: []string{"R"},
|
||||||
|
@ -193,10 +196,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runRemoveLogger(c *cli.Context) error {
|
func runRemoveLogger(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -210,8 +213,8 @@ func runRemoveLogger(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddConnLogger(c *cli.Context) error {
|
func runAddConnLogger(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -237,11 +240,11 @@ func runAddConnLogger(c *cli.Context) error {
|
||||||
if c.IsSet("reconnect-on-message") {
|
if c.IsSet("reconnect-on-message") {
|
||||||
vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
|
vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
|
||||||
}
|
}
|
||||||
return commonAddLogger(c, mode, vals)
|
return commonAddLogger(ctx, c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddFileLogger(c *cli.Context) error {
|
func runAddFileLogger(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -270,10 +273,10 @@ func runAddFileLogger(c *cli.Context) error {
|
||||||
if c.IsSet("compression-level") {
|
if c.IsSet("compression-level") {
|
||||||
vals["compressionLevel"] = c.Int("compression-level")
|
vals["compressionLevel"] = c.Int("compression-level")
|
||||||
}
|
}
|
||||||
return commonAddLogger(c, mode, vals)
|
return commonAddLogger(ctx, c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[string]any) error {
|
||||||
if len(c.String("level")) > 0 {
|
if len(c.String("level")) > 0 {
|
||||||
vals["level"] = log.LevelFromString(c.String("level")).String()
|
vals["level"] = log.LevelFromString(c.String("level")).String()
|
||||||
}
|
}
|
||||||
|
@ -300,15 +303,15 @@ func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
||||||
if c.IsSet("writer") {
|
if c.IsSet("writer") {
|
||||||
writer = c.String("writer")
|
writer = c.String("writer")
|
||||||
}
|
}
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
extra := private.AddLogger(ctx, logger, writer, mode, vals)
|
extra := private.AddLogger(ctx, logger, writer, mode, vals)
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPauseLogging(c *cli.Context) error {
|
func runPauseLogging(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -317,8 +320,8 @@ func runPauseLogging(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runResumeLogging(c *cli.Context) error {
|
func runResumeLogging(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -327,8 +330,8 @@ func runResumeLogging(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runReleaseReopenLogging(c *cli.Context) error {
|
func runReleaseReopenLogging(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -337,8 +340,8 @@ func runReleaseReopenLogging(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSetLogSQL(c *cli.Context) error {
|
func runSetLogSQL(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
|
||||||
|
|
|
@ -11,19 +11,21 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrate represents the available migrate sub-command.
|
// CmdMigrate represents the available migrate sub-command.
|
||||||
var CmdMigrate = &cli.Command{
|
func cmdMigrate() *cli.Command {
|
||||||
Name: "migrate",
|
return &cli.Command{
|
||||||
Usage: "Migrate the database",
|
Name: "migrate",
|
||||||
Description: "This is a command for migrating the database, so that you can run 'forgejo admin user create' before starting the server.",
|
Usage: "Migrate the database",
|
||||||
Action: runMigrate,
|
Description: "This is a command for migrating the database, so that you can run 'forgejo admin user create' before starting the server.",
|
||||||
|
Action: runMigrate,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrate(ctx *cli.Context) error {
|
func runMigrate(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -22,79 +22,81 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/modules/storage"
|
"forgejo.org/modules/storage"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrateStorage represents the available migrate storage sub-command.
|
// CmdMigrateStorage represents the available migrate storage sub-command.
|
||||||
var CmdMigrateStorage = &cli.Command{
|
func cmdMigrateStorage() *cli.Command {
|
||||||
Name: "migrate-storage",
|
return &cli.Command{
|
||||||
Usage: "Migrate the storage",
|
Name: "migrate-storage",
|
||||||
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
Usage: "Migrate the storage",
|
||||||
Action: runMigrateStorage,
|
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
||||||
Flags: []cli.Flag{
|
Action: runMigrateStorage,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "type",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"t"},
|
Name: "type",
|
||||||
Value: "",
|
Aliases: []string{"t"},
|
||||||
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'",
|
Value: "",
|
||||||
|
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "storage",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "New storage type: local (default) or minio",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "path",
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "New storage placement if store is local (leave blank for default)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-endpoint",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage endpoint",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-access-key-id",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage accessKeyID",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-secret-access-key",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage secretAccessKey",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-bucket",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage bucket",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-location",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage location to create bucket",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-base-path",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage base path on the bucket",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "minio-use-ssl",
|
||||||
|
Usage: "Enable SSL for minio",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "minio-insecure-skip-verify",
|
||||||
|
Usage: "Skip SSL verification",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-checksum-algorithm",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio checksum algorithm (default/md5)",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "storage",
|
|
||||||
Aliases: []string{"s"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "New storage type: local (default) or minio",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "path",
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "New storage placement if store is local (leave blank for default)",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-endpoint",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage endpoint",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-access-key-id",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage accessKeyID",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-secret-access-key",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage secretAccessKey",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-bucket",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage bucket",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-location",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage location to create bucket",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-base-path",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage base path on the bucket",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "minio-use-ssl",
|
|
||||||
Usage: "Enable SSL for minio",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "minio-insecure-skip-verify",
|
|
||||||
Usage: "Skip SSL verification",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-checksum-algorithm",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio checksum algorithm (default/md5)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||||
|
@ -182,8 +184,8 @@ func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStora
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrateStorage(ctx *cli.Context) error {
|
func runMigrateStorage(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -4,52 +4,55 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdRestoreRepository represents the available restore a repository sub-command.
|
// CmdRestoreRepository represents the available restore a repository sub-command.
|
||||||
var CmdRestoreRepository = &cli.Command{
|
func cmdRestoreRepository() *cli.Command {
|
||||||
Name: "restore-repo",
|
return &cli.Command{
|
||||||
Usage: "Restore the repository from disk",
|
Name: "restore-repo",
|
||||||
Description: "This is a command for restoring the repository data.",
|
Usage: "Restore the repository from disk",
|
||||||
Action: runRestoreRepository,
|
Description: "This is a command for restoring the repository data.",
|
||||||
Flags: []cli.Flag{
|
Action: runRestoreRepository,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "repo_dir",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"r"},
|
Name: "repo_dir",
|
||||||
Value: "./data",
|
Aliases: []string{"r"},
|
||||||
Usage: "Repository dir path to restore from",
|
Value: "./data",
|
||||||
},
|
Usage: "Repository dir path to restore from",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "owner_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "owner_name",
|
||||||
Usage: "Restore destination owner name",
|
Value: "",
|
||||||
},
|
Usage: "Restore destination owner name",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "repo_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "repo_name",
|
||||||
Usage: "Restore destination repository name",
|
Value: "",
|
||||||
},
|
Usage: "Restore destination repository name",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "units",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "units",
|
||||||
Usage: `Which items will be restored, one or more units should be separated as comma.
|
Value: "",
|
||||||
|
Usage: `Which items will be restored, one or more units should be separated as comma.
|
||||||
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "validation",
|
||||||
|
Usage: "Sanity check the content of the files before trying to load them",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "validation",
|
|
||||||
Usage: "Sanity check the content of the files before trying to load them",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestoreRepository(c *cli.Context) error {
|
func runRestoreRepository(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
34
cmd/serv.go
34
cmd/serv.go
|
@ -33,7 +33,7 @@ import (
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/kballard/go-shellquote"
|
"github.com/kballard/go-shellquote"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -41,20 +41,22 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdServ represents the available serv sub-command.
|
// CmdServ represents the available serv sub-command.
|
||||||
var CmdServ = &cli.Command{
|
func cmdServ() *cli.Command {
|
||||||
Name: "serv",
|
return &cli.Command{
|
||||||
Usage: "(internal) Should only be called by SSH shell",
|
Name: "serv",
|
||||||
Description: "Serv provides access auth for repositories",
|
Usage: "(internal) Should only be called by SSH shell",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Description: "Serv provides access auth for repositories",
|
||||||
Action: runServ,
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Flags: []cli.Flag{
|
Action: runServ,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "enable-pprof",
|
&cli.BoolFlag{
|
||||||
|
Name: "enable-pprof",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "debug",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "debug",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(ctx context.Context, debug, gitNeeded bool) {
|
func setup(ctx context.Context, debug, gitNeeded bool) {
|
||||||
|
@ -131,8 +133,8 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServ(c *cli.Context) error {
|
func runServ(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// FIXME: This needs to internationalised
|
// FIXME: This needs to internationalised
|
||||||
|
|
84
cmd/web.go
84
cmd/web.go
|
@ -26,48 +26,50 @@ import (
|
||||||
"forgejo.org/routers/install"
|
"forgejo.org/routers/install"
|
||||||
|
|
||||||
"github.com/felixge/fgprof"
|
"github.com/felixge/fgprof"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PIDFile could be set from build tag
|
// PIDFile could be set from build tag
|
||||||
var PIDFile = "/run/gitea.pid"
|
var PIDFile = "/run/gitea.pid"
|
||||||
|
|
||||||
// CmdWeb represents the available web sub-command.
|
// CmdWeb represents the available web sub-command.
|
||||||
var CmdWeb = &cli.Command{
|
func cmdWeb() *cli.Command {
|
||||||
Name: "web",
|
return &cli.Command{
|
||||||
Usage: "Start the Forgejo web server",
|
Name: "web",
|
||||||
Description: `The Forgejo web server is the only thing you need to run,
|
Usage: "Start the Forgejo web server",
|
||||||
|
Description: `The Forgejo web server is the only thing you need to run,
|
||||||
and it takes care of all the other things for you`,
|
and it takes care of all the other things for you`,
|
||||||
Before: PrepareConsoleLoggerLevel(log.INFO),
|
Before: PrepareConsoleLoggerLevel(log.INFO),
|
||||||
Action: runWeb,
|
Action: runWeb,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "port",
|
Name: "port",
|
||||||
Aliases: []string{"p"},
|
Aliases: []string{"p"},
|
||||||
Value: "3000",
|
Value: "3000",
|
||||||
Usage: "Temporary port number to prevent conflict",
|
Usage: "Temporary port number to prevent conflict",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "install-port",
|
||||||
|
Value: "3000",
|
||||||
|
Usage: "Temporary port number to run the install page on to prevent conflict",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "pid",
|
||||||
|
Aliases: []string{"P"},
|
||||||
|
Value: PIDFile,
|
||||||
|
Usage: "Custom pid file path",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "quiet",
|
||||||
|
Aliases: []string{"q"},
|
||||||
|
Usage: "Only display Fatal logging errors until logging is set-up",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "verbose",
|
||||||
|
Usage: "Set initial logging to TRACE level until logging is properly set-up",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "install-port",
|
|
||||||
Value: "3000",
|
|
||||||
Usage: "Temporary port number to run the install page on to prevent conflict",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "pid",
|
|
||||||
Aliases: []string{"P"},
|
|
||||||
Value: PIDFile,
|
|
||||||
Usage: "Custom pid file path",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "quiet",
|
|
||||||
Aliases: []string{"q"},
|
|
||||||
Usage: "Only display Fatal logging errors until logging is set-up",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "verbose",
|
|
||||||
Usage: "Set initial logging to TRACE level until logging is properly set-up",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHTTPRedirector() {
|
func runHTTPRedirector() {
|
||||||
|
@ -128,7 +130,7 @@ func showWebStartupMessage(msg string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstall(ctx *cli.Context) error {
|
func serveInstall(_ context.Context, ctx *cli.Command) error {
|
||||||
showWebStartupMessage("Prepare to run install page")
|
showWebStartupMessage("Prepare to run install page")
|
||||||
|
|
||||||
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
||||||
|
@ -161,7 +163,7 @@ func serveInstall(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstalled(ctx *cli.Context) error {
|
func serveInstalled(_ context.Context, ctx *cli.Command) error {
|
||||||
setting.InitCfgProvider(setting.CustomConf)
|
setting.InitCfgProvider(setting.CustomConf)
|
||||||
setting.LoadCommonSettings()
|
setting.LoadCommonSettings()
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
@ -233,7 +235,7 @@ func servePprof() {
|
||||||
finished()
|
finished()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWeb(ctx *cli.Context) error {
|
func runWeb(ctx context.Context, cli *cli.Command) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
if panicked := recover(); panicked != nil {
|
if panicked := recover(); panicked != nil {
|
||||||
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
||||||
|
@ -251,12 +253,12 @@ func runWeb(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set pid file setting
|
// Set pid file setting
|
||||||
if ctx.IsSet("pid") {
|
if cli.IsSet("pid") {
|
||||||
createPIDFile(ctx.String("pid"))
|
createPIDFile(cli.String("pid"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setting.InstallLock {
|
if !setting.InstallLock {
|
||||||
if err := serveInstall(ctx); err != nil {
|
if err := serveInstall(ctx, cli); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -267,7 +269,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
go servePprof()
|
go servePprof()
|
||||||
}
|
}
|
||||||
|
|
||||||
return serveInstalled(ctx)
|
return serveInstalled(ctx, cli)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPort(port string) error {
|
func setPort(port string) error {
|
||||||
|
|
|
@ -4,16 +4,17 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Name = "environment-to-ini"
|
app.Name = "environment-to-ini"
|
||||||
app.Usage = "Use provided environment to update configuration ini"
|
app.Usage = "Use provided environment to update configuration ini"
|
||||||
app.Description = `As a helper to allow docker users to update the forgejo configuration
|
app.Description = `As a helper to allow docker users to update the forgejo configuration
|
||||||
|
@ -72,13 +73,13 @@ func main() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Action = runEnvironmentToIni
|
app.Action = runEnvironmentToIni
|
||||||
err := app.Run(os.Args)
|
err := app.Run(context.Background(), os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to run app with %s: %v", os.Args, err)
|
log.Fatal("Failed to run app with %s: %v", os.Args, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runEnvironmentToIni(c *cli.Context) error {
|
func runEnvironmentToIni(ctx context.Context, c *cli.Command) error {
|
||||||
// the config system may change the environment variables, so get a copy first, to be used later
|
// the config system may change the environment variables, so get a copy first, to be used later
|
||||||
env := append([]string{}, os.Environ()...)
|
env := append([]string{}, os.Environ()...)
|
||||||
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
||||||
|
|
9
go.mod
9
go.mod
|
@ -5,7 +5,7 @@ go 1.24
|
||||||
toolchain go1.24.3
|
toolchain go1.24.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.forgejo.org/f3/gof3/v3 v3.10.6
|
code.forgejo.org/f3/gof3/v3 v3.10.8
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251
|
||||||
code.forgejo.org/forgejo/go-rpmutils v1.0.0
|
code.forgejo.org/forgejo/go-rpmutils v1.0.0
|
||||||
code.forgejo.org/forgejo/levelqueue v1.0.0
|
code.forgejo.org/forgejo/levelqueue v1.0.0
|
||||||
|
@ -94,12 +94,13 @@ require (
|
||||||
github.com/syndtr/goleveldb v1.0.0
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
github.com/ulikunitz/xz v0.5.12
|
github.com/ulikunitz/xz v0.5.12
|
||||||
github.com/urfave/cli/v2 v2.27.6
|
github.com/urfave/cli/v2 v2.27.6
|
||||||
|
github.com/urfave/cli/v3 v3.3.3
|
||||||
github.com/valyala/fastjson v1.6.4
|
github.com/valyala/fastjson v1.6.4
|
||||||
github.com/yohcop/openid-go v1.0.1
|
github.com/yohcop/openid-go v1.0.1
|
||||||
github.com/yuin/goldmark v1.7.12
|
github.com/yuin/goldmark v1.7.12
|
||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||||
gitlab.com/gitlab-org/api/client-go v0.126.0
|
gitlab.com/gitlab-org/api/client-go v0.129.0
|
||||||
go.uber.org/mock v0.5.1
|
go.uber.org/mock v0.5.2
|
||||||
golang.org/x/crypto v0.38.0
|
golang.org/x/crypto v0.38.0
|
||||||
golang.org/x/image v0.27.0
|
golang.org/x/image v0.27.0
|
||||||
golang.org/x/net v0.40.0
|
golang.org/x/net v0.40.0
|
||||||
|
@ -237,7 +238,7 @@ require (
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
go.uber.org/zap/exp v0.3.0 // indirect
|
go.uber.org/zap/exp v0.3.0 // indirect
|
||||||
golang.org/x/mod v0.24.0 // indirect
|
golang.org/x/mod v0.24.0 // indirect
|
||||||
golang.org/x/time v0.10.0 // indirect
|
golang.org/x/time v0.11.0 // indirect
|
||||||
golang.org/x/tools v0.31.0 // indirect
|
golang.org/x/tools v0.31.0 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
|
|
18
go.sum
18
go.sum
|
@ -1,7 +1,7 @@
|
||||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||||
code.forgejo.org/f3/gof3/v3 v3.10.6 h1:Ru/Iz+pqM8IPi7atUHE7+q7v3O3DRbYgMFqrFTsO1m8=
|
code.forgejo.org/f3/gof3/v3 v3.10.8 h1:cL5XgOcKffqMdKDOqGCXfMc2OBX89xYvGSj2mz3E/VQ=
|
||||||
code.forgejo.org/f3/gof3/v3 v3.10.6/go.mod h1:K6lQCWQIyN/5rjP/OJL9fMA6fd++satndE20w/I6Kss=
|
code.forgejo.org/f3/gof3/v3 v3.10.8/go.mod h1:ovgb7R8o7k6poQKQ+KWXHOD9uIoanB6tNSmA3kKOMCI=
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU=
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU=
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM=
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM=
|
||||||
code.forgejo.org/forgejo/act v1.26.0 h1:6mTmoaw7d/WpYiw/Pw6AaypxFdgJog5OFi/PMEgEbxs=
|
code.forgejo.org/forgejo/act v1.26.0 h1:6mTmoaw7d/WpYiw/Pw6AaypxFdgJog5OFi/PMEgEbxs=
|
||||||
|
@ -535,6 +535,8 @@ github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
||||||
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
|
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
|
||||||
|
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
|
||||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
@ -562,8 +564,8 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
|
||||||
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
||||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||||
gitlab.com/gitlab-org/api/client-go v0.126.0 h1:VV5TdkF6pMbEdFGvbR2CwEgJwg6qdg1u3bj5eD2tiWk=
|
gitlab.com/gitlab-org/api/client-go v0.129.0 h1:o9KLn6fezmxBQWYnQrnilwyuOjlx4206KP0bUn3HuBE=
|
||||||
gitlab.com/gitlab-org/api/client-go v0.126.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAjE7UeNatu2VWHRf4/LE=
|
gitlab.com/gitlab-org/api/client-go v0.129.0/go.mod h1:ZhSxLAWadqP6J9lMh40IAZOlOxBLPRh7yFOXR/bMJWM=
|
||||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
@ -571,8 +573,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
@ -684,8 +686,8 @@ golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
|
1
release-notes/8035.md
Normal file
1
release-notes/8035.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
The `forgejo docs` command is deprecated and CLI errors are now displayed on stderr instead of stdout. These breaking changes happened because the package used to parse the command line arguments was [upgraded from v2 to v3](https://cli.urfave.org/migrate-v2-to-v3/). A [separate project was initiated](https://github.com/urfave/cli-docs) to re-implement the `docs` command, but it is not yet production ready.
|
|
@ -213,7 +213,7 @@ func (g *GitlabDownloader) GetTopics() ([]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return gr.TagList, err
|
return gr.Topics, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMilestones returns milestones
|
// GetMilestones returns milestones
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ import (
|
||||||
|
|
||||||
func Test_Cmd_AdminUser(t *testing.T) {
|
func Test_Cmd_AdminUser(t *testing.T) {
|
||||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||||
for _, testCase := range []struct {
|
for i, testCase := range []struct {
|
||||||
name string
|
name string
|
||||||
options []string
|
options []string
|
||||||
mustChangePassword bool
|
mustChangePassword bool
|
||||||
|
@ -46,7 +47,7 @@ func Test_Cmd_AdminUser(t *testing.T) {
|
||||||
} {
|
} {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
name := "testuser"
|
name := fmt.Sprintf("testuser%d", i)
|
||||||
|
|
||||||
options := []string{"user", "create", "--username", name, "--password", "password", "--email", name + "@example.com"}
|
options := []string{"user", "create", "--username", name, "--password", "password", "--email", name + "@example.com"}
|
||||||
options = append(options, testCase.options...)
|
options = append(options, testCase.options...)
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
f3_tests "code.forgejo.org/f3/gof3/v3/tree/tests/f3"
|
f3_tests "code.forgejo.org/f3/gof3/v3/tree/tests/f3"
|
||||||
f3_tests_forge "code.forgejo.org/f3/gof3/v3/tree/tests/f3/forge"
|
f3_tests_forge "code.forgejo.org/f3/gof3/v3/tree/tests/f3/forge"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runApp(ctx context.Context, args ...string) (string, error) {
|
func runApp(ctx context.Context, args ...string) (string, error) {
|
||||||
|
@ -33,10 +33,10 @@ func runApp(ctx context.Context, args ...string) (string, error) {
|
||||||
ctx = f3_logger.ContextSetLogger(ctx, l)
|
ctx = f3_logger.ContextSetLogger(ctx, l)
|
||||||
ctx = forgejo.ContextSetNoInit(ctx, true)
|
ctx = forgejo.ContextSetNoInit(ctx, true)
|
||||||
|
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
|
|
||||||
app.Writer = l.GetBuffer()
|
app.Root().Writer = l.GetBuffer()
|
||||||
app.ErrWriter = l.GetBuffer()
|
app.Root().ErrWriter = l.GetBuffer()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -48,7 +48,7 @@ func runApp(ctx context.Context, args ...string) (string, error) {
|
||||||
app.Commands = []*cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
forgejo.SubcmdF3Mirror(ctx),
|
forgejo.SubcmdF3Mirror(ctx),
|
||||||
}
|
}
|
||||||
err := app.Run(args)
|
err := app.Run(ctx, args)
|
||||||
|
|
||||||
fmt.Println(l.String())
|
fmt.Println(l.String())
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ func Test_CmdKeys(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
expectedOutput string
|
expectedOutput string
|
||||||
}{
|
}{
|
||||||
{"test_empty_1", []string{"--username=git", "--type=test", "--content=test"}, true, ""},
|
{"test_empty_1", []string{"--username=git", "--type=test", "--content=test"}, true, "Command error: internal API error response, status=500, err=public key does not exist [id: 0]\n"},
|
||||||
{"test_empty_2", []string{"-e", "git", "-u", "git", "-t", "test", "-k", "test"}, true, ""},
|
{"test_empty_2", []string{"-e", "git", "-u", "git", "-t", "test", "-k", "test"}, true, "Command error: internal API error response, status=500, err=public key does not exist [id: 0]\n"},
|
||||||
{
|
{
|
||||||
"with_key",
|
"with_key",
|
||||||
[]string{"-e", "git", "-u", "git", "-t", "ssh-rsa", "-k", "AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM="},
|
[]string{"-e", "git", "-u", "git", "-t", "ssh-rsa", "-k", "AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM="},
|
||||||
|
@ -44,10 +44,11 @@ func Test_CmdKeys(t *testing.T) {
|
||||||
}
|
}
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
assert.Equal(t, tt.expectedOutput, string(exitErr.Stderr))
|
||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.expectedOutput, out)
|
||||||
}
|
}
|
||||||
assert.Equal(t, tt.expectedOutput, out)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -109,6 +109,9 @@ func runMainAppWithStdin(stdin io.Reader, subcommand string, args ...string) (st
|
||||||
"GITEA_WORK_DIR="+setting.AppWorkPath)
|
"GITEA_WORK_DIR="+setting.AppWorkPath)
|
||||||
cmd.Stdin = stdin
|
cmd.Stdin = stdin
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
|
if ee, ok := err.(*exec.ExitError); ok {
|
||||||
|
log.Error("%s %v exit on error %s", os.Args[0], args, ee.Stderr)
|
||||||
|
}
|
||||||
return string(out), err
|
return string(out), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue