mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-10-10 19:32:02 +00:00
Merge remote-tracking branch 'upstream/forgejo' into port-32327
This commit is contained in:
commit
009a1bcf86
505 changed files with 13602 additions and 5442 deletions
|
@ -87,12 +87,24 @@ forgejo.org/modules/eventsource
|
|||
Event.String
|
||||
|
||||
forgejo.org/modules/forgefed
|
||||
NewForgeFollowFromAp
|
||||
NewForgeFollow
|
||||
ForgeFollow.MarshalJSON
|
||||
ForgeFollow.UnmarshalJSON
|
||||
ForgeFollow.Validate
|
||||
NewForgeUndoLike
|
||||
ForgeUndoLike.UnmarshalJSON
|
||||
ForgeUndoLike.Validate
|
||||
NewForgeUserActivityFromAp
|
||||
NewForgeUserActivity
|
||||
ForgeUserActivity.Validate
|
||||
NewPersonIDFromModel
|
||||
GetItemByType
|
||||
JSONUnmarshalerFn
|
||||
NotEmpty
|
||||
NewForgeUserActivityNoteFromAp
|
||||
newNote
|
||||
ForgeUserActivityNote.Validate
|
||||
ToRepository
|
||||
OnRepository
|
||||
|
||||
|
@ -204,6 +216,7 @@ forgejo.org/modules/util/filebuffer
|
|||
|
||||
forgejo.org/modules/validation
|
||||
IsErrNotValid
|
||||
ValidateIDExists
|
||||
|
||||
forgejo.org/modules/web
|
||||
RouteMock
|
||||
|
|
|
@ -28,7 +28,7 @@ jobs:
|
|||
|
||||
runs-on: docker
|
||||
container:
|
||||
image: data.forgejo.org/renovate/renovate:40.11.19
|
||||
image: data.forgejo.org/renovate/renovate:40.40.0
|
||||
|
||||
steps:
|
||||
- name: Load renovate repo cache
|
||||
|
|
14
Makefile
14
Makefile
|
@ -37,19 +37,18 @@ endif
|
|||
XGO_VERSION := go-1.21.x
|
||||
|
||||
AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.2.1 # renovate: datasource=go
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.3.0 # renovate: datasource=go
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.8.0 # renovate: datasource=go
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 # renovate: datasource=go
|
||||
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go
|
||||
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0 # renovate: datasource=go
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasource=go
|
||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go
|
||||
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.32.0 # renovate: datasource=go
|
||||
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.1 # renovate: datasource=go
|
||||
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.34.0 # renovate: datasource=go
|
||||
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.2 # renovate: datasource=go
|
||||
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.18.1 # renovate: datasource=go
|
||||
RENOVATE_NPM_PACKAGE ?= renovate@40.11.19 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
|
||||
RENOVATE_NPM_PACKAGE ?= renovate@40.40.0 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
|
||||
|
||||
# https://github.com/disposable-email-domains/disposable-email-domains/commits/main/
|
||||
DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ...
|
||||
|
@ -94,7 +93,7 @@ else
|
|||
# drop the "g" prefix prepended by git describe to the commit hash
|
||||
FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always 2>/dev/null | sed 's/^v//' | sed 's/\-g/-/')
|
||||
ifneq ($(FORGEJO_VERSION),)
|
||||
ifneq ($(GITEA_COMPATIBILITY),)
|
||||
ifeq ($(findstring $(GITEA_COMPATIBILITY),$(FORGEJO_VERSION)),)
|
||||
FORGEJO_VERSION := $(FORGEJO_VERSION)+$(GITEA_COMPATIBILITY)
|
||||
endif
|
||||
endif
|
||||
|
@ -557,7 +556,7 @@ test-check:
|
|||
|
||||
.PHONY: 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)
|
||||
|
||||
.PHONY: coverage
|
||||
|
@ -924,7 +923,6 @@ deps-tools:
|
|||
$(GO) install $(GOFUMPT_PACKAGE)
|
||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
$(GO) install $(GXZ_PACKAGE)
|
||||
$(GO) install $(MISSPELL_PACKAGE)
|
||||
$(GO) install $(SWAGGER_PACKAGE)
|
||||
$(GO) install $(XGO_PACKAGE)
|
||||
$(GO) install $(GO_LICENSES_PACKAGE)
|
||||
|
|
20
assets/go-licenses.json
generated
20
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
|
@ -52,7 +52,7 @@ func initBlueMondayPolicy() {
|
|||
policy.AllowAttrs("id").Matching(positionalPlaceholderRe).OnElements("code")
|
||||
|
||||
// Allowed elements with no attributes. Must be a recognized tagname.
|
||||
policy.AllowElements("strong", "br", "b", "strike", "code", "i")
|
||||
policy.AllowElements("strong", "br", "b", "strike", "code", "i", "kbd")
|
||||
|
||||
// TODO: Remove <c> in `actions.workflow.dispatch.trigger_found`.
|
||||
policy.AllowNoAttrs().OnElements("c")
|
||||
|
|
|
@ -4,25 +4,28 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forgejo.org/modules/private"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// CmdActions represents the available actions sub-commands.
|
||||
CmdActions = &cli.Command{
|
||||
// CmdActions represents the available actions sub-commands.
|
||||
func cmdActions() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "actions",
|
||||
Usage: "Manage Forgejo Actions",
|
||||
Subcommands: []*cli.Command{
|
||||
subcmdActionsGenRunnerToken,
|
||||
Commands: []*cli.Command{
|
||||
subcmdActionsGenRunnerToken(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdActionsGenRunnerToken = &cli.Command{
|
||||
func subcmdActionsGenRunnerToken() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "generate-runner-token",
|
||||
Usage: "Generate a new token for a runner to use to register with the server",
|
||||
Action: runGenerateActionsRunnerToken,
|
||||
|
@ -36,10 +39,10 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func runGenerateActionsRunnerToken(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setting.MustInstalled()
|
||||
|
|
70
cmd/admin.go
70
cmd/admin.go
|
@ -15,56 +15,64 @@ import (
|
|||
"forgejo.org/modules/log"
|
||||
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 = &cli.Command{
|
||||
// CmdAdmin represents the available admin sub-command.
|
||||
func cmdAdmin() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "admin",
|
||||
Usage: "Perform common administrative operations",
|
||||
Subcommands: []*cli.Command{
|
||||
subcmdUser,
|
||||
subcmdRepoSyncReleases,
|
||||
subcmdRegenerate,
|
||||
subcmdAuth,
|
||||
subcmdSendMail,
|
||||
Commands: []*cli.Command{
|
||||
subcmdUser(),
|
||||
subcmdRepoSyncReleases(),
|
||||
subcmdRegenerate(),
|
||||
subcmdAuth(),
|
||||
subcmdSendMail(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdRepoSyncReleases = &cli.Command{
|
||||
func subcmdRepoSyncReleases() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "repo-sync-releases",
|
||||
Usage: "Synchronize repository releases with tags",
|
||||
Action: runRepoSyncReleases,
|
||||
}
|
||||
}
|
||||
|
||||
subcmdRegenerate = &cli.Command{
|
||||
func subcmdRegenerate() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "regenerate",
|
||||
Usage: "Regenerate specific files",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
microcmdRegenHooks,
|
||||
microcmdRegenKeys,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdAuth = &cli.Command{
|
||||
func subcmdAuth() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "auth",
|
||||
Usage: "Modify external auth providers",
|
||||
Subcommands: []*cli.Command{
|
||||
microcmdAuthAddOauth,
|
||||
microcmdAuthUpdateOauth,
|
||||
microcmdAuthAddLdapBindDn,
|
||||
microcmdAuthUpdateLdapBindDn,
|
||||
microcmdAuthAddLdapSimpleAuth,
|
||||
microcmdAuthUpdateLdapSimpleAuth,
|
||||
microcmdAuthAddSMTP,
|
||||
microcmdAuthUpdateSMTP,
|
||||
microcmdAuthList,
|
||||
microcmdAuthDelete,
|
||||
Commands: []*cli.Command{
|
||||
microcmdAuthAddOauth(),
|
||||
microcmdAuthUpdateOauth(),
|
||||
microcmdAuthAddLdapBindDn(),
|
||||
microcmdAuthUpdateLdapBindDn(),
|
||||
microcmdAuthAddLdapSimpleAuth(),
|
||||
microcmdAuthUpdateLdapSimpleAuth(),
|
||||
microcmdAuthAddSMTP(),
|
||||
microcmdAuthUpdateSMTP(),
|
||||
microcmdAuthList(),
|
||||
microcmdAuthDelete(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdSendMail = &cli.Command{
|
||||
func subcmdSendMail() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "sendmail",
|
||||
Usage: "Send a message to all users",
|
||||
Action: runSendMail,
|
||||
|
@ -86,15 +94,17 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
idFlag = &cli.Int64Flag{
|
||||
func idFlag() *cli.Int64Flag {
|
||||
return &cli.Int64Flag{
|
||||
Name: "id",
|
||||
Usage: "ID of authentication source",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func runRepoSyncReleases(_ *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -13,17 +14,20 @@ import (
|
|||
"forgejo.org/models/db"
|
||||
auth_service "forgejo.org/services/auth"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
microcmdAuthDelete = &cli.Command{
|
||||
func microcmdAuthDelete() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete specific auth source",
|
||||
Flags: []cli.Flag{idFlag},
|
||||
Flags: []cli.Flag{idFlag()},
|
||||
Action: runDeleteAuth,
|
||||
}
|
||||
microcmdAuthList = &cli.Command{
|
||||
}
|
||||
|
||||
func microcmdAuthList() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List auth sources",
|
||||
Action: runListAuth,
|
||||
|
@ -54,10 +58,10 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func runListAuth(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runListAuth(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
@ -81,7 +85,7 @@ func runListAuth(c *cli.Context) error {
|
|||
|
||||
// loop through each source and print
|
||||
w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags)
|
||||
fmt.Fprintf(w, "ID\tName\tType\tEnabled\n")
|
||||
fmt.Fprint(w, "ID\tName\tType\tEnabled\n")
|
||||
for _, source := range authSources {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive)
|
||||
}
|
||||
|
@ -90,12 +94,12 @@ func runListAuth(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runDeleteAuth(c *cli.Context) error {
|
||||
func runDeleteAuth(ctx context.Context, c *cli.Command) error {
|
||||
if !c.IsSet("id") {
|
||||
return errors.New("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"forgejo.org/models/auth"
|
||||
"forgejo.org/services/auth/source/ldap"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -23,8 +23,8 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
var (
|
||||
commonLdapCLIFlags = []cli.Flag{
|
||||
func commonLdapCLIFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "Authentication name.",
|
||||
|
@ -102,8 +102,10 @@ var (
|
|||
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{
|
||||
Name: "bind-dn",
|
||||
Usage: "The DN to bind to the LDAP server with when searching for the user.",
|
||||
|
@ -128,49 +130,59 @@ var (
|
|||
Name: "page-size",
|
||||
Usage: "Search page size.",
|
||||
})
|
||||
}
|
||||
|
||||
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
|
||||
func ldapSimpleAuthCLIFlags() []cli.Flag {
|
||||
return append(commonLdapCLIFlags(),
|
||||
&cli.StringFlag{
|
||||
Name: "user-dn",
|
||||
Usage: "The user's DN.",
|
||||
})
|
||||
}
|
||||
|
||||
microcmdAuthAddLdapBindDn = &cli.Command{
|
||||
func microcmdAuthAddLdapBindDn() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "add-ldap",
|
||||
Usage: "Add new LDAP (via Bind DN) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
return newAuthService().addLdapBindDn(c)
|
||||
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||
return newAuthService().addLdapBindDn(ctx, cli)
|
||||
},
|
||||
Flags: ldapBindDnCLIFlags,
|
||||
Flags: ldapBindDnCLIFlags(),
|
||||
}
|
||||
}
|
||||
|
||||
microcmdAuthUpdateLdapBindDn = &cli.Command{
|
||||
func microcmdAuthUpdateLdapBindDn() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "update-ldap",
|
||||
Usage: "Update existing LDAP (via Bind DN) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
return newAuthService().updateLdapBindDn(c)
|
||||
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||
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",
|
||||
Usage: "Add new LDAP (simple auth) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
return newAuthService().addLdapSimpleAuth(c)
|
||||
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||
return newAuthService().addLdapSimpleAuth(ctx, cli)
|
||||
},
|
||||
Flags: ldapSimpleAuthCLIFlags,
|
||||
Flags: ldapSimpleAuthCLIFlags(),
|
||||
}
|
||||
}
|
||||
|
||||
microcmdAuthUpdateLdapSimpleAuth = &cli.Command{
|
||||
func microcmdAuthUpdateLdapSimpleAuth() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "update-ldap-simple",
|
||||
Usage: "Update existing LDAP (simple auth) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
return newAuthService().updateLdapSimpleAuth(c)
|
||||
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||
return newAuthService().updateLdapSimpleAuth(ctx, cli)
|
||||
},
|
||||
Flags: append([]cli.Flag{idFlag}, ldapSimpleAuthCLIFlags...),
|
||||
Flags: append([]cli.Flag{idFlag()}, ldapSimpleAuthCLIFlags()...),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// newAuthService creates a service with default functions.
|
||||
func newAuthService() *authService {
|
||||
|
@ -183,7 +195,7 @@ func newAuthService() *authService {
|
|||
}
|
||||
|
||||
// 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") {
|
||||
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.
|
||||
func parseLdapConfig(c *cli.Context, config *ldap.Source) error {
|
||||
func parseLdapConfig(c *cli.Command, config *ldap.Source) error {
|
||||
if c.IsSet("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.
|
||||
// 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 {
|
||||
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.
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
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.
|
||||
func (a *authService) updateLdapBindDn(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
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.
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
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.
|
||||
func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func (a *authService) updateLdapSimpleAuth(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := a.initDB(ctx); err != nil {
|
||||
|
|
|
@ -8,18 +8,17 @@ import (
|
|||
"testing"
|
||||
|
||||
"forgejo.org/models/auth"
|
||||
"forgejo.org/modules/test"
|
||||
"forgejo.org/services/auth/source/ldap"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestAddLdapBindDn(t *testing.T) {
|
||||
// Mock cli functions to do not exit on error
|
||||
osExiter := cli.OsExiter
|
||||
defer func() { cli.OsExiter = osExiter }()
|
||||
cli.OsExiter = func(code int) {}
|
||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||
|
||||
// Test cases
|
||||
cases := []struct {
|
||||
|
@ -226,12 +225,12 @@ func TestAddLdapBindDn(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = microcmdAuthAddLdapBindDn.Flags
|
||||
app := cli.Command{}
|
||||
app.Flags = microcmdAuthAddLdapBindDn().Flags
|
||||
app.Action = service.addLdapBindDn
|
||||
|
||||
// Run it
|
||||
err := app.Run(c.args)
|
||||
err := app.Run(t.Context(), c.args)
|
||||
if c.errMsg != "" {
|
||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||
} else {
|
||||
|
@ -243,9 +242,7 @@ func TestAddLdapBindDn(t *testing.T) {
|
|||
|
||||
func TestAddLdapSimpleAuth(t *testing.T) {
|
||||
// Mock cli functions to do not exit on error
|
||||
osExiter := cli.OsExiter
|
||||
defer func() { cli.OsExiter = osExiter }()
|
||||
cli.OsExiter = func(code int) {}
|
||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||
|
||||
// Test cases
|
||||
cases := []struct {
|
||||
|
@ -457,12 +454,12 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
|
||||
app := cli.Command{}
|
||||
app.Flags = microcmdAuthAddLdapSimpleAuth().Flags
|
||||
app.Action = service.addLdapSimpleAuth
|
||||
|
||||
// Run it
|
||||
err := app.Run(c.args)
|
||||
err := app.Run(t.Context(), c.args)
|
||||
if c.errMsg != "" {
|
||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||
} else {
|
||||
|
@ -474,9 +471,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
|||
|
||||
func TestUpdateLdapBindDn(t *testing.T) {
|
||||
// Mock cli functions to do not exit on error
|
||||
osExiter := cli.OsExiter
|
||||
defer func() { cli.OsExiter = osExiter }()
|
||||
cli.OsExiter = func(code int) {}
|
||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||
|
||||
// Test cases
|
||||
cases := []struct {
|
||||
|
@ -920,12 +915,12 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = microcmdAuthUpdateLdapBindDn.Flags
|
||||
app := cli.Command{}
|
||||
app.Flags = microcmdAuthUpdateLdapBindDn().Flags
|
||||
app.Action = service.updateLdapBindDn
|
||||
|
||||
// Run it
|
||||
err := app.Run(c.args)
|
||||
err := app.Run(t.Context(), c.args)
|
||||
if c.errMsg != "" {
|
||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||
} else {
|
||||
|
@ -937,9 +932,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
|||
|
||||
func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||
// Mock cli functions to do not exit on error
|
||||
osExiter := cli.OsExiter
|
||||
defer func() { cli.OsExiter = osExiter }()
|
||||
cli.OsExiter = func(code int) {}
|
||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||
|
||||
// Test cases
|
||||
cases := []struct {
|
||||
|
@ -1310,12 +1303,12 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
|
||||
app := cli.Command{}
|
||||
app.Flags = microcmdAuthUpdateLdapSimpleAuth().Flags
|
||||
app.Action = service.updateLdapSimpleAuth
|
||||
|
||||
// Run it
|
||||
err := app.Run(c.args)
|
||||
err := app.Run(t.Context(), c.args)
|
||||
if c.errMsg != "" {
|
||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||
} else {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
@ -11,11 +12,11 @@ import (
|
|||
auth_model "forgejo.org/models/auth"
|
||||
"forgejo.org/services/auth/source/oauth2"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
oauthCLIFlags = []cli.Flag{
|
||||
func oauthCLIFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
|
@ -120,23 +121,27 @@ var (
|
|||
Usage: "Activate automatic team membership removal depending on groups",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
microcmdAuthAddOauth = &cli.Command{
|
||||
func microcmdAuthAddOauth() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "add-oauth",
|
||||
Usage: "Add new Oauth authentication source",
|
||||
Action: runAddOauth,
|
||||
Flags: oauthCLIFlags,
|
||||
Flags: oauthCLIFlags(),
|
||||
}
|
||||
}
|
||||
|
||||
microcmdAuthUpdateOauth = &cli.Command{
|
||||
func microcmdAuthUpdateOauth() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "update-oauth",
|
||||
Usage: "Update existing Oauth authentication source",
|
||||
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
|
||||
if c.IsSet("use-custom-urls") {
|
||||
customURLMapping = &oauth2.CustomURLMapping{
|
||||
|
@ -168,15 +173,15 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
|||
}
|
||||
}
|
||||
|
||||
func runAddOauth(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runAddOauth(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := parseOAuth2Config(c)
|
||||
config := parseOAuth2Config(ctx, c)
|
||||
if config.Provider == "openidConnect" {
|
||||
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
||||
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") {
|
||||
return errors.New("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
|
@ -11,11 +12,11 @@ import (
|
|||
"forgejo.org/modules/util"
|
||||
"forgejo.org/services/auth/source/smtp"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
smtpCLIFlags = []cli.Flag{
|
||||
func smtpCLIFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
|
@ -71,23 +72,27 @@ var (
|
|||
Value: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
microcmdAuthAddSMTP = &cli.Command{
|
||||
func microcmdAuthAddSMTP() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "add-smtp",
|
||||
Usage: "Add new SMTP authentication source",
|
||||
Action: runAddSMTP,
|
||||
Flags: smtpCLIFlags,
|
||||
Flags: smtpCLIFlags(),
|
||||
}
|
||||
}
|
||||
|
||||
microcmdAuthUpdateSMTP = &cli.Command{
|
||||
func microcmdAuthUpdateSMTP() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "update-smtp",
|
||||
Usage: "Update existing SMTP authentication source",
|
||||
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") {
|
||||
conf.Auth = c.String("auth-type")
|
||||
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
|
||||
|
@ -123,8 +128,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runAddSMTP(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runAddSMTP(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
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") {
|
||||
return errors.New("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
asymkey_model "forgejo.org/models/asymkey"
|
||||
"forgejo.org/modules/graceful"
|
||||
repo_service "forgejo.org/services/repository"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -25,8 +27,8 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func runRegenerateHooks(_ *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
@ -35,8 +37,8 @@ func runRegenerateHooks(_ *cli.Context) error {
|
|||
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
||||
}
|
||||
|
||||
func runRegenerateKeys(_ *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runRegenerateKeys(ctx context.Context, _ *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,18 +4,21 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var subcmdUser = &cli.Command{
|
||||
Name: "user",
|
||||
Usage: "Modify users",
|
||||
Subcommands: []*cli.Command{
|
||||
microcmdUserCreate,
|
||||
microcmdUserList,
|
||||
microcmdUserChangePassword,
|
||||
microcmdUserDelete,
|
||||
microcmdUserGenerateAccessToken,
|
||||
microcmdUserMustChangePassword,
|
||||
},
|
||||
func subcmdUser() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "user",
|
||||
Usage: "Modify users",
|
||||
Commands: []*cli.Command{
|
||||
microcmdUserCreate(),
|
||||
microcmdUserList(),
|
||||
microcmdUserChangePassword(),
|
||||
microcmdUserDelete(),
|
||||
microcmdUserGenerateAccessToken(),
|
||||
microcmdUserMustChangePassword(),
|
||||
microcmdUserResetMFA(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
|
@ -13,40 +14,42 @@ import (
|
|||
"forgejo.org/modules/setting"
|
||||
user_service "forgejo.org/services/user"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var microcmdUserChangePassword = &cli.Command{
|
||||
Name: "change-password",
|
||||
Usage: "Change a user's password",
|
||||
Action: runChangePassword,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "username",
|
||||
Aliases: []string{"u"},
|
||||
Value: "",
|
||||
Usage: "The user to change password for",
|
||||
func microcmdUserChangePassword() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "change-password",
|
||||
Usage: "Change a user's password",
|
||||
Action: runChangePassword,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "username",
|
||||
Aliases: []string{"u"},
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
@ -15,75 +16,76 @@ import (
|
|||
"forgejo.org/modules/optional"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var microcmdUserCreate = &cli.Command{
|
||||
Name: "create",
|
||||
Usage: "Create a new user in database",
|
||||
Action: runCreateUser,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "Username. DEPRECATED: use username instead",
|
||||
func microcmdUserCreate() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "create",
|
||||
Usage: "Create a new user in database",
|
||||
Action: runCreateUser,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
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
|
||||
// duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future.
|
||||
setting.LoadSettings()
|
||||
|
@ -108,10 +110,10 @@ func runCreateUser(c *cli.Context) error {
|
|||
username = c.String("username")
|
||||
} else {
|
||||
username = c.String("name")
|
||||
_, _ = fmt.Fprintf(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()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
@ -12,41 +13,43 @@ import (
|
|||
"forgejo.org/modules/storage"
|
||||
user_service "forgejo.org/services/user"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var microcmdUserDelete = &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete specific user by id, name or email",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Int64Flag{
|
||||
Name: "id",
|
||||
Usage: "ID of user of the user to delete",
|
||||
func microcmdUserDelete() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete specific user by id, name or email",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Int64Flag{
|
||||
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{
|
||||
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,
|
||||
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") {
|
||||
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()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,49 +4,52 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
auth_model "forgejo.org/models/auth"
|
||||
user_model "forgejo.org/models/user"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var microcmdUserGenerateAccessToken = &cli.Command{
|
||||
Name: "generate-access-token",
|
||||
Usage: "Generate an access token for a specific user",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "username",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Username",
|
||||
func microcmdUserGenerateAccessToken() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "generate-access-token",
|
||||
Usage: "Generate an access token for a specific user",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "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{
|
||||
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,
|
||||
Action: runGenerateAccessToken,
|
||||
}
|
||||
}
|
||||
|
||||
func runGenerateAccessToken(c *cli.Context) error {
|
||||
func runGenerateAccessToken(ctx context.Context, c *cli.Command) error {
|
||||
if !c.IsSet("username") {
|
||||
return errors.New("you must provide a username to generate a token for")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
|
|
@ -4,29 +4,32 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
user_model "forgejo.org/models/user"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var microcmdUserList = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List users",
|
||||
Action: runListUsers,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "admin",
|
||||
Usage: "List only admin users",
|
||||
func microcmdUserList() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List users",
|
||||
Action: runListUsers,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "admin",
|
||||
Usage: "List only admin users",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runListUsers(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runListUsers(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
|
@ -41,7 +44,7 @@ func runListUsers(c *cli.Context) error {
|
|||
w := tabwriter.NewWriter(os.Stdout, 5, 0, 1, ' ', 0)
|
||||
|
||||
if c.IsSet("admin") {
|
||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\n")
|
||||
fmt.Fprint(w, "ID\tUsername\tEmail\tIsActive\n")
|
||||
for _, u := range users {
|
||||
if u.IsAdmin {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", u.ID, u.Name, u.Email, u.IsActive)
|
||||
|
@ -49,7 +52,7 @@ func runListUsers(c *cli.Context) error {
|
|||
}
|
||||
} else {
|
||||
twofa := user_model.UserList(users).GetTwoFaStatus(ctx)
|
||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
|
||||
fmt.Fprint(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
|
||||
for _, u := range users {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
|
||||
}
|
||||
|
|
|
@ -4,38 +4,41 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
user_model "forgejo.org/models/user"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var microcmdUserMustChangePassword = &cli.Command{
|
||||
Name: "must-change-password",
|
||||
Usage: "Set the must change password flag for the provided users or all users",
|
||||
Action: runMustChangePassword,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Aliases: []string{"A"},
|
||||
Usage: "All users must change password, except those explicitly excluded with --exclude",
|
||||
func microcmdUserMustChangePassword() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "must-change-password",
|
||||
Usage: "Set the must change password flag for the provided users or all users",
|
||||
Action: runMustChangePassword,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
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 {
|
||||
ctx, cancel := installSignals()
|
||||
func runMustChangePassword(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if c.NArg() == 0 && !c.IsSet("all") {
|
||||
|
|
73
cmd/admin_user_reset_mfa.go
Normal file
73
cmd/admin_user_reset_mfa.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
auth_model "forgejo.org/models/auth"
|
||||
user_model "forgejo.org/models/user"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func microcmdUserResetMFA() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "reset-mfa",
|
||||
Usage: "Remove all two-factor authentication configurations for a user",
|
||||
Action: runResetMFA,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "username",
|
||||
Aliases: []string{"u"},
|
||||
Value: "",
|
||||
Usage: "The user to update",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runResetMFA(ctx context.Context, c *cli.Command) error {
|
||||
if err := argsSet(c, "username"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user, err := user_model.GetUserByName(ctx, c.String("username"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
webAuthnList, err := auth_model.GetWebAuthnCredentialsByUID(ctx, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, credential := range webAuthnList {
|
||||
if _, err := auth_model.DeleteCredential(ctx, credential.ID, user.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tfaModes, err := auth_model.GetTwoFactorByUID(ctx, user.ID)
|
||||
if err == nil && tfaModes != nil {
|
||||
if err := auth_model.DeleteTwoFactorByID(ctx, tfaModes.ID, user.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, is := err.(auth_model.ErrTwoFactorNotEnrolled); !is {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%s's two-factor authentication settings have been removed!\n", user.Name)
|
||||
return nil
|
||||
}
|
77
cmd/cert.go
77
cmd/cert.go
|
@ -6,6 +6,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
|
@ -20,47 +21,49 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdCert represents the available cert sub-command.
|
||||
var CmdCert = &cli.Command{
|
||||
Name: "cert",
|
||||
Usage: "Generate self-signed certificate",
|
||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||
func cmdCert() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "cert",
|
||||
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.`,
|
||||
Action: runCert,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "host",
|
||||
Value: "",
|
||||
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
|
||||
Action: runCert,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "host",
|
||||
Value: "",
|
||||
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 {
|
||||
|
@ -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 {
|
||||
return err
|
||||
}
|
||||
|
|
26
cmd/cmd.go
26
cmd/cmd.go
|
@ -20,19 +20,21 @@ import (
|
|||
"forgejo.org/modules/setting"
|
||||
"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
|
||||
// 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 {
|
||||
if !c.IsSet(a) {
|
||||
return errors.New(a + " is not set")
|
||||
}
|
||||
|
||||
if util.IsEmptyString(c.String(a)) {
|
||||
return errors.New(a + " is required")
|
||||
if s, ok := c.Value(a).(string); ok {
|
||||
if util.IsEmptyString(s) {
|
||||
return errors.New(a + " is required")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -73,8 +75,8 @@ If this is the intended configuration file complete the [database] section.`, se
|
|||
return nil
|
||||
}
|
||||
|
||||
func installSignals() (context.Context, context.CancelFunc) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
func installSignals(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
go func() {
|
||||
// install notify
|
||||
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)
|
||||
}
|
||||
|
||||
func globalBool(c *cli.Context, name string) bool {
|
||||
func globalBool(c *cli.Command, name string) bool {
|
||||
for _, ctx := range c.Lineage() {
|
||||
if ctx.Bool(name) {
|
||||
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.
|
||||
// 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 {
|
||||
return func(c *cli.Context) error {
|
||||
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||
return func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||
level := defaultLevel
|
||||
if globalBool(c, "quiet") {
|
||||
if globalBool(cli, "quiet") {
|
||||
level = log.FATAL
|
||||
}
|
||||
if globalBool(c, "debug") || globalBool(c, "verbose") {
|
||||
if globalBool(cli, "debug") || globalBool(cli, "verbose") {
|
||||
level = log.TRACE
|
||||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
golog "log"
|
||||
"os"
|
||||
|
@ -19,80 +20,86 @@ import (
|
|||
"forgejo.org/modules/setting"
|
||||
"forgejo.org/services/doctor"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdDoctor represents the available doctor sub-command.
|
||||
var CmdDoctor = &cli.Command{
|
||||
Name: "doctor",
|
||||
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.",
|
||||
func cmdDoctor() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "doctor",
|
||||
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{
|
||||
cmdDoctorCheck,
|
||||
cmdRecreateTable,
|
||||
cmdDoctorConvert,
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
cmdDoctorCheck(),
|
||||
cmdRecreateTable(),
|
||||
cmdDoctorConvert(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var cmdDoctorCheck = &cli.Command{
|
||||
Name: "check",
|
||||
Usage: "Diagnose and optionally fix problems",
|
||||
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.",
|
||||
Action: runDoctorCheck,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "list",
|
||||
Usage: "List the available checks",
|
||||
func cmdDoctorCheck() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "check",
|
||||
Usage: "Diagnose and optionally fix problems",
|
||||
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.",
|
||||
Action: runDoctorCheck,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
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{
|
||||
Name: "recreate-table",
|
||||
Usage: "Recreate tables from XORM definitions and copy the data.",
|
||||
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
Usage: "Print SQL commands sent",
|
||||
func cmdRecreateTable() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "recreate-table",
|
||||
Usage: "Recreate tables from XORM definitions and copy the data.",
|
||||
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
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.
|
||||
|
||||
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 {
|
||||
stdCtx, cancel := installSignals()
|
||||
func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error {
|
||||
stdCtx, cancel := installSignals(stdCtx)
|
||||
defer cancel()
|
||||
|
||||
// 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
|
||||
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
||||
|
||||
|
@ -165,8 +172,8 @@ func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func runDoctorCheck(ctx *cli.Context) error {
|
||||
stdCtx, cancel := installSignals()
|
||||
func runDoctorCheck(stdCtx context.Context, ctx *cli.Command) error {
|
||||
stdCtx, cancel := installSignals(stdCtx)
|
||||
defer cancel()
|
||||
|
||||
colorize := log.CanColorStdout
|
||||
|
|
|
@ -4,25 +4,28 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forgejo.org/models/db"
|
||||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// cmdDoctorConvert represents the available convert sub-command.
|
||||
var cmdDoctorConvert = &cli.Command{
|
||||
Name: "convert",
|
||||
Usage: "Convert the database",
|
||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||
Action: runDoctorConvert,
|
||||
func cmdDoctorConvert() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "convert",
|
||||
Usage: "Convert the database",
|
||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||
Action: runDoctorConvert,
|
||||
}
|
||||
}
|
||||
|
||||
func runDoctorConvert(ctx *cli.Context) error {
|
||||
stdCtx, cancel := installSignals()
|
||||
func runDoctorConvert(stdCtx context.Context, ctx *cli.Command) error {
|
||||
stdCtx, cancel := installSignals(stdCtx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(stdCtx); err != nil {
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"forgejo.org/services/doctor"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestDoctorRun(t *testing.T) {
|
||||
|
@ -22,12 +22,12 @@ func TestDoctorRun(t *testing.T) {
|
|||
|
||||
SkipDatabaseInitialization: true,
|
||||
})
|
||||
app := cli.NewApp()
|
||||
app.Commands = []*cli.Command{cmdDoctorCheck}
|
||||
err := app.Run([]string{"./gitea", "check", "--run", "test-check"})
|
||||
app := cli.Command{}
|
||||
app.Commands = []*cli.Command{cmdDoctorCheck()}
|
||||
err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"})
|
||||
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"`)
|
||||
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"`)
|
||||
}
|
||||
|
|
160
cmd/dump.go
160
cmd/dump.go
|
@ -5,6 +5,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -22,7 +24,7 @@ import (
|
|||
|
||||
"code.forgejo.org/go-chi/session"
|
||||
"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 {
|
||||
|
@ -83,6 +85,10 @@ func (o *outputType) Set(value string) error {
|
|||
return fmt.Errorf("allowed values are %s", o.Join())
|
||||
}
|
||||
|
||||
func (o *outputType) Get() any {
|
||||
return o.String()
|
||||
}
|
||||
|
||||
func (o outputType) String() string {
|
||||
if o.selected == "" {
|
||||
return o.Default
|
||||
|
@ -96,79 +102,81 @@ var outputTypeEnum = &outputType{
|
|||
}
|
||||
|
||||
// CmdDump represents the available dump sub-command.
|
||||
var CmdDump = &cli.Command{
|
||||
Name: "dump",
|
||||
Usage: "Dump Forgejo files and database",
|
||||
Description: `Dump compresses all related files and database into zip file.
|
||||
func cmdDump() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "dump",
|
||||
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`,
|
||||
Action: runDump,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "file",
|
||||
Aliases: []string{"f"},
|
||||
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.",
|
||||
Action: runDump,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "file",
|
||||
Aliases: []string{"f"},
|
||||
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.",
|
||||
},
|
||||
&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) {
|
||||
|
@ -176,7 +184,7 @@ func fatal(format string, args ...any) {
|
|||
log.Fatal(format, args...)
|
||||
}
|
||||
|
||||
func runDump(ctx *cli.Context) error {
|
||||
func runDump(stdCtx context.Context, ctx *cli.Command) error {
|
||||
var file *os.File
|
||||
fileName := ctx.String("file")
|
||||
outType := ctx.String("type")
|
||||
|
@ -212,16 +220,16 @@ func runDump(ctx *cli.Context) error {
|
|||
|
||||
if !setting.InstallLock {
|
||||
log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
|
||||
return fmt.Errorf("forgejo is not initialized")
|
||||
return errors.New("forgejo is not initialized")
|
||||
}
|
||||
setting.LoadSettings() // cannot access session settings otherwise
|
||||
|
||||
verbose := ctx.Bool("verbose")
|
||||
if verbose && ctx.Bool("quiet") {
|
||||
return fmt.Errorf("--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()
|
||||
|
||||
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/migrations"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdDumpRepository represents the available dump repository sub-command.
|
||||
var CmdDumpRepository = &cli.Command{
|
||||
Name: "dump-repo",
|
||||
Usage: "Dump the repository from git/github/gitea/gitlab",
|
||||
Description: "This is a command for dumping the repository data.",
|
||||
Action: runDumpRepository,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "git_service",
|
||||
Value: "",
|
||||
Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo_dir",
|
||||
Aliases: []string{"r"},
|
||||
Value: "./data",
|
||||
Usage: "Repository dir path to store the data",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "clone_addr",
|
||||
Value: "",
|
||||
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_username",
|
||||
Value: "",
|
||||
Usage: "The username to visit the clone_addr",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_password",
|
||||
Value: "",
|
||||
Usage: "The password to visit the clone_addr",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_token",
|
||||
Value: "",
|
||||
Usage: "The personal token to visit the clone_addr",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "owner_name",
|
||||
Value: "",
|
||||
Usage: "The data will be stored on a directory with owner name if not empty",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo_name",
|
||||
Value: "",
|
||||
Usage: "The data will be stored on a directory with repository name if not empty",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "units",
|
||||
Value: "",
|
||||
Usage: `Which items will be migrated, one or more units should be separated as comma.
|
||||
func cmdDumpRepository() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "dump-repo",
|
||||
Usage: "Dump the repository from git/github/gitea/gitlab",
|
||||
Description: "This is a command for dumping the repository data.",
|
||||
Action: runDumpRepository,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "git_service",
|
||||
Value: "",
|
||||
Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo_dir",
|
||||
Aliases: []string{"r"},
|
||||
Value: "./data",
|
||||
Usage: "Repository dir path to store the data",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "clone_addr",
|
||||
Value: "",
|
||||
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_username",
|
||||
Value: "",
|
||||
Usage: "The username to visit the clone_addr",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_password",
|
||||
Value: "",
|
||||
Usage: "The password to visit the clone_addr",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_token",
|
||||
Value: "",
|
||||
Usage: "The personal token to visit the clone_addr",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "owner_name",
|
||||
Value: "",
|
||||
Usage: "The data will be stored on a directory with owner name if not empty",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo_name",
|
||||
Value: "",
|
||||
Usage: "The data will be stored on a directory with repository name if not empty",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "units",
|
||||
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.`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runDumpRepository(ctx *cli.Context) error {
|
||||
stdCtx, cancel := installSignals()
|
||||
func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error {
|
||||
stdCtx, cancel := installSignals(stdCtx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(stdCtx); err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -19,23 +20,25 @@ import (
|
|||
"forgejo.org/modules/util"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdEmbedded represents the available extract sub-command.
|
||||
var (
|
||||
CmdEmbedded = &cli.Command{
|
||||
func cmdEmbedded() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "embedded",
|
||||
Usage: "Extract embedded resources",
|
||||
Description: "A command for extracting embedded resources, like templates and images",
|
||||
Subcommands: []*cli.Command{
|
||||
subcmdList,
|
||||
subcmdView,
|
||||
subcmdExtract,
|
||||
Commands: []*cli.Command{
|
||||
subcmdList(),
|
||||
subcmdView(),
|
||||
subcmdExtract(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdList = &cli.Command{
|
||||
func subcmdList() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List files matching the given pattern",
|
||||
Action: runList,
|
||||
|
@ -47,8 +50,10 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdView = &cli.Command{
|
||||
func subcmdView() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "view",
|
||||
Usage: "View a file matching the given pattern",
|
||||
Action: runView,
|
||||
|
@ -60,8 +65,10 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdExtract = &cli.Command{
|
||||
func subcmdExtract() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "extract",
|
||||
Usage: "Extract resources",
|
||||
Action: runExtract,
|
||||
|
@ -90,9 +97,9 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
matchedAssetFiles []assetFile
|
||||
)
|
||||
var matchedAssetFiles []assetFile
|
||||
|
||||
type assetFile struct {
|
||||
fs *assetfs.LayeredFS
|
||||
|
@ -100,7 +107,7 @@ type assetFile struct {
|
|||
path string
|
||||
}
|
||||
|
||||
func initEmbeddedExtractor(c *cli.Context) error {
|
||||
func initEmbeddedExtractor(_ context.Context, c *cli.Command) error {
|
||||
setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr)
|
||||
|
||||
patterns, err := compileCollectPatterns(c.Args().Slice())
|
||||
|
@ -115,32 +122,32 @@ func initEmbeddedExtractor(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runList(c *cli.Context) error {
|
||||
if err := runListDo(c); err != nil {
|
||||
func runList(ctx context.Context, c *cli.Command) error {
|
||||
if err := runListDo(ctx, c); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runView(c *cli.Context) error {
|
||||
if err := runViewDo(c); err != nil {
|
||||
func runView(ctx context.Context, c *cli.Command) error {
|
||||
if err := runViewDo(ctx, c); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runExtract(c *cli.Context) error {
|
||||
if err := runExtractDo(c); err != nil {
|
||||
func runExtract(ctx context.Context, c *cli.Command) error {
|
||||
if err := runExtractDo(ctx, c); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runListDo(c *cli.Context) error {
|
||||
if err := initEmbeddedExtractor(c); err != nil {
|
||||
func runListDo(ctx context.Context, c *cli.Command) error {
|
||||
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -151,8 +158,8 @@ func runListDo(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runViewDo(c *cli.Context) error {
|
||||
if err := initEmbeddedExtractor(c); err != nil {
|
||||
func runViewDo(ctx context.Context, c *cli.Command) error {
|
||||
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -174,8 +181,8 @@ func runViewDo(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runExtractDo(c *cli.Context) error {
|
||||
if err := initEmbeddedExtractor(c); err != nil {
|
||||
func runExtractDo(ctx context.Context, c *cli.Command) error {
|
||||
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -271,7 +278,7 @@ func extractAsset(d string, a assetFile, overwrite, rename bool) error {
|
|||
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)
|
||||
files, err := fs.ListAllFiles(".", true)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ package forgejo
|
|||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -16,14 +17,14 @@ import (
|
|||
"forgejo.org/modules/setting"
|
||||
private_routers "forgejo.org/routers/private"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func CmdActions(ctx context.Context) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "actions",
|
||||
Usage: "Commands for managing Forgejo Actions",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
SubcmdActionsGenerateRunnerToken(ctx),
|
||||
SubcmdActionsGenerateRunnerSecret(ctx),
|
||||
SubcmdActionsRegister(ctx),
|
||||
|
@ -36,7 +37,7 @@ func SubcmdActionsGenerateRunnerToken(ctx context.Context) *cli.Command {
|
|||
Name: "generate-runner-token",
|
||||
Usage: "Generate a new token for a runner to use to register with the server",
|
||||
Before: prepareWorkPathAndCustomConf(ctx),
|
||||
Action: func(cliCtx *cli.Context) error { return RunGenerateActionsRunnerToken(ctx, cliCtx) },
|
||||
Action: RunGenerateActionsRunnerToken,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "scope",
|
||||
|
@ -52,7 +53,7 @@ func SubcmdActionsGenerateRunnerSecret(ctx context.Context) *cli.Command {
|
|||
return &cli.Command{
|
||||
Name: "generate-secret",
|
||||
Usage: "Generate a secret suitable for input to the register subcommand",
|
||||
Action: func(cliCtx *cli.Context) error { return RunGenerateSecret(ctx, cliCtx) },
|
||||
Action: RunGenerateSecret,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +62,7 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
|||
Name: "register",
|
||||
Usage: "Idempotent registration of a runner using a shared secret",
|
||||
Before: prepareWorkPathAndCustomConf(ctx),
|
||||
Action: func(cliCtx *cli.Context) error { return RunRegister(ctx, cliCtx) },
|
||||
Action: RunRegister,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "secret",
|
||||
|
@ -105,26 +106,26 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
|||
}
|
||||
}
|
||||
|
||||
func readSecret(ctx context.Context, cliCtx *cli.Context) (string, error) {
|
||||
if cliCtx.IsSet("secret") {
|
||||
return cliCtx.String("secret"), nil
|
||||
func readSecret(ctx context.Context, cli *cli.Command) (string, error) {
|
||||
if cli.IsSet("secret") {
|
||||
return cli.String("secret"), nil
|
||||
}
|
||||
if cliCtx.IsSet("secret-stdin") {
|
||||
if cli.IsSet("secret-stdin") {
|
||||
buf, err := io.ReadAll(ContextGetStdin(ctx))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
if cliCtx.IsSet("secret-file") {
|
||||
path := cliCtx.String("secret-file")
|
||||
if cli.IsSet("secret-file") {
|
||||
path := cli.String("secret-file")
|
||||
buf, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
return "", fmt.Errorf("at least one of the --secret, --secret-stdin, --secret-file options is required")
|
||||
return "", errors.New("at least one of the --secret, --secret-stdin, --secret-file options is required")
|
||||
}
|
||||
|
||||
func validateSecret(secret string) error {
|
||||
|
@ -138,18 +139,18 @@ func validateSecret(secret string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getLabels(cliCtx *cli.Context) (*[]string, error) {
|
||||
if !cliCtx.Bool("keep-labels") {
|
||||
lblValue := strings.Split(cliCtx.String("labels"), ",")
|
||||
func getLabels(cli *cli.Command) (*[]string, error) {
|
||||
if !cli.Bool("keep-labels") {
|
||||
lblValue := strings.Split(cli.String("labels"), ",")
|
||||
return &lblValue, nil
|
||||
}
|
||||
if cliCtx.String("labels") != "" {
|
||||
return nil, fmt.Errorf("--labels and --keep-labels should not be used together")
|
||||
if cli.String("labels") != "" {
|
||||
return nil, errors.New("--labels and --keep-labels should not be used together")
|
||||
}
|
||||
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
|
||||
if !ContextGetNoInit(ctx) {
|
||||
ctx, cancel = installSignals(ctx)
|
||||
|
@ -161,17 +162,17 @@ func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
|||
}
|
||||
setting.MustInstalled()
|
||||
|
||||
secret, err := readSecret(ctx, cliCtx)
|
||||
secret, err := readSecret(ctx, cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateSecret(secret); err != nil {
|
||||
return err
|
||||
}
|
||||
scope := cliCtx.String("scope")
|
||||
name := cliCtx.String("name")
|
||||
version := cliCtx.String("version")
|
||||
labels, err := getLabels(cliCtx)
|
||||
scope := cli.String("scope")
|
||||
name := cli.String("name")
|
||||
version := cli.String("version")
|
||||
labels, err := getLabels(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -209,7 +210,7 @@ func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
||||
func RunGenerateSecret(ctx context.Context, cli *cli.Command) error {
|
||||
runner := actions_model.ActionRunner{}
|
||||
if err := runner.GenerateToken(); err != nil {
|
||||
return err
|
||||
|
@ -220,7 +221,7 @@ func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) error {
|
||||
func RunGenerateActionsRunnerToken(ctx context.Context, cli *cli.Command) error {
|
||||
if !ContextGetNoInit(ctx) {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = installSignals(ctx)
|
||||
|
@ -229,7 +230,7 @@ func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) err
|
|||
|
||||
setting.MustInstalled()
|
||||
|
||||
scope := cliCtx.String("scope")
|
||||
scope := cli.String("scope")
|
||||
|
||||
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
||||
if extra.HasError() {
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
package forgejo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"forgejo.org/services/context"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
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 {
|
||||
t.Run(fmt.Sprintf("args: %v", c.args), func(t *testing.T) {
|
||||
// Create a copy of command to test
|
||||
var result *resultType
|
||||
app := cli.NewApp()
|
||||
app := cli.Command{}
|
||||
app.Flags = flags
|
||||
app.Action = func(ctx *cli.Context) error {
|
||||
app.Action = func(_ context.Context, ctx *cli.Command) error {
|
||||
labels, err := getLabels(ctx)
|
||||
result = &resultType{labels, err}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run it
|
||||
_ = app.Run(c.args)
|
||||
_ = app.Run(t.Context(), c.args)
|
||||
|
||||
// Test the results
|
||||
require.NotNil(t, result)
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
f3_cmd "code.forgejo.org/f3/gof3/v3/cmd"
|
||||
f3_logger "code.forgejo.org/f3/gof3/v3/logger"
|
||||
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 {
|
||||
|
@ -28,21 +28,21 @@ func CmdF3(ctx context.Context) *cli.Command {
|
|||
return &cli.Command{
|
||||
Name: "f3",
|
||||
Usage: "F3",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
SubcmdF3Mirror(ctx),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func SubcmdF3Mirror(ctx context.Context) *cli.Command {
|
||||
mirrorCmd := f3_cmd.CreateCmdMirror(ctx)
|
||||
mirrorCmd := f3_cmd.CreateCmdMirror()
|
||||
mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx)
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
if !setting.F3.Enabled {
|
||||
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 {
|
||||
log.Debug("F3 Stack trace\n%s", panicError.Stack())
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"forgejo.org/modules/private"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type key int
|
||||
|
@ -34,7 +34,7 @@ func CmdForgejo(ctx context.Context) *cli.Command {
|
|||
Name: "forgejo-cli",
|
||||
Usage: "Forgejo CLI",
|
||||
Flags: []cli.Flag{},
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
CmdActions(ctx),
|
||||
CmdF3(ctx),
|
||||
},
|
||||
|
@ -147,12 +147,12 @@ func handleCliResponseExtra(ctx context.Context, extra private.ResponseExtra) er
|
|||
return cli.Exit(extra.Error, 1)
|
||||
}
|
||||
|
||||
func prepareWorkPathAndCustomConf(ctx context.Context) func(c *cli.Context) error {
|
||||
return func(c *cli.Context) error {
|
||||
func prepareWorkPathAndCustomConf(ctx context.Context) func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||
return func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||
if !ContextGetNoInit(ctx) {
|
||||
var args setting.ArgWorkPathAndCustomConf
|
||||
// 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 == "" {
|
||||
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)
|
||||
}
|
||||
return nil
|
||||
return ctx, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,56 +5,65 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"forgejo.org/modules/generate"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// CmdGenerate represents the available generate sub-command.
|
||||
CmdGenerate = &cli.Command{
|
||||
// CmdGenerate represents the available generate sub-command.
|
||||
func cmdGenerate() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "generate",
|
||||
Usage: "Generate Gitea's secrets/keys/tokens",
|
||||
Subcommands: []*cli.Command{
|
||||
subcmdSecret,
|
||||
Commands: []*cli.Command{
|
||||
subcmdSecret(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdSecret = &cli.Command{
|
||||
func subcmdSecret() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "Generate a secret token",
|
||||
Subcommands: []*cli.Command{
|
||||
microcmdGenerateInternalToken,
|
||||
microcmdGenerateLfsJwtSecret,
|
||||
microcmdGenerateSecretKey,
|
||||
Commands: []*cli.Command{
|
||||
microcmdGenerateInternalToken(),
|
||||
microcmdGenerateLfsJwtSecret(),
|
||||
microcmdGenerateSecretKey(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
microcmdGenerateInternalToken = &cli.Command{
|
||||
func microcmdGenerateInternalToken() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "INTERNAL_TOKEN",
|
||||
Usage: "Generate a new INTERNAL_TOKEN",
|
||||
Action: runGenerateInternalToken,
|
||||
}
|
||||
}
|
||||
|
||||
microcmdGenerateLfsJwtSecret = &cli.Command{
|
||||
func microcmdGenerateLfsJwtSecret() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "JWT_SECRET",
|
||||
Aliases: []string{"LFS_JWT_SECRET"},
|
||||
Usage: "Generate a new JWT_SECRET",
|
||||
Action: runGenerateLfsJwtSecret,
|
||||
}
|
||||
}
|
||||
|
||||
microcmdGenerateSecretKey = &cli.Command{
|
||||
func microcmdGenerateSecretKey() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "SECRET_KEY",
|
||||
Usage: "Generate a new SECRET_KEY",
|
||||
Action: runGenerateSecretKey,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func runGenerateInternalToken(c *cli.Context) error {
|
||||
func runGenerateInternalToken(ctx context.Context, c *cli.Command) error {
|
||||
internalToken, err := generate.NewInternalToken()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -63,25 +72,25 @@ func runGenerateInternalToken(c *cli.Context) error {
|
|||
fmt.Printf("%s", internalToken)
|
||||
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
fmt.Printf("\n")
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runGenerateLfsJwtSecret(c *cli.Context) error {
|
||||
func runGenerateLfsJwtSecret(ctx context.Context, c *cli.Command) error {
|
||||
_, jwtSecretBase64 := generate.NewJwtSecret()
|
||||
|
||||
fmt.Printf("%s", jwtSecretBase64)
|
||||
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
fmt.Printf("\n")
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runGenerateSecretKey(c *cli.Context) error {
|
||||
func runGenerateSecretKey(ctx context.Context, c *cli.Command) error {
|
||||
secretKey, err := generate.NewSecretKey()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -90,7 +99,7 @@ func runGenerateSecretKey(c *cli.Context) error {
|
|||
fmt.Printf("%s", secretKey)
|
||||
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
fmt.Printf("\n")
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
67
cmd/hook.go
67
cmd/hook.go
|
@ -21,29 +21,31 @@ import (
|
|||
repo_module "forgejo.org/modules/repository"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
hookBatchSize = 30
|
||||
)
|
||||
|
||||
var (
|
||||
// CmdHook represents the available hooks sub-command.
|
||||
CmdHook = &cli.Command{
|
||||
// CmdHook represents the available hooks sub-command.
|
||||
func cmdHook() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "hook",
|
||||
Usage: "(internal) Should only be called by Git",
|
||||
Description: "Delegate commands to corresponding Git hooks",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Subcommands: []*cli.Command{
|
||||
subcmdHookPreReceive,
|
||||
subcmdHookUpdate,
|
||||
subcmdHookPostReceive,
|
||||
subcmdHookProcReceive,
|
||||
Commands: []*cli.Command{
|
||||
subcmdHookPreReceive(),
|
||||
subcmdHookUpdate(),
|
||||
subcmdHookPostReceive(),
|
||||
subcmdHookProcReceive(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdHookPreReceive = &cli.Command{
|
||||
func subcmdHookPreReceive() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "pre-receive",
|
||||
Usage: "Delegate pre-receive Git hook",
|
||||
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",
|
||||
Usage: "Delegate update Git hook",
|
||||
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",
|
||||
Usage: "Delegate post-receive Git hook",
|
||||
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",
|
||||
Usage: "Delegate proc-receive Git hook",
|
||||
Description: "This command should only be called by Git",
|
||||
|
@ -88,7 +99,7 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
type delayWriter struct {
|
||||
internal io.Writer
|
||||
|
@ -161,11 +172,11 @@ func (n *nilWriter) WriteString(s string) (int, error) {
|
|||
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 {
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), true)
|
||||
|
@ -247,7 +258,7 @@ Forgejo or set your environment appropriately.`, "")
|
|||
newCommitIDs[count] = newCommitID
|
||||
refFullNames[count] = refFullName
|
||||
count++
|
||||
fmt.Fprintf(out, "*")
|
||||
fmt.Fprint(out, "*")
|
||||
|
||||
if count >= hookBatchSize {
|
||||
fmt.Fprintf(out, " Checking %d references\n", count)
|
||||
|
@ -263,10 +274,10 @@ Forgejo or set your environment appropriately.`, "")
|
|||
lastline = 0
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(out, ".")
|
||||
fmt.Fprint(out, ".")
|
||||
}
|
||||
if lastline >= hookBatchSize {
|
||||
fmt.Fprintf(out, "\n")
|
||||
fmt.Fprint(out, "\n")
|
||||
lastline = 0
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +294,7 @@ Forgejo or set your environment appropriately.`, "")
|
|||
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
|
||||
}
|
||||
} else if lastline > 0 {
|
||||
fmt.Fprintf(out, "\n")
|
||||
fmt.Fprint(out, "\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(out, "Checked %d references in total\n", total)
|
||||
|
@ -291,13 +302,13 @@ Forgejo or set your environment appropriately.`, "")
|
|||
}
|
||||
|
||||
// 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
|
||||
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
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), "")
|
||||
}
|
||||
|
||||
func runHookPostReceive(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runHookPostReceive(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), true)
|
||||
|
@ -399,7 +410,7 @@ Forgejo or set your environment appropriately.`, "")
|
|||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(out, ".")
|
||||
fmt.Fprint(out, ".")
|
||||
oldCommitIDs[count] = string(fields[0])
|
||||
newCommitIDs[count] = string(fields[1])
|
||||
refFullNames[count] = git.RefName(fields[2])
|
||||
|
@ -487,8 +498,8 @@ func hookPrintResults(results []private.HookPostReceiveBranchResult) {
|
|||
}
|
||||
}
|
||||
|
||||
func runHookProcReceive(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runHookProcReceive(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), true)
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"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.
|
||||
|
@ -134,14 +134,14 @@ func TestDelayWriter(t *testing.T) {
|
|||
defer ts.Close()
|
||||
defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")()
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Commands = []*cli.Command{subcmdHookPreReceive}
|
||||
app := cli.Command{}
|
||||
app.Commands = []*cli.Command{subcmdHookPreReceive()}
|
||||
|
||||
t.Run("Should delay", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)()
|
||||
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)
|
||||
out := finish()
|
||||
|
||||
|
@ -153,7 +153,7 @@ func TestDelayWriter(t *testing.T) {
|
|||
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)()
|
||||
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)
|
||||
out := finish()
|
||||
|
||||
|
@ -163,15 +163,15 @@ func TestDelayWriter(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRunHookUpdate(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
app.Commands = []*cli.Command{subcmdHookUpdate}
|
||||
app := cli.Command{}
|
||||
app.Commands = []*cli.Command{subcmdHookUpdate()}
|
||||
|
||||
t.Run("Removal of internal reference", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||
defer test.MockVariableValue(&setting.IsProd, false)()
|
||||
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()
|
||||
require.Error(t, err)
|
||||
|
||||
|
@ -183,7 +183,7 @@ func TestRunHookUpdate(t *testing.T) {
|
|||
defer test.MockVariableValue(&setting.IsProd, false)()
|
||||
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()
|
||||
require.Error(t, err)
|
||||
|
||||
|
@ -191,12 +191,12 @@ func TestRunHookUpdate(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)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
|
73
cmd/keys.go
73
cmd/keys.go
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
@ -11,45 +12,47 @@ import (
|
|||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/private"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdKeys represents the available keys sub-command
|
||||
var CmdKeys = &cli.Command{
|
||||
Name: "keys",
|
||||
Usage: "(internal) Should only be called by SSH server",
|
||||
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Action: runKeys,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "expected",
|
||||
Aliases: []string{"e"},
|
||||
Value: "git",
|
||||
Usage: "Expected user for whom provide key commands",
|
||||
func cmdKeys() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "keys",
|
||||
Usage: "(internal) Should only be called by SSH server",
|
||||
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Action: runKeys,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "expected",
|
||||
Aliases: []string{"e"},
|
||||
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") {
|
||||
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")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), true)
|
||||
|
@ -78,6 +81,6 @@ func runKeys(c *cli.Context) error {
|
|||
if extra.Error != nil {
|
||||
return extra.Error
|
||||
}
|
||||
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString.Text))
|
||||
_, _ = fmt.Fprintln(c.Root().Writer, strings.TrimSpace(authorizedString.Text))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,16 +4,17 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forgejo.org/modules/private"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func runSendMail(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runSendMail(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setting.MustInstalled()
|
||||
|
|
115
cmd/main.go
115
cmd/main.go
|
@ -14,7 +14,7 @@ import (
|
|||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// cmdHelp is our own help subcommand with more information
|
||||
|
@ -25,18 +25,18 @@ func cmdHelp() *cli.Command {
|
|||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
ArgsUsage: "[command]",
|
||||
Action: func(c *cli.Context) (err error) {
|
||||
lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea, {Command:nil}
|
||||
Action: func(ctx context.Context, c *cli.Command) (err error) {
|
||||
lineage := c.Lineage() // The order is from child to parent: help, doctor, Forgejo
|
||||
targetCmdIdx := 0
|
||||
if c.Command.Name == "help" {
|
||||
if c.Name == "help" {
|
||||
targetCmdIdx = 1
|
||||
}
|
||||
if lineage[targetCmdIdx+1].Command != nil {
|
||||
err = cli.ShowCommandHelp(lineage[targetCmdIdx+1], lineage[targetCmdIdx].Command.Name)
|
||||
if targetCmdIdx+1 < len(lineage) {
|
||||
err = cli.ShowCommandHelp(ctx, lineage[targetCmdIdx+1], lineage[targetCmdIdx].Name)
|
||||
} else {
|
||||
err = cli.ShowAppHelp(c)
|
||||
}
|
||||
_, _ = fmt.Fprintf(c.App.Writer, `
|
||||
_, _ = fmt.Fprintf(c.Root().Writer, `
|
||||
DEFAULT CONFIGURATION:
|
||||
AppPath: %s
|
||||
WorkPath: %s
|
||||
|
@ -77,25 +77,25 @@ func appGlobalFlags() []cli.Flag {
|
|||
}
|
||||
}
|
||||
|
||||
func prepareSubcommandWithConfig(command *cli.Command, globalFlags []cli.Flag) {
|
||||
command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...)
|
||||
func prepareSubcommandWithConfig(command *cli.Command, globalFlags func() []cli.Flag) {
|
||||
command.Flags = append(globalFlags(), command.Flags...)
|
||||
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
||||
command.HideHelp = true
|
||||
if command.Name != "help" {
|
||||
command.Subcommands = append(command.Subcommands, cmdHelp())
|
||||
command.Commands = append(command.Commands, cmdHelp())
|
||||
}
|
||||
for i := range command.Subcommands {
|
||||
prepareSubcommandWithConfig(command.Subcommands[i], globalFlags)
|
||||
for i := range command.Commands {
|
||||
prepareSubcommandWithConfig(command.Commands[i], globalFlags)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) error {
|
||||
return func(ctx *cli.Context) error {
|
||||
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(_ context.Context, _ *cli.Command) error {
|
||||
return func(ctx context.Context, cli *cli.Command) error {
|
||||
var args setting.ArgWorkPathAndCustomConf
|
||||
// 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 == "" {
|
||||
args.WorkPath = curCtx.String("work-path")
|
||||
}
|
||||
|
@ -107,15 +107,15 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
|
|||
}
|
||||
}
|
||||
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"
|
||||
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()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -124,7 +124,7 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
|||
|
||||
subCmdsStandalone := 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
|
||||
|
@ -133,14 +133,16 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
|||
if executable == "forgejo-cli" {
|
||||
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdActions(context.Background()))
|
||||
subCmdWithConfig = append(subCmdWithConfig, forgejo.CmdF3(context.Background()))
|
||||
globalFlags = append(globalFlags, []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "verbose",
|
||||
},
|
||||
}...)
|
||||
globalFlags = func() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "verbose",
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdForgejo(context.Background()))
|
||||
subCmdWithConfig = append(subCmdWithConfig, CmdActions)
|
||||
subCmdWithConfig = append(subCmdWithConfig, cmdActions())
|
||||
}
|
||||
|
||||
return innerNewMainApp(version, versionExtra, subCmdsStandalone, subCmdWithConfig, globalFlags)
|
||||
}
|
||||
|
||||
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs []cli.Flag) *cli.App {
|
||||
app := cli.NewApp()
|
||||
app.HelpName = "forgejo"
|
||||
app.Name = "Forgejo"
|
||||
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs func() []cli.Flag) *cli.Command {
|
||||
app := &cli.Command{}
|
||||
app.Name = "forgejo"
|
||||
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.Version = version + versionExtra
|
||||
app.EnableBashCompletion = true
|
||||
app.EnableShellCompletion = true
|
||||
|
||||
// these sub-commands need to use config file
|
||||
subCmdWithConfig := []*cli.Command{
|
||||
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
||||
CmdWeb,
|
||||
CmdServ,
|
||||
CmdHook,
|
||||
CmdKeys,
|
||||
CmdDump,
|
||||
CmdAdmin,
|
||||
CmdMigrate,
|
||||
CmdDoctor,
|
||||
CmdManager,
|
||||
CmdEmbedded,
|
||||
CmdMigrateStorage,
|
||||
CmdDumpRepository,
|
||||
CmdRestoreRepository,
|
||||
cmdWeb(),
|
||||
cmdServ(),
|
||||
cmdHook(),
|
||||
cmdKeys(),
|
||||
cmdDump(),
|
||||
cmdAdmin(),
|
||||
cmdMigrate(),
|
||||
cmdDoctor(),
|
||||
cmdManager(),
|
||||
cmdEmbedded(),
|
||||
cmdMigrateStorage(),
|
||||
cmdDumpRepository(),
|
||||
cmdRestoreRepository(),
|
||||
}
|
||||
|
||||
subCmdWithConfig = append(subCmdWithConfig, subCmdWithConfigArgs...)
|
||||
|
||||
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
||||
subCmdStandalone := []*cli.Command{
|
||||
CmdCert,
|
||||
CmdGenerate,
|
||||
CmdDocs,
|
||||
cmdCert(),
|
||||
cmdGenerate(),
|
||||
}
|
||||
subCmdStandalone = append(subCmdStandalone, subCmdsStandaloneArgs...)
|
||||
|
||||
app.DefaultCommand = CmdWeb.Name
|
||||
app.DefaultCommand = cmdWeb().Name
|
||||
|
||||
globalFlags := appGlobalFlags()
|
||||
globalFlags = append(globalFlags, globalFlagsArgs...)
|
||||
globalFlags := func() []cli.Flag {
|
||||
return append(appGlobalFlags(), globalFlagsArgs()...)
|
||||
}
|
||||
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.Before = PrepareConsoleLoggerLevel(log.INFO)
|
||||
for i := range subCmdWithConfig {
|
||||
|
@ -210,8 +211,8 @@ func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmd
|
|||
return app
|
||||
}
|
||||
|
||||
func RunMainApp(app *cli.App, args ...string) error {
|
||||
err := app.Run(args)
|
||||
func RunMainApp(app *cli.Command, args ...string) error {
|
||||
err := app.Run(context.Background(), args)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -220,7 +221,7 @@ func RunMainApp(app *cli.App, args ...string) error {
|
|||
cli.OsExiter(1)
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
||||
_, _ = fmt.Fprintf(app.Root().ErrWriter, "Command error: %v\n", err)
|
||||
cli.OsExiter(1)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
@ -16,7 +18,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
@ -27,10 +29,10 @@ func makePathOutput(workPath, customPath, customConf string) string {
|
|||
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")
|
||||
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
|
||||
prepareSubcommandWithConfig(testCmd, appGlobalFlags())
|
||||
prepareSubcommandWithConfig(testCmd, appGlobalFlags)
|
||||
app.Commands = append(app.Commands, testCmd)
|
||||
app.DefaultCommand = testCmd.Name
|
||||
return app
|
||||
|
@ -42,7 +44,7 @@ type runResult struct {
|
|||
ExitCode int
|
||||
}
|
||||
|
||||
func runTestApp(app *cli.App, args ...string) (runResult, error) {
|
||||
func runTestApp(app *cli.Command, args ...string) (runResult, error) {
|
||||
outBuf := new(strings.Builder)
|
||||
errBuf := new(strings.Builder)
|
||||
app.Writer = outBuf
|
||||
|
@ -65,7 +67,6 @@ func TestCliCmd(t *testing.T) {
|
|||
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
|
||||
|
||||
cli.CommandHelpTemplate = "(command help template)"
|
||||
cli.AppHelpTemplate = "(app help template)"
|
||||
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
||||
|
||||
cases := []struct {
|
||||
|
@ -109,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 {
|
||||
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 {
|
||||
t.Setenv(k, v)
|
||||
}
|
||||
|
@ -122,34 +128,34 @@ func TestCliCmd(t *testing.T) {
|
|||
r, err := runTestApp(app, args...)
|
||||
require.NoError(t, err, 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) {
|
||||
app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") })
|
||||
app := newTestApp(func(_ context.Context, ctx *cli.Command) error { return errors.New("normal error") })
|
||||
r, err := runTestApp(app, "./gitea", "test-cmd")
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, 1, r.ExitCode)
|
||||
assert.Empty(t, r.Stdout)
|
||||
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")
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, 2, r.ExitCode)
|
||||
assert.Empty(t, r.Stdout)
|
||||
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")
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, 1, r.ExitCode)
|
||||
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout)
|
||||
assert.Empty(t, r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
|
||||
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.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")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
||||
|
|
|
@ -4,30 +4,34 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"forgejo.org/modules/private"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// CmdManager represents the manager command
|
||||
CmdManager = &cli.Command{
|
||||
// CmdManager represents the manager command
|
||||
func cmdManager() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "manager",
|
||||
Usage: "Manage the running forgejo process",
|
||||
Description: "This is a command for managing the running forgejo process",
|
||||
Subcommands: []*cli.Command{
|
||||
subcmdShutdown,
|
||||
subcmdRestart,
|
||||
subcmdReloadTemplates,
|
||||
subcmdFlushQueues,
|
||||
subcmdLogging,
|
||||
subCmdProcesses,
|
||||
Commands: []*cli.Command{
|
||||
subcmdShutdown(),
|
||||
subcmdRestart(),
|
||||
subcmdReloadTemplates(),
|
||||
subcmdFlushQueues(),
|
||||
subcmdLogging(),
|
||||
subCmdProcesses(),
|
||||
},
|
||||
}
|
||||
subcmdShutdown = &cli.Command{
|
||||
}
|
||||
|
||||
func subcmdShutdown() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "shutdown",
|
||||
Usage: "Gracefully shutdown the running process",
|
||||
Flags: []cli.Flag{
|
||||
|
@ -37,7 +41,10 @@ var (
|
|||
},
|
||||
Action: runShutdown,
|
||||
}
|
||||
subcmdRestart = &cli.Command{
|
||||
}
|
||||
|
||||
func subcmdRestart() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "restart",
|
||||
Usage: "Gracefully restart the running process - (not implemented for windows servers)",
|
||||
Flags: []cli.Flag{
|
||||
|
@ -47,7 +54,10 @@ var (
|
|||
},
|
||||
Action: runRestart,
|
||||
}
|
||||
subcmdReloadTemplates = &cli.Command{
|
||||
}
|
||||
|
||||
func subcmdReloadTemplates() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "reload-templates",
|
||||
Usage: "Reload template files in the running process",
|
||||
Flags: []cli.Flag{
|
||||
|
@ -57,7 +67,10 @@ var (
|
|||
},
|
||||
Action: runReloadTemplates,
|
||||
}
|
||||
subcmdFlushQueues = &cli.Command{
|
||||
}
|
||||
|
||||
func subcmdFlushQueues() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "flush-queues",
|
||||
Usage: "Flush queues in the running process",
|
||||
Action: runFlushQueues,
|
||||
|
@ -76,7 +89,10 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
subCmdProcesses = &cli.Command{
|
||||
}
|
||||
|
||||
func subCmdProcesses() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "processes",
|
||||
Usage: "Display running processes within the current process",
|
||||
Action: runProcesses,
|
||||
|
@ -106,10 +122,10 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func runShutdown(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runShutdown(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -117,8 +133,8 @@ func runShutdown(c *cli.Context) error {
|
|||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runRestart(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runRestart(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -126,8 +142,8 @@ func runRestart(c *cli.Context) error {
|
|||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runReloadTemplates(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runReloadTemplates(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -135,8 +151,8 @@ func runReloadTemplates(c *cli.Context) error {
|
|||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runFlushQueues(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runFlushQueues(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -144,8 +160,8 @@ func runFlushQueues(c *cli.Context) error {
|
|||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runProcesses(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runProcesses(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -11,11 +12,11 @@ import (
|
|||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/private"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultLoggingFlags = []cli.Flag{
|
||||
func defaultLoggingFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "logger",
|
||||
Usage: `Logger name - will default to "default"`,
|
||||
|
@ -56,11 +57,13 @@ var (
|
|||
Name: "debug",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
subcmdLogging = &cli.Command{
|
||||
func subcmdLogging() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "logging",
|
||||
Usage: "Adjust logging commands",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "pause",
|
||||
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",
|
||||
Usage: "Add a logger",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "file",
|
||||
Usage: "Add a file logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
Flags: append(defaultLoggingFlags(), []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "filename",
|
||||
Aliases: []string{"f"},
|
||||
|
@ -152,7 +155,7 @@ var (
|
|||
}, {
|
||||
Name: "conn",
|
||||
Usage: "Add a net conn logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
Flags: append(defaultLoggingFlags(), []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "reconnect-on-message",
|
||||
Aliases: []string{"R"},
|
||||
|
@ -193,10 +196,10 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func runRemoveLogger(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runRemoveLogger(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -210,8 +213,8 @@ func runRemoveLogger(c *cli.Context) error {
|
|||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runAddConnLogger(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runAddConnLogger(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -237,11 +240,11 @@ func runAddConnLogger(c *cli.Context) error {
|
|||
if c.IsSet("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 {
|
||||
ctx, cancel := installSignals()
|
||||
func runAddFileLogger(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -270,10 +273,10 @@ func runAddFileLogger(c *cli.Context) error {
|
|||
if c.IsSet("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 {
|
||||
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") {
|
||||
writer = c.String("writer")
|
||||
}
|
||||
ctx, cancel := installSignals()
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
extra := private.AddLogger(ctx, logger, writer, mode, vals)
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runPauseLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runPauseLogging(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -317,8 +320,8 @@ func runPauseLogging(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runResumeLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runResumeLogging(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -327,8 +330,8 @@ func runResumeLogging(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runReleaseReopenLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runReleaseReopenLogging(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
@ -337,8 +340,8 @@ func runReleaseReopenLogging(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runSetLogSQL(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runSetLogSQL(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
setup(ctx, c.Bool("debug"), false)
|
||||
|
||||
|
|
|
@ -11,19 +11,21 @@ import (
|
|||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdMigrate represents the available migrate sub-command.
|
||||
var CmdMigrate = &cli.Command{
|
||||
Name: "migrate",
|
||||
Usage: "Migrate the database",
|
||||
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 cmdMigrate() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "migrate",
|
||||
Usage: "Migrate the database",
|
||||
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 {
|
||||
stdCtx, cancel := installSignals()
|
||||
func runMigrate(stdCtx context.Context, ctx *cli.Command) error {
|
||||
stdCtx, cancel := installSignals(stdCtx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(stdCtx); err != nil {
|
||||
|
|
|
@ -22,79 +22,81 @@ import (
|
|||
"forgejo.org/modules/setting"
|
||||
"forgejo.org/modules/storage"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// CmdMigrateStorage represents the available migrate storage sub-command.
|
||||
var CmdMigrateStorage = &cli.Command{
|
||||
Name: "migrate-storage",
|
||||
Usage: "Migrate the storage",
|
||||
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
||||
Action: runMigrateStorage,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "type",
|
||||
Aliases: []string{"t"},
|
||||
Value: "",
|
||||
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'",
|
||||
func cmdMigrateStorage() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "migrate-storage",
|
||||
Usage: "Migrate the storage",
|
||||
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
||||
Action: runMigrateStorage,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "type",
|
||||
Aliases: []string{"t"},
|
||||
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 {
|
||||
|
@ -182,8 +184,8 @@ func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStora
|
|||
})
|
||||
}
|
||||
|
||||
func runMigrateStorage(ctx *cli.Context) error {
|
||||
stdCtx, cancel := installSignals()
|
||||
func runMigrateStorage(stdCtx context.Context, ctx *cli.Command) error {
|
||||
stdCtx, cancel := installSignals(stdCtx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(stdCtx); err != nil {
|
||||
|
|
|
@ -4,52 +4,55 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"forgejo.org/modules/private"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdRestoreRepository represents the available restore a repository sub-command.
|
||||
var CmdRestoreRepository = &cli.Command{
|
||||
Name: "restore-repo",
|
||||
Usage: "Restore the repository from disk",
|
||||
Description: "This is a command for restoring the repository data.",
|
||||
Action: runRestoreRepository,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo_dir",
|
||||
Aliases: []string{"r"},
|
||||
Value: "./data",
|
||||
Usage: "Repository dir path to restore from",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "owner_name",
|
||||
Value: "",
|
||||
Usage: "Restore destination owner name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo_name",
|
||||
Value: "",
|
||||
Usage: "Restore destination repository name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "units",
|
||||
Value: "",
|
||||
Usage: `Which items will be restored, one or more units should be separated as comma.
|
||||
func cmdRestoreRepository() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "restore-repo",
|
||||
Usage: "Restore the repository from disk",
|
||||
Description: "This is a command for restoring the repository data.",
|
||||
Action: runRestoreRepository,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo_dir",
|
||||
Aliases: []string{"r"},
|
||||
Value: "./data",
|
||||
Usage: "Repository dir path to restore from",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "owner_name",
|
||||
Value: "",
|
||||
Usage: "Restore destination owner name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo_name",
|
||||
Value: "",
|
||||
Usage: "Restore destination repository name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "units",
|
||||
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.`,
|
||||
},
|
||||
&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 {
|
||||
ctx, cancel := installSignals()
|
||||
func runRestoreRepository(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
setting.MustInstalled()
|
||||
|
|
36
cmd/serv.go
36
cmd/serv.go
|
@ -33,7 +33,7 @@ import (
|
|||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/kballard/go-shellquote"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -41,20 +41,22 @@ const (
|
|||
)
|
||||
|
||||
// CmdServ represents the available serv sub-command.
|
||||
var CmdServ = &cli.Command{
|
||||
Name: "serv",
|
||||
Usage: "(internal) Should only be called by SSH shell",
|
||||
Description: "Serv provides access auth for repositories",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Action: runServ,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "enable-pprof",
|
||||
func cmdServ() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "serv",
|
||||
Usage: "(internal) Should only be called by SSH shell",
|
||||
Description: "Serv provides access auth for repositories",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Action: runServ,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "enable-pprof",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func setup(ctx context.Context, debug, gitNeeded bool) {
|
||||
|
@ -131,8 +133,8 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runServ(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
func runServ(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
// FIXME: This needs to internationalised
|
||||
|
@ -194,7 +196,7 @@ func runServ(c *cli.Context) error {
|
|||
if git.CheckGitVersionAtLeast("2.29") == nil {
|
||||
// for AGit Flow
|
||||
if cmd == "ssh_info" {
|
||||
fmt.Print(`{"type":"gitea","version":1}`)
|
||||
fmt.Print(`{"type":"agit","version":1}`)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
84
cmd/web.go
84
cmd/web.go
|
@ -26,48 +26,50 @@ import (
|
|||
"forgejo.org/routers/install"
|
||||
|
||||
"github.com/felixge/fgprof"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// PIDFile could be set from build tag
|
||||
var PIDFile = "/run/gitea.pid"
|
||||
|
||||
// CmdWeb represents the available web sub-command.
|
||||
var CmdWeb = &cli.Command{
|
||||
Name: "web",
|
||||
Usage: "Start the Forgejo web server",
|
||||
Description: `The Forgejo web server is the only thing you need to run,
|
||||
func cmdWeb() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "web",
|
||||
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`,
|
||||
Before: PrepareConsoleLoggerLevel(log.INFO),
|
||||
Action: runWeb,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "port",
|
||||
Aliases: []string{"p"},
|
||||
Value: "3000",
|
||||
Usage: "Temporary port number to prevent conflict",
|
||||
Before: PrepareConsoleLoggerLevel(log.INFO),
|
||||
Action: runWeb,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "port",
|
||||
Aliases: []string{"p"},
|
||||
Value: "3000",
|
||||
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() {
|
||||
|
@ -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")
|
||||
|
||||
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
||||
|
@ -161,7 +163,7 @@ func serveInstall(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func serveInstalled(ctx *cli.Context) error {
|
||||
func serveInstalled(_ context.Context, ctx *cli.Command) error {
|
||||
setting.InitCfgProvider(setting.CustomConf)
|
||||
setting.LoadCommonSettings()
|
||||
setting.MustInstalled()
|
||||
|
@ -233,7 +235,7 @@ func servePprof() {
|
|||
finished()
|
||||
}
|
||||
|
||||
func runWeb(ctx *cli.Context) error {
|
||||
func runWeb(ctx context.Context, cli *cli.Command) error {
|
||||
defer func() {
|
||||
if panicked := recover(); panicked != nil {
|
||||
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
||||
|
@ -251,12 +253,12 @@ func runWeb(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
// Set pid file setting
|
||||
if ctx.IsSet("pid") {
|
||||
createPIDFile(ctx.String("pid"))
|
||||
if cli.IsSet("pid") {
|
||||
createPIDFile(cli.String("pid"))
|
||||
}
|
||||
|
||||
if !setting.InstallLock {
|
||||
if err := serveInstall(ctx); err != nil {
|
||||
if err := serveInstall(ctx, cli); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
@ -267,7 +269,7 @@ func runWeb(ctx *cli.Context) error {
|
|||
go servePprof()
|
||||
}
|
||||
|
||||
return serveInstalled(ctx)
|
||||
return serveInstalled(ctx, cli)
|
||||
}
|
||||
|
||||
func setPort(port string) error {
|
||||
|
|
|
@ -4,16 +4,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/setting"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app := cli.Command{}
|
||||
app.Name = "environment-to-ini"
|
||||
app.Usage = "Use provided environment to update configuration ini"
|
||||
app.Description = `As a helper to allow docker users to update the forgejo configuration
|
||||
|
@ -72,13 +73,13 @@ func main() {
|
|||
},
|
||||
}
|
||||
app.Action = runEnvironmentToIni
|
||||
err := app.Run(os.Args)
|
||||
err := app.Run(context.Background(), os.Args)
|
||||
if err != nil {
|
||||
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
|
||||
env := append([]string{}, os.Environ()...)
|
||||
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
||||
|
|
|
@ -1025,6 +1025,10 @@ LEVEL = Info
|
|||
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
|
||||
;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls
|
||||
;;
|
||||
;; Comma separated list of default mirror repo units.
|
||||
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
|
||||
;DEFAULT_MIRROR_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.wiki,repo.projects,repo.packages
|
||||
;;
|
||||
;; Prefix archive files by placing them in a directory named after the repository
|
||||
;PREFIX_ARCHIVE_FILES = true
|
||||
;;
|
||||
|
@ -1572,6 +1576,15 @@ LEVEL = Info
|
|||
;; - manage_gpg_keys: a user cannot configure gpg keys
|
||||
;;EXTERNAL_USER_DISABLE_FEATURES =
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[moderation]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; When true enables moderation capabilities; default is false.
|
||||
;; If enabled it will be possible for users to report abusive content (new actions are added in the UI and /report_abuse route will be enabled) and a new Moderation section will be added to Admin settings where the reports can be reviewed.
|
||||
;ENABLED = false
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[openid]
|
||||
|
|
64
go.mod
64
go.mod
|
@ -2,17 +2,18 @@ module forgejo.org
|
|||
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.2
|
||||
toolchain go1.24.4
|
||||
|
||||
require (
|
||||
code.forgejo.org/f3/gof3/v3 v3.10.6
|
||||
code.forgejo.org/f3/gof3/v3 v3.11.0
|
||||
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/levelqueue v1.0.0
|
||||
code.forgejo.org/forgejo/reply v1.0.2
|
||||
code.forgejo.org/go-chi/binding v1.0.0
|
||||
code.forgejo.org/go-chi/cache v1.0.0
|
||||
code.forgejo.org/go-chi/captcha v1.0.1
|
||||
code.forgejo.org/go-chi/session v1.0.1
|
||||
code.forgejo.org/go-chi/binding v1.0.1
|
||||
code.forgejo.org/go-chi/cache v1.0.1
|
||||
code.forgejo.org/go-chi/captcha v1.0.2
|
||||
code.forgejo.org/go-chi/session v1.0.2
|
||||
code.gitea.io/actions-proto-go v0.4.0
|
||||
code.gitea.io/sdk/gitea v0.21.0
|
||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||
|
@ -20,12 +21,12 @@ require (
|
|||
github.com/42wim/httpsig v1.2.3
|
||||
github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||
github.com/ProtonMail/go-crypto v1.1.6
|
||||
github.com/ProtonMail/go-crypto v1.3.0
|
||||
github.com/PuerkitoBio/goquery v1.10.3
|
||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2
|
||||
github.com/alecthomas/chroma/v2 v2.17.2
|
||||
github.com/alecthomas/chroma/v2 v2.18.0
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
github.com/blevesearch/bleve/v2 v2.5.1
|
||||
github.com/blevesearch/bleve/v2 v2.5.2
|
||||
github.com/buildkite/terminal-to-html/v3 v3.16.8
|
||||
github.com/caddyserver/certmagic v0.23.0
|
||||
github.com/chi-middleware/proxy v1.1.1
|
||||
|
@ -40,14 +41,14 @@ require (
|
|||
github.com/gliderlabs/ssh v0.3.8
|
||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||
github.com/go-chi/chi/v5 v5.2.0
|
||||
github.com/go-chi/chi/v5 v5.2.1
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-co-op/gocron v1.37.0
|
||||
github.com/go-enry/go-enry/v2 v2.9.2
|
||||
github.com/go-git/go-git/v5 v5.13.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.6
|
||||
github.com/go-openapi/spec v0.20.14
|
||||
github.com/go-sql-driver/mysql v1.9.1
|
||||
github.com/go-openapi/spec v0.21.0
|
||||
github.com/go-sql-driver/mysql v1.9.2
|
||||
github.com/go-webauthn/webauthn v0.13.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||
|
@ -86,27 +87,27 @@ require (
|
|||
github.com/prometheus/client_golang v1.21.1
|
||||
github.com/redis/go-redis/v9 v9.8.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
|
||||
github.com/sassoftware/go-rpmutils v0.4.0
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
||||
github.com/sergi/go-diff v1.4.0
|
||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/ulikunitz/xz v0.5.12
|
||||
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/yohcop/openid-go v1.0.1
|
||||
github.com/yuin/goldmark v1.7.11
|
||||
github.com/yuin/goldmark v1.7.12
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||
gitlab.com/gitlab-org/api/client-go v0.126.0
|
||||
go.uber.org/mock v0.5.1
|
||||
golang.org/x/crypto v0.38.0
|
||||
gitlab.com/gitlab-org/api/client-go v0.129.0
|
||||
go.uber.org/mock v0.5.2
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/image v0.27.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.14.0
|
||||
golang.org/x/sync v0.15.0
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/text v0.25.0
|
||||
golang.org/x/text v0.26.0
|
||||
google.golang.org/protobuf v1.36.4
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
|
@ -121,7 +122,6 @@ require (
|
|||
dario.cat/mergo v1.0.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
|
@ -146,13 +146,13 @@ require (
|
|||
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v16 v16.2.3 // indirect
|
||||
github.com/blevesearch/zapx/v16 v16.2.4 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect
|
||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.8 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
|
@ -170,9 +170,9 @@ require (
|
|||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
||||
github.com/go-openapi/swag v0.22.7 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
github.com/go-webauthn/x v0.1.21 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
|
@ -237,9 +237,9 @@ require (
|
|||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
golang.org/x/tools v0.31.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
|
124
go.sum
124
go.sum
|
@ -1,13 +1,15 @@
|
|||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
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.6/go.mod h1:K6lQCWQIyN/5rjP/OJL9fMA6fd++satndE20w/I6Kss=
|
||||
code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFsAE=
|
||||
code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ=
|
||||
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/act v1.26.0 h1:6mTmoaw7d/WpYiw/Pw6AaypxFdgJog5OFi/PMEgEbxs=
|
||||
code.forgejo.org/forgejo/act v1.26.0/go.mod h1:HFDFrXPrqfM9aH2RCnMiBdo/3ThxDmZjp58InPjGOfo=
|
||||
code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE=
|
||||
code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
code.forgejo.org/forgejo/go-rpmutils v1.0.0 h1:RZGGeKt70p/WaIEL97pyT6uiiEIoN8/aLmS5Z6WmX0M=
|
||||
code.forgejo.org/forgejo/go-rpmutils v1.0.0/go.mod h1:cg+VbgLXfrDPza9T+kBsMb3TVmmzPN4XseT6gDGLSUk=
|
||||
code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:RArF5AsF9LH4nEoJxqRxcP5r8hhRfWcId84G82YbqzA=
|
||||
code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||
code.forgejo.org/forgejo/levelqueue v1.0.0 h1:9krYpU6BM+j/1Ntj6m+VCAIu0UNnne1/UfU/XgPpLuE=
|
||||
|
@ -16,14 +18,14 @@ code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCd
|
|||
code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U=
|
||||
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 h1:kEZL84+02jY9RxXM4zHBWZ3Fml0B09cmP1LGkDsCfIA=
|
||||
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||
code.forgejo.org/go-chi/binding v1.0.0 h1:EIDJtk9brK7WsT7rvS/D4cxX8XlnhY3LMy8ex1jeHu0=
|
||||
code.forgejo.org/go-chi/binding v1.0.0/go.mod h1:fWwqaHj0H1/KeCpBqdvKunflq8pYfciEHI5v3UUeE2E=
|
||||
code.forgejo.org/go-chi/cache v1.0.0 h1:akLfGxNlHcacmtutovNtYFSTMsbdcp5MGjAEsP4pxnE=
|
||||
code.forgejo.org/go-chi/cache v1.0.0/go.mod h1:OVlZ/TqDYJ+RUJ+R+J+OLxtlyjo3pbjBeK7LAWAB+Vk=
|
||||
code.forgejo.org/go-chi/captcha v1.0.1 h1:/oe1fvGOpdyyeGijg3oMYNOYLvEovNvp79Y3gLe3qbk=
|
||||
code.forgejo.org/go-chi/captcha v1.0.1/go.mod h1:6EbjSVVa7WoZFENgwK/hLAJZq+HBXtgRsjnIngILC8Y=
|
||||
code.forgejo.org/go-chi/session v1.0.1 h1:RNkcJQZJBqlvJoIFXSth87b3kMFZLDBA18VcitD+Z0Y=
|
||||
code.forgejo.org/go-chi/session v1.0.1/go.mod h1:y69sjS984wc7k4xyu77yNE5HKeSlBoQW8VSGdsK7RAs=
|
||||
code.forgejo.org/go-chi/binding v1.0.1 h1:coKNI+X1NzRN7X85LlrpvBRqk0TXpJ+ja28vusQWEuY=
|
||||
code.forgejo.org/go-chi/binding v1.0.1/go.mod h1:oTFFDg/dkwFbmVuusiULB1OlrIJM95cOGK7Nc3GYcoo=
|
||||
code.forgejo.org/go-chi/cache v1.0.1 h1:w6IsDcPbeEnEYZn7M2HJe3/3/Ehtcw/72VjcVK7+lBw=
|
||||
code.forgejo.org/go-chi/cache v1.0.1/go.mod h1:K3aQSyRIN4xiuqV1kanfQ6O4ToDpzDpY3bNOyGjFe3U=
|
||||
code.forgejo.org/go-chi/captcha v1.0.2 h1:vyHDPXkpjDv8bLO9NqtWzZayzstD/WpJ5xwEkAaqZGQ=
|
||||
code.forgejo.org/go-chi/captcha v1.0.2/go.mod h1:lxiPLcJ76UCZHoH31/Wbum4GUi2NgjfFZLrJkKv1lLE=
|
||||
code.forgejo.org/go-chi/session v1.0.2 h1:pG+AXre9L9VXJmTaADXkmeEPuRalhmBXyv6tG2Rvjcc=
|
||||
code.forgejo.org/go-chi/session v1.0.2/go.mod h1:HnEGyBny7WPzCiVLP2vzL5ssma+3gCSl/vLpuVNYrqc=
|
||||
code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU=
|
||||
code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
|
||||
code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4=
|
||||
|
@ -46,13 +48,11 @@ github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U
|
|||
github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
||||
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||
github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
|
||||
|
@ -62,8 +62,8 @@ github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2/go.mod h1:JitQWJ8JuV4Y
|
|||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
||||
github.com/alecthomas/chroma/v2 v2.17.2 h1:Rm81SCZ2mPoH+Q8ZCc/9YvzPUN/E7HgPiPJD8SLV6GI=
|
||||
github.com/alecthomas/chroma/v2 v2.17.2/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
||||
github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4=
|
||||
github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
|
@ -87,8 +87,8 @@ github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCk
|
|||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/blevesearch/bleve/v2 v2.5.1 h1:cc/O++W2Hcjp1SU5ETHeE+QYWv2oV88ldYEPowdmg8M=
|
||||
github.com/blevesearch/bleve/v2 v2.5.1/go.mod h1:9g/wnbWKm9AgXrU8Ecqi+IDdqjUHWymwkQRDg+5tafU=
|
||||
github.com/blevesearch/bleve/v2 v2.5.2 h1:Ab0r0MODV2C5A6BEL87GqLBySqp/s9xFgceCju6BQk8=
|
||||
github.com/blevesearch/bleve/v2 v2.5.2/go.mod h1:5Dj6dUQxZM6aqYT3eutTD/GpWKGFSsV8f7LDidFbwXo=
|
||||
github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y=
|
||||
github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
|
||||
github.com/blevesearch/geo v0.2.3 h1:K9/vbGI9ehlXdxjxDRJtoAMt7zGAsMIzc6n8zWcwnhg=
|
||||
|
@ -121,13 +121,13 @@ github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT
|
|||
github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8=
|
||||
github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k=
|
||||
github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
|
||||
github.com/blevesearch/zapx/v16 v16.2.3 h1:7Y0r+a3diEvlazsncexq1qoFOcBd64xwMS7aDm4lo1s=
|
||||
github.com/blevesearch/zapx/v16 v16.2.3/go.mod h1:wVJ+GtURAaRG9KQAMNYyklq0egV+XJlGcXNCE0OFjjA=
|
||||
github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww=
|
||||
github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
|
@ -150,8 +150,8 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
|
|||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
||||
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
|
@ -215,8 +215,8 @@ github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5La
|
|||
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
|
||||
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
|
||||
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
|
||||
|
@ -239,16 +239,16 @@ github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
|||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
|
||||
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
|
||||
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
||||
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
|
||||
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
|
||||
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
|
||||
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
|
||||
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
|
||||
github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8=
|
||||
github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
|
||||
github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI=
|
||||
github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
|
||||
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
|
@ -499,13 +499,11 @@ github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
|||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
||||
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs=
|
||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
|
@ -537,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/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/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/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
|
@ -554,8 +554,8 @@ github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBz
|
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo=
|
||||
github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY=
|
||||
github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
|
@ -564,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/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
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.126.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAjE7UeNatu2VWHRf4/LE=
|
||||
gitlab.com/gitlab-org/api/client-go v0.129.0 h1:o9KLn6fezmxBQWYnQrnilwyuOjlx4206KP0bUn3HuBE=
|
||||
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/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
|
@ -573,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/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
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.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
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/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
|
@ -591,8 +591,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
|||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||
|
@ -603,8 +603,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
@ -620,8 +620,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -633,8 +633,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -684,10 +684,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
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.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
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.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
|
@ -695,8 +695,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
38
manifest.scm
Normal file
38
manifest.scm
Normal file
|
@ -0,0 +1,38 @@
|
|||
;;; Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
;;; SPDX-License-Identifier: MIT
|
||||
;;;
|
||||
;;; Commentary:
|
||||
;;;
|
||||
;;; This is a GNU Guix manifest that can be used to create a
|
||||
;;; development environment to build and test Forgejo.
|
||||
;;;
|
||||
;;; The following is a usage example to create a containerized
|
||||
;;; environment, with HOME shared for the Go cache and the network
|
||||
;;; made available to fetch required Go and Node dependencies.
|
||||
;;;
|
||||
#|
|
||||
guix shell -CNF --share=$HOME -m manifest.scm
|
||||
export GOTOOLCHAIN=local # to use the Go binary from Guix
|
||||
export CC=gcc CGO_ENABLED=1
|
||||
export TAGS="timetzdata sqlite sqlite_unlock_notify"
|
||||
make clean
|
||||
make -j$(nproc)
|
||||
make test -j$(nproc) # run unit tests
|
||||
make test-sqlite -j$(nproc) # run integration tests
|
||||
make watch # run an instance/rebuild on changes
|
||||
|#
|
||||
(specifications->manifest
|
||||
(list "bash-minimal"
|
||||
"coreutils"
|
||||
"findutils"
|
||||
"gcc-toolchain"
|
||||
"git" ;libpcre support is required
|
||||
"git-lfs"
|
||||
"gnupg"
|
||||
"go"
|
||||
"grep"
|
||||
"make"
|
||||
"node"
|
||||
"nss-certs"
|
||||
"openssh"
|
||||
"sed"))
|
|
@ -5,6 +5,7 @@ package actions
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
@ -222,29 +223,38 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
|||
var hasWaiting bool
|
||||
for _, v := range jobs {
|
||||
id, job := v.Job()
|
||||
needs := job.Needs()
|
||||
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
||||
return err
|
||||
status := StatusFailure
|
||||
payload := []byte{}
|
||||
needs := []string{}
|
||||
name := run.Title
|
||||
runsOn := []string{}
|
||||
if job != nil {
|
||||
needs = job.Needs()
|
||||
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
||||
return err
|
||||
}
|
||||
payload, _ = v.Marshal()
|
||||
|
||||
if len(needs) > 0 || run.NeedApproval {
|
||||
status = StatusBlocked
|
||||
} else {
|
||||
status = StatusWaiting
|
||||
hasWaiting = true
|
||||
}
|
||||
name, _ = util.SplitStringAtByteN(job.Name, 255)
|
||||
runsOn = job.RunsOn()
|
||||
}
|
||||
payload, _ := v.Marshal()
|
||||
status := StatusWaiting
|
||||
if len(needs) > 0 || run.NeedApproval {
|
||||
status = StatusBlocked
|
||||
} else {
|
||||
hasWaiting = true
|
||||
}
|
||||
job.Name, _ = util.SplitStringAtByteN(job.Name, 255)
|
||||
runJobs = append(runJobs, &ActionRunJob{
|
||||
RunID: run.ID,
|
||||
RepoID: run.RepoID,
|
||||
OwnerID: run.OwnerID,
|
||||
CommitSHA: run.CommitSHA,
|
||||
IsForkPullRequest: run.IsForkPullRequest,
|
||||
Name: job.Name,
|
||||
Name: name,
|
||||
WorkflowPayload: payload,
|
||||
JobID: id,
|
||||
Needs: needs,
|
||||
RunsOn: job.RunsOn(),
|
||||
RunsOn: runsOn,
|
||||
Status: status,
|
||||
})
|
||||
}
|
||||
|
@ -346,7 +356,7 @@ func UpdateRunWithoutNotification(ctx context.Context, run *ActionRun, cols ...s
|
|||
return err
|
||||
}
|
||||
if affected == 0 {
|
||||
return fmt.Errorf("run has changed")
|
||||
return errors.New("run has changed")
|
||||
// It's impossible that the run is not found, since Gitea never deletes runs.
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ type FindRunJobOptions struct {
|
|||
CommitSHA string
|
||||
Statuses []Status
|
||||
UpdatedBefore timeutil.TimeStamp
|
||||
Events []string // []webhook_module.HookEventType
|
||||
RunNumber int64
|
||||
}
|
||||
|
||||
func (opts FindRunJobOptions) ToConds() builder.Cond {
|
||||
|
@ -76,5 +78,11 @@ func (opts FindRunJobOptions) ToConds() builder.Cond {
|
|||
if opts.UpdatedBefore > 0 {
|
||||
cond = cond.And(builder.Lt{"updated": opts.UpdatedBefore})
|
||||
}
|
||||
if len(opts.Events) > 0 {
|
||||
cond = cond.And(builder.In("event", opts.Events))
|
||||
}
|
||||
if opts.RunNumber > 0 {
|
||||
cond = cond.And(builder.Eq{"`index`": opts.RunNumber})
|
||||
}
|
||||
return cond
|
||||
}
|
||||
|
|
|
@ -34,6 +34,15 @@ var statusNames = map[Status]string{
|
|||
StatusBlocked: "blocked",
|
||||
}
|
||||
|
||||
var nameToStatus = make(map[string]Status, len(statusNames))
|
||||
|
||||
func init() {
|
||||
// Populate name to status lookup map
|
||||
for status, name := range statusNames {
|
||||
nameToStatus[name] = status
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the string name of the Status
|
||||
func (s Status) String() string {
|
||||
return statusNames[s]
|
||||
|
@ -102,3 +111,8 @@ func (s Status) AsResult() runnerv1.Result {
|
|||
}
|
||||
return runnerv1.Result_RESULT_UNSPECIFIED
|
||||
}
|
||||
|
||||
func StatusFromString(name string) (Status, bool) {
|
||||
status, exists := nameToStatus[name]
|
||||
return status, exists
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package activities
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
|
@ -458,7 +459,7 @@ type GetFeedsOptions struct {
|
|||
// GetFeeds returns actions according to the provided options
|
||||
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
|
||||
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
|
||||
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
||||
return nil, 0, errors.New("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
||||
}
|
||||
|
||||
cond, err := activityQueryCondition(ctx, opts)
|
||||
|
|
|
@ -13,6 +13,12 @@ import (
|
|||
"forgejo.org/modules/timeutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// contributionsMaxAgeSeconds How old data to retrieve for the heatmap.
|
||||
// 371 days to cover the entire heatmap (53 *full* weeks)
|
||||
contributionsMaxAgeSeconds = 32054400
|
||||
)
|
||||
|
||||
// UserHeatmapData represents the data needed to create a heatmap
|
||||
type UserHeatmapData struct {
|
||||
Timestamp timeutil.TimeStamp `json:"timestamp"`
|
||||
|
@ -62,7 +68,7 @@ func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organi
|
|||
Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
||||
Table("action").
|
||||
Where(cond).
|
||||
And("created_unix > ?", timeutil.TimeStampNow()-31536000).
|
||||
And("created_unix >= ?", timeutil.TimeStampNow()-contributionsMaxAgeSeconds).
|
||||
GroupBy("timestamp").
|
||||
OrderBy("timestamp").
|
||||
Find(&hdata)
|
||||
|
|
|
@ -54,6 +54,10 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
|
|||
"multiple actions performed with two grouped together",
|
||||
10, 10, 3, `[{"timestamp":1603009800,"contributions":1},{"timestamp":1603010700,"contributions":2}]`,
|
||||
},
|
||||
{
|
||||
"test cutoff within",
|
||||
40, 40, 1, `[{"timestamp":1577404800,"contributions":1}]`,
|
||||
},
|
||||
}
|
||||
// Prepare
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
|
|
@ -5,6 +5,7 @@ package asymkey
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -209,7 +210,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified
|
|||
// deleteGPGKey does the actual key deletion
|
||||
func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
||||
if keyID == "" {
|
||||
return 0, fmt.Errorf("empty KeyId forbidden") // Should never happen but just to be sure
|
||||
return 0, errors.New("empty KeyId forbidden") // Should never happen but just to be sure
|
||||
}
|
||||
// Delete imported key
|
||||
n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport))
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"bytes"
|
||||
"crypto"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
|
@ -75,7 +76,7 @@ func base64DecPubKey(content string) (*packet.PublicKey, error) {
|
|||
// Check type
|
||||
pkey, ok := p.(*packet.PublicKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key is not a public key")
|
||||
return nil, errors.New("key is not a public key")
|
||||
}
|
||||
return pkey, nil
|
||||
}
|
||||
|
@ -122,15 +123,15 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) {
|
|||
func extractSignature(s string) (*packet.Signature, error) {
|
||||
r, err := readArmoredSign(strings.NewReader(s))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read signature armor")
|
||||
return nil, errors.New("Failed to read signature armor")
|
||||
}
|
||||
p, err := packet.Read(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read signature packet")
|
||||
return nil, errors.New("Failed to read signature packet")
|
||||
}
|
||||
sig, ok := p.(*packet.Signature)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Packet is not a signature")
|
||||
return nil, errors.New("Packet is not a signature")
|
||||
}
|
||||
return sig, nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package asymkey
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"strings"
|
||||
|
@ -316,7 +317,7 @@ func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, si
|
|||
func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
|
||||
// Check if key can sign
|
||||
if !k.CanSign {
|
||||
return fmt.Errorf("key can not sign")
|
||||
return errors.New("key can not sign")
|
||||
}
|
||||
// Decode key
|
||||
pkey, err := base64DecPubKey(k.Content)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
|
@ -93,7 +94,7 @@ func parseKeyString(content string) (string, error) {
|
|||
|
||||
block, _ := pem.Decode([]byte(content))
|
||||
if block == nil {
|
||||
return "", fmt.Errorf("failed to parse PEM block containing the public key")
|
||||
return "", errors.New("failed to parse PEM block containing the public key")
|
||||
}
|
||||
if strings.Contains(block.Type, "PRIVATE") {
|
||||
return "", ErrKeyIsPrivate
|
||||
|
@ -226,7 +227,7 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
|
|||
|
||||
// The ssh library can parse the key, so next we find out what key exactly we have.
|
||||
switch pkeyType {
|
||||
case ssh.KeyAlgoDSA:
|
||||
case ssh.KeyAlgoDSA: //nolint:staticcheck
|
||||
rawPub := struct {
|
||||
Name string
|
||||
P, Q, G, Y *big.Int
|
||||
|
|
|
@ -69,6 +69,9 @@ func (l *XORMLogBridge) Warn(v ...any) {
|
|||
|
||||
// Warnf show warning log
|
||||
func (l *XORMLogBridge) Warnf(format string, v ...any) {
|
||||
if format == "Table %s Column %s db default is %s, struct default is %s" || format == "Table %s Column %s db nullable is %v, struct nullable is %v" {
|
||||
return
|
||||
}
|
||||
l.Log(stackLevel, log.WARN, format, v...)
|
||||
}
|
||||
|
||||
|
|
17
models/fixtures/TestGetUsedForUser/action_artifact.yaml
Normal file
17
models/fixtures/TestGetUsedForUser/action_artifact.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
-
|
||||
id: 1001
|
||||
run_id: 792
|
||||
runner_id: 1
|
||||
repo_id: 4
|
||||
owner_id: 1
|
||||
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
|
||||
storage_path: "27/5/1730330775594233150.chunk"
|
||||
file_size: 693147180559
|
||||
file_compressed_size: 693147180559
|
||||
content_encoding: "application/zip"
|
||||
artifact_path: "big-file.zip"
|
||||
artifact_name: "big-file"
|
||||
status: 4
|
||||
created_unix: 1730330775
|
||||
updated_unix: 1730330775
|
||||
expired_unix: 1738106775
|
|
@ -74,3 +74,11 @@
|
|||
is_private: false
|
||||
created_unix: 1680454039
|
||||
content: '4|' # issueId 5
|
||||
|
||||
- id: 10
|
||||
user_id: 40
|
||||
op_type: 1 # create repo
|
||||
act_user_id: 40
|
||||
repo_id: 60 # public
|
||||
is_private: false
|
||||
created_unix: 1577404800 # end of heatmap
|
|
@ -471,3 +471,64 @@
|
|||
need_approval: 0
|
||||
approved_by: 0
|
||||
event_payload: '{"head_commit":{"id":"5f22f7d0d95d614d25a5b68592adb345a4b5c7fd"}}'
|
||||
|
||||
|
||||
# GET action run(s) test
|
||||
-
|
||||
id: 892
|
||||
title: "successful push run"
|
||||
repo_id: 63
|
||||
owner_id: 2
|
||||
workflow_id: "success.yaml"
|
||||
index: 1
|
||||
trigger_user_id: 2
|
||||
ref: "refs/heads/main"
|
||||
commit_sha: "97f29ee599c373c729132a5c46a046978311e0ee"
|
||||
event: "push"
|
||||
is_fork_pull_request: 0
|
||||
status: 1 # success
|
||||
started: 1683636528
|
||||
stopped: 1683636626
|
||||
created: 1683636108
|
||||
updated: 1683636626
|
||||
need_approval: 0
|
||||
approved_by: 0
|
||||
|
||||
-
|
||||
id: 893
|
||||
title: "failed pull_request run"
|
||||
repo_id: 63
|
||||
owner_id: 2
|
||||
workflow_id: "failed.yaml"
|
||||
index: 2
|
||||
trigger_user_id: 2
|
||||
ref: "refs/heads/bugfix-1"
|
||||
commit_sha: "35c5cddfc19397501ec8f4f7bb808a7c8f04445f"
|
||||
event: "pull_request"
|
||||
is_fork_pull_request: 0
|
||||
status: 2 # failure
|
||||
started: 1683636528
|
||||
stopped: 1683636626
|
||||
created: 1683636108
|
||||
updated: 1683636626
|
||||
need_approval: 0
|
||||
approved_by: 0
|
||||
|
||||
-
|
||||
id: 894
|
||||
title: "running workflow_dispatch run"
|
||||
repo_id: 63
|
||||
owner_id: 2
|
||||
workflow_id: "running.yaml"
|
||||
index: 3
|
||||
trigger_user_id: 2
|
||||
ref: "refs/heads/main"
|
||||
commit_sha: "97f29ee599c373c729132a5c46a046978311e0ee"
|
||||
event: "workflow_dispatch"
|
||||
is_fork_pull_request: 0
|
||||
status: 6 # running
|
||||
started: 1683636528
|
||||
created: 1683636108
|
||||
updated: 1683636626
|
||||
need_approval: 0
|
||||
approved_by: 0
|
||||
|
|
|
@ -17,3 +17,13 @@
|
|||
id: 4
|
||||
user_id: 31
|
||||
follow_id: 33
|
||||
|
||||
-
|
||||
id: 5
|
||||
user_id: 4
|
||||
follow_id: 8
|
||||
|
||||
-
|
||||
id: 6
|
||||
user_id: 5
|
||||
follow_id: 8
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
id: 2
|
||||
hook_id: 1
|
||||
uuid: uuid2
|
||||
is_delivered: false
|
||||
is_delivered: true
|
||||
|
||||
-
|
||||
id: 3
|
||||
|
@ -40,4 +40,4 @@
|
|||
id: 4
|
||||
hook_id: 3
|
||||
uuid: uuid4
|
||||
is_delivered: false
|
||||
is_delivered: true
|
||||
|
|
|
@ -795,3 +795,10 @@
|
|||
type: 10
|
||||
config: "{}"
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 115
|
||||
repo_id: 63
|
||||
type: 10
|
||||
config: "{}"
|
||||
created_unix: 946684810
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
close_issues_via_commit_in_any_branch: false
|
||||
created_unix: 1731254961
|
||||
updated_unix: 1731254961
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 2
|
||||
owner_id: 2
|
||||
|
@ -61,7 +63,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: true
|
||||
|
||||
topics: '[]'
|
||||
-
|
||||
id: 3
|
||||
owner_id: 3
|
||||
|
@ -94,6 +96,7 @@
|
|||
close_issues_via_commit_in_any_branch: false
|
||||
created_unix: 1700000001
|
||||
updated_unix: 1700000001
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 4
|
||||
|
@ -125,6 +128,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 5
|
||||
|
@ -158,6 +162,7 @@
|
|||
close_issues_via_commit_in_any_branch: false
|
||||
created_unix: 1700000002
|
||||
updated_unix: 1700000002
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 6
|
||||
|
@ -190,6 +195,7 @@
|
|||
close_issues_via_commit_in_any_branch: false
|
||||
created_unix: 1710000001
|
||||
updated_unix: 1710000001
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 7
|
||||
|
@ -222,6 +228,7 @@
|
|||
close_issues_via_commit_in_any_branch: false
|
||||
created_unix: 1710000003
|
||||
updated_unix: 1710000003
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 8
|
||||
|
@ -254,6 +261,7 @@
|
|||
close_issues_via_commit_in_any_branch: false
|
||||
created_unix: 1710000002
|
||||
updated_unix: 1710000002
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 9
|
||||
|
@ -284,6 +292,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 10
|
||||
|
@ -315,6 +324,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 11
|
||||
|
@ -346,6 +356,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 12
|
||||
|
@ -376,6 +387,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 13
|
||||
|
@ -406,6 +418,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 14
|
||||
|
@ -437,6 +450,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 15
|
||||
|
@ -468,6 +482,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 16
|
||||
|
@ -499,6 +514,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 17
|
||||
|
@ -529,6 +545,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 18
|
||||
|
@ -559,6 +576,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 19
|
||||
|
@ -589,6 +607,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 20
|
||||
|
@ -619,6 +638,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 21
|
||||
|
@ -649,6 +669,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 22
|
||||
|
@ -679,6 +700,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 23
|
||||
|
@ -709,6 +731,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 24
|
||||
|
@ -739,6 +762,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 25
|
||||
|
@ -769,6 +793,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 26
|
||||
|
@ -799,6 +824,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 27
|
||||
|
@ -829,6 +855,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 28
|
||||
|
@ -859,6 +886,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 29
|
||||
|
@ -889,6 +917,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 30
|
||||
|
@ -919,6 +948,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 31
|
||||
|
@ -950,6 +980,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 32 # org public repo
|
||||
|
@ -982,6 +1013,7 @@
|
|||
close_issues_via_commit_in_any_branch: false
|
||||
created_unix: 1700000003
|
||||
updated_unix: 1700000003
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 33
|
||||
|
@ -1013,6 +1045,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 34
|
||||
|
@ -1043,6 +1076,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 35
|
||||
|
@ -1073,6 +1107,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 36
|
||||
|
@ -1104,6 +1139,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 37
|
||||
|
@ -1135,6 +1171,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 38
|
||||
|
@ -1166,6 +1203,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 39
|
||||
|
@ -1197,6 +1235,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 40
|
||||
|
@ -1228,6 +1267,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 41
|
||||
|
@ -1259,6 +1299,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 42
|
||||
|
@ -1290,6 +1331,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 43
|
||||
|
@ -1320,6 +1362,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 44
|
||||
|
@ -1351,6 +1394,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 45
|
||||
|
@ -1381,6 +1425,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 46
|
||||
|
@ -1412,6 +1457,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 47
|
||||
|
@ -1443,6 +1489,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 48
|
||||
|
@ -1474,6 +1521,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 49
|
||||
|
@ -1506,6 +1554,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 50
|
||||
|
@ -1537,6 +1586,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 51
|
||||
|
@ -1568,6 +1618,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 52
|
||||
|
@ -1599,6 +1650,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 53
|
||||
|
@ -1627,6 +1679,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 54
|
||||
|
@ -1639,6 +1692,7 @@
|
|||
is_archived: false
|
||||
is_private: true
|
||||
status: 0
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 55
|
||||
|
@ -1651,6 +1705,7 @@
|
|||
is_private: true
|
||||
num_issues: 1
|
||||
status: 0
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 56
|
||||
|
@ -1664,6 +1719,7 @@
|
|||
is_private: true
|
||||
status: 0
|
||||
num_issues: 0
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 57
|
||||
|
@ -1677,6 +1733,7 @@
|
|||
is_private: false
|
||||
status: 0
|
||||
num_issues: 0
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 58 # org public repo
|
||||
|
@ -1708,6 +1765,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 1059
|
||||
|
@ -1721,6 +1779,7 @@
|
|||
is_private: false
|
||||
status: 0
|
||||
num_issues: 0
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 59
|
||||
|
@ -1734,6 +1793,7 @@
|
|||
is_private: true
|
||||
status: 0
|
||||
num_issues: 0
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 60
|
||||
|
@ -1765,6 +1825,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 61
|
||||
|
@ -1796,6 +1857,7 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
- id: 62
|
||||
owner_id: 2
|
||||
|
@ -1826,3 +1888,36 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
-
|
||||
id: 63
|
||||
owner_id: 2
|
||||
owner_name: user2
|
||||
lower_name: test_action_run_search
|
||||
name: test_action_run_search
|
||||
default_branch: main
|
||||
num_watches: 0
|
||||
num_stars: 0
|
||||
num_forks: 0
|
||||
num_issues: 0
|
||||
num_closed_issues: 0
|
||||
num_pulls: 0
|
||||
num_closed_pulls: 0
|
||||
num_milestones: 0
|
||||
num_closed_milestones: 0
|
||||
num_projects: 0
|
||||
num_closed_projects: 0
|
||||
is_private: true
|
||||
is_empty: false
|
||||
is_archived: false
|
||||
is_mirror: false
|
||||
status: 0
|
||||
is_fork: false
|
||||
fork_id: 0
|
||||
is_template: false
|
||||
template_id: 0
|
||||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
login_source: 0
|
||||
login_name: user2
|
||||
type: 0
|
||||
website: https://keyoxide.org/eb114f5e6c0dc2bcdd183550a4b61a2dc5923710
|
||||
salt: ZogKvWdyEx
|
||||
max_repo_creation: -1
|
||||
is_active: true
|
||||
|
@ -69,7 +70,7 @@
|
|||
num_followers: 2
|
||||
num_following: 1
|
||||
num_stars: 2
|
||||
num_repos: 17
|
||||
num_repos: 18
|
||||
num_teams: 0
|
||||
num_members: 0
|
||||
visibility: 0
|
||||
|
@ -93,7 +94,7 @@
|
|||
login_name: org3
|
||||
type: 1
|
||||
salt: ZogKvWdyEx
|
||||
max_repo_creation: -1
|
||||
max_repo_creation: 1000
|
||||
is_active: false
|
||||
is_admin: false
|
||||
is_restricted: false
|
||||
|
@ -143,7 +144,7 @@
|
|||
avatar_email: user4@example.com
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 1
|
||||
num_following: 2
|
||||
num_stars: 0
|
||||
num_repos: 0
|
||||
num_teams: 0
|
||||
|
@ -181,7 +182,7 @@
|
|||
avatar_email: user5@example.com
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_following: 1
|
||||
num_stars: 0
|
||||
num_repos: 1
|
||||
num_teams: 0
|
||||
|
@ -294,7 +295,7 @@
|
|||
avatar: ""
|
||||
avatar_email: user8@example.com
|
||||
use_custom_avatar: true
|
||||
num_followers: 1
|
||||
num_followers: 3
|
||||
num_following: 1
|
||||
num_stars: 0
|
||||
num_repos: 0
|
||||
|
|
|
@ -35,7 +35,7 @@ func Test_FederationHostValidation(t *testing.T) {
|
|||
HostSchema: "https",
|
||||
}
|
||||
if res, _ := validation.IsValid(sut); res {
|
||||
t.Errorf("sut should be invalid: HostFqdn empty")
|
||||
t.Error("sut should be invalid: HostFqdn empty")
|
||||
}
|
||||
|
||||
sut = FederationHost{
|
||||
|
@ -48,7 +48,7 @@ func Test_FederationHostValidation(t *testing.T) {
|
|||
HostSchema: "https",
|
||||
}
|
||||
if res, _ := validation.IsValid(sut); res {
|
||||
t.Errorf("sut should be invalid: HostFqdn too long (len=256)")
|
||||
t.Error("sut should be invalid: HostFqdn too long (len=256)")
|
||||
}
|
||||
|
||||
sut = FederationHost{
|
||||
|
@ -59,7 +59,7 @@ func Test_FederationHostValidation(t *testing.T) {
|
|||
HostSchema: "https",
|
||||
}
|
||||
if res, _ := validation.IsValid(sut); res {
|
||||
t.Errorf("sut should be invalid: NodeInfo invalid")
|
||||
t.Error("sut should be invalid: NodeInfo invalid")
|
||||
}
|
||||
|
||||
sut = FederationHost{
|
||||
|
@ -72,7 +72,7 @@ func Test_FederationHostValidation(t *testing.T) {
|
|||
HostSchema: "https",
|
||||
}
|
||||
if res, _ := validation.IsValid(sut); res {
|
||||
t.Errorf("sut should be invalid: Future timestamp")
|
||||
t.Error("sut should be invalid: Future timestamp")
|
||||
}
|
||||
|
||||
sut = FederationHost{
|
||||
|
@ -85,6 +85,6 @@ func Test_FederationHostValidation(t *testing.T) {
|
|||
HostSchema: "https",
|
||||
}
|
||||
if res, _ := validation.IsValid(sut); res {
|
||||
t.Errorf("sut should be invalid: HostFqdn lower case")
|
||||
t.Error("sut should be invalid: HostFqdn lower case")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
package forgefed
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -28,7 +28,7 @@ func Test_NodeInfoWellKnownUnmarshalJSON(t *testing.T) {
|
|||
},
|
||||
"empty": {
|
||||
item: []byte(``),
|
||||
wantErr: fmt.Errorf("cannot parse JSON: cannot parse empty string; unparsed tail: \"\""),
|
||||
wantErr: errors.New("cannot parse JSON: cannot parse empty string; unparsed tail: \"\""),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ func Test_NewNodeInfoWellKnown(t *testing.T) {
|
|||
|
||||
_, err := NewNodeInfoWellKnown([]byte(`invalid`))
|
||||
if err == nil {
|
||||
t.Errorf("error was expected here")
|
||||
t.Error("error was expected here")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,6 @@ func Test_NewNodeInfo(t *testing.T) {
|
|||
|
||||
_, err := NewNodeInfo([]byte(`invalid`))
|
||||
if err == nil {
|
||||
t.Errorf("error was expected here")
|
||||
t.Error("error was expected here")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ package forgejo_migrations //nolint:revive
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
|
@ -98,6 +99,10 @@ var migrations = []*Migration{
|
|||
NewMigration("Add public key information to `FederatedUser` and `FederationHost`", AddPublicKeyInformationForFederation),
|
||||
// v29 -> v30
|
||||
NewMigration("Migrate `User.NormalizedFederatedURI` column to extract port & schema into FederatedHost", MigrateNormalizedFederatedURI),
|
||||
// v30 -> v31
|
||||
NewMigration("Normalize repository.topics to empty slice instead of null", SetTopicsAsEmptySlice),
|
||||
// v31 -> v32
|
||||
NewMigration("Migrate maven package name concatenation", ChangeMavenArtifactConcatenation),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current Forgejo database version.
|
||||
|
@ -130,7 +135,7 @@ func EnsureUpToDate(x *xorm.Engine) error {
|
|||
}
|
||||
|
||||
if currentDB < 0 {
|
||||
return fmt.Errorf("database has not been initialized")
|
||||
return errors.New("database has not been initialized")
|
||||
}
|
||||
|
||||
expected := ExpectedVersion()
|
||||
|
|
58
models/forgejo_migrations/v31.go
Normal file
58
models/forgejo_migrations/v31.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2025 The Forgejo Authors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package forgejo_migrations //nolint:revive
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func SetTopicsAsEmptySlice(x *xorm.Engine) error {
|
||||
var err error
|
||||
switch x.Dialect().URI().DBType {
|
||||
case schemas.MYSQL:
|
||||
_, err = x.Exec("UPDATE `repository` SET topics = '[]' WHERE topics IS NULL OR topics = 'null'")
|
||||
case schemas.SQLITE:
|
||||
_, err = x.Exec("UPDATE `repository` SET topics = '[]' WHERE topics IS NULL OR topics = 'null'")
|
||||
case schemas.POSTGRES:
|
||||
_, err = x.Exec("UPDATE `repository` SET topics = '[]' WHERE topics IS NULL OR topics::text = 'null'")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if x.Dialect().URI().DBType == schemas.SQLITE {
|
||||
sessMigration := x.NewSession()
|
||||
defer sessMigration.Close()
|
||||
if err := sessMigration.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sessMigration.Exec("ALTER TABLE `repository` RENAME COLUMN `topics` TO `topics_backup`")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sessMigration.Exec("ALTER TABLE `repository` ADD COLUMN `topics` TEXT NOT NULL DEFAULT '[]'")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sessMigration.Exec("UPDATE `repository` SET `topics` = `topics_backup`")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sessMigration.Exec("ALTER TABLE `repository` DROP COLUMN `topics_backup`")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sessMigration.Commit()
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Topics []string `xorm:"TEXT JSON NOT NULL"`
|
||||
}
|
||||
|
||||
return x.Sync(new(Repository))
|
||||
}
|
38
models/forgejo_migrations/v31_test.go
Normal file
38
models/forgejo_migrations/v31_test.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2025 The Forgejo Authors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package forgejo_migrations //nolint:revive
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
migration_tests "forgejo.org/models/migrations/test"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_SetTopicsAsEmptySlice(t *testing.T) {
|
||||
type Repository struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Topics []string `xorm:"TEXT JSON"`
|
||||
}
|
||||
|
||||
x, deferable := migration_tests.PrepareTestEnv(t, 0, new(Repository))
|
||||
defer deferable()
|
||||
if x == nil || t.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, SetTopicsAsEmptySlice(x))
|
||||
|
||||
var repos []Repository
|
||||
require.NoError(t, x.Find(&repos))
|
||||
|
||||
for _, repo := range repos {
|
||||
if repo.ID == 2 {
|
||||
require.Equal(t, []string{"go", "dev"}, repo.Topics, "Valid topics should remain unchanged")
|
||||
} else {
|
||||
require.Equal(t, []string{}, repo.Topics, "NULL topics should be set to empty array")
|
||||
}
|
||||
}
|
||||
}
|
414
models/forgejo_migrations/v32.go
Normal file
414
models/forgejo_migrations/v32.go
Normal file
|
@ -0,0 +1,414 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package forgejo_migrations //nolint:revive
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"forgejo.org/models/packages"
|
||||
"forgejo.org/modules/json"
|
||||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/packages/maven"
|
||||
packages_service "forgejo.org/services/packages"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
var getPackage = packages_service.GetPackageFileStream
|
||||
|
||||
type Snapshot struct {
|
||||
baseVersion string
|
||||
date string
|
||||
time string
|
||||
build int
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
XMLName xml.Name `xml:"metadata"`
|
||||
ModelVersion string `xml:"modelVersion,attr"`
|
||||
GroupID string `xml:"groupId"`
|
||||
ArtifactID string `xml:"artifactId"`
|
||||
Version string `xml:"version"`
|
||||
}
|
||||
|
||||
type mavenPackageResult struct {
|
||||
PackageFile *packages.PackageFile `xorm:"extends"`
|
||||
PackageVersion *packages.PackageVersion `xorm:"extends"`
|
||||
Package *packages.Package `xorm:"extends"`
|
||||
PackageName string `xorm:"-"`
|
||||
Snapshot *Snapshot `xorm:"-"`
|
||||
GroupID string `xorm:"-"`
|
||||
ArtifactID string `xorm:"-"`
|
||||
}
|
||||
|
||||
// ChangeMavenArtifactConcatenation resolves old dash-concatenated Maven coordinates and regenerates metadata.
|
||||
// Note: runs per-owner in a single transaction; failures roll back all owners.
|
||||
func ChangeMavenArtifactConcatenation(x *xorm.Engine) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get unique owner IDs of Maven packages
|
||||
var ownerIDs []*int64
|
||||
if err := sess.
|
||||
Table("package").
|
||||
Select("package.owner_id").
|
||||
Where("package.type = 'maven'").
|
||||
GroupBy("package.owner_id").
|
||||
OrderBy("package.owner_id DESC").
|
||||
Find(&ownerIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, id := range ownerIDs {
|
||||
if err := fixMavenArtifactPerOwner(sess, id); err != nil {
|
||||
log.Error("owner %d migration failed: %v", id, err)
|
||||
return err // rollback all
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func fixMavenArtifactPerOwner(sess *xorm.Session, ownerID *int64) error {
|
||||
results, err := getMavenPackageResultsToUpdate(sess, ownerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = resolvePackageCollisions(results, sess); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = processPackageVersions(results, sess); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return processPackageFiles(results, sess)
|
||||
}
|
||||
|
||||
// processPackageFiles updates Maven package files and versions in the database
|
||||
// Returns an error if any database or processing operation fails.
|
||||
func processPackageFiles(results []*mavenPackageResult, sess *xorm.Session) error {
|
||||
processedVersion := make(map[string][]*mavenPackageResult)
|
||||
|
||||
for _, r := range results {
|
||||
if r.Snapshot != nil {
|
||||
key := fmt.Sprintf("%s:%s", r.PackageName, r.PackageVersion.LowerVersion)
|
||||
processedVersion[key] = append(processedVersion[key], r)
|
||||
}
|
||||
|
||||
// Only update version_id when it differs
|
||||
if r.PackageVersion.ID != r.PackageFile.VersionID {
|
||||
pattern := strings.TrimSuffix(r.PackageFile.Name, ".pom") + "%"
|
||||
// Per routers/api/packages/maven/maven.go:338, POM files already have the `IsLead`, so no update needed for this prop
|
||||
if _, err := sess.Exec("UPDATE package_file SET version_id = ? WHERE version_id = ? and name like ?", r.PackageVersion.ID, r.PackageFile.VersionID, pattern); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If maven-metadata.xml is missing (snapshot path collision), skip regeneration
|
||||
// Without this metadata, Maven cannot resolve snapshot details
|
||||
for _, packageResults := range processedVersion {
|
||||
sort.Slice(packageResults, func(i, j int) bool {
|
||||
return packageResults[i].Snapshot.build > packageResults[j].Snapshot.build
|
||||
})
|
||||
|
||||
rs := packageResults[0]
|
||||
|
||||
pf, md, err := parseMetadata(sess, rs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if pf != nil && md != nil && md.GroupID == rs.GroupID && md.ArtifactID == rs.ArtifactID {
|
||||
if pf.VersionID != rs.PackageFile.VersionID {
|
||||
if _, err := sess.ID(pf.ID).Cols("version_id").Update(pf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
log.Warn("no maven-metadata.xml found for (id: %d) [%s:%s]", rs.PackageVersion.ID, rs.PackageName, rs.PackageVersion.Version)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseMetadata retrieves metadata for a Maven package file from the database and decodes it into a Metadata object.
|
||||
// Returns the associated PackageFile, Metadata, and any error encountered during processing.
|
||||
func parseMetadata(sess *xorm.Session, snapshot *mavenPackageResult) (*packages.PackageFile, *Metadata, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
var pf packages.PackageFile
|
||||
found, err := sess.Table(pf).
|
||||
Where("version_id = ?", snapshot.PackageFile.VersionID). // still the old id
|
||||
And("lower_name = ?", "maven-metadata.xml").
|
||||
Get(&pf)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
s, _, _, err := getPackage(ctx, &pf)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
defer s.Close()
|
||||
dec := xml.NewDecoder(s)
|
||||
var m Metadata
|
||||
if err := dec.Decode(&m); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &pf, &m, nil
|
||||
}
|
||||
|
||||
// processPackageVersions processes Maven package versions by updating metadata or inserting new records as necessary.
|
||||
// It avoids redundant updates by tracking already processed versions using a map. Returns an error on failure.
|
||||
func processPackageVersions(results []*mavenPackageResult, sess *xorm.Session) error {
|
||||
processedVersion := make(map[string]int64)
|
||||
|
||||
for _, r := range results {
|
||||
key := fmt.Sprintf("%s:%s", r.PackageName, r.PackageVersion.Version)
|
||||
|
||||
if id, ok := processedVersion[key]; ok {
|
||||
r.PackageVersion.ID = id
|
||||
continue
|
||||
}
|
||||
|
||||
// for non collisions, just update the metadata
|
||||
if r.PackageVersion.PackageID == r.Package.ID {
|
||||
if _, err := sess.ID(r.PackageVersion.ID).Cols("metadata_json").Update(r.PackageVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Info("Create new maven package version for %s:%s", r.PackageName, r.PackageVersion.Version)
|
||||
r.PackageVersion.ID = 0
|
||||
r.PackageVersion.PackageID = r.Package.ID
|
||||
if _, err := sess.Insert(r.PackageVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
processedVersion[key] = r.PackageVersion.ID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getMavenPackageResultsToUpdate retrieves Maven package results that need updates based on the owner ID.
|
||||
// It processes POM metadata, fixes package inconsistencies, and filters corrupted package versions.
|
||||
func getMavenPackageResultsToUpdate(sess *xorm.Session, ownerID *int64) ([]*mavenPackageResult, error) {
|
||||
ctx := context.Background()
|
||||
var candidates []*mavenPackageResult
|
||||
if err := sess.
|
||||
Table("package_file").
|
||||
Select("package_file.*, package_version.*, package.*").
|
||||
Join("INNER", "package_version", "package_version.id = package_file.version_id").
|
||||
Join("INNER", "package", "package.id = package_version.package_id").
|
||||
Where("package_file.lower_name LIKE ?", "%.pom").
|
||||
And("package.type = ?", "maven").
|
||||
And("package.owner_id = ?", ownerID).
|
||||
OrderBy("package_version.id DESC, package_file.id DESC").
|
||||
Find(&candidates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results []*mavenPackageResult
|
||||
var corruptedVersionIDs []int64
|
||||
|
||||
// fetch actual metadata from blob as all packages needs to be fixed following the new string concatenation
|
||||
for _, r := range candidates {
|
||||
if err := processPomMetadata(ctx, r); err != nil {
|
||||
// Skip corrupted versions; admin intervention may be needed to repair these files.
|
||||
log.Warn("Failed to process package file [id: %d] ignoring package version[%d]: %v", r.PackageFile.ID, r.PackageVersion.ID, err)
|
||||
|
||||
corruptedVersionIDs = append(corruptedVersionIDs, r.PackageVersion.ID)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
results = append(results, r)
|
||||
log.Debug("Resolved id [%d] from [%s:%s] to [%s:%s] [Snapshot: %v]", r.Package.ID, r.Package.Name, r.PackageVersion.Version, r.PackageName, r.PackageVersion.Version, r.Snapshot)
|
||||
}
|
||||
|
||||
for _, corruptedVersionID := range corruptedVersionIDs {
|
||||
for i := 0; i < len(results); {
|
||||
if corruptedVersionID == results[i].PackageVersion.ID {
|
||||
results = append(results[:i], results[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// resolvePackageCollisions handles name collisions by keeping the first existing record and inserting new Package records for subsequent collisions.
|
||||
// Returns a map from PackageName to its resolved Package.ID.
|
||||
func resolvePackageCollisions(results []*mavenPackageResult, sess *xorm.Session) error {
|
||||
// Group new names by lowerName
|
||||
collisions := make(map[string][]string)
|
||||
for _, r := range results {
|
||||
names := collisions[r.Package.LowerName]
|
||||
if !slices.Contains(names, r.PackageName) {
|
||||
collisions[r.Package.LowerName] = append(names, r.PackageName)
|
||||
}
|
||||
}
|
||||
|
||||
pkgIDByName := make(map[string]int64)
|
||||
var err error
|
||||
|
||||
for _, r := range results {
|
||||
list := collisions[r.Package.LowerName]
|
||||
|
||||
// update to the upcoming package name which is colon separated
|
||||
r.Package.Name = r.PackageName
|
||||
r.Package.LowerName = r.PackageName
|
||||
|
||||
// exiting entry
|
||||
if id, ok := pkgIDByName[r.PackageName]; ok {
|
||||
r.Package.ID = id
|
||||
// first package kept the current id
|
||||
} else if list[0] == r.PackageName {
|
||||
pkgIDByName[r.PackageName] = r.Package.ID
|
||||
|
||||
if _, err = sess.ID(r.Package.ID).Cols("name", "lower_name").Update(r.Package); err != nil {
|
||||
return err
|
||||
}
|
||||
// create a new entry
|
||||
} else {
|
||||
log.Info("Create new maven package for %s", r.Package.Name)
|
||||
|
||||
r.Package.ID = 0
|
||||
if _, err = sess.Insert(r.Package); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkgIDByName[r.PackageName] = r.Package.ID
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processPomMetadata processes a Maven package file, parses its POM metadata, and updates PackageVersion information.
|
||||
func processPomMetadata(ctx context.Context, mpr *mavenPackageResult) error {
|
||||
s, _, _, err := getPackage(ctx, mpr.PackageFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get package stream: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
actualPom, err := maven.ParsePackageMetaData(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse POM metadata: %v", err)
|
||||
}
|
||||
|
||||
raw, err := json.Marshal(actualPom)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal metadata: %v", err)
|
||||
}
|
||||
|
||||
var currentPom *maven.Metadata
|
||||
if err = json.Unmarshal([]byte(mpr.PackageVersion.MetadataJSON), ¤tPom); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal metadata: %v", err)
|
||||
}
|
||||
|
||||
// since the rest api can also be (ab)used to upload artifacts wrong, just ignore them
|
||||
if isInvalidMatch(currentPom, actualPom) {
|
||||
return fmt.Errorf("artifact mismatch: actual [%s] expected [%s]", actualPom.ArtifactID, currentPom.ArtifactID)
|
||||
}
|
||||
|
||||
// this will also fix packages that missed its groupID
|
||||
// Ref: https://codeberg.org/forgejo/forgejo/pulls/6329
|
||||
mpr.PackageVersion.MetadataJSON = string(raw)
|
||||
|
||||
// Since Maven packages are case-sensitive, avoid potential clashes and clean-ups
|
||||
// by enforcing consistent case handling similar to RPM packages.
|
||||
mpr.PackageName = fmt.Sprintf("%s:%s", actualPom.GroupID, actualPom.ArtifactID)
|
||||
|
||||
mpr.GroupID = actualPom.GroupID
|
||||
mpr.ArtifactID = actualPom.ArtifactID
|
||||
|
||||
if strings.HasSuffix(mpr.PackageVersion.Version, "-SNAPSHOT") {
|
||||
snap, err := extraSnapshotDetails(currentPom, actualPom, mpr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mpr.Snapshot = snap
|
||||
} else {
|
||||
// only snapshots are affected but kept in case of not complete fixtures
|
||||
expectedFileName := fmt.Sprintf("%s-%s.pom", actualPom.ArtifactID, mpr.PackageVersion.Version)
|
||||
if mpr.PackageFile.Name != expectedFileName {
|
||||
log.Warn("invalid package file name - this is a collision which needs to be resolved expected [%s], actual [%s]", expectedFileName, mpr.PackageFile.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// extraSnapshotDetails extracts detailed snapshot information
|
||||
// Returns a Snapshot object encapsulating the extracted details or an error if the filename is invalid or parsing fails.
|
||||
func extraSnapshotDetails(currentPom, actualPom *maven.Metadata, mpr *mavenPackageResult) (*Snapshot, error) {
|
||||
pattern := `^%s-` +
|
||||
`(?P<baseVersion>[\d\.]+)-` +
|
||||
`(?P<date>\d{8})\.` +
|
||||
`(?P<time>\d{6})-` +
|
||||
`(?P<build>\d+)\.pom$`
|
||||
re := regexp.MustCompile(fmt.Sprintf(pattern, regexp.QuoteMeta(currentPom.ArtifactID)))
|
||||
|
||||
if re.FindStringSubmatch(mpr.PackageFile.Name) == nil {
|
||||
log.Warn("invalid package file name - this is a collision which needs to be resolved %s", mpr.PackageFile.Name)
|
||||
}
|
||||
|
||||
re = regexp.MustCompile(fmt.Sprintf(pattern, regexp.QuoteMeta(actualPom.ArtifactID)))
|
||||
match := re.FindStringSubmatch(mpr.PackageFile.Name)
|
||||
|
||||
if match == nil {
|
||||
return nil, fmt.Errorf("invalid snapshot filename: %s", mpr.PackageFile.Name)
|
||||
}
|
||||
|
||||
baseIdx := re.SubexpIndex("baseVersion")
|
||||
dateIdx := re.SubexpIndex("date")
|
||||
timeIdx := re.SubexpIndex("time")
|
||||
buildIdx := re.SubexpIndex("build")
|
||||
|
||||
buildNum, _ := strconv.Atoi(match[buildIdx])
|
||||
|
||||
return &Snapshot{
|
||||
baseVersion: match[baseIdx],
|
||||
date: match[dateIdx],
|
||||
time: match[timeIdx],
|
||||
build: buildNum,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// isInvalidMatch returns true if the stored metadata’s groupID:artifactID
|
||||
// differs from actual values—accounting for an earlier bug that sometimes omitted the groupID.
|
||||
func isInvalidMatch(current, actual *maven.Metadata) bool {
|
||||
bare := fmt.Sprintf("-%s", actual.ArtifactID)
|
||||
full := fmt.Sprintf("%s-%s", actual.GroupID, actual.ArtifactID)
|
||||
currentID := fmt.Sprintf("%s-%s", current.GroupID, current.ArtifactID)
|
||||
|
||||
return currentID != full && currentID != bare
|
||||
}
|
369
models/forgejo_migrations/v32_test.go
Normal file
369
models/forgejo_migrations/v32_test.go
Normal file
|
@ -0,0 +1,369 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package forgejo_migrations //nolint:revive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
migration_tests "forgejo.org/models/migrations/test"
|
||||
"forgejo.org/models/packages"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type readSeekCloser struct {
|
||||
*bytes.Reader
|
||||
}
|
||||
|
||||
func (rsc readSeekCloser) Close() error {
|
||||
// No resources to close, so we simply provide a no-op implementation.
|
||||
return nil
|
||||
}
|
||||
|
||||
func StringToReadSeekCloser(s string) io.ReadSeekCloser {
|
||||
return readSeekCloser{Reader: bytes.NewReader([]byte(s))}
|
||||
}
|
||||
|
||||
func Test_ChangeMavenArtifactConcatenation(t *testing.T) {
|
||||
getPackage = func(ctx context.Context, pf *packages.PackageFile) (io.ReadSeekCloser, *url.URL, *packages.PackageFile, error) {
|
||||
var data string
|
||||
|
||||
switch pf.BlobID {
|
||||
case 1:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>1.0-SNAPSHOT</version></project>`
|
||||
case 3:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.example</groupId><artifactId>parent-project</artifactId></parent><groupId></groupId><artifactId>sub-module</artifactId><version>1.0-SNAPSHOT</version></project>`
|
||||
case 6:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>7.0.0</version></project>`
|
||||
case 7:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.example</groupId><artifactId>parent-project</artifactId></parent><groupId></groupId><artifactId>sub-module</artifactId><version>7.0.0</version></project>`
|
||||
case 9:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>7.0.0</version></project>`
|
||||
case 11:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo-</groupId><artifactId>bar</artifactId><version>1.0-SNAPSHOT</version></project>`
|
||||
case 13:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo-</groupId><artifactId>bar</artifactId><version>7.0.0</version></project>`
|
||||
case 14:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo</groupId><artifactId>-bar</artifactId><version>1.0-SNAPSHOT</version></project>`
|
||||
case 16:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo</groupId><artifactId>-bar</artifactId><version>7.0.0</version></project>`
|
||||
case 20:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>8.0.0</version></project>`
|
||||
case 21:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.example</groupId><artifactId>parent-project</artifactId></parent><groupId></groupId><artifactId>sub-module</artifactId><version>8.0.0</version></project>`
|
||||
case 23:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>8.0.0</version></project>`
|
||||
case 26:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo-</groupId><artifactId>bar</artifactId><version>8.0.0</version></project>`
|
||||
case 28:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo</groupId><artifactId>-bar</artifactId><version>8.0.0</version></project>`
|
||||
case 32:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>9.0.0</version></project>`
|
||||
case 33:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.example</groupId><artifactId>parent-project</artifactId></parent><groupId></groupId><artifactId>sub-module</artifactId><version>9.0.0</version></project>`
|
||||
case 35:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>9.0.0</version></project>`
|
||||
case 38:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo-</groupId><artifactId>bar</artifactId><version>9.0.0</version></project>`
|
||||
case 40:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo</groupId><artifactId>-bar</artifactId><version>9.0.0</version></project>`
|
||||
case 44:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>10.0.0</version></project>`
|
||||
case 45:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.example</groupId><artifactId>parent-project</artifactId></parent><groupId></groupId><artifactId>sub-module</artifactId><version>10.0.0</version></project>`
|
||||
case 47:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>10.0.0</version></project>`
|
||||
case 50:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo-</groupId><artifactId>bar</artifactId><version>10.0.0</version></project>`
|
||||
case 52:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo</groupId><artifactId>-bar</artifactId><version>10.0.0</version></project>`
|
||||
case 56:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>11.0.0</version></project>`
|
||||
case 57:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.example</groupId><artifactId>parent-project</artifactId></parent><groupId></groupId><artifactId>sub-module</artifactId><version>11.0.0</version></project>`
|
||||
case 59:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>11.0.0</version></project>`
|
||||
case 62:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo-</groupId><artifactId>bar</artifactId><version>11.0.0</version></project>`
|
||||
case 64:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>foo</groupId><artifactId>-bar</artifactId><version>11.0.0</version></project>`
|
||||
case 66:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.broken</groupId><artifactId>br-parent</artifactId></parent><groupId></groupId><artifactId>br-rest-webmvc</artifactId><version></version></project>`
|
||||
case 68:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.broken</groupId><artifactId>br-parent</artifactId></parent><groupId></groupId><artifactId>br-openapi-base</artifactId><version></version></project>`
|
||||
case 72:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><parent><groupId>de.loosetie</groupId><artifactId>lt-parent-kotlin</artifactId></parent><groupId>com.broken</groupId><artifactId>br-root</artifactId><version>1.2.4</version></project>`
|
||||
case 74:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.broken</groupId><artifactId>br-parent</artifactId></parent><groupId></groupId><artifactId>br-repo-jooq</artifactId><version></version></project>`
|
||||
case 76:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging></packaging><parent><groupId>com.broken</groupId><artifactId>br-parent</artifactId></parent><groupId></groupId><artifactId>br-repo-in-memory</artifactId><version></version></project>`
|
||||
case 78:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><parent><groupId>com.broken</groupId><artifactId>br-root</artifactId></parent><groupId></groupId><artifactId>br-parent</artifactId><version></version></project>`
|
||||
case 79:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>group</groupId><artifactId>bar-art</artifactId><version>11.0.0</version></project>`
|
||||
case 80:
|
||||
data = `<project><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><groupId>group-bar</groupId><artifactId>art</artifactId><version>11.0.0</version></project>`
|
||||
case 55:
|
||||
data = `<?xml version="1.0" encoding="UTF-8"?><metadata modelVersion="1.1.0"><groupId>com.example</groupId><artifactId>sub-module</artifactId><version>1.0-SNAPSHOT</version></metadata>`
|
||||
case 53:
|
||||
data = `<?xml version="1.0" encoding="UTF-8"?><metadata modelVersion="1.1.0"><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>1.0-SNAPSHOT</version></metadata>`
|
||||
case 63:
|
||||
data = `<?xml version="1.0" encoding="UTF-8"?><metadata modelVersion="1.1.0"><groupId>foo</groupId><artifactId>-bar</artifactId><version>1.0-SNAPSHOT</version></metadata>`
|
||||
default:
|
||||
t.Fatalf("Unknown package file type: %d", pf.BlobID)
|
||||
}
|
||||
|
||||
return StringToReadSeekCloser(data), nil, nil, nil
|
||||
}
|
||||
|
||||
x, deferable := migration_tests.PrepareTestEnv(t, 0, new(packages.Package), new(packages.PackageFile), new(packages.PackageVersion), new(packages.PackageBlob))
|
||||
defer deferable()
|
||||
if x == nil || t.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
cnt, err := x.Table("package").Count()
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, 8, cnt)
|
||||
|
||||
cnt, err = x.Table("package_file").Count()
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, 87, cnt)
|
||||
|
||||
cnt, err = x.Table("package_version").Count()
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, 31, cnt)
|
||||
|
||||
cnt, err = x.Table("package_blob").Count()
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, 80, cnt)
|
||||
|
||||
require.NoError(t, ChangeMavenArtifactConcatenation(x))
|
||||
|
||||
var pks []*packages.Package
|
||||
require.NoError(t, x.OrderBy("id").Find(&pks))
|
||||
validatePackages(t, pks)
|
||||
|
||||
var pvs []*packages.PackageVersion
|
||||
require.NoError(t, x.OrderBy("id").Find(&pvs))
|
||||
validatePackageVersions(t, pvs)
|
||||
|
||||
var pfs []*packages.PackageFile
|
||||
require.NoError(t, x.OrderBy("id").Find(&pfs))
|
||||
validatePackageFiles(t, pfs)
|
||||
}
|
||||
|
||||
func validatePackages(t *testing.T, pbs []*packages.Package) {
|
||||
assertPackage := func(id, ownerID, repoID int64, name string) {
|
||||
pb := pbs[id-1]
|
||||
|
||||
require.Equal(t, id, pb.ID)
|
||||
require.Equal(t, ownerID, pb.OwnerID)
|
||||
require.Equal(t, repoID, pb.RepoID)
|
||||
require.Equal(t, name, pb.Name)
|
||||
require.Equal(t, name, pb.LowerName)
|
||||
require.Equal(t, packages.TypeMaven, pb.Type)
|
||||
}
|
||||
|
||||
require.Len(t, pbs, 10)
|
||||
|
||||
assertPackage(1, 2, 0, "com.example:parent-project")
|
||||
assertPackage(2, 2, 0, "com.example:sub-module")
|
||||
assertPackage(3, 1, 0, "com.example:parent-project")
|
||||
assertPackage(4, 1, 0, "com.example:sub-module")
|
||||
assertPackage(5, 1, 0, "foo:-bar")
|
||||
assertPackage(6, 8, 54, "com.broken:br-rest-webmvc")
|
||||
// broken poms completely ignored as it is impossible to look up the correct metadata
|
||||
assertPackage(7, 8, 54, "com.broken-br-openapi-base")
|
||||
assertPackage(8, 1, 0, "group-bar:art")
|
||||
|
||||
// new created entries
|
||||
assertPackage(9, 1, 0, "group:bar-art")
|
||||
assertPackage(10, 1, 0, "foo-:bar")
|
||||
}
|
||||
|
||||
func validatePackageVersions(t *testing.T, pvs []*packages.PackageVersion) {
|
||||
require.Len(t, pvs, 38)
|
||||
|
||||
assertPackageVersion := func(id, packageId, creatorId, createdUnix int64, version, metadata string) {
|
||||
pv := pvs[id-1]
|
||||
|
||||
require.Equal(t, id, pv.ID)
|
||||
require.Equal(t, packageId, pv.PackageID)
|
||||
|
||||
require.Equal(t, creatorId, pv.CreatorID)
|
||||
require.Equal(t, version, pv.Version)
|
||||
require.Equal(t, strings.ToLower(version), pv.LowerVersion)
|
||||
require.JSONEq(t, metadata, pv.MetadataJSON)
|
||||
}
|
||||
|
||||
assertPackageVersion(1, 1, 1, 1746256357, "1.0-SNAPSHOT", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
assertPackageVersion(2, 2, 1, 1746256358, "1.0-SNAPSHOT", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(3, 1, 1, 1746256360, "7.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
// added groupId
|
||||
assertPackageVersion(4, 2, 1, 1746256361, "7.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(5, 3, 1, 1746256364, "7.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
// added groupId
|
||||
assertPackageVersion(6, 4, 1, 1746256365, "7.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(7, 5, 1, 1746256367, "1.0-SNAPSHOT", `{"artifact_id":"-bar","group_id":"foo"}`)
|
||||
assertPackageVersion(8, 5, 1, 1746256370, "7.0.0", `{"artifact_id":"-bar","group_id":"foo"}`)
|
||||
assertPackageVersion(9, 1, 1, 1746256389, "8.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
// added groupId
|
||||
assertPackageVersion(10, 2, 1, 1746256390, "8.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(11, 3, 1, 1746256393, "8.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
// added groupId
|
||||
assertPackageVersion(12, 4, 1, 1746256394, "8.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(13, 5, 1, 1746256399, "8.0.0", `{"artifact_id":"-bar","group_id":"foo"}`)
|
||||
assertPackageVersion(14, 1, 1, 1746256419, "9.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
// added groupId
|
||||
assertPackageVersion(15, 2, 1, 1746256420, "9.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(16, 3, 1, 1746256423, "9.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
// added groupId
|
||||
assertPackageVersion(17, 4, 1, 1746256424, "9.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(18, 5, 1, 1746256429, "9.0.0", `{"artifact_id":"-bar","group_id":"foo"}`)
|
||||
assertPackageVersion(19, 1, 1, 1746256449, "10.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
assertPackageVersion(20, 2, 1, 1746256450, "10.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(21, 3, 1, 1746256452, "10.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
assertPackageVersion(22, 4, 1, 1746256453, "10.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(23, 5, 1, 1746256459, "10.0.0", `{"artifact_id":"-bar","group_id":"foo"}`)
|
||||
assertPackageVersion(24, 1, 1, 1746256478, "11.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
assertPackageVersion(25, 2, 1, 1746256479, "11.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(26, 3, 1, 1746256482, "11.0.0", `{"artifact_id":"parent-project","group_id":"com.example"}`)
|
||||
assertPackageVersion(27, 4, 1, 1746256483, "11.0.0", `{"artifact_id":"sub-module","group_id":"com.example"}`)
|
||||
assertPackageVersion(28, 5, 1, 1746256488, "11.0.0", `{"artifact_id":"-bar","group_id":"foo"}`)
|
||||
// should be untouched at all. fixtures doesn't contain names
|
||||
assertPackageVersion(29, 7, 6, 1746256488, "1.2.4", `{"group_id":"com.broken","artifact_id":"br-root","name":"Foo"}`)
|
||||
// added group name
|
||||
assertPackageVersion(30, 6, 6, 1746256488, "1.2.4", `{"artifact_id":"br-rest-webmvc", "group_id":"com.broken"}`)
|
||||
assertPackageVersion(31, 8, 1, 1746256488, "11.0.0", `{"artifact_id":"art","group_id":"group-bar"}`)
|
||||
|
||||
// new entries
|
||||
assertPackageVersion(32, 9, 1, 1746256488, "11.0.0", `{"artifact_id":"bar-art","group_id":"group"}`)
|
||||
assertPackageVersion(33, 10, 1, 1746256488, "11.0.0", `{"artifact_id":"bar","group_id":"foo-"}`)
|
||||
assertPackageVersion(34, 10, 1, 1746256488, "10.0.0", `{"artifact_id":"bar","group_id":"foo-"}`)
|
||||
assertPackageVersion(35, 10, 1, 1746256488, "9.0.0", `{"artifact_id":"bar","group_id":"foo-"}`)
|
||||
assertPackageVersion(36, 10, 1, 1746256488, "8.0.0", `{"artifact_id":"bar","group_id":"foo-"}`)
|
||||
assertPackageVersion(37, 10, 1, 1746256488, "7.0.0", `{"artifact_id":"bar","group_id":"foo-"}`)
|
||||
assertPackageVersion(38, 10, 1, 1746256488, "1.0-SNAPSHOT", `{"artifact_id":"bar","group_id":"foo-"}`)
|
||||
}
|
||||
|
||||
func validatePackageFiles(t *testing.T, pfs []*packages.PackageFile) {
|
||||
assertPackageVersion := func(pos, id, versionId, blobId, createdUnix int64, name string, isLead bool) {
|
||||
pf := pfs[pos]
|
||||
|
||||
require.Equal(t, id, pf.ID)
|
||||
require.Equal(t, versionId, pf.VersionID)
|
||||
require.Equal(t, blobId, pf.BlobID)
|
||||
require.Equal(t, name, pf.Name)
|
||||
require.Equal(t, strings.ToLower(name), pf.LowerName)
|
||||
require.Empty(t, pf.CompositeKey)
|
||||
require.Equal(t, isLead, pf.IsLead)
|
||||
require.EqualValues(t, createdUnix, pf.CreatedUnix)
|
||||
|
||||
require.Empty(t, pf.CompositeKey)
|
||||
}
|
||||
assertPackageVersion(0, 1, 1, 1, 1746256357, "parent-project-1.0-20250503.071237-1.pom", true)
|
||||
assertPackageVersion(1, 3, 2, 3, 1746256358, "sub-module-1.0-20250503.071237-1.pom", true)
|
||||
assertPackageVersion(2, 4, 2, 4, 1746256358, "sub-module-1.0-20250503.071237-1.jar", false)
|
||||
assertPackageVersion(3, 6, 3, 6, 1746256360, "parent-project-7.0.0.pom", true)
|
||||
assertPackageVersion(4, 7, 4, 7, 1746256361, "sub-module-7.0.0.pom", true)
|
||||
assertPackageVersion(5, 8, 4, 8, 1746256361, "sub-module-7.0.0.jar", false)
|
||||
assertPackageVersion(6, 9, 5, 9, 1746256364, "parent-project-7.0.0.pom", true)
|
||||
assertPackageVersion(7, 10, 6, 7, 1746256365, "sub-module-7.0.0.pom", true)
|
||||
assertPackageVersion(8, 11, 6, 10, 1746256365, "sub-module-7.0.0.jar", false)
|
||||
// new versionId 7 -> 38
|
||||
assertPackageVersion(9, 12, 38, 11, 1746256367, "bar-1.0-20250503.071248-1.pom", true)
|
||||
// new versionId 37
|
||||
assertPackageVersion(10, 14, 37, 13, 1746256370, "bar-7.0.0.pom", true)
|
||||
assertPackageVersion(11, 15, 7, 14, 1746256373, "-bar-1.0-20250503.071253-2.pom", true)
|
||||
assertPackageVersion(12, 17, 8, 16, 1746256375, "-bar-7.0.0.pom", true)
|
||||
assertPackageVersion(13, 18, 1, 1, 1746256385, "parent-project-1.0-20250503.071306-2.pom", true)
|
||||
assertPackageVersion(14, 20, 2, 3, 1746256386, "sub-module-1.0-20250503.071306-2.pom", true)
|
||||
assertPackageVersion(15, 21, 2, 18, 1746256386, "sub-module-1.0-20250503.071306-2.jar", false)
|
||||
assertPackageVersion(16, 23, 9, 20, 1746256389, "parent-project-8.0.0.pom", true)
|
||||
assertPackageVersion(17, 24, 10, 21, 1746256390, "sub-module-8.0.0.pom", true)
|
||||
assertPackageVersion(18, 25, 10, 22, 1746256390, "sub-module-8.0.0.jar", false)
|
||||
assertPackageVersion(19, 26, 11, 23, 1746256393, "parent-project-8.0.0.pom", true)
|
||||
assertPackageVersion(20, 27, 12, 21, 1746256394, "sub-module-8.0.0.pom", true)
|
||||
assertPackageVersion(21, 28, 12, 24, 1746256394, "sub-module-8.0.0.jar", false)
|
||||
// new versionId 7 -> 38
|
||||
assertPackageVersion(22, 29, 38, 11, 1746256397, "bar-1.0-20250503.071317-3.pom", true)
|
||||
assertPackageVersion(23, 31, 36, 26, 1746256399, "bar-8.0.0.pom", true)
|
||||
assertPackageVersion(24, 32, 7, 14, 1746256402, "-bar-1.0-20250503.071323-4.pom", true)
|
||||
assertPackageVersion(25, 34, 13, 28, 1746256405, "-bar-8.0.0.pom", true)
|
||||
assertPackageVersion(26, 35, 1, 1, 1746256415, "parent-project-1.0-20250503.071335-3.pom", true)
|
||||
assertPackageVersion(27, 37, 2, 3, 1746256416, "sub-module-1.0-20250503.071335-3.pom", true)
|
||||
assertPackageVersion(28, 38, 2, 30, 1746256416, "sub-module-1.0-20250503.071335-3.jar", false)
|
||||
assertPackageVersion(29, 40, 14, 32, 1746256419, "parent-project-9.0.0.pom", true)
|
||||
assertPackageVersion(30, 41, 15, 33, 1746256420, "sub-module-9.0.0.pom", true)
|
||||
assertPackageVersion(31, 42, 15, 34, 1746256420, "sub-module-9.0.0.jar", false)
|
||||
assertPackageVersion(32, 43, 16, 35, 1746256423, "parent-project-9.0.0.pom", true)
|
||||
assertPackageVersion(33, 44, 17, 33, 1746256424, "sub-module-9.0.0.pom", true)
|
||||
assertPackageVersion(34, 45, 17, 36, 1746256424, "sub-module-9.0.0.jar", false)
|
||||
// new versionId 7 -> 38
|
||||
assertPackageVersion(35, 46, 38, 11, 1746256427, "bar-1.0-20250503.071347-5.pom", true)
|
||||
// new versionId 18 -> 35
|
||||
assertPackageVersion(36, 48, 35, 38, 1746256429, "bar-9.0.0.pom", true)
|
||||
assertPackageVersion(37, 49, 7, 14, 1746256432, "-bar-1.0-20250503.071353-6.pom", true)
|
||||
assertPackageVersion(38, 51, 18, 40, 1746256435, "-bar-9.0.0.pom", true)
|
||||
assertPackageVersion(39, 52, 1, 1, 1746256445, "parent-project-1.0-20250503.071405-4.pom", true)
|
||||
assertPackageVersion(40, 54, 2, 3, 1746256446, "sub-module-1.0-20250503.071405-4.pom", true)
|
||||
assertPackageVersion(41, 55, 2, 42, 1746256446, "sub-module-1.0-20250503.071405-4.jar", false)
|
||||
assertPackageVersion(42, 57, 19, 44, 1746256449, "parent-project-10.0.0.pom", true)
|
||||
assertPackageVersion(43, 58, 20, 45, 1746256450, "sub-module-10.0.0.pom", true)
|
||||
assertPackageVersion(44, 59, 20, 46, 1746256450, "sub-module-10.0.0.jar", false)
|
||||
assertPackageVersion(45, 60, 21, 47, 1746256452, "parent-project-10.0.0.pom", true)
|
||||
assertPackageVersion(46, 61, 22, 45, 1746256453, "sub-module-10.0.0.pom", true)
|
||||
assertPackageVersion(47, 62, 22, 48, 1746256453, "sub-module-10.0.0.jar", false)
|
||||
// new versionId 7 -> 38
|
||||
assertPackageVersion(48, 63, 38, 11, 1746256456, "bar-1.0-20250503.071416-7.pom", true)
|
||||
// new versionId 34
|
||||
assertPackageVersion(49, 65, 34, 50, 1746256459, "bar-10.0.0.pom", true)
|
||||
assertPackageVersion(50, 66, 7, 14, 1746256461, "-bar-1.0-20250503.071422-8.pom", true)
|
||||
assertPackageVersion(51, 68, 23, 52, 1746256464, "-bar-10.0.0.pom", true)
|
||||
assertPackageVersion(52, 69, 1, 1, 1746256474, "parent-project-1.0-20250503.071435-5.pom", true)
|
||||
assertPackageVersion(53, 70, 1, 53, 1746256474, "maven-metadata.xml", false)
|
||||
assertPackageVersion(54, 71, 2, 3, 1746256475, "sub-module-1.0-20250503.071435-5.pom", true)
|
||||
assertPackageVersion(55, 72, 2, 54, 1746256475, "sub-module-1.0-20250503.071435-5.jar", false)
|
||||
assertPackageVersion(56, 73, 2, 55, 1746256476, "maven-metadata.xml", false)
|
||||
assertPackageVersion(57, 74, 24, 56, 1746256478, "parent-project-11.0.0.pom", true)
|
||||
assertPackageVersion(58, 75, 25, 57, 1746256479, "sub-module-11.0.0.pom", true)
|
||||
assertPackageVersion(59, 76, 25, 58, 1746256479, "sub-module-11.0.0.jar", false)
|
||||
assertPackageVersion(60, 77, 26, 59, 1746256482, "parent-project-11.0.0.pom", true)
|
||||
assertPackageVersion(61, 78, 27, 57, 1746256483, "sub-module-11.0.0.pom", true)
|
||||
assertPackageVersion(62, 79, 27, 60, 1746256483, "sub-module-11.0.0.jar", false)
|
||||
// new versionId 7 -> 38
|
||||
assertPackageVersion(63, 80, 38, 11, 1746256486, "bar-1.0-20250503.071446-9.pom", true)
|
||||
// new versionId 33
|
||||
assertPackageVersion(64, 82, 33, 62, 1746256488, "bar-11.0.0.pom", true)
|
||||
assertPackageVersion(65, 83, 7, 14, 1746256491, "-bar-1.0-20250503.071451-10.pom", true)
|
||||
assertPackageVersion(66, 84, 7, 63, 1746256491, "maven-metadata.xml", false)
|
||||
assertPackageVersion(67, 85, 28, 64, 1746256494, "-bar-11.0.0.pom", true)
|
||||
assertPackageVersion(68, 86, 29, 75, 174625649444986, "br-repo-jooq-1.2.4-sources.jar", false)
|
||||
assertPackageVersion(69, 87, 29, 65, 174625649446161, "br-rest-webmvc-1.2.4.jar", false)
|
||||
assertPackageVersion(70, 88, 29, 68, 174625649444734, "br-openapi-base-1.2.4.pom", true)
|
||||
assertPackageVersion(71, 89, 29, 69, 174625649444746, "br-openapi-base-1.2.4.jar", false)
|
||||
assertPackageVersion(72, 90, 29, 70, 174625649444775, "br-openapi-base-1.2.4-sources.jar", false)
|
||||
assertPackageVersion(73, 91, 29, 78, 174625649444852, "br-parent-1.2.4.pom", true)
|
||||
assertPackageVersion(74, 92, 29, 76, 174625649444900, "br-repo-in-memory-1.2.4.pom", true)
|
||||
assertPackageVersion(75, 93, 29, 73, 174625649444911, "br-repo-in-memory-1.2.4.jar", false)
|
||||
assertPackageVersion(76, 94, 29, 77, 174625649444922, "br-repo-in-memory-1.2.4-sources.jar", false)
|
||||
assertPackageVersion(77, 95, 29, 74, 174625649444953, "br-repo-jooq-1.2.4.pom", true)
|
||||
assertPackageVersion(78, 96, 29, 67, 174625649444969, "br-repo-jooq-1.2.4.jar", false)
|
||||
assertPackageVersion(79, 97, 29, 71, 174625649446161, "br-rest-webmvc-1.2.4-sources.jar", false)
|
||||
assertPackageVersion(80, 98, 29, 66, 174625649446195, "br-rest-webmvc-1.2.4.pom", true)
|
||||
assertPackageVersion(81, 99, 29, 72, 174625649446217, "br-root-1.2.4.pom", true)
|
||||
assertPackageVersion(82, 100, 30, 66, 174625649446311, "br-rest-webmvc-1.2.4.pom", true)
|
||||
assertPackageVersion(83, 101, 30, 65, 174625649446312, "br-rest-webmvc-1.2.4.jar", false)
|
||||
assertPackageVersion(84, 102, 30, 71, 174625649446312, "br-rest-webmvc-1.2.4-sources.jar", false)
|
||||
// new versionId 31 -> 32
|
||||
assertPackageVersion(85, 103, 32, 79, 1746280832, "bar-art-11.0.0.pom", true)
|
||||
assertPackageVersion(86, 104, 31, 80, 1746280843, "art-11.0.0.pom", true)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2018 The Gitea Authors.
|
||||
// Copyright 2016 The Gogs Authors.
|
||||
// All rights reserved.
|
||||
// Copyright 2016 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
@ -324,6 +324,9 @@ type Comment struct {
|
|||
NewCommit string `xorm:"-"`
|
||||
CommitsNum int64 `xorm:"-"`
|
||||
IsForcePush bool `xorm:"-"`
|
||||
|
||||
// If you add new fields that might be used to store abusive content (mainly string fields),
|
||||
// please also add them in the CommentData struct and the corresponding constructor.
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -649,8 +652,11 @@ func (c *Comment) LoadAssigneeUserAndTeam(ctx context.Context) error {
|
|||
|
||||
if c.Issue.Repo.Owner.IsOrganization() {
|
||||
c.AssigneeTeam, err = organization.GetTeamByID(ctx, c.AssigneeTeamID)
|
||||
if err != nil && !organization.IsErrTeamNotExist(err) {
|
||||
return err
|
||||
if err != nil {
|
||||
if !organization.IsErrTeamNotExist(err) {
|
||||
return err
|
||||
}
|
||||
c.AssigneeTeam = organization.NewGhostTeam()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1149,6 +1155,11 @@ func UpdateComment(ctx context.Context, c *Comment, contentVersion int, doer *us
|
|||
}
|
||||
defer committer.Close()
|
||||
|
||||
// If the comment was reported as abusive, a shadow copy should be created before first update.
|
||||
if err := IfNeededCreateShadowCopyForComment(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.LoadIssue(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1184,6 +1195,12 @@ func UpdateComment(ctx context.Context, c *Comment, contentVersion int, doer *us
|
|||
// DeleteComment deletes the comment
|
||||
func DeleteComment(ctx context.Context, comment *Comment) error {
|
||||
e := db.GetEngine(ctx)
|
||||
|
||||
// If the comment was reported as abusive, a shadow copy should be created before deletion.
|
||||
if err := IfNeededCreateShadowCopyForComment(ctx, comment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package issues
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"regexp"
|
||||
|
@ -822,7 +823,7 @@ func (issue *Issue) MovePin(ctx context.Context, newPosition int) error {
|
|||
}
|
||||
|
||||
if newPosition < 1 {
|
||||
return fmt.Errorf("The Position can't be lower than 1")
|
||||
return errors.New("The Position can't be lower than 1")
|
||||
}
|
||||
|
||||
dbctx, committer, err := db.TxContext(ctx)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -275,6 +277,11 @@ func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User
|
|||
}
|
||||
}
|
||||
|
||||
// If the issue was reported as abusive, a shadow copy should be created before first update.
|
||||
if err := IfNeededCreateShadowCopyForIssue(ctx, issue); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
issue.Content = content
|
||||
issue.ContentVersion = contentVersion + 1
|
||||
|
||||
|
@ -332,10 +339,10 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue
|
|||
}
|
||||
|
||||
if opts.Issue.Index <= 0 {
|
||||
return fmt.Errorf("no issue index provided")
|
||||
return errors.New("no issue index provided")
|
||||
}
|
||||
if opts.Issue.ID > 0 {
|
||||
return fmt.Errorf("issue exist")
|
||||
return errors.New("issue exist")
|
||||
}
|
||||
|
||||
opts.Issue.Created = timeutil.TimeStampNanoNow()
|
||||
|
|
106
models/issues/moderation.go
Normal file
106
models/issues/moderation.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"forgejo.org/models/moderation"
|
||||
"forgejo.org/modules/json"
|
||||
"forgejo.org/modules/timeutil"
|
||||
)
|
||||
|
||||
// IssueData represents a trimmed down issue that is used for preserving
|
||||
// only the fields needed for abusive content reports (mainly string fields).
|
||||
type IssueData struct {
|
||||
RepoID int64
|
||||
Index int64
|
||||
PosterID int64
|
||||
Title string
|
||||
Content string
|
||||
ContentVersion int
|
||||
CreatedUnix timeutil.TimeStamp
|
||||
UpdatedUnix timeutil.TimeStamp
|
||||
}
|
||||
|
||||
// newIssueData creates a trimmed down issue to be used just to create a JSON structure
|
||||
// (keeping only the fields relevant for moderation purposes)
|
||||
func newIssueData(issue *Issue) IssueData {
|
||||
return IssueData{
|
||||
RepoID: issue.RepoID,
|
||||
Index: issue.Index,
|
||||
PosterID: issue.PosterID,
|
||||
Content: issue.Content,
|
||||
Title: issue.Title,
|
||||
ContentVersion: issue.ContentVersion,
|
||||
CreatedUnix: issue.CreatedUnix,
|
||||
UpdatedUnix: issue.UpdatedUnix,
|
||||
}
|
||||
}
|
||||
|
||||
// CommentData represents a trimmed down comment that is used for preserving
|
||||
// only the fields needed for abusive content reports (mainly string fields).
|
||||
type CommentData struct {
|
||||
PosterID int64
|
||||
IssueID int64
|
||||
Content string
|
||||
ContentVersion int
|
||||
CreatedUnix timeutil.TimeStamp
|
||||
UpdatedUnix timeutil.TimeStamp
|
||||
}
|
||||
|
||||
// newCommentData creates a trimmed down comment to be used just to create a JSON structure
|
||||
// (keeping only the fields relevant for moderation purposes)
|
||||
func newCommentData(comment *Comment) CommentData {
|
||||
return CommentData{
|
||||
PosterID: comment.PosterID,
|
||||
IssueID: comment.IssueID,
|
||||
Content: comment.Content,
|
||||
ContentVersion: comment.ContentVersion,
|
||||
CreatedUnix: comment.CreatedUnix,
|
||||
UpdatedUnix: comment.UpdatedUnix,
|
||||
}
|
||||
}
|
||||
|
||||
// IfNeededCreateShadowCopyForIssue checks if for the given issue there are any reports of abusive content submitted
|
||||
// and if found a shadow copy of relevant issue fields will be stored into DB and linked to the above report(s).
|
||||
// This function should be called before a issue is deleted or updated.
|
||||
func IfNeededCreateShadowCopyForIssue(ctx context.Context, issue *Issue) error {
|
||||
shadowCopyNeeded, err := moderation.IsShadowCopyNeeded(ctx, moderation.ReportedContentTypeIssue, issue.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if shadowCopyNeeded {
|
||||
issueData := newIssueData(issue)
|
||||
content, err := json.Marshal(issueData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return moderation.CreateShadowCopyForIssue(ctx, issue.ID, string(content))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IfNeededCreateShadowCopyForComment checks if for the given comment there are any reports of abusive content submitted
|
||||
// and if found a shadow copy of relevant comment fields will be stored into DB and linked to the above report(s).
|
||||
// This function should be called before a comment is deleted or updated.
|
||||
func IfNeededCreateShadowCopyForComment(ctx context.Context, comment *Comment) error {
|
||||
shadowCopyNeeded, err := moderation.IsShadowCopyNeeded(ctx, moderation.ReportedContentTypeComment, comment.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if shadowCopyNeeded {
|
||||
commentData := newCommentData(comment)
|
||||
content, err := json.Marshal(commentData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return moderation.CreateShadowCopyForComment(ctx, comment.ID, string(content))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -6,6 +6,7 @@ package issues
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
|
@ -795,7 +796,7 @@ func (pr *PullRequest) GetWorkInProgressPrefix(ctx context.Context) string {
|
|||
// UpdateCommitDivergence update Divergence of a pull request
|
||||
func (pr *PullRequest) UpdateCommitDivergence(ctx context.Context, ahead, behind int) error {
|
||||
if pr.ID == 0 {
|
||||
return fmt.Errorf("pull ID is 0")
|
||||
return errors.New("pull ID is 0")
|
||||
}
|
||||
pr.CommitsAhead = ahead
|
||||
pr.CommitsBehind = behind
|
||||
|
|
|
@ -5,6 +5,7 @@ package issues
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
@ -349,7 +350,7 @@ func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error
|
|||
review.Type = ReviewTypeRequest
|
||||
review.ReviewerTeamID = opts.ReviewerTeam.ID
|
||||
} else {
|
||||
return nil, fmt.Errorf("provide either reviewer or reviewer team")
|
||||
return nil, errors.New("provide either reviewer or reviewer team")
|
||||
}
|
||||
|
||||
if _, err := sess.Insert(review); err != nil {
|
||||
|
@ -908,7 +909,7 @@ func MarkConversation(ctx context.Context, comment *Comment, doer *user_model.Us
|
|||
// the PR writer , offfcial reviewer and poster can do it
|
||||
func CanMarkConversation(ctx context.Context, issue *Issue, doer *user_model.User) (permResult bool, err error) {
|
||||
if doer == nil || issue == nil {
|
||||
return false, fmt.Errorf("issue or doer is nil")
|
||||
return false, errors.New("issue or doer is nil")
|
||||
}
|
||||
|
||||
if doer.ID != issue.PosterID {
|
||||
|
@ -945,11 +946,11 @@ func DeleteReview(ctx context.Context, r *Review) error {
|
|||
defer committer.Close()
|
||||
|
||||
if r.ID == 0 {
|
||||
return fmt.Errorf("review is not allowed to be 0")
|
||||
return errors.New("review is not allowed to be 0")
|
||||
}
|
||||
|
||||
if r.Type == ReviewTypeRequest {
|
||||
return fmt.Errorf("review request can not be deleted using this method")
|
||||
return errors.New("review request can not be deleted using this method")
|
||||
}
|
||||
|
||||
opts := FindCommentsOptions{
|
||||
|
|
|
@ -74,7 +74,7 @@ func RecreateTable(sess *xorm.Session, bean any) error {
|
|||
}
|
||||
newTableColumns := table.Columns()
|
||||
if len(newTableColumns) == 0 {
|
||||
return fmt.Errorf("no columns in new table")
|
||||
return errors.New("no columns in new table")
|
||||
}
|
||||
hasID := false
|
||||
for _, column := range newTableColumns {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
- id: 1
|
||||
owner_id: 2
|
||||
repo_id: 0
|
||||
type: maven
|
||||
name: com.example-parent-project
|
||||
lower_name: com.example-parent-project
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
||||
- id: 2
|
||||
owner_id: 2
|
||||
repo_id: 0
|
||||
type: maven
|
||||
name: com.example-sub-module
|
||||
lower_name: com.example-sub-module
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
||||
- id: 3
|
||||
owner_id: 1
|
||||
repo_id: 0
|
||||
type: maven
|
||||
name: com.example-parent-project
|
||||
lower_name: com.example-parent-project
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
||||
- id: 4
|
||||
owner_id: 1
|
||||
repo_id: 0
|
||||
type: maven
|
||||
name: com.example-sub-module
|
||||
lower_name: com.example-sub-module
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
||||
- id: 5
|
||||
owner_id: 1
|
||||
repo_id: 0
|
||||
type: maven
|
||||
name: foo--bar
|
||||
lower_name: foo--bar
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
||||
# broken uploads
|
||||
- id: 6
|
||||
owner_id: 8
|
||||
repo_id: 54
|
||||
type: maven
|
||||
name: com.broken-br-rest-webmvc
|
||||
lower_name: com.broken-br-rest-webmvc
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
||||
- id: 7
|
||||
owner_id: 8
|
||||
repo_id: 54
|
||||
type: maven
|
||||
name: com.broken-br-openapi-base
|
||||
lower_name: com.broken-br-openapi-base
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
||||
# collision
|
||||
- id: 8
|
||||
owner_id: 1
|
||||
repo_id: 0
|
||||
type: maven
|
||||
name: group-bar-art
|
||||
lower_name: group-bar-art
|
||||
semver_compatible: 0
|
||||
is_internal: 0
|
|
@ -0,0 +1,641 @@
|
|||
- id: 1
|
||||
size: 1038
|
||||
hash_md5: 6096f13928b6de3103a2bd4857fcf1fa
|
||||
hash_sha1: bbdfeca76d178834b5750cd8d14b8a698847c554
|
||||
hash_sha256: 82d2245520562132935dc1d0caa181df125587917de9f14ed9dfeb2f2f88f0f0
|
||||
hash_sha512: 898896789a69a87252b44e13c253ecadfbe04867c8319931eccddf4fef57b04b066061792b515c17d4480e3bbafc82590781a0c3fd43c6a64abe0e5cff05e057
|
||||
created_unix: 1746256357
|
||||
hash_blake2b: null
|
||||
- id: 2
|
||||
size: 598
|
||||
hash_md5: 390df8dad491a0aba1b5098801735d5b
|
||||
hash_sha1: e96e2d1909a9dc88f6a34cdd2e34e2308d9a0283
|
||||
hash_sha256: a292499ce09f7ec89fbcf97d7816dd7f9c90e3deb0163be5704a28e3eb0dc819
|
||||
hash_sha512: 8ddb3201adbdb4bdf97d27f563db097a032f910fefcf64de1b09d533aaa44affb8622b037143ea620df1010bdba56e5206dff6bd9de4450e43ba214ac2bf67d9
|
||||
created_unix: 1746256357
|
||||
hash_blake2b: null
|
||||
- id: 3
|
||||
size: 763
|
||||
hash_md5: bb4f70724a5c4197d91f9bf1e36e49c3
|
||||
hash_sha1: 6fd741578f83b0f1d10dbc0a53f339e790d93c16
|
||||
hash_sha256: e6e07ed923d3c316d4174449be423171bc46a8c6dad0c864d3d2b916eda5bb5f
|
||||
hash_sha512: 773336c44e8cd5aa92c3b3c921418392661ae5a4c51305341e2766d39ad978e3dfdf4f4992bbcc88bdce3fb824b6a75b1e86a161211940d55e6a4715dab924c6
|
||||
created_unix: 1746256358
|
||||
hash_blake2b: null
|
||||
- id: 4
|
||||
size: 2099
|
||||
hash_md5: 72dbbe63f0c475783e53cc8760183dbc
|
||||
hash_sha1: c1f6bff52587f6cc11dd26549873e5dd4bfdf4df
|
||||
hash_sha256: d79571250439111a13090e69b5dd5e3ba02f980fcf6aca46943f854a0762145f
|
||||
hash_sha512: bda94c619b66d9c01e75385b2e77be630b38e70d8a4163894c059550d9c6bd8300656f9dbf6c81c06112061b18c4bdc32102019ed1dd151556bd02ba433175d4
|
||||
created_unix: 1746256358
|
||||
hash_blake2b: null
|
||||
- id: 5
|
||||
size: 765
|
||||
hash_md5: dba88ff4468713b2de10b2151115a3cd
|
||||
hash_sha1: f2ba30eda8fd818a8e435a720c242acd77db4498
|
||||
hash_sha256: 5fc713fca3c8daeef084fc9bebc08c0dc49dfccbbd6da774180f6b57dab2a0b1
|
||||
hash_sha512: 5b494fffce128d83a5a5891c2615709efa8ed2ab7bf557ba33c4d6cc4cc2386af11e74e0db28c162bb402a6e9cdfd270f2dadb033832e9cf313c6ac5ee5493b9
|
||||
created_unix: 1746256358
|
||||
hash_blake2b: null
|
||||
- id: 6
|
||||
size: 1031
|
||||
hash_md5: 32aec2cc3a9369dbd7fd062267ddc0de
|
||||
hash_sha1: 611b0d7b0e10574a87ca3fee6172f3b77b3fc824
|
||||
hash_sha256: d53eaadc924150a5e5b7be4a0fdbbf20d2c996b01bb01f4388570815166fbabd
|
||||
hash_sha512: f1b516945b8faf99e4943171c9b149114753b7cbe53707f901c7fa07f810662a8e2fe1a9dd4a7b1ee8989c4c26499c3e4ce5e233cadf5ee897dc5b4839353071
|
||||
created_unix: 1746256360
|
||||
hash_blake2b: null
|
||||
- id: 7
|
||||
size: 749
|
||||
hash_md5: dadab7af17fffd4ba67b2161f0573840
|
||||
hash_sha1: 8438861bf54c263273cfb3d85bd4aa060d983cfe
|
||||
hash_sha256: 28acf9ad32b66ee2e02fe58e6c61aafd12fc299fdb9add83a6043244a5e211a6
|
||||
hash_sha512: bf009a26ab2f863fe4571840fd5ea3586ceb02270e1d52319ae65a96709aa0b81cbbf95cbd28add5b8803e20431579a1e61cd98dc089febf4f471d309efb124a
|
||||
created_unix: 1746256361
|
||||
hash_blake2b: null
|
||||
- id: 8
|
||||
size: 2081
|
||||
hash_md5: 65f26423829a7cda51535dfd8649927e
|
||||
hash_sha1: c9436ace1e28aca3c546be746e8986f66a3beafd
|
||||
hash_sha256: 9c2c053ac72e9fb571b6cd7a31019759126b5fae331753d8594cb8a0aa210e58
|
||||
hash_sha512: 185728651b566828e8ee69cbd4d9fb331403c0f2e01bbf2e5be65d8e70a049390c78a08e5eff5ead7c070efaff7e3e7b4d13e8ca48d94f9b7a714be954259d94
|
||||
created_unix: 1746256361
|
||||
hash_blake2b: null
|
||||
- id: 9
|
||||
size: 1016
|
||||
hash_md5: 8c19574fa57e395ce6f35d8d5644048d
|
||||
hash_sha1: 0dea7bcebea9d4f506da68a5c3a592ab6bbb8150
|
||||
hash_sha256: c31fcee243ed68fa575c7ffbacfacfdcb24001bd86e261475220d91603d4995c
|
||||
hash_sha512: eb92ec4f81e9beba3473f4504f8bb387aeac632a70a5016b27b6527ac70dcc4c940fb940a225452892701b8e6ecfdcd3858b6bd74b87f94a3b5f5bb1de369645
|
||||
created_unix: 1746256364
|
||||
hash_blake2b: null
|
||||
- id: 10
|
||||
size: 2081
|
||||
hash_md5: 42e97d6c79d8c7dfa4f80c90534a3a7e
|
||||
hash_sha1: edeb74a2a1a05ad4851629b90b65463559976995
|
||||
hash_sha256: 228213798b1af7033aed779446cb5a657b765f72dc47626ca2a0ad7aaca846e6
|
||||
hash_sha512: 65d83d6a96e8b59ec0ae35a184a8bbe844e572eb7b2c66b022f92925dc31edcad02312e59d1312d944ee1ace163729e6d0ec95b1c97163c61a19b40b18156cca
|
||||
created_unix: 1746256365
|
||||
hash_blake2b: null
|
||||
- id: 11
|
||||
size: 947
|
||||
hash_md5: a1aa1f55f9579b5b81d2b2c797677d3a
|
||||
hash_sha1: 27f82af8e6580ad7fecad111665666cb08f90274
|
||||
hash_sha256: ec8b8d74a0074f391e5b9fb25f4924c5dc30e8767df07096f7ea9b4f038fe0a2
|
||||
hash_sha512: eb59b7154f208bfbc5da207b7fbe8288917d637bd2ad09f60e525d1208ab41a5a312d349715b527012f46b32351494bff7f5c6510b4521fda0c9164afc87b50c
|
||||
created_unix: 1746256367
|
||||
hash_blake2b: null
|
||||
- id: 12
|
||||
size: 580
|
||||
hash_md5: a4e26488fa83b5945d1c0373fe07d6c0
|
||||
hash_sha1: 891cde56160342b16e4e3eab187487b1e7d4c155
|
||||
hash_sha256: 8d27bf11781cad6d864da15e7b04080a6b1c4f8908d2e5baba79b855f6049194
|
||||
hash_sha512: ea05ff7b6e8566609063f3492c0b2551ae1275912b8c370c5345fadda9e3a408d0879c749a94160e180161eb7727a93d7a3a8aaa1dde892f75748fc4d62fece5
|
||||
created_unix: 1746256368
|
||||
hash_blake2b: null
|
||||
- id: 13
|
||||
size: 940
|
||||
hash_md5: 2b1ec34161144a7100b6988347f80e4c
|
||||
hash_sha1: 29e71c96e109efccb8a7f756c1828e16b19d5303
|
||||
hash_sha256: 97b8e8d2bf656e30a60328054fe47cb901ebe3aa7a4c30fa7f4cdbe1b2600663
|
||||
hash_sha512: 8fb46a5898cb29eebac4a73b7c02dbcfe5c596c8f273b8e4483ea5778a3475718e792ec50b031879146e6072e396b022fdc6ee1cbf83369acdc0ee341cc9090c
|
||||
created_unix: 1746256370
|
||||
hash_blake2b: null
|
||||
- id: 14
|
||||
size: 947
|
||||
hash_md5: 086cba5b2139e72ea02ba0ba40bb1cef
|
||||
hash_sha1: e62e69071a629c0c46465e132b530b33da90a49d
|
||||
hash_sha256: 51c4395507768e97e7e6426f6acf0b054eb64fcdb5cff64b78680a013c8dbe14
|
||||
hash_sha512: ced379957d362b70a60f188d6c8c24ef2b3bc9828b32314a629574dea760c17225f1ef91875e9906ba4063fcff522fcd1d8c47d0a9a1ee9c6fe6d28d35219aa3
|
||||
created_unix: 1746256373
|
||||
hash_blake2b: null
|
||||
- id: 15
|
||||
size: 580
|
||||
hash_md5: 4091fac7a4f1754f86ddcc52734d5628
|
||||
hash_sha1: 5478354b11895f4495337e6c1ffd1480a05c4558
|
||||
hash_sha256: 930a7c95b67d8f6bcef5587a522b945f16840d7466ca45408b43a320ae28ec11
|
||||
hash_sha512: 93b69bc6c84fd03e66d42c49620d1efed6f3354598b82937528347b67088ed4042705b85989cbb9ce59c256cfc9fef8a706c3f149511643ceafbc88d660404fb
|
||||
created_unix: 1746256373
|
||||
hash_blake2b: null
|
||||
- id: 16
|
||||
size: 940
|
||||
hash_md5: 0714ceb54fbe397bd632a61e66498265
|
||||
hash_sha1: d66dc74c7f5a092c266aaa18d236840e2ab1b7e7
|
||||
hash_sha256: 6a8557a171e8808ed59b3e2c95f9499851e4a222654fa7320d3658c094bbc40d
|
||||
hash_sha512: a6b34065742e12611f3df651d7b3c859d7f4d058bfb7aee3901e69755aa13342720530a8d4a8253f2696389db0d2df6ecb0d4068d7c747d7f480ec2fcb3846c1
|
||||
created_unix: 1746256375
|
||||
hash_blake2b: null
|
||||
- id: 17
|
||||
size: 598
|
||||
hash_md5: 65e94a8db881efaf0944e26c8c8262f0
|
||||
hash_sha1: 60b143474f8dd311ccdd3eb08a1589a3f8b757df
|
||||
hash_sha256: 9ffad7e3c4c868a02c08b5956e67a4ae86b3a516ef56ca3345d6e8416e7585fd
|
||||
hash_sha512: 1441415dce05f8f2d44027bc5c78133e8a757454d3b26171e576d154c23b81d97ae8ed59861ee072e15ece88dfb187d53cd052972af46d35880cabc9fe31d670
|
||||
created_unix: 1746256385
|
||||
hash_blake2b: null
|
||||
- id: 18
|
||||
size: 2099
|
||||
hash_md5: 8e3ec93159d2190db2f80778756d33af
|
||||
hash_sha1: 65a0719f6c8a19768852a7314fc3672c6f992347
|
||||
hash_sha256: 2bdd4a5ebe1a6ac3043cb56485051a8b3332a16b6461899c3fd298156ebae4e6
|
||||
hash_sha512: e33122f943f62ba64bdf16c9249495e643b836c756252de9d001069de6367792bfdfe22e00f689663b88e661309cd5d1af2a7dc6ab24a96e5542db065dfa5230
|
||||
created_unix: 1746256386
|
||||
hash_blake2b: null
|
||||
- id: 19
|
||||
size: 765
|
||||
hash_md5: 823b9b5f66afb761bfd3db0d5f7e7b35
|
||||
hash_sha1: 822357b0ba18bb302272bd77227361beaac414d8
|
||||
hash_sha256: 255da7936e3a5df32cd3ef0d8af7ecb9b273aee15d08932806ffa3feb0a15368
|
||||
hash_sha512: ef0a455f0c7eb01403c51d85676a95d912622af4ea428fbf44818bcfd1b0a06d628decd27079f77d7913255ebfa0837411dbabf1b87d08caee3ca950a752f04a
|
||||
created_unix: 1746256386
|
||||
hash_blake2b: null
|
||||
- id: 20
|
||||
size: 1031
|
||||
hash_md5: a3952027a659d6199f4b5f6534465bd4
|
||||
hash_sha1: e14f78cd8cf1561cce5dabbee03778be99f298f1
|
||||
hash_sha256: 1bc987782dc3aa48b2fedca48c13bbc752d7e55c642d5b2194db88940652cef0
|
||||
hash_sha512: 34298f6f1cccddd5489d6bee98a3bb16efdfe78edf38c71c2641aa49e316bc8efc1fda3423026343336d1e76211ac535678c7f0b144b6580cb3eae8c9dcd37f2
|
||||
created_unix: 1746256389
|
||||
hash_blake2b: null
|
||||
- id: 21
|
||||
size: 749
|
||||
hash_md5: 35decba84a82a8b52e9b81c29574ed82
|
||||
hash_sha1: 1397366dbecb13de99f8caf9eb758afd23951824
|
||||
hash_sha256: 060fb4fddb2d6b85cc5d49c531aedebdafd10638447ec7582122c2d6a05874bf
|
||||
hash_sha512: 4dad39a4cf8d99f866492181bbda829a58123d1e5c70df06f83b2dc9690ccec149795f493ff814a7f2e32003033b47ea8d37ddbcce970f1a248a92b1ed791769
|
||||
created_unix: 1746256390
|
||||
hash_blake2b: null
|
||||
- id: 22
|
||||
size: 2081
|
||||
hash_md5: 8f02a5a705e82c7b4cd279714095f43e
|
||||
hash_sha1: 0cd14ac45ee96a739e74921b11fd39145240be23
|
||||
hash_sha256: bbc981db64f0cb352740e76df76452ccc1c0a5c0bc73929d63cbd12033976cf3
|
||||
hash_sha512: 66bb3adec4666246c27844f89eaed600863a6e93143064d4edba1494efc474e095997e462480bd928680f090639205b8917486815181f3399115f21ce1233ad4
|
||||
created_unix: 1746256390
|
||||
hash_blake2b: null
|
||||
- id: 23
|
||||
size: 1016
|
||||
hash_md5: 9f446caee85b293c8b7aafadf38973d4
|
||||
hash_sha1: 446a2c6fc2dda6ad2e00818afdff8771211ed08d
|
||||
hash_sha256: 1379abf81c435e90cc4e9658bd7d6fad4437bf92bbc8610c2e0ed12e57e03150
|
||||
hash_sha512: ed7a09670cd9cc74ce977c2a24f6ed98e2d72de7abc37ccf077c56f78320bcb37fdc702743837ded3d25d8b4dcab75e0559649486ba589a657a1b72954c2d8fb
|
||||
created_unix: 1746256393
|
||||
hash_blake2b: null
|
||||
- id: 24
|
||||
size: 2081
|
||||
hash_md5: 799454b1553262175f9f151a037e922e
|
||||
hash_sha1: d56f9adcd116fd93d11d3692440bd6bd033c9e5a
|
||||
hash_sha256: 4c6051a3051e44e747f38cc3fe96d20a2bc4272dc25cc0c374eca4d3bd45884b
|
||||
hash_sha512: 7243936532054ee059bf8bc996a23e80ff5ec90ce5724235ec91e13ed501693dfe881f78e70dde01cb2f3ad1de428fdf0c86a740dc473f7401159bb1719ad59a
|
||||
created_unix: 1746256394
|
||||
hash_blake2b: null
|
||||
- id: 25
|
||||
size: 580
|
||||
hash_md5: 7ca05a7b4ef9c35504122ea71260a7ac
|
||||
hash_sha1: dc9091893ec24b36d8e88ec1d64e58fed315744c
|
||||
hash_sha256: f6cb7d1d54e02ddf93e1f1d9a9131f12770d19cc2432982f4af33a42f9d2f8ea
|
||||
hash_sha512: d011cb7f41761ec032fa1c0ecd5733fe152d07a498f7d048e7ff0fe9e04cbc472594795ee427c86d71e104cc36bb4765fe652457bf02f6cfafb39bce1554e9e5
|
||||
created_unix: 1746256397
|
||||
hash_blake2b: null
|
||||
- id: 26
|
||||
size: 940
|
||||
hash_md5: 979ff1d9d17988d15d74a9125f2ec53f
|
||||
hash_sha1: aa540f051f67d77d27edc2468addd77f50a9e134
|
||||
hash_sha256: 1983f79e2cc3b39feada90a938d6b06772e87ec74a40540a347bad3f367824fb
|
||||
hash_sha512: 2c8b53b796990c028cafe26d20183b4a3ddb0221274756d68a81c8cd3f00dc1de2e8346a9e9f83ccc119e94bc058576f96bc633be6a6499806877c42912d1208
|
||||
created_unix: 1746256399
|
||||
hash_blake2b: null
|
||||
- id: 27
|
||||
size: 580
|
||||
hash_md5: e8c6c698b114078242994350e2c59cfe
|
||||
hash_sha1: 965f728ce742af25f364f840e05b9cd8c21e4505
|
||||
hash_sha256: b83a283c38737abcbb23462117ef35e6ee4a4d86513a2440bb4d41fa0e117dc9
|
||||
hash_sha512: 418aaf3bcd26cf63856e36ddba8c972ea99a764c25ed9fcfe6003236f6cc1e812885bf153d6f8a1b9fe712a3af04d4d99ea4d87a57ce06663f285cc1388a34b5
|
||||
created_unix: 1746256402
|
||||
hash_blake2b: null
|
||||
- id: 28
|
||||
size: 940
|
||||
hash_md5: 4831302596f19f696b56d59564d1991d
|
||||
hash_sha1: 92e6531a2e7bc42727d4ff455efa8f1408c38c55
|
||||
hash_sha256: b24b3aeb82d6dd3d532f6047e0b697b062fb10f2c4e1849b11eb1a7494450578
|
||||
hash_sha512: ef61c607cec6ab378cbf2522c985fe699ab2843072068e0809f06ae02c7d9b8476663104ffded3af3c96335d0db817bb78dbbc062dc48ed84b104826cb4642a6
|
||||
created_unix: 1746256405
|
||||
hash_blake2b: null
|
||||
- id: 29
|
||||
size: 598
|
||||
hash_md5: 56a57f536a07cfd465c022e69bfc064d
|
||||
hash_sha1: 4fd298455cddb9a0381410e5e05bcebb54d66639
|
||||
hash_sha256: e8b37be762d1ab0fc8bbc297ba1b27c507d0098a287973c3b7003772839d81ce
|
||||
hash_sha512: e1ed956616b3314eb247cf24586b36ce90435635ae40b57814c7a6cf0ef92c38bf13fbc2f07895ca6f67dfb9c3b9c0b4cf5556d69320b424dca989d1e4f74856
|
||||
created_unix: 1746256415
|
||||
hash_blake2b: null
|
||||
- id: 30
|
||||
size: 2099
|
||||
hash_md5: 4bc4c156c6a6a6d421e6b2a0f9bad601
|
||||
hash_sha1: 7c8746c62bb8418d1570fd0884cf9f846e055ffa
|
||||
hash_sha256: 3f56bd9d542d9b944c47fb946277d72445ef2d34dfee108ea3a8c2d06dbca50b
|
||||
hash_sha512: 7b47cc1e588c8e358cc29aa2135bcccb0f919bfbd9bc26b8342a352f4fdde3f3d2b5ad935c1efd6fc2d9e7cec5b1dc5c3e6630c9b3b979e47ff4fbce7863ea3d
|
||||
created_unix: 1746256416
|
||||
hash_blake2b: null
|
||||
- id: 31
|
||||
size: 765
|
||||
hash_md5: 5c30fe5aa7e261d6c6575cc8265697a1
|
||||
hash_sha1: cdc6f4ed95e723af264f3b6aae46bd0a98deacea
|
||||
hash_sha256: fc9e302e423b982dad68720d5f940452a312cf3c287a96dc66582460265a1b01
|
||||
hash_sha512: 079c9cdc9a919dac4225f42c26ffb34d4d115db8ab5e51cbcdd2b248f06935dfcb169f0a9e04f49b143615dafd5a6742ed231a1be13bc5c814af75ae173bd0e0
|
||||
created_unix: 1746256416
|
||||
hash_blake2b: null
|
||||
- id: 32
|
||||
size: 1031
|
||||
hash_md5: 0a379e399f7918290e303348c8cd6b07
|
||||
hash_sha1: ab53de2814344cfd8998d209c6927a415df147ff
|
||||
hash_sha256: 2267f735bd581417efae14f797ece94779fcea40ab28ac700734c0ee38b284e2
|
||||
hash_sha512: 967ebc462c40ecda18ad36abba96534459d8c653c14628ea2d8a2f1e18b313b2cf07d36080cce0aed921780b7717913ab1a77063632845d0daebb4d93bee595e
|
||||
created_unix: 1746256419
|
||||
hash_blake2b: null
|
||||
- id: 33
|
||||
size: 749
|
||||
hash_md5: 861a7d2013e965382bb9404175aa4f44
|
||||
hash_sha1: caf88fc255776f9460c5bd689973a66f528d447f
|
||||
hash_sha256: 9c592110208bcd6624661c36180ce96f238dbe6c6f9ad9749a0d3df828172743
|
||||
hash_sha512: f7a6a16bf8c972fc12871030e3b681c1341b2eccc047f64904b2e6139f8f41015387d517e1ae0e9a19fde8dd0c3d9188db3e433120618f096e7894d3646c765e
|
||||
created_unix: 1746256420
|
||||
hash_blake2b: null
|
||||
- id: 34
|
||||
size: 2081
|
||||
hash_md5: d05558896004f742e8bbe6bbb318deda
|
||||
hash_sha1: 2537f2f2127f5bfeb43ab064aaabb8278ad4bc08
|
||||
hash_sha256: 4e931208c50f458bd523ef5ef55c5367335c62d558be4e24615dd200a75c378d
|
||||
hash_sha512: 8a4fece3a1dd51c870c160d526e58fc96c3282dd770a1e9ce38b39492cda676dd48ecf258ba3282ed081997142503967a7114646481cde6d5b7eb7be49fcff37
|
||||
created_unix: 1746256420
|
||||
hash_blake2b: null
|
||||
- id: 35
|
||||
size: 1016
|
||||
hash_md5: 835a5a3fe19145a134e4a0508fbb9411
|
||||
hash_sha1: 707c30bed611042d57c52d0db2bcd0f609016a5a
|
||||
hash_sha256: 650248c779adbb13c81316902d4b7b27ef294530b0bbd484a3f3a1d369ca995b
|
||||
hash_sha512: 81810ccaf38ad57a9e384336f872d2f39da9474abd648024e8da6733c9d0fd214757563cc7c8a7dcff12cd3e64ba4b694afa6854a6f55bd4e5a53152eef6a7f2
|
||||
created_unix: 1746256423
|
||||
hash_blake2b: null
|
||||
- id: 36
|
||||
size: 2081
|
||||
hash_md5: 599464902943b0e7499180d1c2547754
|
||||
hash_sha1: cab101f1bb3a73e91c3d75f7897067fb29c7747a
|
||||
hash_sha256: 5e960e634845737a49b2bf758496e2a42cfb227ab24455a9d182bde7f597d4a6
|
||||
hash_sha512: 759dde21a878216a6e629bdbd91e2fa4dcc04b7c56116683b5c7433eba277ca3f17daf918c4575130dd14a6d2dcf453bc7861f7e99b7abf150c3b058a299743e
|
||||
created_unix: 1746256424
|
||||
hash_blake2b: null
|
||||
- id: 37
|
||||
size: 580
|
||||
hash_md5: 6e23997166dfb6e2bf3cddb0d7a7f6ff
|
||||
hash_sha1: a9972937cb840e3c961fa00ed8512c45fa9d75a3
|
||||
hash_sha256: c95111d06b75e32cf4d507b818544dbb5245bc0b7dd8b3a1f5d8479772a06b1e
|
||||
hash_sha512: ca549fae977e7fcda088e3211d362a3636c47bd914e2c5ce08ddff2703e60b06dbd66339bae819c881425364f679f1839b1e0685f3bced32747a969d00775a8c
|
||||
created_unix: 1746256427
|
||||
hash_blake2b: null
|
||||
- id: 38
|
||||
size: 940
|
||||
hash_md5: bda9707822e39ed52a6d0b9bb5e9af96
|
||||
hash_sha1: f6ea322c0b9c6211747129636a59ff95e5dbb165
|
||||
hash_sha256: 364f44514fb924cfcddc84c31bbf3dccf9060d9e3ef1e3e6dd28f5789a79e4c6
|
||||
hash_sha512: 7636858249476a81c886c529997eb55ef8c36c52430f0e98050f628fcd440dc09e57f43f88e272f827f86c95451aa4b1927a8d860f970427d1df8348590e7869
|
||||
created_unix: 1746256429
|
||||
hash_blake2b: null
|
||||
- id: 39
|
||||
size: 580
|
||||
hash_md5: 5b373c943e67125442c5a573eece9404
|
||||
hash_sha1: 84b40e3373b8c172d8c302dd304f792838a3f788
|
||||
hash_sha256: d6355300d7e51c649efe19b3419d0dec57d42d4c75079e4ca06ea081f8260f5c
|
||||
hash_sha512: bd926b535bd19f60d69d76a858db2c48f6057223bc23a3575a4fb49fc9ea455250f2bdedad09efdb098c4ac16c6e3d2451a6c182ef191f076276de790448506f
|
||||
created_unix: 1746256432
|
||||
hash_blake2b: null
|
||||
- id: 40
|
||||
size: 940
|
||||
hash_md5: e3817ea0b2f58dd5cc570c0d337a2ecd
|
||||
hash_sha1: 2acc853133cb0ddb46a546fb31f7b4f23df1c676
|
||||
hash_sha256: 775271730e0c4b923a81f539ce97d1b21a1db78ca201065dc886fd42d4e0251b
|
||||
hash_sha512: cb28a65b2f5f7e1e9ec45f6151ed322ee751de5266f413940655de7d739ebf2f7ac9168ccd9676e5b1696d3dcfb57d0bbc404141dfb321a2d28c1a6dcf32b0a7
|
||||
created_unix: 1746256435
|
||||
hash_blake2b: null
|
||||
- id: 41
|
||||
size: 598
|
||||
hash_md5: fb3df5314eda77cfc0da782d86a1574e
|
||||
hash_sha1: 874c3e4aeaad0dcb91f955357c008ed3de52883f
|
||||
hash_sha256: a1f80fc25f3a4cacc21c4ab3e263cc722f7e44bc829a38e7fa927853737cbf9c
|
||||
hash_sha512: b27519f9792ac72b715ff591895deba46d4c6455ea04a4b416e8c5a13eb234176ebd85a21cee5b473f3baa679c6c03cfb72d6d552dee7baa9e7d75535c776557
|
||||
created_unix: 1746256445
|
||||
hash_blake2b: null
|
||||
- id: 42
|
||||
size: 2099
|
||||
hash_md5: f12303e4cfd6cb446c8411f8c2c5c54d
|
||||
hash_sha1: 74af4b51471a501f0fd65ff19498cda87c8252d3
|
||||
hash_sha256: 9fde3ad1d6dc79a40d9ef1c41bb22d00db53df558c0f4d305aaddc0dc2cc0bba
|
||||
hash_sha512: 0f19704ff822157723138bbbf027d418a601cbe0fd21db16478d6e870ad74b80084d5aa35d529a2c6555237cfea19a6c1f955df0c4b00b5ed94f0f1b42465bd6
|
||||
created_unix: 1746256446
|
||||
hash_blake2b: null
|
||||
- id: 43
|
||||
size: 765
|
||||
hash_md5: 0ee9f9dbd150f2fba1f2d151243a23ea
|
||||
hash_sha1: 521db5e9e0e2d25e8b80c9a168ece7263e0b548c
|
||||
hash_sha256: 034554ebaf63c4c20d9290e86b45375616b4e289a28e480f58e25a791c361639
|
||||
hash_sha512: 23ba0f0847083365fbbd0c4de0d71a6560e50781f413e1546a11e9d9d4aad7daee1116b5b94844ee0a431f4d70796561a337a648ec052ac3c5e4bad5accf73ea
|
||||
created_unix: 1746256446
|
||||
hash_blake2b: null
|
||||
- id: 44
|
||||
size: 1032
|
||||
hash_md5: c4c544a801fb99281c6c473c22e0545b
|
||||
hash_sha1: 1c686f728522cb8387a8415a259c62c1af8a0fd1
|
||||
hash_sha256: ce8c82a53d379498784a981f3c69d847947420fb7e1077f5a2b3d9f41fb7c8ed
|
||||
hash_sha512: d9d1bb2a1bcc7886f8c2fd5a413cd954fe2043d4a81dbb1f9ace06a1676684047a7ef2bdc27c9d3f9b800657dbf7226acc0f32b71fc6dc0c9e2662a5c64f7fea
|
||||
created_unix: 1746256449
|
||||
hash_blake2b: null
|
||||
- id: 45
|
||||
size: 751
|
||||
hash_md5: 89b82f20b8be3ea17a068b46e7497428
|
||||
hash_sha1: 27f1389a68febf6786e0d79c698dd1d66c9abfd2
|
||||
hash_sha256: db4ea60e526f85e9829a45e2d75c1f48509e7429a79f7a5d24bc536596c66ab5
|
||||
hash_sha512: b441c6ba00bfcca18adaa976ac37bbf9cab17cac8e7d24e54bc40122dec33781faec7b07db97b3dcaefec7ff8a4251e96728772995d91d196691d8e3494b5768
|
||||
created_unix: 1746256450
|
||||
hash_blake2b: null
|
||||
- id: 46
|
||||
size: 2081
|
||||
hash_md5: 96d24b1f1bec73579c5dbf85ee52b332
|
||||
hash_sha1: 4f407843baaa58116c1022b73f5e411f1c531840
|
||||
hash_sha256: 6866d5d85796b5fc8576310f8ed1d9d9c85825727007809cfc9ff666f1dbdbf0
|
||||
hash_sha512: 8c7c62afaeec008d7c6bc8e390f4adbb11c4ca11337aa1c6832ba83de19f0c75d52ea4fd72a822acdc4f567158120119ed121e0b68213db7a7a7a4f3a731f8fb
|
||||
created_unix: 1746256450
|
||||
hash_blake2b: null
|
||||
- id: 47
|
||||
size: 1017
|
||||
hash_md5: 71a491bc2a2bbb08ec5b3682d09c3f1f
|
||||
hash_sha1: a126e70bed9837bf4609f32d74b20d2ca3e47b59
|
||||
hash_sha256: 2bcacea4eefed11c6f6a23da44ddd575689460262af046a37872e32aa76b79c3
|
||||
hash_sha512: d647d5f7122d76928ac349bdb147fad8b2cd68b7be75a4f580c768feaf86c5e1f7ec484786b6c81324b9df00329cc89217cb00d379138b40adfc81f74d06e6bb
|
||||
created_unix: 1746256452
|
||||
hash_blake2b: null
|
||||
- id: 48
|
||||
size: 2081
|
||||
hash_md5: 26e05a44a2e1989b418aac50feda163e
|
||||
hash_sha1: 224cefa64086537d1d571644abc2180803128035
|
||||
hash_sha256: ea09c61dff5dec488b378b2ce0d4dd64891394606aa318dd57d5f2158d7441fd
|
||||
hash_sha512: 4ca6c77760a11e44f7826b3a23bd5b607ab1e323f47aa76acd9226f1771551fa4dd45c58002c8d3ba6fc4867ed17ad34edb1695a9ab94a31afb8255862633976
|
||||
created_unix: 1746256453
|
||||
hash_blake2b: null
|
||||
- id: 49
|
||||
size: 580
|
||||
hash_md5: a9e65f66ed8ba4769f366fc93142ae07
|
||||
hash_sha1: c170e29851dc3fb44e115a907de7152efd5fb85e
|
||||
hash_sha256: 8ae9c630848588ab6bafebbc6ebcb3b6fe329350e89894852db5c55cc52a4c2c
|
||||
hash_sha512: e0bdaf7430a5176640c0fd57910e1b3e98b4dcc0d34a5a4e898be6c30ccd2d3b59c22dcf94619e3349003ba7b7882ab43216d6175471becffd874143d74ace17
|
||||
created_unix: 1746256456
|
||||
hash_blake2b: null
|
||||
- id: 50
|
||||
size: 941
|
||||
hash_md5: accc00b46ba0c6abc545ed79c2a2f88b
|
||||
hash_sha1: 44a47e8601fe1785bbabc21dbc9efc61ff16d47f
|
||||
hash_sha256: 6f514c55dca294288b5821f415cd24ba11649f001edcfe219e1052d252fd49d8
|
||||
hash_sha512: 9ee7ebd7280fdb51f46610a7923212236b668e7a62a083bae7f2e2f1472d06cb0a9d0f38069e5537fa3b8689f13abeb3e38a1e8432d55f247a06c0522e74374e
|
||||
created_unix: 1746256459
|
||||
hash_blake2b: null
|
||||
- id: 51
|
||||
size: 580
|
||||
hash_md5: 700171de0c83b136769d88af94c1b9b3
|
||||
hash_sha1: c3baca0fb897aeb9462f3718369a30515a68e415
|
||||
hash_sha256: 96eec3e81eebd724a3ef0e6215e337543b3979f2a3355a193933dc7489aa4616
|
||||
hash_sha512: bfb5bb19da1aa65d7cc78ad4f3c57769aefef90ffd5edab3ecd0db5272550bb0666de00acb2a053e03a9473e09d9a77b5026e46bbe18cf669ec4e953b49256c9
|
||||
created_unix: 1746256462
|
||||
hash_blake2b: null
|
||||
- id: 52
|
||||
size: 941
|
||||
hash_md5: 613b6c98a027fc929ecdb06482859626
|
||||
hash_sha1: 39878c4f57ff81bcdc2ce191c44a9a9b31384646
|
||||
hash_sha256: 78fe74176a46873c6fe0c519270641ea45b3e879b1d4caa595bf67dc69d760b0
|
||||
hash_sha512: 16c23e52c02fa0d30dd60704299a375eb6ca75c3fb471fa3501720e53118254bc8888dbf44f75c3cdb2a98ac0ff9ae6fff72e9026fa9a241eaa25841f4fbdaaf
|
||||
created_unix: 1746256464
|
||||
hash_blake2b: null
|
||||
- id: 53
|
||||
size: 598
|
||||
hash_md5: f3015c6cc30b064cd13392a252b61038
|
||||
hash_sha1: 5b6a6ba01238ec187d18ed02f080456d9b0d8416
|
||||
hash_sha256: c331e46fb09c0bcc4aa8019b39d9ed7ddfacbcd139407557f6089f36e5861c57
|
||||
hash_sha512: 64d91206800c8fcc22e449591952289fb83eff85dcc2bf898f2daab66d40ff4e8f9b665335b7a6bd2c0663d78a2ddf1debef923f3306f6813dae98caf02a0f95
|
||||
created_unix: 1746256474
|
||||
hash_blake2b: 1ae012597dbf2d40644c82e06dc6267d88638571b0c669c62e59d15463c289e170f602420e0147da1f9524cea5095f63868bc36ab5630383360e8101b3796d49
|
||||
- id: 54
|
||||
size: 2099
|
||||
hash_md5: 84d83643c58073eb48d88ae591920e50
|
||||
hash_sha1: ef931c2b87b9e2c10b7bbb2bb592cb5dbe82aed7
|
||||
hash_sha256: 8b554f322b8fce952f2221bf08be8447b8606e2ce54d8846b5edcc80ec1fbafd
|
||||
hash_sha512: a2b1a5321f67ed8a324e17903497fac845169cbbb49cc3dfdad9800b164877a7d8f5fcc8f9d6a8e2b394cb13c9a512b27e39149f3b017dd28f26cfcb168fc4c6
|
||||
created_unix: 1746256475
|
||||
hash_blake2b: e4ca11cdd35926a89604589782e538c8140911fef2dad8a934685b33ad841e3cc96ea9d36c90ae413147ce2cabe6c5517045320049fbb3b0069f3620df753bfc
|
||||
- id: 55
|
||||
size: 765
|
||||
hash_md5: 1e9a236068db2f888b41ad1737e26764
|
||||
hash_sha1: 03c5b9eb6e2fea31d3e774c51d3719227810414b
|
||||
hash_sha256: b117af5eaca1f723b7fc3646853298bbffddbb02c63af5cf09d853f0585afb89
|
||||
hash_sha512: c24ff96a33c8eb5f96a212923e1381d41e2813be978772f407aac30090c8657558427b40cbc129dc8b43b96c988ab888703ef5d5e139dff32bf727041a90fca5
|
||||
created_unix: 1746256476
|
||||
hash_blake2b: f4549d79377a1d01fd8c0a19d4a015dfcc50b58820d57ec7bd14fdc5fbaa8166fdd11432200d728d5f1052e54cab2069c8f80818616377c1baa1013fc7679356
|
||||
- id: 56
|
||||
size: 1032
|
||||
hash_md5: 6cda2dee8f57ccc1730f40917a6ec85c
|
||||
hash_sha1: 9689d59af6cf615be6ac21106dcbcc79250b2909
|
||||
hash_sha256: 012e2bbd675130a45b6b6255142254428a86b35c5cffd17546331e9f1bbadb55
|
||||
hash_sha512: 06b79141428bb93d1ba14a82f132dd068ac4b68db3e55029a25ff4bd2be6274a33898f263dc225eed1186462f7eb3fa4e7a24925e996dda0dd1bdbd265eef6b4
|
||||
created_unix: 1746256478
|
||||
hash_blake2b: 0e148046a9984fe45d2109d227ed31b58329afc532eee4817d2113584ff034aa1c5ff09d44240c715d9a80a1a3ea89480bfb425e173df154aedde6398e2ec347
|
||||
- id: 57
|
||||
size: 751
|
||||
hash_md5: 00c8d9ca6462b0e95a30325307a1d855
|
||||
hash_sha1: 525a79e7dfe6553e5e4b4057e80e090d48b43c84
|
||||
hash_sha256: 5b74c950ced8330e3dae432f6c5b0330c6c8e3a72f706f2d8128db989640a02a
|
||||
hash_sha512: 0777a9af5eb936fe5c1a28bb5df26c06db7e290f858cb1ac2e7717236c9be949e8bb214d4007b865ed9d22776b5abd4f8f1e16f862beb9d2db7388f16c9f0ac4
|
||||
created_unix: 1746256479
|
||||
hash_blake2b: 65ed24d1a672a0ec358359f0f9b1dcefce0b64fb8ebaf0342dcf5fd9826b3664a95ac54628a9c245ddfac0843ff36f70de3dff288d5782c54539e1a95c0466d4
|
||||
- id: 58
|
||||
size: 2082
|
||||
hash_md5: 610e6b411ad6a885613f3df4e022e8c2
|
||||
hash_sha1: 5090aa11b88cc5c22895fdcd9e303eb5f89b414f
|
||||
hash_sha256: b87955056b214c1404e58c6e60d2e8b203c249ed141ba80ef6e2d22e4d62d187
|
||||
hash_sha512: c70e98ee7f6b22b427aed9232abdab8380385c841cb6d93af25328bc0a4ed0d1aa4342b363850fde06a1c4f68b0b63c2da99fa36e5934aed5314cdcf6e47e830
|
||||
created_unix: 1746256479
|
||||
hash_blake2b: e3d37152d65d1874f932f18ad0325b8bad850dd220e6f81f99ce58b3117a7f9ee40a3467992d8be78988af7434a5303f264cb5bdf4d4ab66752904a55fe4ac44
|
||||
- id: 59
|
||||
size: 1017
|
||||
hash_md5: 155aada9969270a2d3cc9e7cbd72398d
|
||||
hash_sha1: 6f7140f45bbf17a98d8b51f87c6672c30cbfe114
|
||||
hash_sha256: 3ff912d0c3e4a91d6f5394d8af0a361ca7f183ff6f8a606a32e68e80d4341300
|
||||
hash_sha512: 04558b2154b25463060f6ac999426e816682c7b6e866bf3b9198b4b6cf41288f762439871858831bee627559906e920b478c21525e3ddf85b9896d55840775c5
|
||||
created_unix: 1746256482
|
||||
hash_blake2b: 485c3a16ff1036dfbc05cc55bbb175d5e782b16a97bc4b47fb29b3af824abab016f808fc6cdc96690c4f657b4acadd69bbcf0dec7dc478c91dd09137b7cb3e2f
|
||||
- id: 60
|
||||
size: 2082
|
||||
hash_md5: dc9d45bb32e8f3490634bd513cbf9ece
|
||||
hash_sha1: ea91296f560ab8eb978b7ed0db8efe2fd0e8b413
|
||||
hash_sha256: acf6b1fc9b5b93d9832b6c59e58feb352fd8b07e04356b4b60bbc35dd77c3aac
|
||||
hash_sha512: ff31a45035f8092995bd6ff8e55e6fa35cdcaa4aeaf296da0382657d080541f49687a5adeccbde9ebac0fdbe814ac1e080e7f266bb38acfacd038ce0a6b6a632
|
||||
created_unix: 1746256483
|
||||
hash_blake2b: e24f6cd27d8702026d8d750734fd28d36b1621d8bc7bad18b403b61d0390829a31db679aeea559b7b3f7df27212cad968415d67a72c33abf5744cd61e96e8080
|
||||
- id: 61
|
||||
size: 580
|
||||
hash_md5: efddf19ae15f14a76ad89882c5687f1e
|
||||
hash_sha1: 4241c3e18d179d31a02032e6fbb31014adf9f3f5
|
||||
hash_sha256: eee31b528413c52085cc0b0aa0245ac472cfd364e80fde1c5386e78e75372890
|
||||
hash_sha512: cb752b230dd53a380573dcbd2d406a497ad9279b4fff5fe7de493c34d354de35f343788673830f59912651c1eab81da04513f3ecef0ab6a30dc2f1b39fd9701c
|
||||
created_unix: 1746256486
|
||||
hash_blake2b: 02729bb20121140d8f8904adc712dd7432fb1117bba8a3d878b86aa59afdb3e6d26e3d597b072b0364666fea48c2c5721d5d3bdabb12241267d7fbed0668c927
|
||||
- id: 62
|
||||
size: 941
|
||||
hash_md5: 0aeb1040c1716c32a6ee5a3da7e4b7ca
|
||||
hash_sha1: b7cca777ecd4e4d969f2e4c5e91d30fc7cb75070
|
||||
hash_sha256: e2f0da45a23db0feddb37e44fbf6600e69187530e52234fe1bcc7ce3d1bd2a28
|
||||
hash_sha512: c3394a2adb2bc062cd0015751b5a0d64c7e2600a9dd15b7153782bc9c45f57a734bd6ef7d12d35f48bf2b281e5949d8846fd61612f162c227d19a8a0de1f2ce9
|
||||
created_unix: 1746256488
|
||||
hash_blake2b: 3fe0bc2e796722fa3c26146ab7f5690eba647ce9463e94266998c68cefc2a834092f92ecddd70d98d1e8774808ebd87df429248c61e73144332b8cd8a571b4b0
|
||||
- id: 63
|
||||
size: 582
|
||||
hash_md5: 1262bc37cc2b04b123ae5c1e7a739c4c
|
||||
hash_sha1: 2990625d65fed9184ea3da0553722c128dc962c4
|
||||
hash_sha256: 49ef9afc4951add83afa570b9fef916c5bd22d236fd74752dbfb29944dac4db9
|
||||
hash_sha512: 9012ae4e297da75320c057c78220f34c64889a1905c49467f4fce7400f87b2957ffa9b1f93b7048746d84320081ec7aa69338e2d57422e53cf3c06a5365f87ef
|
||||
created_unix: 1746256491
|
||||
hash_blake2b: a822759b7592218d9571f96ed3039dc934aab2b175476530926ff8bd874b94b05a9c6a275d8b3c2b50fc2efa67fd6045edb659bad9aa11e83044e53cc54564ec
|
||||
- id: 64
|
||||
size: 941
|
||||
hash_md5: 53561653378116758da59c1e5682d024
|
||||
hash_sha1: ac27f3a6e7bd048aaa784273b6bfc92030708065
|
||||
hash_sha256: 1da9c5d5281b8467a86fe7fb015f3ebf1807d3d975c8555959399b91628d7b8f
|
||||
hash_sha512: a97b7265b7df742c903d68b2358f0d14cfc2511c20d2c61a8f2a24505a5fbeaff624b2dd47eca988a3466f55ce7910c0831e7c1617b41a5e560dd584f8b8c28d
|
||||
created_unix: 1746256494
|
||||
hash_blake2b: b6a911084595fdcddbab8c70e5482a2cf038bfde93b27258978a42465d894b92725f9abc81646d28a9c4b80a773c6347aaf43cf7d2067135a15edc2f1ad40b08
|
||||
# broken uploads
|
||||
- id: 65
|
||||
size: 66356
|
||||
hash_md5: 298a5b68e9783c9f193f3818b6362c0b
|
||||
hash_sha1: 20eecad725f7c40a579fd06f438fa366e9dc5887
|
||||
hash_sha256: 6b6802be078be4c07b38b9d0a156521459c81d2cc742be8cf115398890baf95c
|
||||
hash_sha512: 983db2a7ccdf88c8765bacaf6da98eaea04aebd42e1e67943172e7e862c8f62a88cfc96adaf59bb3ad65d889c39e7281f55eb7d706b281782e4c9d0690091d2f
|
||||
created_unix: 1734346161
|
||||
hash_blake2b: null
|
||||
- id: 66
|
||||
size: 2968
|
||||
hash_md5: fa67973e250e94fb4a888ebdb4fa86d7
|
||||
hash_sha1: dce5f1b461883dd50f9191d52aaab01a5a06e578
|
||||
hash_sha256: aae8a7ee5a446ffbb59eb3e3a70ff8809b61cdc235105397e8550b30d12d145b
|
||||
hash_sha512: 6b2f0e33da8204e72903a8f13f6ab4b77ef6b387453777e308088d8c44b925c1b1d226bd8836e32af89ce96a586de0ac0d7ebd351a9534fde7de73634b2fa802
|
||||
created_unix: 1734346195
|
||||
hash_blake2b: null
|
||||
- id: 67
|
||||
size: 64135
|
||||
hash_md5: d9c454fa89301aed28ffc712cd230c56
|
||||
hash_sha1: 9c4b65d14fda070c3248e9ad6da78ef118cd7bec
|
||||
hash_sha256: 9a41e5fec8381a75c41c0e4cc5df56546bbc0ac70019e9ec3716bdf3f7c0da0e
|
||||
hash_sha512: 04e706e34c62602ab129dcb3e817fe4d3b6843b823686c375cebc3cb6adfb758227cf02aca015a808d340a3aeda7424e9ce35de14456d1a8d40874782239f250
|
||||
created_unix: 1734344969
|
||||
hash_blake2b: null
|
||||
- id: 68
|
||||
size: 1053
|
||||
hash_md5: d686ee5f6ce4b91cc317354f49cde759
|
||||
hash_sha1: 8ff8b4d60a1062fe468ff5c310833151932ec628
|
||||
hash_sha256: fd61ac88b2ad7760fd4798613bae50994a85e5346002409837f221a5120de03f
|
||||
hash_sha512: d1705bb7dad6b70a6a9041276bfc41e1e265ac0b8ba65f0ee3bd680e3ad681d813f555b82e81ba162eaae37e5453846fb569c9d64498a69efcfbfa42bd75b82e
|
||||
created_unix: 1734344734
|
||||
hash_blake2b: null
|
||||
- id: 69
|
||||
size: 24995
|
||||
hash_md5: 555c619b35ccc37ef448e0627e1c91bc
|
||||
hash_sha1: 2715bef2d294e8ef9bd8142b8cb92b4f20930792
|
||||
hash_sha256: 90769f198e34910cf842b36e1ae790e801656fa9dc8c072c8ce06a031c195dcb
|
||||
hash_sha512: 1d1f5f1badc779bb387259dcd6bf4deec7b8d711e67b62b2c6c85c1f2a6aab3ed463c82e7f5c7d2060bddbd6797ffd070b4120a7d66eea8a57ee345de2822c8e
|
||||
created_unix: 1734344746
|
||||
hash_blake2b: null
|
||||
- id: 70
|
||||
size: 6307
|
||||
hash_md5: 70833f96aba4e4aae6a66459e1f48640
|
||||
hash_sha1: e049c72bc8f5990c1e63c0a9ed17c12b0096efe6
|
||||
hash_sha256: 55f6f783455b4737078b1b7ec9361299ec336ad0982fdc70e8f861c69be847ca
|
||||
hash_sha512: 8ac7ab63762560227892717c23a1ba2cd6b3f0a59cd8cfcaa86076c65e63dcbac8f0c47213dab21677f7583b672487ddbff28a4aa2446581e25f5d98edc70eca
|
||||
created_unix: 1734344775
|
||||
hash_blake2b: null
|
||||
- id: 71
|
||||
size: 14826
|
||||
hash_md5: 426d22a7b0b57a8a00681191c4f22ae6
|
||||
hash_sha1: 69781f39415518ae823d8745ce4720e743172019
|
||||
hash_sha256: 0fd63dcc4af83babbdff690441ea9182a640ed9d40b1312cdb1b457b2a03f38f
|
||||
hash_sha512: 681fa091abad08a33950f6a308f46ead8c9af8529a42032835c03c960f4578a744b44bd4773aef73438b25b42cc51302498424aead7198eff623f96de6914176
|
||||
created_unix: 1734346161
|
||||
hash_blake2b: null
|
||||
- id: 72
|
||||
size: 863
|
||||
hash_md5: 9acc0ca46cfe4c2adfe0b6e5062a8a15
|
||||
hash_sha1: 0d946b74eac616923103506ee350d82f6c9066bd
|
||||
hash_sha256: f6641da8427411dcf13c15e7e10cabef802383d859301ffc2de0a49b0f213fc3
|
||||
hash_sha512: 4ca12e3af7ca08d58307c610042c31775683011b47345064f213312211134cfe5919c71ba4211019565052364262ced0d9b7dffd058199a36c741f2fef39e2af
|
||||
created_unix: 1734346217
|
||||
hash_blake2b: null
|
||||
- id: 73
|
||||
size: 10272
|
||||
hash_md5: 6a4f701abfb602e3838ba300f9cb6ccc
|
||||
hash_sha1: 0e30a16b8e1b74c51abd08e33dc5341404b71e3b
|
||||
hash_sha256: 0c3e7c7143843491b221af0225ad4205b48ab871aa66ff00bce4d3954b9e0987
|
||||
hash_sha512: b917580c12f09044e117adca76bd1551df5fb92af1860851700b232d07445b2e8293bb73a9c18bfecc6e6d5dbb6df86d954d6a5d93d0442847f6168125fc91be
|
||||
created_unix: 1734344911
|
||||
hash_blake2b: null
|
||||
- id: 74
|
||||
size: 4229
|
||||
hash_md5: 260b6982c5690d674ac546b3bcc743dc
|
||||
hash_sha1: 8e3214aba795ae5849386dac742deb01caf04b8b
|
||||
hash_sha256: ee2e1fe649bf8fc670b9ea5f34815d66c85ba7f8fcd861a557afb0aa9679f652
|
||||
hash_sha512: 6c58c7d0eca2943f3a4a5a2785b961e00d18bf1a9d246879b487120e27f986a0364edb842748875f25244df1c9f939fb705086ad437fce4890f7c8e2b31a79ab
|
||||
created_unix: 1734344953
|
||||
hash_blake2b: null
|
||||
- id: 75
|
||||
size: 12410
|
||||
hash_md5: c511f1c9b10762bd9f907e834d7d01cb
|
||||
hash_sha1: 4998c52d0d23dd3d218e2d9d336f24c0c073601e
|
||||
hash_sha256: cdcf5d6a2c273647885dc4d1a3da4d64922042a4a0bb16beaf561f29b7c59209
|
||||
hash_sha512: 6db8db82f436cec9066b4174a280e0e5bbd21cc829cb2beaf2071fe6ff1f8c77a5a7e5e8a168a41551a21c98bf03e6441375c87dc64a0ef2646720f348d3927d
|
||||
created_unix: 1734344986
|
||||
hash_blake2b: null
|
||||
- id: 76
|
||||
size: 770
|
||||
hash_md5: f123e1549bdb0cf99f89a8944f25d8f0
|
||||
hash_sha1: 01507b6530a5b134a5c660765e0f552cdb5131d2
|
||||
hash_sha256: 81bbd81ba91c24024c7d4790fa1cd5c25acfb7b9c7c4fa9814e0d9f399b6b622
|
||||
hash_sha512: 0738901ad6678a9ab202d5a0356d8bc49c1ed1ec21922718ff706b0990446f78b87adf3bfd25273db8a8910dd7b19f8c232f469b1f65dacffafb6fde29182104
|
||||
created_unix: 1734344900
|
||||
hash_blake2b: null
|
||||
- id: 77
|
||||
size: 4034
|
||||
hash_md5: 4bf84ceb6e877a385f40ad51166bfc1a
|
||||
hash_sha1: eaf6225714366c3a05d4c56c20b034efd8a5f037
|
||||
hash_sha256: f375ec85318662e1789bd34750e578cb2fcf99c2bf005ecc06fabf64e23daafc
|
||||
hash_sha512: 470c5ed2bf14a7ed426453ff026ad2269bbd503ba8c2cd767c89793530c77a7e7e503c68ee542d125bbceda3b49cdc5c846931981eac739a865ffb0cabbe4d89
|
||||
created_unix: 1734344922
|
||||
hash_blake2b: null
|
||||
- id: 78
|
||||
size: 6088
|
||||
hash_md5: 0a4d805af108af059f9af308168ddcfb
|
||||
hash_sha1: bef8a000beaec4bbe5d68b008868d76c90f3f25d
|
||||
hash_sha256: 5b055f5fa634434bdcde8b8174c783d768abb5a253ccef648bb522af603836ae
|
||||
hash_sha512: 9254409431fa52da3144960c272e7aaa0bb646297601cbc6bf88f6c736903aa70943cb56fdbddfac096c10444de25bfd53084b2cf3139ef5b650aae38dd42c26
|
||||
created_unix: 1734344852
|
||||
hash_blake2b: null
|
||||
- id: 79
|
||||
size: 946
|
||||
hash_md5: 3f78acb32897fd77fe467b9776744c12
|
||||
hash_sha1: 3d70df43777d56ad3388ad0036979fcb77443b4c
|
||||
hash_sha256: f9b8b7d3050abecc367bc1523cf5ec17282b5d7181ee833ced319cf382f92616
|
||||
hash_sha512: 2886114ebaef9a77b21d7240591d376a0ef898986882e25e86e0633d465bb9e8096355a4ca6273eb9cf532f02efadd5195b786249986d7c2fafe40f94a8c5ca9
|
||||
created_unix: 1746280832
|
||||
hash_blake2b: cef2628cf51cca9907bdcc69f4e6cbc65c121d37eccb9eccc29fb11179a09af67dccbe0eb04fcd2b87b23925f96082f33feae5c9c550307ab6c6f260aa532f8b
|
||||
- id: 80
|
||||
size: 946
|
||||
hash_md5: 222067385a69840b897fb1177a404876
|
||||
hash_sha1: d56d3378e8492c6ceee3f967f41123fe59082770
|
||||
hash_sha256: 3710e14622091c60701b5ee6357d80681ad3b236baf639d2f848887f0cf681a4
|
||||
hash_sha512: 2de5f0f547b60272ce3da6933309f7c967b23a839c0b7321ae952c229241091033e0640c9e64a199b10936ea64bbc3520ff56a5b6cf339856ca3d089bd5d5487
|
||||
created_unix: 1746280843
|
||||
hash_blake2b: e7e3034bcbc26fba242f2d1c8ec4f653e175178e303b1d120adfed0eec2f6c674b29d5fec4ac2ecb862f491682af480c7d3234be633ad9b288cfdc29cd020beb
|
|
@ -0,0 +1,698 @@
|
|||
- id: 1
|
||||
version_id: 1
|
||||
blob_id: 1
|
||||
name: parent-project-1.0-20250503.071237-1.pom
|
||||
lower_name: parent-project-1.0-20250503.071237-1.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256357
|
||||
- id: 3
|
||||
version_id: 2
|
||||
blob_id: 3
|
||||
name: sub-module-1.0-20250503.071237-1.pom
|
||||
lower_name: sub-module-1.0-20250503.071237-1.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256358
|
||||
- id: 4
|
||||
version_id: 2
|
||||
blob_id: 4
|
||||
name: sub-module-1.0-20250503.071237-1.jar
|
||||
lower_name: sub-module-1.0-20250503.071237-1.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256358
|
||||
- id: 6
|
||||
version_id: 3
|
||||
blob_id: 6
|
||||
name: parent-project-7.0.0.pom
|
||||
lower_name: parent-project-7.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256360
|
||||
- id: 7
|
||||
version_id: 4
|
||||
blob_id: 7
|
||||
name: sub-module-7.0.0.pom
|
||||
lower_name: sub-module-7.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256361
|
||||
- id: 8
|
||||
version_id: 4
|
||||
blob_id: 8
|
||||
name: sub-module-7.0.0.jar
|
||||
lower_name: sub-module-7.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256361
|
||||
- id: 9
|
||||
version_id: 5
|
||||
blob_id: 9
|
||||
name: parent-project-7.0.0.pom
|
||||
lower_name: parent-project-7.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256364
|
||||
- id: 10
|
||||
version_id: 6
|
||||
blob_id: 7
|
||||
name: sub-module-7.0.0.pom
|
||||
lower_name: sub-module-7.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256365
|
||||
- id: 11
|
||||
version_id: 6
|
||||
blob_id: 10
|
||||
name: sub-module-7.0.0.jar
|
||||
lower_name: sub-module-7.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256365
|
||||
- id: 12
|
||||
version_id: 7
|
||||
blob_id: 11
|
||||
name: bar-1.0-20250503.071248-1.pom
|
||||
lower_name: bar-1.0-20250503.071248-1.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256367
|
||||
- id: 14
|
||||
version_id: 8
|
||||
blob_id: 13
|
||||
name: bar-7.0.0.pom
|
||||
lower_name: bar-7.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256370
|
||||
- id: 15
|
||||
version_id: 7
|
||||
blob_id: 14
|
||||
name: -bar-1.0-20250503.071253-2.pom
|
||||
lower_name: -bar-1.0-20250503.071253-2.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256373
|
||||
- id: 17
|
||||
version_id: 8
|
||||
blob_id: 16
|
||||
name: -bar-7.0.0.pom
|
||||
lower_name: -bar-7.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256375
|
||||
- id: 18
|
||||
version_id: 1
|
||||
blob_id: 1
|
||||
name: parent-project-1.0-20250503.071306-2.pom
|
||||
lower_name: parent-project-1.0-20250503.071306-2.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256385
|
||||
- id: 20
|
||||
version_id: 2
|
||||
blob_id: 3
|
||||
name: sub-module-1.0-20250503.071306-2.pom
|
||||
lower_name: sub-module-1.0-20250503.071306-2.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256386
|
||||
- id: 21
|
||||
version_id: 2
|
||||
blob_id: 18
|
||||
name: sub-module-1.0-20250503.071306-2.jar
|
||||
lower_name: sub-module-1.0-20250503.071306-2.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256386
|
||||
- id: 23
|
||||
version_id: 9
|
||||
blob_id: 20
|
||||
name: parent-project-8.0.0.pom
|
||||
lower_name: parent-project-8.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256389
|
||||
- id: 24
|
||||
version_id: 10
|
||||
blob_id: 21
|
||||
name: sub-module-8.0.0.pom
|
||||
lower_name: sub-module-8.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256390
|
||||
- id: 25
|
||||
version_id: 10
|
||||
blob_id: 22
|
||||
name: sub-module-8.0.0.jar
|
||||
lower_name: sub-module-8.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256390
|
||||
- id: 26
|
||||
version_id: 11
|
||||
blob_id: 23
|
||||
name: parent-project-8.0.0.pom
|
||||
lower_name: parent-project-8.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256393
|
||||
- id: 27
|
||||
version_id: 12
|
||||
blob_id: 21
|
||||
name: sub-module-8.0.0.pom
|
||||
lower_name: sub-module-8.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256394
|
||||
- id: 28
|
||||
version_id: 12
|
||||
blob_id: 24
|
||||
name: sub-module-8.0.0.jar
|
||||
lower_name: sub-module-8.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256394
|
||||
- id: 29
|
||||
version_id: 7
|
||||
blob_id: 11
|
||||
name: bar-1.0-20250503.071317-3.pom
|
||||
lower_name: bar-1.0-20250503.071317-3.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256397
|
||||
- id: 31
|
||||
version_id: 13
|
||||
blob_id: 26
|
||||
name: bar-8.0.0.pom
|
||||
lower_name: bar-8.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256399
|
||||
- id: 32
|
||||
version_id: 7
|
||||
blob_id: 14
|
||||
name: -bar-1.0-20250503.071323-4.pom
|
||||
lower_name: -bar-1.0-20250503.071323-4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256402
|
||||
- id: 34
|
||||
version_id: 13
|
||||
blob_id: 28
|
||||
name: -bar-8.0.0.pom
|
||||
lower_name: -bar-8.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256405
|
||||
- id: 35
|
||||
version_id: 1
|
||||
blob_id: 1
|
||||
name: parent-project-1.0-20250503.071335-3.pom
|
||||
lower_name: parent-project-1.0-20250503.071335-3.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256415
|
||||
- id: 37
|
||||
version_id: 2
|
||||
blob_id: 3
|
||||
name: sub-module-1.0-20250503.071335-3.pom
|
||||
lower_name: sub-module-1.0-20250503.071335-3.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256416
|
||||
- id: 38
|
||||
version_id: 2
|
||||
blob_id: 30
|
||||
name: sub-module-1.0-20250503.071335-3.jar
|
||||
lower_name: sub-module-1.0-20250503.071335-3.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256416
|
||||
- id: 40
|
||||
version_id: 14
|
||||
blob_id: 32
|
||||
name: parent-project-9.0.0.pom
|
||||
lower_name: parent-project-9.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256419
|
||||
- id: 41
|
||||
version_id: 15
|
||||
blob_id: 33
|
||||
name: sub-module-9.0.0.pom
|
||||
lower_name: sub-module-9.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256420
|
||||
- id: 42
|
||||
version_id: 15
|
||||
blob_id: 34
|
||||
name: sub-module-9.0.0.jar
|
||||
lower_name: sub-module-9.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256420
|
||||
- id: 43
|
||||
version_id: 16
|
||||
blob_id: 35
|
||||
name: parent-project-9.0.0.pom
|
||||
lower_name: parent-project-9.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256423
|
||||
- id: 44
|
||||
version_id: 17
|
||||
blob_id: 33
|
||||
name: sub-module-9.0.0.pom
|
||||
lower_name: sub-module-9.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256424
|
||||
- id: 45
|
||||
version_id: 17
|
||||
blob_id: 36
|
||||
name: sub-module-9.0.0.jar
|
||||
lower_name: sub-module-9.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256424
|
||||
- id: 46
|
||||
version_id: 7
|
||||
blob_id: 11
|
||||
name: bar-1.0-20250503.071347-5.pom
|
||||
lower_name: bar-1.0-20250503.071347-5.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256427
|
||||
- id: 48
|
||||
version_id: 18
|
||||
blob_id: 38
|
||||
name: bar-9.0.0.pom
|
||||
lower_name: bar-9.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256429
|
||||
- id: 49
|
||||
version_id: 7
|
||||
blob_id: 14
|
||||
name: -bar-1.0-20250503.071353-6.pom
|
||||
lower_name: -bar-1.0-20250503.071353-6.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256432
|
||||
- id: 51
|
||||
version_id: 18
|
||||
blob_id: 40
|
||||
name: -bar-9.0.0.pom
|
||||
lower_name: -bar-9.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256435
|
||||
- id: 52
|
||||
version_id: 1
|
||||
blob_id: 1
|
||||
name: parent-project-1.0-20250503.071405-4.pom
|
||||
lower_name: parent-project-1.0-20250503.071405-4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256445
|
||||
- id: 54
|
||||
version_id: 2
|
||||
blob_id: 3
|
||||
name: sub-module-1.0-20250503.071405-4.pom
|
||||
lower_name: sub-module-1.0-20250503.071405-4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256446
|
||||
- id: 55
|
||||
version_id: 2
|
||||
blob_id: 42
|
||||
name: sub-module-1.0-20250503.071405-4.jar
|
||||
lower_name: sub-module-1.0-20250503.071405-4.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256446
|
||||
- id: 57
|
||||
version_id: 19
|
||||
blob_id: 44
|
||||
name: parent-project-10.0.0.pom
|
||||
lower_name: parent-project-10.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256449
|
||||
- id: 58
|
||||
version_id: 20
|
||||
blob_id: 45
|
||||
name: sub-module-10.0.0.pom
|
||||
lower_name: sub-module-10.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256450
|
||||
- id: 59
|
||||
version_id: 20
|
||||
blob_id: 46
|
||||
name: sub-module-10.0.0.jar
|
||||
lower_name: sub-module-10.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256450
|
||||
- id: 60
|
||||
version_id: 21
|
||||
blob_id: 47
|
||||
name: parent-project-10.0.0.pom
|
||||
lower_name: parent-project-10.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256452
|
||||
- id: 61
|
||||
version_id: 22
|
||||
blob_id: 45
|
||||
name: sub-module-10.0.0.pom
|
||||
lower_name: sub-module-10.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256453
|
||||
- id: 62
|
||||
version_id: 22
|
||||
blob_id: 48
|
||||
name: sub-module-10.0.0.jar
|
||||
lower_name: sub-module-10.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256453
|
||||
- id: 63
|
||||
version_id: 7
|
||||
blob_id: 11
|
||||
name: bar-1.0-20250503.071416-7.pom
|
||||
lower_name: bar-1.0-20250503.071416-7.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256456
|
||||
- id: 65
|
||||
version_id: 23
|
||||
blob_id: 50
|
||||
name: bar-10.0.0.pom
|
||||
lower_name: bar-10.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256459
|
||||
- id: 66
|
||||
version_id: 7
|
||||
blob_id: 14
|
||||
name: -bar-1.0-20250503.071422-8.pom
|
||||
lower_name: -bar-1.0-20250503.071422-8.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256461
|
||||
- id: 68
|
||||
version_id: 23
|
||||
blob_id: 52
|
||||
name: -bar-10.0.0.pom
|
||||
lower_name: -bar-10.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256464
|
||||
- id: 69
|
||||
version_id: 1
|
||||
blob_id: 1
|
||||
name: parent-project-1.0-20250503.071435-5.pom
|
||||
lower_name: parent-project-1.0-20250503.071435-5.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256474
|
||||
- id: 70
|
||||
version_id: 1
|
||||
blob_id: 53
|
||||
name: maven-metadata.xml
|
||||
lower_name: maven-metadata.xml
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256474
|
||||
- id: 71
|
||||
version_id: 2
|
||||
blob_id: 3
|
||||
name: sub-module-1.0-20250503.071435-5.pom
|
||||
lower_name: sub-module-1.0-20250503.071435-5.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256475
|
||||
- id: 72
|
||||
version_id: 2
|
||||
blob_id: 54
|
||||
name: sub-module-1.0-20250503.071435-5.jar
|
||||
lower_name: sub-module-1.0-20250503.071435-5.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256475
|
||||
- id: 73
|
||||
version_id: 2
|
||||
blob_id: 55
|
||||
name: maven-metadata.xml
|
||||
lower_name: maven-metadata.xml
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256476
|
||||
- id: 74
|
||||
version_id: 24
|
||||
blob_id: 56
|
||||
name: parent-project-11.0.0.pom
|
||||
lower_name: parent-project-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256478
|
||||
- id: 75
|
||||
version_id: 25
|
||||
blob_id: 57
|
||||
name: sub-module-11.0.0.pom
|
||||
lower_name: sub-module-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256479
|
||||
- id: 76
|
||||
version_id: 25
|
||||
blob_id: 58
|
||||
name: sub-module-11.0.0.jar
|
||||
lower_name: sub-module-11.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256479
|
||||
- id: 77
|
||||
version_id: 26
|
||||
blob_id: 59
|
||||
name: parent-project-11.0.0.pom
|
||||
lower_name: parent-project-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256482
|
||||
- id: 78
|
||||
version_id: 27
|
||||
blob_id: 57
|
||||
name: sub-module-11.0.0.pom
|
||||
lower_name: sub-module-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256483
|
||||
- id: 79
|
||||
version_id: 27
|
||||
blob_id: 60
|
||||
name: sub-module-11.0.0.jar
|
||||
lower_name: sub-module-11.0.0.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256483
|
||||
- id: 80
|
||||
version_id: 7
|
||||
blob_id: 11
|
||||
name: bar-1.0-20250503.071446-9.pom
|
||||
lower_name: bar-1.0-20250503.071446-9.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256486
|
||||
- id: 82
|
||||
version_id: 28
|
||||
blob_id: 62
|
||||
name: bar-11.0.0.pom
|
||||
lower_name: bar-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256488
|
||||
- id: 83
|
||||
version_id: 7
|
||||
blob_id: 14
|
||||
name: -bar-1.0-20250503.071451-10.pom
|
||||
lower_name: -bar-1.0-20250503.071451-10.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256491
|
||||
- id: 84
|
||||
version_id: 7
|
||||
blob_id: 63
|
||||
name: maven-metadata.xml
|
||||
lower_name: maven-metadata.xml
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 1746256491
|
||||
- id: 85
|
||||
version_id: 28
|
||||
blob_id: 64
|
||||
name: -bar-11.0.0.pom
|
||||
lower_name: -bar-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746256494
|
||||
# broken uploads
|
||||
- id: 86
|
||||
version_id: 29
|
||||
blob_id: 75
|
||||
name: br-repo-jooq-1.2.4-sources.jar
|
||||
lower_name: br-repo-jooq-1.2.4-sources.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649444986
|
||||
- id: 87
|
||||
version_id: 29
|
||||
blob_id: 65
|
||||
name: br-rest-webmvc-1.2.4.jar
|
||||
lower_name: br-rest-webmvc-1.2.4.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649446161
|
||||
- id: 88
|
||||
version_id: 29
|
||||
blob_id: 68
|
||||
name: br-openapi-base-1.2.4.pom
|
||||
lower_name: br-openapi-base-1.2.4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 174625649444734
|
||||
- id: 89
|
||||
version_id: 29
|
||||
blob_id: 69
|
||||
name: br-openapi-base-1.2.4.jar
|
||||
lower_name: br-openapi-base-1.2.4.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649444746
|
||||
- id: 90
|
||||
version_id: 29
|
||||
blob_id: 70
|
||||
name: br-openapi-base-1.2.4-sources.jar
|
||||
lower_name: br-openapi-base-1.2.4-sources.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649444775
|
||||
- id: 91
|
||||
version_id: 29
|
||||
blob_id: 78
|
||||
name: br-parent-1.2.4.pom
|
||||
lower_name: br-parent-1.2.4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 174625649444852
|
||||
- id: 92
|
||||
version_id: 29
|
||||
blob_id: 76
|
||||
name: br-repo-in-memory-1.2.4.pom
|
||||
lower_name: br-repo-in-memory-1.2.4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 174625649444900
|
||||
- id: 93
|
||||
version_id: 29
|
||||
blob_id: 73
|
||||
name: br-repo-in-memory-1.2.4.jar
|
||||
lower_name: br-repo-in-memory-1.2.4.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649444911
|
||||
- id: 94
|
||||
version_id: 29
|
||||
blob_id: 77
|
||||
name: br-repo-in-memory-1.2.4-sources.jar
|
||||
lower_name: br-repo-in-memory-1.2.4-sources.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649444922
|
||||
- id: 95
|
||||
version_id: 29
|
||||
blob_id: 74
|
||||
name: br-repo-jooq-1.2.4.pom
|
||||
lower_name: br-repo-jooq-1.2.4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 174625649444953
|
||||
- id: 96
|
||||
version_id: 29
|
||||
blob_id: 67
|
||||
name: br-repo-jooq-1.2.4.jar
|
||||
lower_name: br-repo-jooq-1.2.4.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649444969
|
||||
- id: 97
|
||||
version_id: 29
|
||||
blob_id: 71
|
||||
name: br-rest-webmvc-1.2.4-sources.jar
|
||||
lower_name: br-rest-webmvc-1.2.4-sources.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649446161
|
||||
- id: 98
|
||||
version_id: 29
|
||||
blob_id: 66
|
||||
name: br-rest-webmvc-1.2.4.pom
|
||||
lower_name: br-rest-webmvc-1.2.4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 174625649446195
|
||||
- id: 99
|
||||
version_id: 29
|
||||
blob_id: 72
|
||||
name: br-root-1.2.4.pom
|
||||
lower_name: br-root-1.2.4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 174625649446217
|
||||
- id: 100
|
||||
version_id: 30
|
||||
blob_id: 66
|
||||
name: br-rest-webmvc-1.2.4.pom
|
||||
lower_name: br-rest-webmvc-1.2.4.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 174625649446311
|
||||
- id: 101
|
||||
version_id: 30
|
||||
blob_id: 65
|
||||
name: br-rest-webmvc-1.2.4.jar
|
||||
lower_name: br-rest-webmvc-1.2.4.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649446312
|
||||
- id: 102
|
||||
version_id: 30
|
||||
blob_id: 71
|
||||
name: br-rest-webmvc-1.2.4-sources.jar
|
||||
lower_name: br-rest-webmvc-1.2.4-sources.jar
|
||||
composite_key: ""
|
||||
is_lead: 0
|
||||
created_unix: 174625649446312
|
||||
# collision
|
||||
- id: 103
|
||||
version_id: 31
|
||||
blob_id: 79
|
||||
name: bar-art-11.0.0.pom
|
||||
lower_name: bar-art-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746280832
|
||||
- id: 104
|
||||
version_id: 31
|
||||
blob_id: 80
|
||||
name: art-11.0.0.pom
|
||||
lower_name: art-11.0.0.pom
|
||||
composite_key: ""
|
||||
is_lead: 1
|
||||
created_unix: 1746280843
|
|
@ -0,0 +1,281 @@
|
|||
- id: 1
|
||||
package_id: 1
|
||||
creator_id: 1
|
||||
version: 1.0-SNAPSHOT
|
||||
lower_version: 1.0-snapshot
|
||||
created_unix: 1746256357
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 2
|
||||
package_id: 2
|
||||
creator_id: 1
|
||||
version: 1.0-SNAPSHOT
|
||||
lower_version: 1.0-snapshot
|
||||
created_unix: 1746256358
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 3
|
||||
package_id: 1
|
||||
creator_id: 1
|
||||
version: 7.0.0
|
||||
lower_version: 7.0.0
|
||||
created_unix: 1746256360
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 4
|
||||
package_id: 2
|
||||
creator_id: 1
|
||||
version: 7.0.0
|
||||
lower_version: 7.0.0
|
||||
created_unix: 1746256361
|
||||
is_internal: 0
|
||||
metadata_json: '{"artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 5
|
||||
package_id: 3
|
||||
creator_id: 1
|
||||
version: 7.0.0
|
||||
lower_version: 7.0.0
|
||||
created_unix: 1746256364
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 6
|
||||
package_id: 4
|
||||
creator_id: 1
|
||||
version: 7.0.0
|
||||
lower_version: 7.0.0
|
||||
created_unix: 1746256365
|
||||
is_internal: 0
|
||||
metadata_json: '{"artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 7
|
||||
package_id: 5
|
||||
creator_id: 1
|
||||
version: 1.0-SNAPSHOT
|
||||
lower_version: 1.0-snapshot
|
||||
created_unix: 1746256367
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"foo","artifact_id":"-bar","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 8
|
||||
package_id: 5
|
||||
creator_id: 1
|
||||
version: 7.0.0
|
||||
lower_version: 7.0.0
|
||||
created_unix: 1746256370
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"foo","artifact_id":"-bar","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 9
|
||||
package_id: 1
|
||||
creator_id: 1
|
||||
version: 8.0.0
|
||||
lower_version: 8.0.0
|
||||
created_unix: 1746256389
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 10
|
||||
package_id: 2
|
||||
creator_id: 1
|
||||
version: 8.0.0
|
||||
lower_version: 8.0.0
|
||||
created_unix: 1746256390
|
||||
is_internal: 0
|
||||
metadata_json: '{"artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 11
|
||||
package_id: 3
|
||||
creator_id: 1
|
||||
version: 8.0.0
|
||||
lower_version: 8.0.0
|
||||
created_unix: 1746256393
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 12
|
||||
package_id: 4
|
||||
creator_id: 1
|
||||
version: 8.0.0
|
||||
lower_version: 8.0.0
|
||||
created_unix: 1746256394
|
||||
is_internal: 0
|
||||
metadata_json: '{"artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 13
|
||||
package_id: 5
|
||||
creator_id: 1
|
||||
version: 8.0.0
|
||||
lower_version: 8.0.0
|
||||
created_unix: 1746256399
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"foo","artifact_id":"-bar","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 14
|
||||
package_id: 1
|
||||
creator_id: 1
|
||||
version: 9.0.0
|
||||
lower_version: 9.0.0
|
||||
created_unix: 1746256419
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 15
|
||||
package_id: 2
|
||||
creator_id: 1
|
||||
version: 9.0.0
|
||||
lower_version: 9.0.0
|
||||
created_unix: 1746256420
|
||||
is_internal: 0
|
||||
metadata_json: '{"artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 16
|
||||
package_id: 3
|
||||
creator_id: 1
|
||||
version: 9.0.0
|
||||
lower_version: 9.0.0
|
||||
created_unix: 1746256423
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 17
|
||||
package_id: 4
|
||||
creator_id: 1
|
||||
version: 9.0.0
|
||||
lower_version: 9.0.0
|
||||
created_unix: 1746256424
|
||||
is_internal: 0
|
||||
metadata_json: '{"artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 18
|
||||
package_id: 5
|
||||
creator_id: 1
|
||||
version: 9.0.0
|
||||
lower_version: 9.0.0
|
||||
created_unix: 1746256429
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"foo","artifact_id":"-bar","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 19
|
||||
package_id: 1
|
||||
creator_id: 1
|
||||
version: 10.0.0
|
||||
lower_version: 10.0.0
|
||||
created_unix: 1746256449
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 20
|
||||
package_id: 2
|
||||
creator_id: 1
|
||||
version: 10.0.0
|
||||
lower_version: 10.0.0
|
||||
created_unix: 1746256450
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 21
|
||||
package_id: 3
|
||||
creator_id: 1
|
||||
version: 10.0.0
|
||||
lower_version: 10.0.0
|
||||
created_unix: 1746256452
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 22
|
||||
package_id: 4
|
||||
creator_id: 1
|
||||
version: 10.0.0
|
||||
lower_version: 10.0.0
|
||||
created_unix: 1746256453
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 23
|
||||
package_id: 5
|
||||
creator_id: 1
|
||||
version: 10.0.0
|
||||
lower_version: 10.0.0
|
||||
created_unix: 1746256459
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"foo","artifact_id":"-bar","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 24
|
||||
package_id: 1
|
||||
creator_id: 1
|
||||
version: 11.0.0
|
||||
lower_version: 11.0.0
|
||||
created_unix: 1746256478
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 25
|
||||
package_id: 2
|
||||
creator_id: 1
|
||||
version: 11.0.0
|
||||
lower_version: 11.0.0
|
||||
created_unix: 1746256479
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 26
|
||||
package_id: 3
|
||||
creator_id: 1
|
||||
version: 11.0.0
|
||||
lower_version: 11.0.0
|
||||
created_unix: 1746256482
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"parent-project","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
- id: 27
|
||||
package_id: 4
|
||||
creator_id: 1
|
||||
version: 11.0.0
|
||||
lower_version: 11.0.0
|
||||
created_unix: 1746256483
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.example","artifact_id":"sub-module","name":"Example :: SubModule ","dependencies":[{"group_id":"junit","artifact_id":"junit","version":"3.8.1"}]}'
|
||||
download_count: 0
|
||||
- id: 28
|
||||
package_id: 5
|
||||
creator_id: 1
|
||||
version: 11.0.0
|
||||
lower_version: 11.0.0
|
||||
created_unix: 1746256488
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"foo","artifact_id":"-bar","name":"Example :: Parent "}'
|
||||
download_count: 0
|
||||
# broken uploads
|
||||
- id: 29
|
||||
package_id: 7
|
||||
creator_id: 6
|
||||
version: 1.2.4
|
||||
lower_version: 1.2.4
|
||||
created_unix: 1746256488
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"com.broken","artifact_id":"br-root","name":"Foo"}'
|
||||
download_count: 0
|
||||
- id: 30
|
||||
package_id: 6
|
||||
creator_id: 6
|
||||
version: 1.2.4
|
||||
lower_version: 1.2.4
|
||||
created_unix: 1746256488
|
||||
is_internal: 0
|
||||
metadata_json: '{"artifact_id":"br-rest-webmvc","name":"Foo :: REST :: Web MVC","dependencies":[{"group_id":"com.broken","artifact_id":"br-base"},{"group_id":"jakarta.servlet","artifact_id":"jakarta.servlet-api"},{"group_id":"jakarta.validation","artifact_id":"jakarta.validation-api"},{"group_id":"org.springframework","artifact_id":"spring-webmvc"},{"group_id":"org.springframework.hateoas","artifact_id":"spring-hateoas"},{"group_id":"org.springframework.boot","artifact_id":"spring-boot-starter-test"},{"group_id":"com.broken","artifact_id":"br-test"},{"group_id":"com.broken","artifact_id":"br-repo-in-memory"},{"group_id":"org.hibernate.validator","artifact_id":"hibernate-validator"},{"group_id":"org.glassfish.expressly","artifact_id":"expressly"}]}'
|
||||
download_count: 0
|
||||
# collision
|
||||
- id: 31
|
||||
package_id: 8
|
||||
creator_id: 1
|
||||
version: 11.0.0
|
||||
lower_version: 11.0.0
|
||||
created_unix: 1746256488
|
||||
is_internal: 0
|
||||
metadata_json: '{"group_id":"group-bar","artifact_id":"art","name":"Example :: Parent "}'
|
||||
download_count: 0
|
|
@ -0,0 +1,9 @@
|
|||
# type Repository struct {
|
||||
# ID int64 `xorm:"pk autoincr"`
|
||||
# Topics []string `xorm:"TEXT JSON"`
|
||||
# }
|
||||
-
|
||||
id: 1
|
||||
-
|
||||
id: 2
|
||||
topics: '["go", "dev"]'
|
|
@ -6,6 +6,7 @@ package migrations
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"forgejo.org/models/db"
|
||||
|
@ -412,7 +413,7 @@ func EnsureUpToDate(x *xorm.Engine) error {
|
|||
}
|
||||
|
||||
if currentDB < 0 {
|
||||
return fmt.Errorf("database has not been initialized")
|
||||
return errors.New("database has not been initialized")
|
||||
}
|
||||
|
||||
if minDBVersion > currentDB {
|
||||
|
|
|
@ -5,6 +5,7 @@ package v1_13 //nolint
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -83,7 +84,7 @@ func SetDefaultPasswordToArgon2(x *xorm.Engine) error {
|
|||
|
||||
newTableColumns := table.Columns()
|
||||
if len(newTableColumns) == 0 {
|
||||
return fmt.Errorf("no columns in new table")
|
||||
return errors.New("no columns in new table")
|
||||
}
|
||||
hasID := false
|
||||
for _, column := range newTableColumns {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
package v1_14 //nolint
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"forgejo.org/modules/log"
|
||||
|
@ -72,7 +72,7 @@ func UpdateCodeCommentReplies(x *xorm.Engine) error {
|
|||
case setting.Database.Type.IsSQLite3():
|
||||
sqlCmd = sqlSelect + sqlTail + " LIMIT " + strconv.Itoa(batchSize) + " OFFSET " + strconv.Itoa(start)
|
||||
default:
|
||||
return fmt.Errorf("Unsupported database type")
|
||||
return errors.New("Unsupported database type")
|
||||
}
|
||||
|
||||
if err := sess.SQL(sqlCmd).Find(&comments); err != nil {
|
||||
|
|
|
@ -73,12 +73,12 @@ func Test_DeleteOrphanedIssueLabels(t *testing.T) {
|
|||
|
||||
// Now test what is left
|
||||
if _, ok := postMigration[2]; ok {
|
||||
t.Errorf("Orphaned Label[2] survived the migration")
|
||||
t.Error("Orphaned Label[2] survived the migration")
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := postMigration[5]; ok {
|
||||
t.Errorf("Orphaned Label[5] survived the migration")
|
||||
t.Error("Orphaned Label[5] survived the migration")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ package v1_17 //nolint
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"forgejo.org/models/migrations/base"
|
||||
|
@ -29,7 +30,7 @@ func DropOldCredentialIDColumn(x *xorm.Engine) error {
|
|||
}
|
||||
if !credentialIDBytesExists {
|
||||
// looks like 221 hasn't properly run
|
||||
return fmt.Errorf("webauthn_credential does not have a credential_id_bytes column... it is not safe to run this migration")
|
||||
return errors.New("webauthn_credential does not have a credential_id_bytes column... it is not safe to run this migration")
|
||||
}
|
||||
|
||||
// Create webauthnCredential table
|
||||
|
|
|
@ -5,7 +5,7 @@ package v1_21 //nolint
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"errors"
|
||||
|
||||
"forgejo.org/models/db"
|
||||
"forgejo.org/modules/timeutil"
|
||||
|
@ -57,7 +57,7 @@ func AddBranchTable(x *xorm.Engine) error {
|
|||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return fmt.Errorf("no admin user found")
|
||||
return errors.New("no admin user found")
|
||||
}
|
||||
|
||||
branches := make([]Branch, 0, 100)
|
||||
|
|
177
models/moderation/abuse_report.go
Normal file
177
models/moderation/abuse_report.go
Normal file
|
@ -0,0 +1,177 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package moderation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"slices"
|
||||
|
||||
"forgejo.org/models/db"
|
||||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/timeutil"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// ReportStatusType defines the statuses a report (of abusive content) can have.
|
||||
type ReportStatusType int
|
||||
|
||||
const (
|
||||
// ReportStatusTypeOpen represents the status of open reports that were not yet handled in any way.
|
||||
ReportStatusTypeOpen ReportStatusType = iota + 1 // 1
|
||||
// ReportStatusTypeHandled represents the status of valid reports, that have been acted upon.
|
||||
ReportStatusTypeHandled // 2
|
||||
// ReportStatusTypeIgnored represents the status of ignored reports, that were closed without any action.
|
||||
ReportStatusTypeIgnored // 3
|
||||
)
|
||||
|
||||
type (
|
||||
// AbuseCategoryType defines the categories in which a user can include the reported content.
|
||||
AbuseCategoryType int
|
||||
|
||||
// AbuseCategoryItem defines a pair of value and it's corresponding translation key
|
||||
// (used to add options within the dropdown shown when new reports are submitted).
|
||||
AbuseCategoryItem struct {
|
||||
Value AbuseCategoryType
|
||||
TranslationKey string
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
AbuseCategoryTypeOther AbuseCategoryType = iota + 1 // 1 (Other violations of platform rules)
|
||||
AbuseCategoryTypeSpam // 2
|
||||
AbuseCategoryTypeMalware // 3
|
||||
AbuseCategoryTypeIllegalContent // 4
|
||||
)
|
||||
|
||||
// GetAbuseCategoriesList returns a list of pairs with the available abuse category types
|
||||
// and their corresponding translation keys
|
||||
func GetAbuseCategoriesList() []AbuseCategoryItem {
|
||||
return []AbuseCategoryItem{
|
||||
{AbuseCategoryTypeSpam, "moderation.abuse_category.spam"},
|
||||
{AbuseCategoryTypeMalware, "moderation.abuse_category.malware"},
|
||||
{AbuseCategoryTypeIllegalContent, "moderation.abuse_category.illegal_content"},
|
||||
{AbuseCategoryTypeOther, "moderation.abuse_category.other_violations"},
|
||||
}
|
||||
}
|
||||
|
||||
// ReportedContentType defines the types of content that can be reported
|
||||
// (i.e. user/organization profile, repository, issue/pull, comment).
|
||||
type ReportedContentType int
|
||||
|
||||
const (
|
||||
// ReportedContentTypeUser should be used when reporting abusive users or organizations.
|
||||
ReportedContentTypeUser ReportedContentType = iota + 1 // 1
|
||||
|
||||
// ReportedContentTypeRepository should be used when reporting a repository with abusive content.
|
||||
ReportedContentTypeRepository // 2
|
||||
|
||||
// ReportedContentTypeIssue should be used when reporting an issue or pull request with abusive content.
|
||||
ReportedContentTypeIssue // 3
|
||||
|
||||
// ReportedContentTypeComment should be used when reporting a comment with abusive content.
|
||||
ReportedContentTypeComment // 4
|
||||
)
|
||||
|
||||
var allReportedContentTypes = []ReportedContentType{
|
||||
ReportedContentTypeUser,
|
||||
ReportedContentTypeRepository,
|
||||
ReportedContentTypeIssue,
|
||||
ReportedContentTypeComment,
|
||||
}
|
||||
|
||||
func (t ReportedContentType) IsValid() bool {
|
||||
return slices.Contains(allReportedContentTypes, t)
|
||||
}
|
||||
|
||||
// AbuseReport represents a report of abusive content.
|
||||
type AbuseReport struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Status ReportStatusType `xorm:"INDEX NOT NULL DEFAULT 1"`
|
||||
// The ID of the user who submitted the report.
|
||||
ReporterID int64 `xorm:"NOT NULL"`
|
||||
// Reported content type: user/organization profile, repository, issue/pull or comment.
|
||||
ContentType ReportedContentType `xorm:"INDEX NOT NULL"`
|
||||
// The ID of the reported item (based on ContentType: user, repository, issue or comment).
|
||||
ContentID int64 `xorm:"NOT NULL"`
|
||||
// The abuse category selected by the reporter.
|
||||
Category AbuseCategoryType `xorm:"INDEX NOT NULL"`
|
||||
// Remarks provided by the reporter.
|
||||
Remarks string
|
||||
// The ID of the corresponding shadow-copied content when exists; otherwise null.
|
||||
ShadowCopyID sql.NullInt64 `xorm:"DEFAULT NULL"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
|
||||
}
|
||||
|
||||
var ErrSelfReporting = errors.New("reporting yourself is not allowed")
|
||||
|
||||
func init() {
|
||||
// RegisterModel will create the table if does not already exist
|
||||
// or any missing columns if the table was previously created.
|
||||
// It will not drop or rename existing columns (when struct has changed).
|
||||
db.RegisterModel(new(AbuseReport))
|
||||
}
|
||||
|
||||
// IsShadowCopyNeeded reports whether one or more reports were already submitted
|
||||
// for contentType and contentID and not yet linked to a shadow copy (regardless their status).
|
||||
func IsShadowCopyNeeded(ctx context.Context, contentType ReportedContentType, contentID int64) (bool, error) {
|
||||
return db.GetEngine(ctx).Cols("id").Where(builder.IsNull{"shadow_copy_id"}).Exist(
|
||||
&AbuseReport{ContentType: contentType, ContentID: contentID},
|
||||
)
|
||||
}
|
||||
|
||||
// AlreadyReportedByAndOpen returns if doerID has already submitted a report for contentType and contentID that is still Open.
|
||||
func AlreadyReportedByAndOpen(ctx context.Context, doerID int64, contentType ReportedContentType, contentID int64) bool {
|
||||
reported, _ := db.GetEngine(ctx).Exist(&AbuseReport{
|
||||
Status: ReportStatusTypeOpen,
|
||||
ReporterID: doerID,
|
||||
ContentType: contentType,
|
||||
ContentID: contentID,
|
||||
})
|
||||
return reported
|
||||
}
|
||||
|
||||
// ReportAbuse creates a new abuse report in the DB with 'Open' status.
|
||||
// If the reported content is the user profile of the reporter ErrSelfReporting is returned.
|
||||
// If there is already an open report submitted by the same user for the same content,
|
||||
// the request will be ignored without returning an error (and a warning will be logged).
|
||||
func ReportAbuse(ctx context.Context, report *AbuseReport) error {
|
||||
if report.ContentType == ReportedContentTypeUser && report.ReporterID == report.ContentID {
|
||||
return ErrSelfReporting
|
||||
}
|
||||
|
||||
if AlreadyReportedByAndOpen(ctx, report.ReporterID, report.ContentType, report.ContentID) {
|
||||
log.Warn("Seems that user %d wanted to report again the content with type %d and ID %d; this request will be ignored.", report.ReporterID, report.ContentType, report.ContentID)
|
||||
return nil
|
||||
}
|
||||
|
||||
report.Status = ReportStatusTypeOpen
|
||||
_, err := db.GetEngine(ctx).Insert(report)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
// MarkAsHandled will change the status to 'Handled' for all reports linked to the same item (user, repository, issue or comment).
|
||||
func MarkAsHandled(ctx context.Context, contentType ReportedContentType, contentID int64) error {
|
||||
return updateStatus(ctx, contentType, contentID, ReportStatusTypeHandled)
|
||||
}
|
||||
|
||||
// MarkAsIgnored will change the status to 'Ignored' for all reports linked to the same item (user, repository, issue or comment).
|
||||
func MarkAsIgnored(ctx context.Context, contentType ReportedContentType, contentID int64) error {
|
||||
return updateStatus(ctx, contentType, contentID, ReportStatusTypeIgnored)
|
||||
}
|
||||
|
||||
// updateStatus will set the provided status for any reports linked to the item with the given type and ID.
|
||||
func updateStatus(ctx context.Context, contentType ReportedContentType, contentID int64, status ReportStatusType) error {
|
||||
_, err := db.GetEngine(ctx).Where(builder.Eq{
|
||||
"content_type": contentType,
|
||||
"content_id": contentID,
|
||||
}).Cols("status").Update(&AbuseReport{Status: status})
|
||||
|
||||
return err
|
||||
}
|
||||
*/
|
76
models/moderation/shadow_copy.go
Normal file
76
models/moderation/shadow_copy.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package moderation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"forgejo.org/models/db"
|
||||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/timeutil"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type AbuseReportShadowCopy struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RawValue string `xorm:"NOT NULL"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
|
||||
}
|
||||
|
||||
// Returns the ID encapsulated in a sql.NullInt64 struct.
|
||||
func (sc AbuseReportShadowCopy) NullableID() sql.NullInt64 {
|
||||
return sql.NullInt64{Int64: sc.ID, Valid: sc.ID > 0}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// RegisterModel will create the table if does not already exist
|
||||
// or any missing columns if the table was previously created.
|
||||
// It will not drop or rename existing columns (when struct has changed).
|
||||
db.RegisterModel(new(AbuseReportShadowCopy))
|
||||
}
|
||||
|
||||
func CreateShadowCopyForUser(ctx context.Context, userID int64, content string) error {
|
||||
return createShadowCopy(ctx, ReportedContentTypeUser, userID, content)
|
||||
}
|
||||
|
||||
func CreateShadowCopyForRepository(ctx context.Context, repoID int64, content string) error {
|
||||
return createShadowCopy(ctx, ReportedContentTypeRepository, repoID, content)
|
||||
}
|
||||
|
||||
func CreateShadowCopyForIssue(ctx context.Context, issueID int64, content string) error {
|
||||
return createShadowCopy(ctx, ReportedContentTypeIssue, issueID, content)
|
||||
}
|
||||
|
||||
func CreateShadowCopyForComment(ctx context.Context, commentID int64, content string) error {
|
||||
return createShadowCopy(ctx, ReportedContentTypeComment, commentID, content)
|
||||
}
|
||||
|
||||
func createShadowCopy(ctx context.Context, contentType ReportedContentType, contentID int64, content string) error {
|
||||
err := db.WithTx(ctx, func(ctx context.Context) error {
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
shadowCopy := &AbuseReportShadowCopy{RawValue: content}
|
||||
affected, err := sess.Insert(shadowCopy)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if affected == 0 {
|
||||
log.Warn("Something went wrong while trying to create the shadow copy for reported content with type %d and ID %d.", contentType, contentID)
|
||||
}
|
||||
|
||||
_, err = sess.Where(builder.Eq{
|
||||
"content_type": contentType,
|
||||
"content_id": contentID,
|
||||
}).And(builder.IsNull{"shadow_copy_id"}).Update(&AbuseReport{ShadowCopyID: shadowCopy.NullableID()})
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not link the shadow copy (%d) to reported content with type %d and ID %d - %w", shadowCopy.ID, contentType, contentID, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
5
models/organization/TestFindOrgs/org_user.yml
Normal file
5
models/organization/TestFindOrgs/org_user.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
-
|
||||
id: 1000
|
||||
uid: 4
|
||||
org_id: 22
|
||||
is_public: true
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue