mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-15 02:00:18 +00:00
Compare commits
100 Commits
v1.20.0-rc
...
v1.20.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
221b90d289 | ||
|
|
81f5a87eb4 | ||
|
|
8b002b429d | ||
|
|
dfd371a363 | ||
|
|
54a516e9da | ||
|
|
ac129d4b4c | ||
|
|
4d5e3b9372 | ||
|
|
1ba0baa030 | ||
|
|
28e8c691a6 | ||
|
|
f81a612eb1 | ||
|
|
ee47face12 | ||
|
|
864bdd0ac8 | ||
|
|
037a3f0d8c | ||
|
|
227c3b67e0 | ||
|
|
5c3662b902 | ||
|
|
ab54310731 | ||
|
|
b7d054e4b5 | ||
|
|
d032500687 | ||
|
|
9159964ada | ||
|
|
9369b38315 | ||
|
|
6e82d0bb7c | ||
|
|
36b9a86bd8 | ||
|
|
e627f161c2 | ||
|
|
de8127e78b | ||
|
|
f7e271ff85 | ||
|
|
186f07bbf7 | ||
|
|
45b1f4dd3b | ||
|
|
026e745b9e | ||
|
|
c334be8284 | ||
|
|
353dcc5ad4 | ||
|
|
7811027ca1 | ||
|
|
abe9c641ce | ||
|
|
052e65e63f | ||
|
|
c1a10be07e | ||
|
|
2b79d3fd52 | ||
|
|
b4460cf541 | ||
|
|
a1bc2aa05e | ||
|
|
d713cf6150 | ||
|
|
012b804a9a | ||
|
|
372b622c2b | ||
|
|
06bcdfe77a | ||
|
|
a5a3c81412 | ||
|
|
ea2c9de3c4 | ||
|
|
348a6bf70d | ||
|
|
68a3961bf1 | ||
|
|
91dadedddf | ||
|
|
32eaba1b40 | ||
|
|
582dcaa12e | ||
|
|
917ca5ded9 | ||
|
|
e595dfeec7 | ||
|
|
03cacf971e | ||
|
|
68e0c802f7 | ||
|
|
09668b2e2e | ||
|
|
04eea29ecb | ||
|
|
511be9fe6e | ||
|
|
24e64fe372 | ||
|
|
4e310133f9 | ||
|
|
491f36d32a | ||
|
|
9111d2d037 | ||
|
|
5510ed34f1 | ||
|
|
39fce5750d | ||
|
|
1f90376041 | ||
|
|
0af6542a34 | ||
|
|
69bdcf41f3 | ||
|
|
e610b0389a | ||
|
|
13ffa287b1 | ||
|
|
e5b684e567 | ||
|
|
64ed262e18 | ||
|
|
f51c8e0008 | ||
|
|
d8a59d5f12 | ||
|
|
1ddfe03131 | ||
|
|
24cf06592e | ||
|
|
0b6f7fb607 | ||
|
|
c27a3af728 | ||
|
|
12aca3ef20 | ||
|
|
2390a46d0f | ||
|
|
51b6a78791 | ||
|
|
e6f62eea70 | ||
|
|
8981f6d0fc | ||
|
|
b2b5c80cb2 | ||
|
|
77db40e084 | ||
|
|
7222bac4e3 | ||
|
|
0eb4ab4246 | ||
|
|
102dcfa3a0 | ||
|
|
614d6df2d8 | ||
|
|
345a25d016 | ||
|
|
e8a7cd4a1d | ||
|
|
6c43b9f6f6 | ||
|
|
40744f8976 | ||
|
|
9d69a4758e | ||
|
|
53747a58a0 | ||
|
|
00ba826360 | ||
|
|
9bbb4d8d6d | ||
|
|
5703a0d3e3 | ||
|
|
85bad22ff8 | ||
|
|
71d2a6a41a | ||
|
|
d1f1f1142e | ||
|
|
2cd9d6b3f9 | ||
|
|
050c38ca19 | ||
|
|
51789ba12d |
1192
CHANGELOG.md
1192
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
var optionLogVerbose bool
|
||||
|
||||
func logVerbose(msg string, args ...interface{}) {
|
||||
func logVerbose(msg string, args ...any) {
|
||||
if optionLogVerbose {
|
||||
log.Printf(msg, args...)
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||
},
|
||||
}
|
||||
|
||||
func publicKey(priv interface{}) interface{} {
|
||||
func publicKey(priv any) any {
|
||||
switch k := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &k.PublicKey
|
||||
@@ -74,7 +74,7 @@ func publicKey(priv interface{}) interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func pemBlockForKey(priv interface{}) *pem.Block {
|
||||
func pemBlockForKey(priv any) *pem.Block {
|
||||
switch k := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
||||
@@ -94,7 +94,7 @@ func runCert(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var priv interface{}
|
||||
var priv any
|
||||
var err error
|
||||
switch c.String("ecdsa-curve") {
|
||||
case "":
|
||||
|
||||
18
cmd/cmd.go
18
cmd/cmd.go
@@ -106,5 +106,21 @@ func setupConsoleLogger(level log.Level, colorize bool, out io.Writer) {
|
||||
WriterOption: log.WriterConsoleOption{Stderr: out == os.Stderr},
|
||||
}
|
||||
writer := log.NewEventWriterConsole("console-default", writeMode)
|
||||
log.GetManager().GetLogger(log.DEFAULT).RemoveAllWriters().AddWriters(writer)
|
||||
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
level := defaultLevel
|
||||
if c.Bool("quiet") || c.GlobalBoolT("quiet") {
|
||||
level = log.FATAL
|
||||
}
|
||||
if c.Bool("debug") || c.GlobalBool("debug") || c.Bool("verbose") || c.GlobalBool("verbose") {
|
||||
level = log.TRACE
|
||||
}
|
||||
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
||||
log.FallbackErrorf("unable to create file log writer: %v", err)
|
||||
return
|
||||
}
|
||||
log.GetManager().GetLogger(log.DEFAULT).RemoveAllWriters().AddWriters(writer)
|
||||
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
|
||||
},
|
||||
}
|
||||
|
||||
func fatal(format string, args ...interface{}) {
|
||||
func fatal(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||
log.Fatal(format, args...)
|
||||
}
|
||||
@@ -236,7 +236,7 @@ func runDump(ctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var iface interface{}
|
||||
var iface any
|
||||
if fileName == "-" {
|
||||
iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType))
|
||||
} else {
|
||||
|
||||
@@ -22,9 +22,9 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Cmdembedded represents the available extract sub-command.
|
||||
// CmdEmbedded represents the available extract sub-command.
|
||||
var (
|
||||
Cmdembedded = cli.Command{
|
||||
CmdEmbedded = cli.Command{
|
||||
Name: "embedded",
|
||||
Usage: "Extract embedded resources",
|
||||
Description: "A command for extracting embedded resources, like templates and images",
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -32,6 +33,7 @@ var (
|
||||
Name: "hook",
|
||||
Usage: "Delegate commands to corresponding Git hooks",
|
||||
Description: "This should only be called by Git",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Subcommands: []cli.Command{
|
||||
subcmdHookPreReceive,
|
||||
subcmdHookUpdate,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
var CmdKeys = cli.Command{
|
||||
Name: "keys",
|
||||
Usage: "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Action: runKeys,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
|
||||
@@ -178,7 +178,7 @@ func runAddConnLogger(c *cli.Context) error {
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
vals := map[string]any{}
|
||||
mode := "conn"
|
||||
vals["net"] = "tcp"
|
||||
if c.IsSet("protocol") {
|
||||
@@ -208,7 +208,7 @@ func runAddFileLogger(c *cli.Context) error {
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
vals := map[string]any{}
|
||||
mode := "file"
|
||||
if c.IsSet("filename") {
|
||||
vals["filename"] = c.String("filename")
|
||||
@@ -236,7 +236,7 @@ func runAddFileLogger(c *cli.Context) error {
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) error {
|
||||
func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
||||
if len(c.String("level")) > 0 {
|
||||
vals["level"] = log.LevelFromString(c.String("level")).String()
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ var CmdServ = cli.Command{
|
||||
Name: "serv",
|
||||
Usage: "This command 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{
|
||||
@@ -94,7 +95,7 @@ var (
|
||||
|
||||
// fail prints message to stdout, it's mainly used for git serv and git hook commands.
|
||||
// The output will be passed to git client and shown to user.
|
||||
func fail(ctx context.Context, userMessage, logMsgFmt string, args ...interface{}) error {
|
||||
func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error {
|
||||
if userMessage == "" {
|
||||
userMessage = "Internal Server Error (no specific error)"
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ var CmdWeb = cli.Command{
|
||||
Usage: "Start Gitea web server",
|
||||
Description: `Gitea 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{
|
||||
@@ -206,11 +207,6 @@ func servePprof() {
|
||||
}
|
||||
|
||||
func runWeb(ctx *cli.Context) error {
|
||||
if ctx.Bool("verbose") {
|
||||
setupConsoleLogger(log.TRACE, log.CanColorStdout, os.Stdout)
|
||||
} else if ctx.Bool("quiet") {
|
||||
setupConsoleLogger(log.FATAL, log.CanColorStdout, os.Stdout)
|
||||
}
|
||||
defer func() {
|
||||
if panicked := recover(); panicked != nil {
|
||||
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
||||
|
||||
@@ -5,7 +5,6 @@ package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -13,9 +12,6 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// EnvironmentPrefix environment variables prefixed with this represent ini values to write
|
||||
const EnvironmentPrefix = "GITEA"
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "environment-to-ini"
|
||||
@@ -70,15 +66,6 @@ func main() {
|
||||
Value: "",
|
||||
Usage: "Destination file to write to",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "clear",
|
||||
Usage: "Clears the matched variables from the environment",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "prefix, p",
|
||||
Value: EnvironmentPrefix,
|
||||
Usage: "Environment prefix to look for - will be suffixed by __ (2 underscores)",
|
||||
},
|
||||
}
|
||||
app.Action = runEnvironmentToIni
|
||||
err := app.Run(os.Args)
|
||||
@@ -88,7 +75,9 @@ func main() {
|
||||
}
|
||||
|
||||
func runEnvironmentToIni(c *cli.Context) error {
|
||||
setting.InitWorkPathAndCommonConfig(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
||||
// 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{
|
||||
WorkPath: c.String("work-path"),
|
||||
CustomPath: c.String("custom-path"),
|
||||
CustomConf: c.String("config"),
|
||||
@@ -99,9 +88,7 @@ func runEnvironmentToIni(c *cli.Context) error {
|
||||
log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
||||
}
|
||||
|
||||
prefixGitea := c.String("prefix") + "__"
|
||||
suffixFile := "__FILE"
|
||||
changed := setting.EnvironmentToConfig(cfg, prefixGitea, suffixFile, os.Environ())
|
||||
changed := setting.EnvironmentToConfig(cfg, env)
|
||||
|
||||
// try to save the config file
|
||||
destination := c.String("out")
|
||||
@@ -116,19 +103,5 @@ func runEnvironmentToIni(c *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
// clear Gitea's specific environment variables if requested
|
||||
if c.Bool("clear") {
|
||||
for _, kv := range os.Environ() {
|
||||
idx := strings.IndexByte(kv, '=')
|
||||
if idx < 0 {
|
||||
continue
|
||||
}
|
||||
eKey := kv[:idx]
|
||||
if strings.HasPrefix(eKey, prefixGitea) {
|
||||
_ = os.Unsetenv(eKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,26 +16,23 @@
|
||||
;;
|
||||
;; - _`AppPath`_: This is the absolute path of the running gitea binary.
|
||||
;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
|
||||
;; - The "WORK_PATH" option in "app.ini" file
|
||||
;; - The `--work-path` flag passed to the binary
|
||||
;; - The environment variable `$GITEA_WORK_DIR`
|
||||
;; - A built-in value set at build time (see building from source)
|
||||
;; - Otherwise it defaults to the directory of the _`AppPath`_
|
||||
;; - If any of the above are relative paths then they are made absolute against
|
||||
;; the directory of the _`AppPath`_
|
||||
;; - _`CustomPath`_: This is the base directory for custom templates and other options.
|
||||
;; It is determined by using the first set thing in the following hierarchy:
|
||||
;; - If any of the above are relative paths then they are made absolute against the directory of the _`AppPath`_
|
||||
;; - _`CustomPath`_: This is the base directory for custom templates and other options. It is determined by using the first set thing in the following hierarchy:
|
||||
;; - The `--custom-path` flag passed to the binary
|
||||
;; - The environment variable `$GITEA_CUSTOM`
|
||||
;; - A built-in value set at build time (see building from source)
|
||||
;; - Otherwise it defaults to _`AppWorkPath`_`/custom`
|
||||
;; - If any of the above are relative paths then they are made absolute against the
|
||||
;; the directory of the _`AppWorkPath`_
|
||||
;; - If any of the above are relative paths then they are made absolute against the directory of the _`AppWorkPath`_
|
||||
;; - _`CustomConf`_: This is the path to the `app.ini` file.
|
||||
;; - The `--config` flag passed to the binary
|
||||
;; - A built-in value set at build time (see building from source)
|
||||
;; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
|
||||
;; - If any of the above are relative paths then they are made absolute against the
|
||||
;; the directory of the _`CustomPath`_
|
||||
;; - If any of the above are relative paths then they are made absolute against the directory of the _`CustomPath`_
|
||||
;;
|
||||
;; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
||||
|
||||
@@ -52,6 +49,9 @@ RUN_USER = ; git
|
||||
;; Application run mode, affects performance and debugging: "dev" or "prod", default is "prod"
|
||||
;; Mode "dev" makes Gitea easier to develop and debug, values other than "dev" are treated as "prod" which is for production use.
|
||||
;RUN_MODE = prod
|
||||
;;
|
||||
;; The working directory, see the comment of AppWorkPath above
|
||||
;WORK_PATH =
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -2541,8 +2541,8 @@ LEVEL = Info
|
||||
;; Enable/Disable actions capabilities
|
||||
;ENABLED = false
|
||||
;;
|
||||
;; Default address to get action plugins, e.g. the default value means downloading from "https://gitea.com/actions/checkout" for "uses: actions/checkout@v3"
|
||||
;DEFAULT_ACTIONS_URL = https://gitea.com
|
||||
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
||||
;DEFAULT_ACTIONS_URL = github
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -2,7 +2,15 @@
|
||||
|
||||
if [ ! -d /data/git/.ssh ]; then
|
||||
mkdir -p /data/git/.ssh
|
||||
chmod 700 /data/git/.ssh
|
||||
fi
|
||||
|
||||
# Set the correct permissions on the .ssh directory and authorized_keys file,
|
||||
# or sshd will refuse to use them and lead to clone/push/pull failures.
|
||||
# It could happen when users have copied their data to a new volume and changed the file permission by accident,
|
||||
# and it would be very hard to troubleshoot unless users know how to check the logs of sshd which is started by s6.
|
||||
chmod 700 /data/git/.ssh
|
||||
if [ -f /data/git/.ssh/authorized_keys ]; then
|
||||
chmod 600 /data/git/.ssh/authorized_keys
|
||||
fi
|
||||
|
||||
if [ ! -f /data/git/.ssh/environment ]; then
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
# And place the original in /usr/lib/gitea with working files in /data/gitea
|
||||
GITEA="/app/gitea/gitea"
|
||||
WORK_DIR="/app/gitea"
|
||||
WORK_DIR="/data/gitea"
|
||||
CUSTOM_PATH="/data/gitea"
|
||||
|
||||
# Provide docker defaults
|
||||
|
||||
@@ -46,9 +46,9 @@ directory. There should be some output similar to the following:
|
||||
|
||||
Inside the `gitea-dump-1482906742.zip` file, will be the following:
|
||||
|
||||
- `app.ini` - Optional copy of configuration file if originally stored outside of the default `custom/` directory
|
||||
- `app.ini` - Optional copy of configuration file if originally stored outside the default `custom/` directory
|
||||
- `custom` - All config or customization files in `custom/`.
|
||||
- `data` - Data directory in <GITEA_WORK_DIR>, except sessions if you are using file session. This directory includes `attachments`, `avatars`, `lfs`, `indexers`, SQLite file if you are using SQLite.
|
||||
- `data` - Data directory (APP_DATA_PATH), except sessions if you are using file session. This directory includes `attachments`, `avatars`, `lfs`, `indexers`, SQLite file if you are using SQLite.
|
||||
- `gitea-db.sql` - SQL dump of database
|
||||
- `gitea-repo.zip` - Complete copy of the repository directory.
|
||||
- `log/` - Various logs. They are not needed for a recovery or migration.
|
||||
@@ -139,16 +139,6 @@ chown -R git:git /data
|
||||
|
||||
The default user in the gitea container is `git` (1000:1000). Please replace `2a83b293548e` with your gitea container id or name.
|
||||
|
||||
These are the default paths used in the container:
|
||||
|
||||
```text
|
||||
DEFAULT CONFIGURATION:
|
||||
CustomPath: /data/gitea (GITEA_CUSTOM)
|
||||
CustomConf: /data/gitea/conf/app.ini
|
||||
AppPath: /usr/local/bin/gitea
|
||||
AppWorkPath: /usr/local/bin
|
||||
```
|
||||
|
||||
### Using Docker-rootless (`restore`)
|
||||
|
||||
The restore workflow in Docker-rootless containers differs only in the directories to be used:
|
||||
|
||||
@@ -31,9 +31,9 @@ All global options can be placed at the command level.
|
||||
|
||||
- `--help`, `-h`: Show help text and exit. Optional.
|
||||
- `--version`, `-v`: Show version and exit. Optional. (example: `Gitea version 1.1.0+218-g7b907ed built with: bindata, sqlite`).
|
||||
- `--custom-path path`, `-C path`: Location of the Gitea custom folder. Optional. (default: `AppWorkPath`/custom or `$GITEA_CUSTOM`).
|
||||
- `--config path`, `-c path`: Gitea configuration file path. Optional. (default: `custom`/conf/app.ini).
|
||||
- `--work-path path`, `-w path`: Gitea `AppWorkPath`. Optional. (default: LOCATION_OF_GITEA_BINARY or `$GITEA_WORK_DIR`)
|
||||
- `--work-path path`, `-w path`: Gitea's work path. Optional. (default: the binary's path or `$GITEA_WORK_DIR`)
|
||||
- `--custom-path path`, `-C path`: Gitea's custom folder path. Optional. (default: `WorkPath`/custom or `$GITEA_CUSTOM`).
|
||||
- `--config path`, `-c path`: Gitea configuration file path. Optional. (default: `CustomPath`/conf/app.ini).
|
||||
|
||||
NB: The defaults custom-path, config and work-path can also be
|
||||
changed at build time (if preferred).
|
||||
@@ -108,6 +108,14 @@ Admin operations:
|
||||
- `--all`, `-A`: Force a password change for all users
|
||||
- `--exclude username`, `-e username`: Exclude the given user. Can be set multiple times.
|
||||
- `--unset`: Revoke forced password change for the given users
|
||||
- `generate-access-token`:
|
||||
- Options:
|
||||
- `--username value`, `-u value`: Username. Required.
|
||||
- `--token-name value`, `-t value`: Token name. Required.
|
||||
- `--scopes value`: Comma-separated list of scopes. Scopes follow the format `[read|write]:<block>` or `all` where `<block>` is one of the available visual groups you can see when opening the API page showing the available routes (for example `repo`).
|
||||
- Examples:
|
||||
- `gitea admin user generate-access-token --username myname --token-name mytoken`
|
||||
- `gitea admin user generate-access-token --help`
|
||||
- `regenerate`
|
||||
- Options:
|
||||
- `hooks`: Regenerate Git Hooks for all repositories
|
||||
|
||||
@@ -44,28 +44,27 @@ reported as part of the default configuration when running `gitea --help` or on
|
||||
|
||||
- _`AppPath`_: This is the absolute path of the running gitea binary.
|
||||
- _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
|
||||
- The `WORK_PATH` option in `app.ini`
|
||||
- The `--work-path` flag passed to the binary
|
||||
- The environment variable `$GITEA_WORK_DIR`
|
||||
- A built-in value set at build time (see building from source)
|
||||
- Otherwise it defaults to the directory of the _`AppPath`_
|
||||
- If any of the above are relative paths then they are made absolute against
|
||||
the directory of the _`AppPath`_
|
||||
- Otherwise, it defaults to the directory of the _`AppPath`_
|
||||
- If any of the above are relative paths then they are made absolute against the directory of the _`AppPath`_
|
||||
- _`CustomPath`_: This is the base directory for custom templates and other options.
|
||||
It is determined by using the first set thing in the following hierarchy:
|
||||
- The `--custom-path` flag passed to the binary
|
||||
- The environment variable `$GITEA_CUSTOM`
|
||||
- A built-in value set at build time (see building from source)
|
||||
- Otherwise it defaults to _`AppWorkPath`_`/custom`
|
||||
- Otherwise, it defaults to _`AppWorkPath`_`/custom`
|
||||
- If any of the above are relative paths then they are made absolute against the
|
||||
the directory of the _`AppWorkPath`_
|
||||
- _`CustomConf`_: This is the path to the `app.ini` file.
|
||||
- The `--config` flag passed to the binary
|
||||
- A built-in value set at build time (see building from source)
|
||||
- Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
|
||||
- If any of the above are relative paths then they are made absolute against the
|
||||
the directory of the _`CustomPath`_
|
||||
- Otherwise, it defaults to _`CustomPath`_`/conf/app.ini`
|
||||
- If any of the above are relative paths then they are made absolute against the directory of the _`CustomPath`_
|
||||
|
||||
In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
||||
In addition, there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
||||
|
||||
## Overall (`DEFAULT`)
|
||||
|
||||
@@ -74,6 +73,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
|
||||
This should be a dedicated system (non-user) account. Setting this incorrectly will cause Gitea
|
||||
to not start.
|
||||
- `RUN_MODE`: **prod**: Application run mode, affects performance and debugging: `dev` or `prod`, default is `prod`. Mode `dev` makes Gitea easier to develop and debug, values other than `dev` are treated as `prod` which is for production use.
|
||||
- `WORK_PATH`: **_the-work-path_**: The working directory, see the comment of AppWorkPath above.
|
||||
|
||||
## Repository (`repository`)
|
||||
|
||||
@@ -1374,39 +1374,22 @@ PROXY_HOSTS = *.github.com
|
||||
## Actions (`actions`)
|
||||
|
||||
- `ENABLED`: **false**: Enable/Disable actions capabilities
|
||||
- `DEFAULT_ACTIONS_URL`: **https://gitea.com**: Default address to get action plugins, e.g. the default value means downloading from "<https://gitea.com/actions/checkout>" for "uses: actions/checkout@v3"
|
||||
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
||||
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
||||
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
||||
|
||||
`DEFAULT_ACTIONS_URL` indicates where should we find the relative path action plugin. i.e. when use an action in a workflow file like
|
||||
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
|
||||
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.
|
||||
And it can be changed to `self` to make it `root_url_of_your_gitea/actions/checkout@v3`.
|
||||
|
||||
```yaml
|
||||
name: versions
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- releases/*
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
```
|
||||
Please note that using `self` is not recommended for most cases, as it could make names globally ambiguous.
|
||||
Additionally, it requires you to mirror all the actions you need to your Gitea instance, which may not be worth it.
|
||||
Therefore, please use `self` only if you understand what you are doing.
|
||||
|
||||
Now we need to know how to get actions/checkout, this configuration is the default git server to get it. That means we will get the repository via git clone ${DEFAULT_ACTIONS_URL}/actions/checkout and fetch tag v3.
|
||||
|
||||
To help people who don't want to mirror these actions in their git instances, the default value is https://gitea.com
|
||||
To help people run actions totally in their network, they can change the value and copy all necessary action repositories into their git server.
|
||||
|
||||
Of course we should support the form in future PRs like
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: gitea.com/actions/checkout@v3
|
||||
```
|
||||
|
||||
although Github don't support this form.
|
||||
In earlier versions (<= 1.19), `DEFAULT_ACTIONS_URL` cound be set to any custom URLs like `https://gitea.com` or `http://your-git-server,https://gitea.com`, and the default value was `https://gitea.com`.
|
||||
However, later updates removed those options, and now the only options are `github` and `self`, with the default value being `github`.
|
||||
However, if you want to use actions from other git server, you can use a complete URL in `uses` field, it's supported by Gitea (but not GitHub).
|
||||
Like `uses: https://gitea.com/actions/checkout@v3` or `uses: http://your-git-server/actions/checkout@v3`.
|
||||
|
||||
## Other (`other`)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ menu:
|
||||
# Customizing Gitea
|
||||
|
||||
Customizing Gitea is typically done using the `CustomPath` folder - by default this is
|
||||
the `custom` folder from the running directory, but may be different if your build has
|
||||
the `custom` folder from the working directory (WorkPath), but may be different if your build has
|
||||
set this differently. This is the central place to override configuration settings,
|
||||
templates, etc. You can check the `CustomPath` using `gitea help`. You can also find
|
||||
the path on the _Configuration_ tab in the _Site Administration_ page. You can override
|
||||
|
||||
@@ -43,10 +43,7 @@ For documentation about each of the variables available, refer to the
|
||||
## Gitea files
|
||||
|
||||
- `GITEA_WORK_DIR`: Absolute path of working directory.
|
||||
- `GITEA_CUSTOM`: Gitea uses `GITEA_WORK_DIR`/custom folder by default. Use this variable
|
||||
to change _custom_ directory.
|
||||
- `GOGS_WORK_DIR`: Deprecated, use `GITEA_WORK_DIR`
|
||||
- `GOGS_CUSTOM`: Deprecated, use `GITEA_CUSTOM`
|
||||
- `GITEA_CUSTOM`: Gitea uses `WorkPath`/custom folder by default. Use this variable to change _custom_ directory.
|
||||
|
||||
## Operating system specifics
|
||||
|
||||
|
||||
@@ -59,11 +59,12 @@ https://github.com/loganinak/MigrateGitlabToGogs
|
||||
## Where does Gitea store what file
|
||||
|
||||
- _`AppWorkPath`_
|
||||
- The `--work-path` flag
|
||||
- The `WORK_PATH` option in `app.ini`
|
||||
- Else the `--work-path` flag
|
||||
- Else Environment variable `GITEA_WORK_DIR`
|
||||
- Else a built-in value set at build time
|
||||
- Else the directory that contains the Gitea binary
|
||||
- `%(APP_DATA_PATH)` (default for database, indexers, etc.)
|
||||
- `AppDataPath` (default for database, indexers, etc.)
|
||||
- `APP_DATA_PATH` from `app.ini`
|
||||
- Else _`AppWorkPath`_`/data`
|
||||
- _`CustomPath`_ (custom templates)
|
||||
@@ -112,9 +113,6 @@ Gitea's custom templates must be added to the correct location or Gitea will not
|
||||
The correct path for the template(s) will be relative to the `CustomPath`
|
||||
|
||||
1. To find `CustomPath`, look for Custom File Root Path in Site Administration -> Configuration
|
||||
|
||||
If that doesn't exist, you can try `echo $GITEA_CUSTOM`
|
||||
|
||||
2. If you are still unable to find a path, the default can be [calculated above](#where-does-gitea-store-what-file)
|
||||
3. Once you have figured out the correct custom path, you can refer to the [customizing Gitea]({{< relref "doc/administration/customizing-gitea.en-us.md" >}}) page to add your template to the correct location.
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ sudo chown 1000:1000 config/ data/
|
||||
|
||||
> If you don't give the volume correct permissions, the container may not start.
|
||||
|
||||
For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:dev-rootless` would be an appropriate tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev-rootless` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev-rootless`)
|
||||
For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:nightly-rootless` would be an appropriate tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-nightly-rootless` tag, where x is the minor version of Gitea. (e.g. `:1.16-nightly-rootless`)
|
||||
|
||||
## Custom port
|
||||
|
||||
@@ -119,7 +119,7 @@ services:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "222:22"
|
||||
- "2222:2222"
|
||||
+ depends_on:
|
||||
+ - db
|
||||
+
|
||||
@@ -288,7 +288,7 @@ docker-compose up -d
|
||||
|
||||
In addition to the environment variables above, any settings in `app.ini` can be set
|
||||
or overridden with an environment variable of the form: `GITEA__SECTION_NAME__KEY_NAME`.
|
||||
These settings are applied each time the docker container starts.
|
||||
These settings are applied each time the docker container starts, and won't be passed into Gitea's sub-processes.
|
||||
Full information [here](https://github.com/go-gitea/gitea/tree/main/contrib/environment-to-ini).
|
||||
|
||||
These environment variables can be passed to the docker container in `docker-compose.yml`.
|
||||
|
||||
@@ -36,7 +36,7 @@ image as a service. Since there is no database available, one can be initialized
|
||||
Create a directory like `gitea` and paste the following content into a file named `docker-compose.yml`.
|
||||
Note that the volume should be owned by the user/group with the UID/GID specified in the config file.
|
||||
If you don't give the volume correct permissions, the container may not start.
|
||||
For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:dev` tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev`)
|
||||
For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:nightly` tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-nightly` tag, where x is the minor version of Gitea. (e.g. `:1.16-nightly`)
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
@@ -289,7 +289,7 @@ docker-compose up -d
|
||||
|
||||
In addition to the environment variables above, any settings in `app.ini` can be set
|
||||
or overridden with an environment variable of the form: `GITEA__SECTION_NAME__KEY_NAME`.
|
||||
These settings are applied each time the docker container starts.
|
||||
These settings are applied each time the docker container starts, and won't be passed into Gitea's sub-processes.
|
||||
Full information [here](https://github.com/go-gitea/gitea/tree/master/contrib/environment-to-ini).
|
||||
|
||||
These environment variables can be passed to the docker container in `docker-compose.yml`.
|
||||
|
||||
@@ -164,3 +164,23 @@ Although we would like to provide more options, our limited manpower means that
|
||||
However, both Gitea and act runner are completely open source, so anyone can create a new/better implementation.
|
||||
We support your choice, no matter how you decide.
|
||||
In case you fork act runner to create your own version: Please contribute the changes back if you can and if you think your changes will help others as well.
|
||||
|
||||
## What workflow trigger events does Gitea support?
|
||||
|
||||
All events listed in this table are supported events and are compatible with GitHub.
|
||||
For events supported only by GitHub, see GitHub's [documentation](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows).
|
||||
|
||||
| trigger event | activity types |
|
||||
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------|
|
||||
| create | not applicable |
|
||||
| delete | not applicable |
|
||||
| fork | not applicable |
|
||||
| gollum | not applicable |
|
||||
| push | not applicable |
|
||||
| issues | `opened`, `edited`, `closed`, `reopened`, `assigned`, `unassigned`, `milestoned`, `demilestoned`, `labeled`, `unlabeled` |
|
||||
| issue_comment | `created`, `edited`, `deleted` |
|
||||
| pull_request | `opened`, `edited`, `closed`, `reopened`, `assigned`, `unassigned`, `synchronize`, `labeled`, `unlabeled` |
|
||||
| pull_request_review | `submitted`, `edited` |
|
||||
| pull_request_review_comment | `created`, `edited` |
|
||||
| release | `published`, `edited` |
|
||||
| registry_package | `published` |
|
||||
|
||||
@@ -164,3 +164,23 @@ defaults:
|
||||
然而,无论您如何决定,Gitea 和act runner都是完全开源的,所以任何人都可以创建一个新的/更好的实现。
|
||||
我们支持您的选择,无论您如何决定。
|
||||
如果您选择分支act runner来创建自己的版本,请在您认为您的更改对其他人也有帮助的情况下贡献这些更改。
|
||||
|
||||
## Gitea 支持哪些工作流触发事件?
|
||||
|
||||
表格中列出的所有事件都是支持的,并且与 GitHub 兼容。
|
||||
对于仅 GitHub 支持的事件,请参阅 GitHub 的[文档](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows)。
|
||||
|
||||
| 触发事件 | 活动类型 |
|
||||
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------|
|
||||
| create | 不适用 |
|
||||
| delete | 不适用 |
|
||||
| fork | 不适用 |
|
||||
| gollum | 不适用 |
|
||||
| push | 不适用 |
|
||||
| issues | `opened`, `edited`, `closed`, `reopened`, `assigned`, `unassigned`, `milestoned`, `demilestoned`, `labeled`, `unlabeled` |
|
||||
| issue_comment | `created`, `edited`, `deleted` |
|
||||
| pull_request | `opened`, `edited`, `closed`, `reopened`, `assigned`, `unassigned`, `synchronize`, `labeled`, `unlabeled` |
|
||||
| pull_request_review | `submitted`, `edited` |
|
||||
| pull_request_review_comment | `created`, `edited` |
|
||||
| release | `published`, `edited` |
|
||||
| registry_package | `published` |
|
||||
|
||||
@@ -44,7 +44,7 @@ The following package managers are currently supported:
|
||||
| [NuGet]({{< relref "doc/usage/packages/nuget.en-us.md" >}}) | .NET | `nuget` |
|
||||
| [Pub]({{< relref "doc/usage/packages/pub.en-us.md" >}}) | Dart | `dart`, `flutter` |
|
||||
| [PyPI]({{< relref "doc/usage/packages/pypi.en-us.md" >}}) | Python | `pip`, `twine` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.en-us.md" >}}) | - | `yum`, `dnf` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.en-us.md" >}}) | - | `yum`, `dnf`, `zypper` |
|
||||
| [RubyGems]({{< relref "doc/usage/packages/rubygems.en-us.md" >}}) | Ruby | `gem`, `Bundler` |
|
||||
| [Swift]({{< relref "doc/usage/packages/rubygems.en-us.md" >}}) | Swift | `swift` |
|
||||
| [Vagrant]({{< relref "doc/usage/packages/vagrant.en-us.md" >}}) | - | `vagrant` |
|
||||
|
||||
@@ -44,7 +44,7 @@ menu:
|
||||
| [NuGet]({{< relref "doc/usage/packages/nuget.zh-cn.md" >}}) | .NET | `nuget` |
|
||||
| [Pub]({{< relref "doc/usage/packages/pub.zh-cn.md" >}}) | Dart | `dart`, `flutter` |
|
||||
| [PyPI]({{< relref "doc/usage/packages/pypi.zh-cn.md" >}}) | Python | `pip`, `twine` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.zh-cn.md" >}}) | - | `yum`, `dnf` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.zh-cn.md" >}}) | - | `yum`, `dnf`, `zypper` |
|
||||
| [RubyGems]({{< relref "doc/usage/packages/rubygems.zh-cn.md" >}}) | Ruby | `gem`, `Bundler` |
|
||||
| [Swift]({{< relref "doc/usage/packages/rubygems.zh-cn.md" >}}) | Swift | `swift` |
|
||||
| [Vagrant]({{< relref "doc/usage/packages/vagrant.zh-cn.md" >}}) | - | `vagrant` |
|
||||
|
||||
@@ -22,7 +22,7 @@ Publish [RPM](https://rpm.org/) packages for your user or organization.
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the RPM registry, you need to use a package manager like `yum` or `dnf` to consume packages.
|
||||
To work with the RPM registry, you need to use a package manager like `yum`, `dnf` or `zypper` to consume packages.
|
||||
|
||||
The following examples use `dnf`.
|
||||
|
||||
@@ -79,7 +79,7 @@ The server responds with the following HTTP Status codes.
|
||||
|
||||
## Delete a package
|
||||
|
||||
To delete a Debian package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
|
||||
To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
|
||||
|
||||
```
|
||||
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
|
||||
|
||||
@@ -22,7 +22,7 @@ menu:
|
||||
|
||||
## 要求
|
||||
|
||||
要使用RPM注册表,您需要使用像 `yum` 或 `dnf` 这样的软件包管理器来消费软件包。
|
||||
要使用RPM注册表,您需要使用像 `yum`, `dnf` 或 `zypper` 这样的软件包管理器来消费软件包。
|
||||
|
||||
以下示例使用 `dnf`。
|
||||
|
||||
|
||||
12
go.mod
12
go.mod
@@ -76,7 +76,7 @@ require (
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/meilisearch/meilisearch-go v0.24.0
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.24
|
||||
github.com/microcosm-cc/bluemonday v1.0.25
|
||||
github.com/minio/minio-go/v7 v7.0.52
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
github.com/msteinert/pam v1.1.0
|
||||
@@ -107,12 +107,12 @@ require (
|
||||
github.com/yuin/goldmark v1.5.4
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
golang.org/x/crypto v0.9.0
|
||||
golang.org/x/crypto v0.11.0
|
||||
golang.org/x/image v0.7.0
|
||||
golang.org/x/net v0.10.0
|
||||
golang.org/x/net v0.12.0
|
||||
golang.org/x/oauth2 v0.8.0
|
||||
golang.org/x/sys v0.8.0
|
||||
golang.org/x/text v0.9.0
|
||||
golang.org/x/sys v0.10.0
|
||||
golang.org/x/text v0.11.0
|
||||
golang.org/x/tools v0.8.0
|
||||
google.golang.org/grpc v1.53.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
@@ -122,7 +122,7 @@ require (
|
||||
mvdan.cc/xurls/v2 v2.4.0
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||
xorm.io/builder v0.3.12
|
||||
xorm.io/xorm v1.3.3-0.20230219231735-056cecc97e9e
|
||||
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
25
go.sum
25
go.sum
@@ -877,8 +877,8 @@ github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
|
||||
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
|
||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw=
|
||||
github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
|
||||
github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
@@ -1322,8 +1322,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1421,8 +1421,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1534,8 +1534,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -1545,7 +1545,7 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1558,8 +1558,9 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1923,5 +1924,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:
|
||||
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM=
|
||||
xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/xorm v1.3.3-0.20230219231735-056cecc97e9e h1:d5PY6mwuQK5/7T6VKfFswaKMzLmGTHkJ/ZS7+cUIAjk=
|
||||
xorm.io/xorm v1.3.3-0.20230219231735-056cecc97e9e/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
|
||||
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75 h1:ReBAlO50dCIXCWF8Gbi0ZRa62AGAwCJNCPaUNUa7JSg=
|
||||
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
|
||||
|
||||
45
main.go
45
main.go
@@ -47,7 +47,9 @@ func init() {
|
||||
// ./gitea -h
|
||||
// ./gitea web help
|
||||
// ./gitea web -h (due to cli lib limitation, this won't call our cmdHelp, so no extra info)
|
||||
// ./gitea admin help auth
|
||||
// ./gitea admin
|
||||
// ./gitea admin help
|
||||
// ./gitea admin auth help
|
||||
// ./gitea -c /tmp/app.ini -h
|
||||
// ./gitea -c /tmp/app.ini help
|
||||
// ./gitea help -c /tmp/app.ini
|
||||
@@ -85,28 +87,36 @@ func main() {
|
||||
app.Description = `By default, Gitea will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".`
|
||||
app.Version = Version + formatBuiltWith()
|
||||
app.EnableBashCompletion = true
|
||||
app.Commands = []cli.Command{
|
||||
|
||||
// these sub-commands need to use config file
|
||||
subCmdWithIni := []cli.Command{
|
||||
cmd.CmdWeb,
|
||||
cmd.CmdServ,
|
||||
cmd.CmdHook,
|
||||
cmd.CmdDump,
|
||||
cmd.CmdCert,
|
||||
cmd.CmdAdmin,
|
||||
cmd.CmdGenerate,
|
||||
cmd.CmdMigrate,
|
||||
cmd.CmdKeys,
|
||||
cmd.CmdConvert,
|
||||
cmd.CmdDoctor,
|
||||
cmd.CmdManager,
|
||||
cmd.Cmdembedded,
|
||||
cmd.CmdEmbedded,
|
||||
cmd.CmdMigrateStorage,
|
||||
cmd.CmdDocs,
|
||||
cmd.CmdDumpRepository,
|
||||
cmd.CmdRestoreRepository,
|
||||
cmd.CmdActions,
|
||||
cmdHelp, // TODO: the "help" sub-command was used to show the more information for "work path" and "custom config", in the future, it should avoid doing so
|
||||
}
|
||||
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
||||
subCmdStandalone := []cli.Command{
|
||||
cmd.CmdCert,
|
||||
cmd.CmdGenerate,
|
||||
cmd.CmdDocs,
|
||||
}
|
||||
|
||||
// default configuration flags
|
||||
// shared configuration flags, they are for global and for each sub-command at the same time
|
||||
// eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
|
||||
// keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore.
|
||||
globalFlags := []cli.Flag{
|
||||
cli.HelpFlag,
|
||||
cli.StringFlag{
|
||||
@@ -126,13 +136,15 @@ func main() {
|
||||
|
||||
// Set the default to be equivalent to cmdWeb and add the default flags
|
||||
app.Flags = append(app.Flags, globalFlags...)
|
||||
app.Flags = append(app.Flags, cmd.CmdWeb.Flags...)
|
||||
app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) // TODO: the web flags polluted the global flags, they are not really global flags
|
||||
app.Action = prepareWorkPathAndCustomConf(cmd.CmdWeb.Action)
|
||||
app.HideHelp = true // use our own help action to show helps (with more information like default config)
|
||||
app.Commands = append(app.Commands, cmdHelp)
|
||||
for i := range app.Commands {
|
||||
prepareSubcommands(&app.Commands[i], globalFlags)
|
||||
app.Before = cmd.PrepareConsoleLoggerLevel(log.INFO)
|
||||
for i := range subCmdWithIni {
|
||||
prepareSubcommands(&subCmdWithIni[i], globalFlags)
|
||||
}
|
||||
app.Commands = append(app.Commands, subCmdWithIni...)
|
||||
app.Commands = append(app.Commands, subCmdStandalone...)
|
||||
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
@@ -156,11 +168,7 @@ func prepareSubcommands(command *cli.Command, defaultFlags []cli.Flag) {
|
||||
|
||||
// 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(a any) func(ctx *cli.Context) error {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
action := a.(func(*cli.Context) error)
|
||||
func prepareWorkPathAndCustomConf(action any) func(ctx *cli.Context) error {
|
||||
return func(ctx *cli.Context) error {
|
||||
var args setting.ArgWorkPathAndCustomConf
|
||||
curCtx := ctx
|
||||
@@ -177,10 +185,11 @@ func prepareWorkPathAndCustomConf(a any) func(ctx *cli.Context) error {
|
||||
curCtx = curCtx.Parent()
|
||||
}
|
||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||
if ctx.Bool("help") {
|
||||
if ctx.Bool("help") || action == nil {
|
||||
// the default behavior of "urfave/cli": "nil action" means "show help"
|
||||
return cmdHelp.Action.(func(ctx *cli.Context) error)(ctx)
|
||||
}
|
||||
return action(ctx)
|
||||
return action.(func(*cli.Context) error)(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -346,6 +346,9 @@ func UpdateTask(ctx context.Context, task *ActionTask, cols ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateTaskByState updates the task by the state.
|
||||
// It will always update the task if the state is not final, even there is no change.
|
||||
// So it will update ActionTask.Updated to avoid the task being judged as a zombie task.
|
||||
func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionTask, error) {
|
||||
stepStates := map[int64]*runnerv1.StepState{}
|
||||
for _, v := range state.Steps {
|
||||
@@ -386,6 +389,12 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT
|
||||
}, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Force update ActionTask.Updated to avoid the task being judged as a zombie task
|
||||
task.Updated = timeutil.TimeStampNow()
|
||||
if err := UpdateTask(ctx, task, "updated"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := task.LoadAttributes(ctx); err != nil {
|
||||
|
||||
@@ -44,7 +44,7 @@ func init() {
|
||||
// TranslatableMessage represents JSON struct that can be translated with a Locale
|
||||
type TranslatableMessage struct {
|
||||
Format string
|
||||
Args []interface{} `json:"omitempty"`
|
||||
Args []any `json:"omitempty"`
|
||||
}
|
||||
|
||||
// LoadRepo loads repository of the task
|
||||
|
||||
@@ -47,7 +47,7 @@ var sshOpLocker sync.Mutex
|
||||
// AuthorizedStringForKey creates the authorized keys string appropriate for the provided key
|
||||
func AuthorizedStringForKey(key *PublicKey) string {
|
||||
sb := &strings.Builder{}
|
||||
_ = setting.SSH.AuthorizedKeysCommandTemplateTemplate.Execute(sb, map[string]interface{}{
|
||||
_ = setting.SSH.AuthorizedKeysCommandTemplateTemplate.Execute(sb, map[string]any{
|
||||
"AppPath": util.ShellEscape(setting.AppPath),
|
||||
"AppWorkPath": util.ShellEscape(setting.AppWorkPath),
|
||||
"CustomConf": util.ShellEscape(setting.CustomConf),
|
||||
@@ -175,7 +175,7 @@ func RewriteAllPublicKeys() error {
|
||||
|
||||
// RegeneratePublicKeys regenerates the authorized_keys file
|
||||
func RegeneratePublicKeys(ctx context.Context, t io.StringWriter) error {
|
||||
if err := db.GetEngine(ctx).Where("type != ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
|
||||
if err := db.GetEngine(ctx).Where("type != ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean any) (err error) {
|
||||
_, err = t.WriteString((bean.(*PublicKey)).AuthorizedString())
|
||||
return err
|
||||
}); err != nil {
|
||||
|
||||
@@ -97,7 +97,7 @@ func RewriteAllPrincipalKeys(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func regeneratePrincipalKeys(ctx context.Context, t io.StringWriter) error {
|
||||
if err := db.GetEngine(ctx).Where("type = ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
|
||||
if err := db.GetEngine(ctx).Where("type = ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean any) (err error) {
|
||||
_, err = t.WriteString((bean.(*PublicKey)).AuthorizedString())
|
||||
return err
|
||||
}); err != nil {
|
||||
|
||||
@@ -52,7 +52,7 @@ func (ctx *Context) Engine() Engine {
|
||||
}
|
||||
|
||||
// Value shadows Value for context.Context but allows us to get ourselves and an Engined object
|
||||
func (ctx *Context) Value(key interface{}) interface{} {
|
||||
func (ctx *Context) Value(key any) any {
|
||||
if key == enginedContextKey {
|
||||
return ctx
|
||||
}
|
||||
@@ -163,28 +163,28 @@ func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error)
|
||||
}
|
||||
|
||||
// Insert inserts records into database
|
||||
func Insert(ctx context.Context, beans ...interface{}) error {
|
||||
func Insert(ctx context.Context, beans ...any) error {
|
||||
_, err := GetEngine(ctx).Insert(beans...)
|
||||
return err
|
||||
}
|
||||
|
||||
// Exec executes a sql with args
|
||||
func Exec(ctx context.Context, sqlAndArgs ...interface{}) (sql.Result, error) {
|
||||
func Exec(ctx context.Context, sqlAndArgs ...any) (sql.Result, error) {
|
||||
return GetEngine(ctx).Exec(sqlAndArgs...)
|
||||
}
|
||||
|
||||
// GetByBean filled empty fields of the bean according non-empty fields to query in database.
|
||||
func GetByBean(ctx context.Context, bean interface{}) (bool, error) {
|
||||
func GetByBean(ctx context.Context, bean any) (bool, error) {
|
||||
return GetEngine(ctx).Get(bean)
|
||||
}
|
||||
|
||||
// DeleteByBean deletes all records according non-empty fields of the bean as conditions.
|
||||
func DeleteByBean(ctx context.Context, bean interface{}) (int64, error) {
|
||||
func DeleteByBean(ctx context.Context, bean any) (int64, error) {
|
||||
return GetEngine(ctx).Delete(bean)
|
||||
}
|
||||
|
||||
// DeleteByID deletes the given bean with the given ID
|
||||
func DeleteByID(ctx context.Context, id int64, bean interface{}) (int64, error) {
|
||||
func DeleteByID(ctx context.Context, id int64, bean any) (int64, error) {
|
||||
return GetEngine(ctx).ID(id).NoAutoTime().Delete(bean)
|
||||
}
|
||||
|
||||
@@ -203,13 +203,13 @@ func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([
|
||||
|
||||
// DecrByIDs decreases the given column for entities of the "bean" type with one of the given ids by one
|
||||
// Timestamps of the entities won't be updated
|
||||
func DecrByIDs(ctx context.Context, ids []int64, decrCol string, bean interface{}) error {
|
||||
func DecrByIDs(ctx context.Context, ids []int64, decrCol string, bean any) error {
|
||||
_, err := GetEngine(ctx).Decr(decrCol).In("id", ids).NoAutoCondition().NoAutoTime().Update(bean)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteBeans deletes all given beans, beans must contain delete conditions.
|
||||
func DeleteBeans(ctx context.Context, beans ...interface{}) (err error) {
|
||||
func DeleteBeans(ctx context.Context, beans ...any) (err error) {
|
||||
e := GetEngine(ctx)
|
||||
for i := range beans {
|
||||
if _, err = e.Delete(beans[i]); err != nil {
|
||||
@@ -220,7 +220,7 @@ func DeleteBeans(ctx context.Context, beans ...interface{}) (err error) {
|
||||
}
|
||||
|
||||
// TruncateBeans deletes all given beans, beans may contain delete conditions.
|
||||
func TruncateBeans(ctx context.Context, beans ...interface{}) (err error) {
|
||||
func TruncateBeans(ctx context.Context, beans ...any) (err error) {
|
||||
e := GetEngine(ctx)
|
||||
for i := range beans {
|
||||
if _, err = e.Truncate(beans[i]); err != nil {
|
||||
@@ -231,12 +231,12 @@ func TruncateBeans(ctx context.Context, beans ...interface{}) (err error) {
|
||||
}
|
||||
|
||||
// CountByBean counts the number of database records according non-empty fields of the bean as conditions.
|
||||
func CountByBean(ctx context.Context, bean interface{}) (int64, error) {
|
||||
func CountByBean(ctx context.Context, bean any) (int64, error) {
|
||||
return GetEngine(ctx).Count(bean)
|
||||
}
|
||||
|
||||
// TableName returns the table name according a bean object
|
||||
func TableName(bean interface{}) string {
|
||||
func TableName(bean any) string {
|
||||
return x.TableName(bean)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
var (
|
||||
x *xorm.Engine
|
||||
tables []interface{}
|
||||
tables []any
|
||||
initFuncs []func() error
|
||||
|
||||
// HasEngine specifies if we have a xorm.Engine
|
||||
@@ -34,41 +34,41 @@ var (
|
||||
|
||||
// Engine represents a xorm engine or session.
|
||||
type Engine interface {
|
||||
Table(tableNameOrBean interface{}) *xorm.Session
|
||||
Count(...interface{}) (int64, error)
|
||||
Decr(column string, arg ...interface{}) *xorm.Session
|
||||
Delete(...interface{}) (int64, error)
|
||||
Truncate(...interface{}) (int64, error)
|
||||
Exec(...interface{}) (sql.Result, error)
|
||||
Find(interface{}, ...interface{}) error
|
||||
Get(beans ...interface{}) (bool, error)
|
||||
ID(interface{}) *xorm.Session
|
||||
In(string, ...interface{}) *xorm.Session
|
||||
Incr(column string, arg ...interface{}) *xorm.Session
|
||||
Insert(...interface{}) (int64, error)
|
||||
Iterate(interface{}, xorm.IterFunc) error
|
||||
Join(joinOperator string, tablename, condition interface{}, args ...interface{}) *xorm.Session
|
||||
SQL(interface{}, ...interface{}) *xorm.Session
|
||||
Where(interface{}, ...interface{}) *xorm.Session
|
||||
Table(tableNameOrBean any) *xorm.Session
|
||||
Count(...any) (int64, error)
|
||||
Decr(column string, arg ...any) *xorm.Session
|
||||
Delete(...any) (int64, error)
|
||||
Truncate(...any) (int64, error)
|
||||
Exec(...any) (sql.Result, error)
|
||||
Find(any, ...any) error
|
||||
Get(beans ...any) (bool, error)
|
||||
ID(any) *xorm.Session
|
||||
In(string, ...any) *xorm.Session
|
||||
Incr(column string, arg ...any) *xorm.Session
|
||||
Insert(...any) (int64, error)
|
||||
Iterate(any, xorm.IterFunc) error
|
||||
Join(joinOperator string, tablename, condition any, args ...any) *xorm.Session
|
||||
SQL(any, ...any) *xorm.Session
|
||||
Where(any, ...any) *xorm.Session
|
||||
Asc(colNames ...string) *xorm.Session
|
||||
Desc(colNames ...string) *xorm.Session
|
||||
Limit(limit int, start ...int) *xorm.Session
|
||||
NoAutoTime() *xorm.Session
|
||||
SumInt(bean interface{}, columnName string) (res int64, err error)
|
||||
Sync2(...interface{}) error
|
||||
SumInt(bean any, columnName string) (res int64, err error)
|
||||
Sync2(...any) error
|
||||
Select(string) *xorm.Session
|
||||
NotIn(string, ...interface{}) *xorm.Session
|
||||
OrderBy(interface{}, ...interface{}) *xorm.Session
|
||||
Exist(...interface{}) (bool, error)
|
||||
NotIn(string, ...any) *xorm.Session
|
||||
OrderBy(any, ...any) *xorm.Session
|
||||
Exist(...any) (bool, error)
|
||||
Distinct(...string) *xorm.Session
|
||||
Query(...interface{}) ([]map[string][]byte, error)
|
||||
Query(...any) ([]map[string][]byte, error)
|
||||
Cols(...string) *xorm.Session
|
||||
Context(ctx context.Context) *xorm.Session
|
||||
Ping() error
|
||||
}
|
||||
|
||||
// TableInfo returns table's information via an object
|
||||
func TableInfo(v interface{}) (*schemas.Table, error) {
|
||||
func TableInfo(v any) (*schemas.Table, error) {
|
||||
return x.TableInfo(v)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func DumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) erro
|
||||
}
|
||||
|
||||
// RegisterModel registers model, if initfunc provided, it will be invoked after data model sync
|
||||
func RegisterModel(bean interface{}, initFunc ...func() error) {
|
||||
func RegisterModel(bean any, initFunc ...func() error) {
|
||||
tables = append(tables, bean)
|
||||
if len(initFuncs) > 0 && initFunc[0] != nil {
|
||||
initFuncs = append(initFuncs, initFunc[0])
|
||||
@@ -123,7 +123,10 @@ func newXORMEngine() (*xorm.Engine, error) {
|
||||
|
||||
// SyncAllTables sync the schemas of all tables, is required by unit test code
|
||||
func SyncAllTables() error {
|
||||
return x.StoreEngine("InnoDB").Sync2(tables...)
|
||||
_, err := x.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{
|
||||
WarnIfDatabaseColumnMissed: true,
|
||||
}, tables...)
|
||||
return err
|
||||
}
|
||||
|
||||
// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext
|
||||
@@ -206,14 +209,14 @@ func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine)
|
||||
}
|
||||
|
||||
// NamesToBean return a list of beans or an error
|
||||
func NamesToBean(names ...string) ([]interface{}, error) {
|
||||
beans := []interface{}{}
|
||||
func NamesToBean(names ...string) ([]any, error) {
|
||||
beans := []any{}
|
||||
if len(names) == 0 {
|
||||
beans = append(beans, tables...)
|
||||
return beans, nil
|
||||
}
|
||||
// Need to map provided names to beans...
|
||||
beanMap := make(map[string]interface{})
|
||||
beanMap := make(map[string]any)
|
||||
for _, bean := range tables {
|
||||
|
||||
beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean
|
||||
@@ -221,7 +224,7 @@ func NamesToBean(names ...string) ([]interface{}, error) {
|
||||
beanMap[strings.ToLower(x.TableName(bean, true))] = bean
|
||||
}
|
||||
|
||||
gotBean := make(map[interface{}]bool)
|
||||
gotBean := make(map[any]bool)
|
||||
for _, name := range names {
|
||||
bean, ok := beanMap[strings.ToLower(strings.TrimSpace(name))]
|
||||
if !ok {
|
||||
@@ -263,7 +266,7 @@ func DumpDatabase(filePath, dbType string) error {
|
||||
}
|
||||
|
||||
// MaxBatchInsertSize returns the table's max batch insert size
|
||||
func MaxBatchInsertSize(bean interface{}) int {
|
||||
func MaxBatchInsertSize(bean any) int {
|
||||
t, err := x.TableInfo(bean)
|
||||
if err != nil {
|
||||
return 50
|
||||
@@ -283,7 +286,7 @@ func DeleteAllRecords(tableName string) error {
|
||||
}
|
||||
|
||||
// GetMaxID will return max id of the table
|
||||
func GetMaxID(beanOrTableName interface{}) (maxID int64, err error) {
|
||||
func GetMaxID(beanOrTableName any) (maxID int64, err error) {
|
||||
_, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID)
|
||||
return maxID, err
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func (err ErrCancelled) Error() string {
|
||||
}
|
||||
|
||||
// ErrCancelledf returns an ErrCancelled for the provided format and args
|
||||
func ErrCancelledf(format string, args ...interface{}) error {
|
||||
func ErrCancelledf(format string, args ...any) error {
|
||||
return ErrCancelled{
|
||||
fmt.Sprintf(format, args...),
|
||||
}
|
||||
|
||||
@@ -28,47 +28,47 @@ func NewXORMLogger(showSQL bool) xormlog.Logger {
|
||||
const stackLevel = 8
|
||||
|
||||
// Log a message with defined skip and at logging level
|
||||
func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...interface{}) {
|
||||
func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...any) {
|
||||
l.logger.Log(skip+1, level, format, v...)
|
||||
}
|
||||
|
||||
// Debug show debug log
|
||||
func (l *XORMLogBridge) Debug(v ...interface{}) {
|
||||
func (l *XORMLogBridge) Debug(v ...any) {
|
||||
l.Log(stackLevel, log.DEBUG, "%s", fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Debugf show debug log
|
||||
func (l *XORMLogBridge) Debugf(format string, v ...interface{}) {
|
||||
func (l *XORMLogBridge) Debugf(format string, v ...any) {
|
||||
l.Log(stackLevel, log.DEBUG, format, v...)
|
||||
}
|
||||
|
||||
// Error show error log
|
||||
func (l *XORMLogBridge) Error(v ...interface{}) {
|
||||
func (l *XORMLogBridge) Error(v ...any) {
|
||||
l.Log(stackLevel, log.ERROR, "%s", fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Errorf show error log
|
||||
func (l *XORMLogBridge) Errorf(format string, v ...interface{}) {
|
||||
func (l *XORMLogBridge) Errorf(format string, v ...any) {
|
||||
l.Log(stackLevel, log.ERROR, format, v...)
|
||||
}
|
||||
|
||||
// Info show information level log
|
||||
func (l *XORMLogBridge) Info(v ...interface{}) {
|
||||
func (l *XORMLogBridge) Info(v ...any) {
|
||||
l.Log(stackLevel, log.INFO, "%s", fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Infof show information level log
|
||||
func (l *XORMLogBridge) Infof(format string, v ...interface{}) {
|
||||
func (l *XORMLogBridge) Infof(format string, v ...any) {
|
||||
l.Log(stackLevel, log.INFO, format, v...)
|
||||
}
|
||||
|
||||
// Warn show warning log
|
||||
func (l *XORMLogBridge) Warn(v ...interface{}) {
|
||||
func (l *XORMLogBridge) Warn(v ...any) {
|
||||
l.Log(stackLevel, log.WARN, "%s", fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Warnf show warnning log
|
||||
func (l *XORMLogBridge) Warnf(format string, v ...interface{}) {
|
||||
func (l *XORMLogBridge) Warnf(format string, v ...any) {
|
||||
l.Log(stackLevel, log.WARN, format, v...)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -21,6 +22,7 @@ var defaultFileBlockSize int64 = 32 * 1024
|
||||
type File interface {
|
||||
io.ReadWriteCloser
|
||||
io.Seeker
|
||||
fs.File
|
||||
}
|
||||
|
||||
type file struct {
|
||||
@@ -193,10 +195,26 @@ func (f *file) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *file) Stat() (os.FileInfo, error) {
|
||||
if f.metaID == 0 {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
fileMeta, err := findFileMetaByID(f.ctx, f.metaID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fileMeta, nil
|
||||
}
|
||||
|
||||
func timeToFileTimestamp(t time.Time) int64 {
|
||||
return t.UnixMicro()
|
||||
}
|
||||
|
||||
func fileTimestampToTime(timestamp int64) time.Time {
|
||||
return time.UnixMicro(timestamp)
|
||||
}
|
||||
|
||||
func (f *file) loadMetaByPath() (*dbfsMeta, error) {
|
||||
var fileMeta dbfsMeta
|
||||
if ok, err := db.GetEngine(f.ctx).Where("full_path = ?", f.fullPath).Get(&fileMeta); err != nil {
|
||||
|
||||
@@ -5,7 +5,10 @@ package dbfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
)
|
||||
@@ -100,3 +103,29 @@ func Remove(ctx context.Context, name string) error {
|
||||
defer f.Close()
|
||||
return f.delete()
|
||||
}
|
||||
|
||||
var _ fs.FileInfo = (*dbfsMeta)(nil)
|
||||
|
||||
func (m *dbfsMeta) Name() string {
|
||||
return path.Base(m.FullPath)
|
||||
}
|
||||
|
||||
func (m *dbfsMeta) Size() int64 {
|
||||
return m.FileSize
|
||||
}
|
||||
|
||||
func (m *dbfsMeta) Mode() fs.FileMode {
|
||||
return os.ModePerm
|
||||
}
|
||||
|
||||
func (m *dbfsMeta) ModTime() time.Time {
|
||||
return fileTimestampToTime(m.ModifyTimestamp)
|
||||
}
|
||||
|
||||
func (m *dbfsMeta) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *dbfsMeta) Sys() any {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -111,6 +111,19 @@ func TestDbfsBasic(t *testing.T) {
|
||||
|
||||
_, err = OpenFile(db.DefaultContext, "test2.txt", os.O_RDONLY)
|
||||
assert.Error(t, err)
|
||||
|
||||
// test stat
|
||||
f, err = OpenFile(db.DefaultContext, "test/test.txt", os.O_RDWR|os.O_CREATE)
|
||||
assert.NoError(t, err)
|
||||
stat, err := f.Stat()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "test.txt", stat.Name())
|
||||
assert.EqualValues(t, 0, stat.Size())
|
||||
_, err = f.Write([]byte("0123456789"))
|
||||
assert.NoError(t, err)
|
||||
stat, err = f.Stat()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 10, stat.Size())
|
||||
}
|
||||
|
||||
func TestDbfsReadWrite(t *testing.T) {
|
||||
|
||||
49
models/fixtures/mirror.yml
Normal file
49
models/fixtures/mirror.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
-
|
||||
id: 1
|
||||
repo_id: 5
|
||||
interval: 3600
|
||||
enable_prune: false
|
||||
updated_unix: 0
|
||||
next_update_unix: 0
|
||||
lfs_enabled: false
|
||||
lfs_endpoint: ""
|
||||
|
||||
-
|
||||
id: 2
|
||||
repo_id: 25
|
||||
interval: 3600
|
||||
enable_prune: false
|
||||
updated_unix: 0
|
||||
next_update_unix: 0
|
||||
lfs_enabled: false
|
||||
lfs_endpoint: ""
|
||||
|
||||
-
|
||||
id: 3
|
||||
repo_id: 26
|
||||
interval: 3600
|
||||
enable_prune: false
|
||||
updated_unix: 0
|
||||
next_update_unix: 0
|
||||
lfs_enabled: false
|
||||
lfs_endpoint: ""
|
||||
|
||||
-
|
||||
id: 4
|
||||
repo_id: 27
|
||||
interval: 3600
|
||||
enable_prune: false
|
||||
updated_unix: 0
|
||||
next_update_unix: 0
|
||||
lfs_enabled: false
|
||||
lfs_endpoint: ""
|
||||
|
||||
-
|
||||
id: 5
|
||||
repo_id: 28
|
||||
interval: 3600
|
||||
enable_prune: false
|
||||
updated_unix: 0
|
||||
next_update_unix: 0
|
||||
lfs_enabled: false
|
||||
lfs_endpoint: ""
|
||||
@@ -81,3 +81,21 @@
|
||||
uid: 5
|
||||
org_id: 23
|
||||
is_public: false
|
||||
|
||||
-
|
||||
id: 15
|
||||
uid: 1
|
||||
org_id: 35
|
||||
is_public: true
|
||||
|
||||
-
|
||||
id: 16
|
||||
uid: 1
|
||||
org_id: 36
|
||||
is_public: true
|
||||
|
||||
-
|
||||
id: 17
|
||||
uid: 5
|
||||
org_id: 36
|
||||
is_public: true
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
creator_id: 2
|
||||
board_type: 1
|
||||
type: 2
|
||||
created_unix: 1688973030
|
||||
updated_unix: 1688973030
|
||||
|
||||
-
|
||||
id: 2
|
||||
@@ -17,6 +19,8 @@
|
||||
creator_id: 3
|
||||
board_type: 1
|
||||
type: 2
|
||||
created_unix: 1688973010
|
||||
updated_unix: 1688973010
|
||||
|
||||
-
|
||||
id: 3
|
||||
@@ -27,6 +31,8 @@
|
||||
creator_id: 5
|
||||
board_type: 1
|
||||
type: 2
|
||||
created_unix: 1688973020
|
||||
updated_unix: 1688973020
|
||||
|
||||
-
|
||||
id: 4
|
||||
@@ -37,3 +43,5 @@
|
||||
creator_id: 2
|
||||
board_type: 1
|
||||
type: 2
|
||||
created_unix: 1688973000
|
||||
updated_unix: 1688973000
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
num_projects: 0
|
||||
num_closed_projects: 0
|
||||
is_private: true
|
||||
is_empty: true
|
||||
is_empty: false
|
||||
is_archived: false
|
||||
is_mirror: true
|
||||
status: 0
|
||||
|
||||
@@ -184,3 +184,36 @@
|
||||
num_members: 1
|
||||
includes_all_repositories: false
|
||||
can_create_org_repo: true
|
||||
|
||||
-
|
||||
id: 18
|
||||
org_id: 35
|
||||
lower_name: owners
|
||||
name: Owners
|
||||
authorize: 4 # owner
|
||||
num_repos: 0
|
||||
num_members: 1
|
||||
includes_all_repositories: false
|
||||
can_create_org_repo: true
|
||||
|
||||
-
|
||||
id: 19
|
||||
org_id: 36
|
||||
lower_name: owners
|
||||
name: Owners
|
||||
authorize: 4 # owner
|
||||
num_repos: 0
|
||||
num_members: 1
|
||||
includes_all_repositories: false
|
||||
can_create_org_repo: true
|
||||
|
||||
-
|
||||
id: 20
|
||||
org_id: 36
|
||||
lower_name: team20writepackage
|
||||
name: team20writepackage
|
||||
authorize: 1
|
||||
num_repos: 0
|
||||
num_members: 1
|
||||
includes_all_repositories: false
|
||||
can_create_org_repo: true
|
||||
|
||||
@@ -273,4 +273,10 @@
|
||||
id: 46
|
||||
team_id: 17
|
||||
type: 9 # package
|
||||
access_mode: 0
|
||||
access_mode: 2
|
||||
|
||||
-
|
||||
id: 47
|
||||
team_id: 20
|
||||
type: 9 # package
|
||||
access_mode: 2
|
||||
|
||||
@@ -105,3 +105,21 @@
|
||||
org_id: 23
|
||||
team_id: 17
|
||||
uid: 5
|
||||
|
||||
-
|
||||
id: 19
|
||||
org_id: 35
|
||||
team_id: 18
|
||||
uid: 1
|
||||
|
||||
-
|
||||
id: 20
|
||||
org_id: 36
|
||||
team_id: 19
|
||||
uid: 1
|
||||
|
||||
-
|
||||
id: 21
|
||||
org_id: 36
|
||||
team_id: 20
|
||||
uid: 5
|
||||
|
||||
@@ -1258,3 +1258,77 @@
|
||||
repo_admin_change_team_access: false
|
||||
theme: ""
|
||||
keep_activity_private: false
|
||||
|
||||
-
|
||||
id: 35
|
||||
lower_name: private_org35
|
||||
name: private_org35
|
||||
full_name: Private Org 35
|
||||
email: private_org35@example.com
|
||||
keep_email_private: false
|
||||
email_notifications_preference: enabled
|
||||
passwd: ZogKvWdyEx:password
|
||||
passwd_hash_algo: dummy
|
||||
must_change_password: false
|
||||
login_source: 0
|
||||
login_name: private_org35
|
||||
type: 1
|
||||
salt: ZogKvWdyEx
|
||||
max_repo_creation: -1
|
||||
is_active: true
|
||||
is_admin: false
|
||||
is_restricted: false
|
||||
allow_git_hook: false
|
||||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar35
|
||||
avatar_email: private_org35@example.com
|
||||
use_custom_avatar: false
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
num_repos: 0
|
||||
num_teams: 1
|
||||
num_members: 1
|
||||
visibility: 2
|
||||
repo_admin_change_team_access: false
|
||||
theme: ""
|
||||
keep_activity_private: false
|
||||
|
||||
-
|
||||
id: 36
|
||||
lower_name: limited_org36
|
||||
name: limited_org36
|
||||
full_name: Limited Org 36
|
||||
email: limited_org36@example.com
|
||||
keep_email_private: false
|
||||
email_notifications_preference: enabled
|
||||
passwd: ZogKvWdyEx:password
|
||||
passwd_hash_algo: dummy
|
||||
must_change_password: false
|
||||
login_source: 0
|
||||
login_name: limited_org36
|
||||
type: 1
|
||||
salt: ZogKvWdyEx
|
||||
max_repo_creation: -1
|
||||
is_active: true
|
||||
is_admin: false
|
||||
is_restricted: false
|
||||
allow_git_hook: false
|
||||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar22
|
||||
avatar_email: limited_org36@example.com
|
||||
use_custom_avatar: false
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
num_repos: 0
|
||||
num_teams: 2
|
||||
num_members: 2
|
||||
visibility: 1
|
||||
repo_admin_change_team_access: false
|
||||
theme: ""
|
||||
keep_activity_private: false
|
||||
|
||||
@@ -172,7 +172,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
|
||||
// 3. Update all not merged pull request base branch name
|
||||
_, err = sess.Table("pull_request").Where("base_repo_id=? AND base_branch=? AND has_merged=?",
|
||||
repo.ID, from, false).
|
||||
Update(map[string]interface{}{"base_branch": to})
|
||||
Update(map[string]any{"base_branch": to})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ func LFSAutoAssociate(ctx context.Context, metas []*LFSMetaObject, user *user_mo
|
||||
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
oids := make([]interface{}, len(metas))
|
||||
oids := make([]any, len(metas))
|
||||
oidMap := make(map[string]*LFSMetaObject, len(metas))
|
||||
for i, meta := range metas {
|
||||
oids[i] = meta.Oid
|
||||
|
||||
@@ -1131,7 +1131,7 @@ func DeleteComment(ctx context.Context, comment *Comment) error {
|
||||
}
|
||||
if _, err := e.Table("action").
|
||||
Where("comment_id = ?", comment.ID).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"is_deleted": true,
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -1156,7 +1156,7 @@ func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID
|
||||
}),
|
||||
)).
|
||||
And("comment.original_author_id = ?", originalAuthorID).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"poster_id": posterID,
|
||||
"original_author": "",
|
||||
"original_author_id": 0,
|
||||
|
||||
@@ -714,7 +714,7 @@ func (issue *Issue) Pin(ctx context.Context, user *user_model.User) error {
|
||||
|
||||
_, err = db.GetEngine(ctx).Table("issue").
|
||||
Where("id = ?", issue.ID).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"pin_order": maxPin + 1,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -750,7 +750,7 @@ func (issue *Issue) Unpin(ctx context.Context, user *user_model.User) error {
|
||||
|
||||
_, err = db.GetEngine(ctx).Table("issue").
|
||||
Where("id = ?", issue.ID).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"pin_order": 0,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -822,7 +822,7 @@ func (issue *Issue) MovePin(ctx context.Context, newPosition int) error {
|
||||
|
||||
_, err = db.GetEngine(dbctx).Table("issue").
|
||||
Where("id = ?", issue.ID).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"pin_order": newPosition,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -229,39 +229,41 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (issues IssueList) getProjectIDs() []int64 {
|
||||
ids := make(container.Set[int64], len(issues))
|
||||
for _, issue := range issues {
|
||||
ids.Add(issue.ProjectID())
|
||||
}
|
||||
return ids.Values()
|
||||
}
|
||||
func (issues IssueList) LoadProjects(ctx context.Context) error {
|
||||
issueIDs := issues.getIssueIDs()
|
||||
projectMaps := make(map[int64]*project_model.Project, len(issues))
|
||||
left := len(issueIDs)
|
||||
|
||||
func (issues IssueList) loadProjects(ctx context.Context) error {
|
||||
projectIDs := issues.getProjectIDs()
|
||||
if len(projectIDs) == 0 {
|
||||
return nil
|
||||
type projectWithIssueID struct {
|
||||
*project_model.Project `xorm:"extends"`
|
||||
IssueID int64
|
||||
}
|
||||
|
||||
projectMaps := make(map[int64]*project_model.Project, len(projectIDs))
|
||||
left := len(projectIDs)
|
||||
for left > 0 {
|
||||
limit := db.DefaultMaxInSize
|
||||
if left < limit {
|
||||
limit = left
|
||||
}
|
||||
|
||||
projects := make([]*projectWithIssueID, 0, limit)
|
||||
err := db.GetEngine(ctx).
|
||||
In("id", projectIDs[:limit]).
|
||||
Find(&projectMaps)
|
||||
Table("project").
|
||||
Select("project.*, project_issue.issue_id").
|
||||
Join("INNER", "project_issue", "project.id = project_issue.project_id").
|
||||
In("project_issue.issue_id", issueIDs[:limit]).
|
||||
Find(&projects)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, project := range projects {
|
||||
projectMaps[project.IssueID] = project.Project
|
||||
}
|
||||
left -= limit
|
||||
projectIDs = projectIDs[limit:]
|
||||
issueIDs = issueIDs[limit:]
|
||||
}
|
||||
|
||||
for _, issue := range issues {
|
||||
issue.Project = projectMaps[issue.ProjectID()]
|
||||
issue.Project = projectMaps[issue.ID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -541,7 +543,7 @@ func (issues IssueList) loadAttributes(ctx context.Context) error {
|
||||
return fmt.Errorf("issue.loadAttributes: loadMilestones: %w", err)
|
||||
}
|
||||
|
||||
if err := issues.loadProjects(ctx); err != nil {
|
||||
if err := issues.LoadProjects(ctx); err != nil {
|
||||
return fmt.Errorf("issue.loadAttributes: loadProjects: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,10 @@ func TestIssueList_LoadAttributes(t *testing.T) {
|
||||
}
|
||||
if issue.ID == int64(1) {
|
||||
assert.Equal(t, int64(400), issue.TotalTrackedTime)
|
||||
} else if issue.ID == int64(2) {
|
||||
assert.Equal(t, int64(3682), issue.TotalTrackedTime)
|
||||
assert.NotNil(t, issue.Project)
|
||||
assert.Equal(t, int64(1), issue.Project.ID)
|
||||
} else {
|
||||
assert.Nil(t, issue.Project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,22 +16,18 @@ import (
|
||||
func (issue *Issue) LoadProject(ctx context.Context) (err error) {
|
||||
if issue.Project == nil {
|
||||
var p project_model.Project
|
||||
if _, err = db.GetEngine(ctx).Table("project").
|
||||
has, err := db.GetEngine(ctx).Table("project").
|
||||
Join("INNER", "project_issue", "project.id=project_issue.project_id").
|
||||
Where("project_issue.issue_id = ?", issue.ID).
|
||||
Get(&p); err != nil {
|
||||
Where("project_issue.issue_id = ?", issue.ID).Get(&p)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
issue.Project = &p
|
||||
}
|
||||
issue.Project = &p
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ProjectID return project id if issue was assigned to one
|
||||
func (issue *Issue) ProjectID() int64 {
|
||||
return issue.projectID(db.DefaultContext)
|
||||
}
|
||||
|
||||
func (issue *Issue) projectID(ctx context.Context) int64 {
|
||||
var ip project_model.ProjectIssue
|
||||
has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip)
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -539,3 +540,47 @@ func TestCountIssues(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 18, count)
|
||||
}
|
||||
|
||||
func TestIssueLoadAttributes(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
setting.Service.EnableTimetracking = true
|
||||
|
||||
issueList := issues_model.IssueList{
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}),
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}),
|
||||
}
|
||||
|
||||
for _, issue := range issueList {
|
||||
assert.NoError(t, issue.LoadAttributes(db.DefaultContext))
|
||||
assert.EqualValues(t, issue.RepoID, issue.Repo.ID)
|
||||
for _, label := range issue.Labels {
|
||||
assert.EqualValues(t, issue.RepoID, label.RepoID)
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
||||
}
|
||||
if issue.PosterID > 0 {
|
||||
assert.EqualValues(t, issue.PosterID, issue.Poster.ID)
|
||||
}
|
||||
if issue.AssigneeID > 0 {
|
||||
assert.EqualValues(t, issue.AssigneeID, issue.Assignee.ID)
|
||||
}
|
||||
if issue.MilestoneID > 0 {
|
||||
assert.EqualValues(t, issue.MilestoneID, issue.Milestone.ID)
|
||||
}
|
||||
if issue.IsPull {
|
||||
assert.EqualValues(t, issue.ID, issue.PullRequest.IssueID)
|
||||
}
|
||||
for _, attachment := range issue.Attachments {
|
||||
assert.EqualValues(t, issue.ID, attachment.IssueID)
|
||||
}
|
||||
for _, comment := range issue.Comments {
|
||||
assert.EqualValues(t, issue.ID, comment.IssueID)
|
||||
}
|
||||
if issue.ID == int64(1) {
|
||||
assert.Equal(t, int64(400), issue.TotalTrackedTime)
|
||||
assert.NotNil(t, issue.Project)
|
||||
assert.Equal(t, int64(1), issue.Project.ID)
|
||||
} else {
|
||||
assert.Nil(t, issue.Project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *us
|
||||
}
|
||||
|
||||
// DeleteInIssue delete records in beans with external key issue_id = ?
|
||||
func DeleteInIssue(ctx context.Context, issueID int64, beans ...interface{}) error {
|
||||
func DeleteInIssue(ctx context.Context, issueID int64, beans ...any) error {
|
||||
e := db.GetEngine(ctx)
|
||||
for _, bean := range beans {
|
||||
if _, err := e.In("issue_id", issueID).Delete(bean); err != nil {
|
||||
@@ -673,7 +673,7 @@ func UpdateIssuesMigrationsByType(gitServiceType api.GitServiceType, originalAut
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("issue").
|
||||
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
||||
And("original_author_id = ?", originalAuthorID).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"poster_id": posterID,
|
||||
"original_author": "",
|
||||
"original_author_id": 0,
|
||||
@@ -686,7 +686,7 @@ func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, original
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("reaction").
|
||||
Where("original_author_id = ?", originalAuthorID).
|
||||
And(migratedIssueCond(gitServiceType)).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"user_id": userID,
|
||||
"original_author": "",
|
||||
"original_author_id": 0,
|
||||
|
||||
@@ -1090,7 +1090,7 @@ func UpdateReviewsMigrationsByType(tp structs.GitServiceType, originalAuthorID s
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("review").
|
||||
Where("original_author_id = ?", originalAuthorID).
|
||||
And(migratedIssueCond(tp)).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"reviewer_id": posterID,
|
||||
"original_author": "",
|
||||
"original_author_id": 0,
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
|
||||
// RecreateTables will recreate the tables for the provided beans using the newly provided bean definition and move all data to that new table
|
||||
// WARNING: YOU MUST PROVIDE THE FULL BEAN DEFINITION
|
||||
func RecreateTables(beans ...interface{}) func(*xorm.Engine) error {
|
||||
func RecreateTables(beans ...any) func(*xorm.Engine) error {
|
||||
return func(x *xorm.Engine) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
@@ -48,7 +48,7 @@ func RecreateTables(beans ...interface{}) func(*xorm.Engine) error {
|
||||
// RecreateTable will recreate the table using the newly provided bean definition and move all data to that new table
|
||||
// WARNING: YOU MUST PROVIDE THE FULL BEAN DEFINITION
|
||||
// WARNING: YOU MUST COMMIT THE SESSION AT THE END
|
||||
func RecreateTable(sess *xorm.Session, bean interface{}) error {
|
||||
func RecreateTable(sess *xorm.Session, bean any) error {
|
||||
// TODO: This will not work if there are foreign keys
|
||||
|
||||
tableName := sess.Engine().TableName(bean)
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
// Provide models to be sync'd with the database - in particular any models you expect fixtures to be loaded from.
|
||||
//
|
||||
// fixtures in `models/migrations/fixtures/<TestName>` will be loaded automatically
|
||||
func PrepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.Engine, func()) {
|
||||
func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, func()) {
|
||||
t.Helper()
|
||||
ourSkip := 2
|
||||
ourSkip += skip
|
||||
|
||||
@@ -59,11 +59,11 @@ func UpdateMigrationServiceTypes(x *xorm.Engine) error {
|
||||
}
|
||||
|
||||
type ExternalLoginUser struct {
|
||||
ExternalID string `xorm:"pk NOT NULL"`
|
||||
UserID int64 `xorm:"INDEX NOT NULL"`
|
||||
LoginSourceID int64 `xorm:"pk NOT NULL"`
|
||||
RawData map[string]interface{} `xorm:"TEXT JSON"`
|
||||
Provider string `xorm:"index VARCHAR(25)"`
|
||||
ExternalID string `xorm:"pk NOT NULL"`
|
||||
UserID int64 `xorm:"INDEX NOT NULL"`
|
||||
LoginSourceID int64 `xorm:"pk NOT NULL"`
|
||||
RawData map[string]any `xorm:"TEXT JSON"`
|
||||
Provider string `xorm:"index VARCHAR(25)"`
|
||||
Email string
|
||||
Name string
|
||||
FirstName string
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func UnwrapLDAPSourceCfg(x *xorm.Engine) error {
|
||||
jsonUnmarshalHandleDoubleEncode := func(bs []byte, v interface{}) error {
|
||||
jsonUnmarshalHandleDoubleEncode := func(bs []byte, v any) error {
|
||||
err := json.Unmarshal(bs, v)
|
||||
if err != nil {
|
||||
ok := true
|
||||
@@ -54,7 +54,7 @@ func UnwrapLDAPSourceCfg(x *xorm.Engine) error {
|
||||
const dldapType = 5
|
||||
|
||||
type WrappedSource struct {
|
||||
Source map[string]interface{}
|
||||
Source map[string]any
|
||||
}
|
||||
|
||||
// change lower_email as unique
|
||||
@@ -77,7 +77,7 @@ func UnwrapLDAPSourceCfg(x *xorm.Engine) error {
|
||||
|
||||
for _, source := range sources {
|
||||
wrapped := &WrappedSource{
|
||||
Source: map[string]interface{}{},
|
||||
Source: map[string]any{},
|
||||
}
|
||||
err := jsonUnmarshalHandleDoubleEncode([]byte(source.Cfg), &wrapped)
|
||||
if err != nil {
|
||||
|
||||
@@ -62,8 +62,8 @@ func Test_UnwrapLDAPSourceCfg(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
converted := map[string]interface{}{}
|
||||
expected := map[string]interface{}{}
|
||||
converted := map[string]any{}
|
||||
expected := map[string]any{}
|
||||
|
||||
if err := json.Unmarshal([]byte(source.Cfg), &converted); err != nil {
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -79,7 +79,7 @@ func Test_AddHeaderAuthorizationEncryptedColWebhook(t *testing.T) {
|
||||
return
|
||||
}
|
||||
for _, h := range hookTasks {
|
||||
var m map[string]interface{}
|
||||
var m map[string]any
|
||||
err := json.Unmarshal([]byte(h.PayloadContent), &m)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, m["access_token"])
|
||||
|
||||
@@ -81,11 +81,11 @@ func AddIssueDependencies(x *xorm.Engine) (err error) {
|
||||
// RepoUnit describes all units of a repository
|
||||
type RepoUnit struct {
|
||||
ID int64
|
||||
RepoID int64 `xorm:"INDEX(s)"`
|
||||
Type int `xorm:"INDEX(s)"`
|
||||
Config map[string]interface{} `xorm:"JSON"`
|
||||
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
||||
Created time.Time `xorm:"-"`
|
||||
RepoID int64 `xorm:"INDEX(s)"`
|
||||
Type int `xorm:"INDEX(s)"`
|
||||
Config map[string]any `xorm:"JSON"`
|
||||
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
||||
Created time.Time `xorm:"-"`
|
||||
}
|
||||
|
||||
// Updating existing issue units
|
||||
@@ -96,7 +96,7 @@ func AddIssueDependencies(x *xorm.Engine) (err error) {
|
||||
}
|
||||
for _, unit := range units {
|
||||
if unit.Config == nil {
|
||||
unit.Config = make(map[string]interface{})
|
||||
unit.Config = make(map[string]any)
|
||||
}
|
||||
if _, ok := unit.Config["EnableDependencies"]; !ok {
|
||||
unit.Config["EnableDependencies"] = setting.Service.DefaultEnableDependencies
|
||||
|
||||
@@ -15,10 +15,10 @@ func AddPullRequestRebaseWithMerge(x *xorm.Engine) error {
|
||||
// RepoUnit describes all units of a repository
|
||||
type RepoUnit struct {
|
||||
ID int64
|
||||
RepoID int64 `xorm:"INDEX(s)"`
|
||||
Type int `xorm:"INDEX(s)"`
|
||||
Config map[string]interface{} `xorm:"JSON"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
|
||||
RepoID int64 `xorm:"INDEX(s)"`
|
||||
Type int `xorm:"INDEX(s)"`
|
||||
Config map[string]any `xorm:"JSON"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -46,7 +46,7 @@ func AddPullRequestRebaseWithMerge(x *xorm.Engine) error {
|
||||
}
|
||||
for _, unit := range units {
|
||||
if unit.Config == nil {
|
||||
unit.Config = make(map[string]interface{})
|
||||
unit.Config = make(map[string]any)
|
||||
}
|
||||
// Allow the new merge style if all other merge styles are allowed
|
||||
allowMergeRebase := true
|
||||
|
||||
@@ -532,27 +532,6 @@ func GetOrgsCanCreateRepoByUserID(userID int64) ([]*Organization, error) {
|
||||
Find(&orgs)
|
||||
}
|
||||
|
||||
// GetOrgUsersByUserID returns all organization-user relations by user ID.
|
||||
func GetOrgUsersByUserID(uid int64, opts *SearchOrganizationsOptions) ([]*OrgUser, error) {
|
||||
ous := make([]*OrgUser, 0, 10)
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
Join("LEFT", "`user`", "`org_user`.org_id=`user`.id").
|
||||
Where("`org_user`.uid=?", uid)
|
||||
if !opts.All {
|
||||
// Only show public organizations
|
||||
sess.And("is_public=?", true)
|
||||
}
|
||||
|
||||
if opts.PageSize != 0 {
|
||||
sess = db.SetSessionPagination(sess, opts)
|
||||
}
|
||||
|
||||
err := sess.
|
||||
Asc("`user`.name").
|
||||
Find(&ous)
|
||||
return ous, err
|
||||
}
|
||||
|
||||
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
|
||||
func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) {
|
||||
sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID)
|
||||
|
||||
@@ -207,42 +207,6 @@ func TestFindOrgs(t *testing.T) {
|
||||
assert.EqualValues(t, 1, total)
|
||||
}
|
||||
|
||||
func TestGetOrgUsersByUserID(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
orgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: true})
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, orgUsers, 3) {
|
||||
assert.Equal(t, organization.OrgUser{
|
||||
ID: orgUsers[0].ID,
|
||||
OrgID: 23,
|
||||
UID: 5,
|
||||
IsPublic: false,
|
||||
}, *orgUsers[0])
|
||||
assert.Equal(t, organization.OrgUser{
|
||||
ID: orgUsers[1].ID,
|
||||
OrgID: 6,
|
||||
UID: 5,
|
||||
IsPublic: true,
|
||||
}, *orgUsers[1])
|
||||
assert.Equal(t, organization.OrgUser{
|
||||
ID: orgUsers[2].ID,
|
||||
OrgID: 7,
|
||||
UID: 5,
|
||||
IsPublic: false,
|
||||
}, *orgUsers[2])
|
||||
}
|
||||
|
||||
publicOrgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: false})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, publicOrgUsers, 1)
|
||||
assert.Equal(t, *orgUsers[1], *publicOrgUsers[0])
|
||||
|
||||
orgUsers, err = organization.GetOrgUsersByUserID(1, &organization.SearchOrganizationsOptions{All: true})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, orgUsers, 0)
|
||||
}
|
||||
|
||||
func TestGetOrgUsersByOrgID(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ type PackageDescriptor struct {
|
||||
Creator *user_model.User
|
||||
PackageProperties PackagePropertyList
|
||||
VersionProperties PackagePropertyList
|
||||
Metadata interface{}
|
||||
Metadata any
|
||||
Files []*PackageFileDescriptor
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var metadata interface{}
|
||||
var metadata any
|
||||
switch p.Type {
|
||||
case TypeAlpine:
|
||||
metadata = &alpine.VersionMetadata{}
|
||||
|
||||
@@ -5,11 +5,18 @@ package packages
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// ErrPackageBlobNotExist indicates a package blob not exist error
|
||||
@@ -98,3 +105,42 @@ func GetTotalUnreferencedBlobSize(ctx context.Context) (int64, error) {
|
||||
Where("package_file.id IS NULL").
|
||||
SumInt(&PackageBlob{}, "size")
|
||||
}
|
||||
|
||||
// IsBlobAccessibleForUser tests if the user has access to the blob
|
||||
func IsBlobAccessibleForUser(ctx context.Context, blobID int64, user *user_model.User) (bool, error) {
|
||||
if user.IsAdmin {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
maxTeamAuthorize := builder.
|
||||
Select("max(team.authorize)").
|
||||
From("team").
|
||||
InnerJoin("team_user", "team_user.team_id = team.id").
|
||||
Where(builder.Eq{"team_user.uid": user.ID}.And(builder.Expr("team_user.org_id = `user`.id")))
|
||||
|
||||
maxTeamUnitAccessMode := builder.
|
||||
Select("max(team_unit.access_mode)").
|
||||
From("team").
|
||||
InnerJoin("team_user", "team_user.team_id = team.id").
|
||||
InnerJoin("team_unit", "team_unit.team_id = team.id").
|
||||
Where(builder.Eq{"team_user.uid": user.ID, "team_unit.type": unit.TypePackages}.And(builder.Expr("team_user.org_id = `user`.id")))
|
||||
|
||||
cond := builder.Eq{"package_blob.id": blobID}.And(
|
||||
// owner = user
|
||||
builder.Eq{"`user`.id": user.ID}.
|
||||
// user can see owner
|
||||
Or(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}.Or(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited})).
|
||||
// owner is an organization and user has access to it
|
||||
Or(builder.Eq{"`user`.type": user_model.UserTypeOrganization}.
|
||||
And(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamAuthorize}.Or(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamUnitAccessMode}))),
|
||||
)
|
||||
|
||||
return db.GetEngine(ctx).
|
||||
Table("package_blob").
|
||||
Join("INNER", "package_file", "package_file.blob_id = package_blob.id").
|
||||
Join("INNER", "package_version", "package_version.id = package_file.version_id").
|
||||
Join("INNER", "package", "package.id = package_version.package_id").
|
||||
Join("INNER", "user", "`user`.id = package.owner_id").
|
||||
Where(cond).
|
||||
Exist(&PackageBlob{})
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ type SearchOptions struct {
|
||||
RepoID int64
|
||||
Page int
|
||||
IsClosed util.OptionalBool
|
||||
SortType string
|
||||
OrderBy db.SearchOrderBy
|
||||
Type Type
|
||||
}
|
||||
|
||||
@@ -226,26 +226,28 @@ func CountProjects(ctx context.Context, opts SearchOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toConds()).Count(new(Project))
|
||||
}
|
||||
|
||||
func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy {
|
||||
switch sortType {
|
||||
case "oldest":
|
||||
return db.SearchOrderByOldest
|
||||
case "recentupdate":
|
||||
return db.SearchOrderByRecentUpdated
|
||||
case "leastupdate":
|
||||
return db.SearchOrderByLeastUpdated
|
||||
default:
|
||||
return db.SearchOrderByNewest
|
||||
}
|
||||
}
|
||||
|
||||
// FindProjects returns a list of all projects that have been created in the repository
|
||||
func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) {
|
||||
e := db.GetEngine(ctx).Where(opts.toConds())
|
||||
e := db.GetEngine(ctx).Where(opts.toConds()).OrderBy(opts.OrderBy.String())
|
||||
projects := make([]*Project, 0, setting.UI.IssuePagingNum)
|
||||
|
||||
if opts.Page > 0 {
|
||||
e = e.Limit(setting.UI.IssuePagingNum, (opts.Page-1)*setting.UI.IssuePagingNum)
|
||||
}
|
||||
|
||||
switch opts.SortType {
|
||||
case "oldest":
|
||||
e.Desc("created_unix")
|
||||
case "recentupdate":
|
||||
e.Desc("updated_unix")
|
||||
case "leastupdate":
|
||||
e.Asc("updated_unix")
|
||||
default:
|
||||
e.Asc("created_unix")
|
||||
}
|
||||
|
||||
count, err := e.FindAndCount(&projects)
|
||||
return projects, count, err
|
||||
}
|
||||
|
||||
@@ -82,3 +82,42 @@ func TestProject(t *testing.T) {
|
||||
|
||||
assert.True(t, projectFromDB.IsClosed)
|
||||
}
|
||||
|
||||
func TestProjectsSort(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
tests := []struct {
|
||||
sortType string
|
||||
wants []int64
|
||||
}{
|
||||
{
|
||||
sortType: "default",
|
||||
wants: []int64{1, 3, 2, 4},
|
||||
},
|
||||
{
|
||||
sortType: "oldest",
|
||||
wants: []int64{4, 2, 3, 1},
|
||||
},
|
||||
{
|
||||
sortType: "recentupdate",
|
||||
wants: []int64{1, 3, 2, 4},
|
||||
},
|
||||
{
|
||||
sortType: "leastupdate",
|
||||
wants: []int64{4, 2, 3, 1},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
projects, count, err := FindProjects(db.DefaultContext, SearchOptions{
|
||||
OrderBy: GetSearchOrderByBySortType(tt.sortType),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, int64(4), count)
|
||||
if assert.Len(t, projects, 4) {
|
||||
for i := range projects {
|
||||
assert.EqualValues(t, tt.wants[i], projects[i].ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +456,7 @@ func repoStatsCorrectNumClosedPulls(ctx context.Context, id int64) error {
|
||||
return repo_model.UpdateRepoIssueNumbers(ctx, id, true, true)
|
||||
}
|
||||
|
||||
func statsQuery(args ...interface{}) func(context.Context) ([]map[string][]byte, error) {
|
||||
func statsQuery(args ...any) func(context.Context) ([]map[string][]byte, error) {
|
||||
return func(ctx context.Context) ([]map[string][]byte, error) {
|
||||
return db.GetEngine(ctx).Query(args...)
|
||||
}
|
||||
|
||||
@@ -65,13 +65,6 @@ func (a *Attachment) DownloadURL() string {
|
||||
return setting.AppURL + "attachments/" + url.PathEscape(a.UUID)
|
||||
}
|
||||
|
||||
// _____ __ __ .__ __
|
||||
// / _ \_/ |__/ |______ ____ | |__ _____ ____ _____/ |_
|
||||
// / /_\ \ __\ __\__ \ _/ ___\| | \ / \_/ __ \ / \ __\
|
||||
// / | \ | | | / __ \\ \___| Y \ Y Y \ ___/| | \ |
|
||||
// \____|__ /__| |__| (____ /\___ >___| /__|_| /\___ >___| /__|
|
||||
// \/ \/ \/ \/ \/ \/ \/
|
||||
|
||||
// ErrAttachmentNotExist represents a "AttachmentNotExist" kind of error.
|
||||
type ErrAttachmentNotExist struct {
|
||||
ID int64
|
||||
|
||||
@@ -33,6 +33,19 @@ func TestRepository_GetCollaborators(t *testing.T) {
|
||||
test(2)
|
||||
test(3)
|
||||
test(4)
|
||||
|
||||
// Test db.ListOptions
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
||||
|
||||
collaborators1, err := repo_model.GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{PageSize: 1, Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, collaborators1, 1)
|
||||
|
||||
collaborators2, err := repo_model.GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{PageSize: 1, Page: 2})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, collaborators2, 1)
|
||||
|
||||
assert.NotEqualValues(t, collaborators1[0].ID, collaborators2[0].ID)
|
||||
}
|
||||
|
||||
func TestRepository_IsCollaborator(t *testing.T) {
|
||||
@@ -66,5 +79,80 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) {
|
||||
|
||||
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, unittest.NonexistentID, perm.AccessModeAdmin))
|
||||
|
||||
// Disvard invalid input.
|
||||
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessMode(unittest.NonexistentID)))
|
||||
|
||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID})
|
||||
}
|
||||
|
||||
func TestRepository_CountCollaborators(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||
count, err := repo_model.CountCollaborators(repo1.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, count)
|
||||
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
||||
count, err = repo_model.CountCollaborators(repo2.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, count)
|
||||
|
||||
// Non-existent repository.
|
||||
count, err = repo_model.CountCollaborators(unittest.NonexistentID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, count)
|
||||
}
|
||||
|
||||
func TestRepository_IsOwnerMemberCollaborator(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||
|
||||
// Organisation owner.
|
||||
actual, err := repo_model.IsOwnerMemberCollaborator(repo1, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
|
||||
// Team member.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 4)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
|
||||
// Normal user.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, actual)
|
||||
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||
|
||||
// Collaborator.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo2, 4)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15})
|
||||
|
||||
// Repository owner.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo3, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
}
|
||||
|
||||
func TestRepo_GetCollaboration(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||
|
||||
// Existing collaboration.
|
||||
collab, err := repo_model.GetCollaboration(db.DefaultContext, repo.ID, 4)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, collab)
|
||||
assert.EqualValues(t, 4, collab.UserID)
|
||||
assert.EqualValues(t, 4, collab.RepoID)
|
||||
|
||||
// Non-existing collaboration.
|
||||
collab, err = repo_model.GetCollaboration(db.DefaultContext, repo.ID, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, collab)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ type MergeStyle string
|
||||
const (
|
||||
// MergeStyleMerge create merge commit
|
||||
MergeStyleMerge MergeStyle = "merge"
|
||||
// MergeStyleRebase rebase before merging
|
||||
// MergeStyleRebase rebase before merging, and fast-forward
|
||||
MergeStyleRebase MergeStyle = "rebase"
|
||||
// MergeStyleRebaseMerge rebase before merging with merge commit (--no-ff)
|
||||
MergeStyleRebaseMerge MergeStyle = "rebase-merge"
|
||||
|
||||
@@ -105,7 +105,7 @@ func DeleteMirrorByRepoID(repoID int64) error {
|
||||
}
|
||||
|
||||
// MirrorsIterate iterates all mirror repositories.
|
||||
func MirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
|
||||
func MirrorsIterate(limit int, f func(idx int, bean any) error) error {
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
Where("next_update_unix<=?", time.Now().Unix()).
|
||||
And("next_update_unix!=0").
|
||||
|
||||
@@ -127,7 +127,7 @@ func GetPushMirrorsSyncedOnCommit(ctx context.Context, repoID int64) ([]*PushMir
|
||||
}
|
||||
|
||||
// PushMirrorsIterate iterates all push-mirror repositories.
|
||||
func PushMirrorsIterate(ctx context.Context, limit int, f func(idx int, bean interface{}) error) error {
|
||||
func PushMirrorsIterate(ctx context.Context, limit int, f func(idx int, bean any) error) error {
|
||||
sess := db.GetEngine(ctx).
|
||||
Where("last_update + (`interval` / ?) <= ?", time.Second, time.Now().Unix()).
|
||||
And("`interval` != 0").
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestPushMirrorsIterate(t *testing.T) {
|
||||
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
|
||||
repo_model.PushMirrorsIterate(db.DefaultContext, 1, func(idx int, bean interface{}) error {
|
||||
repo_model.PushMirrorsIterate(db.DefaultContext, 1, func(idx int, bean any) error {
|
||||
m, ok := bean.(*repo_model.PushMirror)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "test-1", m.RemoteName)
|
||||
|
||||
@@ -442,7 +442,7 @@ func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, origi
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("release").
|
||||
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
||||
And("original_author_id = ?", originalAuthorID).
|
||||
Update(map[string]interface{}{
|
||||
Update(map[string]any{
|
||||
"publisher_id": posterID,
|
||||
"original_author": "",
|
||||
"original_author_id": 0,
|
||||
|
||||
@@ -560,7 +560,7 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c
|
||||
opts.OrderBy = db.SearchOrderByAlphabetically
|
||||
}
|
||||
|
||||
args := make([]interface{}, 0)
|
||||
args := make([]any, 0)
|
||||
if opts.PriorityOwnerID > 0 {
|
||||
opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = ? THEN 0 ELSE owner_id END, %s", opts.OrderBy))
|
||||
args = append(args, opts.PriorityOwnerID)
|
||||
|
||||
@@ -43,7 +43,7 @@ func (n *Notice) TrStr() string {
|
||||
}
|
||||
|
||||
// CreateNotice creates new system notice.
|
||||
func CreateNotice(ctx context.Context, tp NoticeType, desc string, args ...interface{}) error {
|
||||
func CreateNotice(ctx context.Context, tp NoticeType, desc string, args ...any) error {
|
||||
if len(args) > 0 {
|
||||
desc = fmt.Sprintf(desc, args...)
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func CreateNotice(ctx context.Context, tp NoticeType, desc string, args ...inter
|
||||
}
|
||||
|
||||
// CreateRepositoryNotice creates new system notice with type NoticeRepository.
|
||||
func CreateRepositoryNotice(desc string, args ...interface{}) error {
|
||||
func CreateRepositoryNotice(desc string, args ...any) error {
|
||||
// Note we use the db.DefaultContext here rather than passing in a context as the context may be cancelled
|
||||
return CreateNotice(db.DefaultContext, NoticeRepository, desc, args...)
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ const (
|
||||
modelsCommentTypeComment = 0
|
||||
)
|
||||
|
||||
var consistencyCheckMap = make(map[string]func(t assert.TestingT, bean interface{}))
|
||||
var consistencyCheckMap = make(map[string]func(t assert.TestingT, bean any))
|
||||
|
||||
// CheckConsistencyFor test that all matching database entries are consistent
|
||||
func CheckConsistencyFor(t assert.TestingT, beansToCheck ...interface{}) {
|
||||
func CheckConsistencyFor(t assert.TestingT, beansToCheck ...any) {
|
||||
for _, bean := range beansToCheck {
|
||||
sliceType := reflect.SliceOf(reflect.TypeOf(bean))
|
||||
sliceValue := reflect.MakeSlice(sliceType, 0, 10)
|
||||
@@ -42,7 +42,7 @@ func CheckConsistencyFor(t assert.TestingT, beansToCheck ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func checkForConsistency(t assert.TestingT, bean interface{}) {
|
||||
func checkForConsistency(t assert.TestingT, bean any) {
|
||||
tb, err := db.TableInfo(bean)
|
||||
assert.NoError(t, err)
|
||||
f := consistencyCheckMap[tb.Name]
|
||||
@@ -63,7 +63,7 @@ func init() {
|
||||
return i
|
||||
}
|
||||
|
||||
checkForUserConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForUserConsistency := func(t assert.TestingT, bean any) {
|
||||
user := reflectionWrap(bean)
|
||||
AssertCountByCond(t, "repository", builder.Eq{"owner_id": user.int("ID")}, user.int("NumRepos"))
|
||||
AssertCountByCond(t, "star", builder.Eq{"uid": user.int("ID")}, user.int("NumStars"))
|
||||
@@ -77,7 +77,7 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
checkForRepoConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForRepoConsistency := func(t assert.TestingT, bean any) {
|
||||
repo := reflectionWrap(bean)
|
||||
assert.Equal(t, repo.str("LowerName"), strings.ToLower(repo.str("Name")), "repo: %+v", repo)
|
||||
AssertCountByCond(t, "star", builder.Eq{"repo_id": repo.int("ID")}, repo.int("NumStars"))
|
||||
@@ -113,7 +113,7 @@ func init() {
|
||||
"Unexpected number of closed milestones for repo id: %d", repo.int("ID"))
|
||||
}
|
||||
|
||||
checkForIssueConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForIssueConsistency := func(t assert.TestingT, bean any) {
|
||||
issue := reflectionWrap(bean)
|
||||
typeComment := modelsCommentTypeComment
|
||||
actual := GetCountByCond(t, "comment", builder.Eq{"`type`": typeComment, "issue_id": issue.int("ID")})
|
||||
@@ -124,14 +124,14 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
checkForPullRequestConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForPullRequestConsistency := func(t assert.TestingT, bean any) {
|
||||
pr := reflectionWrap(bean)
|
||||
issueRow := AssertExistsAndLoadMap(t, "issue", builder.Eq{"id": pr.int("IssueID")})
|
||||
assert.True(t, parseBool(issueRow["is_pull"]))
|
||||
assert.EqualValues(t, parseInt(issueRow["index"]), pr.int("Index"), "Unexpected index for pull request id: %d", pr.int("ID"))
|
||||
}
|
||||
|
||||
checkForMilestoneConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForMilestoneConsistency := func(t assert.TestingT, bean any) {
|
||||
milestone := reflectionWrap(bean)
|
||||
AssertCountByCond(t, "issue", builder.Eq{"milestone_id": milestone.int("ID")}, milestone.int("NumIssues"))
|
||||
|
||||
@@ -145,7 +145,7 @@ func init() {
|
||||
assert.Equal(t, completeness, milestone.int("Completeness"))
|
||||
}
|
||||
|
||||
checkForLabelConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForLabelConsistency := func(t assert.TestingT, bean any) {
|
||||
label := reflectionWrap(bean)
|
||||
issueLabels, err := db.GetEngine(db.DefaultContext).Table("issue_label").
|
||||
Where(builder.Eq{"label_id": label.int("ID")}).
|
||||
@@ -166,13 +166,13 @@ func init() {
|
||||
assert.EqualValues(t, expected, label.int("NumClosedIssues"), "Unexpected number of closed issues for label id: %d", label.int("ID"))
|
||||
}
|
||||
|
||||
checkForTeamConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForTeamConsistency := func(t assert.TestingT, bean any) {
|
||||
team := reflectionWrap(bean)
|
||||
AssertCountByCond(t, "team_user", builder.Eq{"team_id": team.int("ID")}, team.int("NumMembers"))
|
||||
AssertCountByCond(t, "team_repo", builder.Eq{"team_id": team.int("ID")}, team.int("NumRepos"))
|
||||
}
|
||||
|
||||
checkForActionConsistency := func(t assert.TestingT, bean interface{}) {
|
||||
checkForActionConsistency := func(t assert.TestingT, bean any) {
|
||||
action := reflectionWrap(bean)
|
||||
if action.int("RepoID") != 1700 { // dangling intentional
|
||||
repoRow := AssertExistsAndLoadMap(t, "repository", builder.Eq{"id": action.int("RepoID")})
|
||||
|
||||
@@ -23,7 +23,7 @@ type reflectionValue struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func reflectionWrap(v interface{}) *reflectionValue {
|
||||
func reflectionWrap(v any) *reflectionValue {
|
||||
return &reflectionValue{v: reflect.ValueOf(v)}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ func FixturesDir() string {
|
||||
return fixturesDir
|
||||
}
|
||||
|
||||
func fatalTestError(fmtStr string, args ...interface{}) {
|
||||
func fatalTestError(fmtStr string, args ...any) {
|
||||
_, _ = fmt.Fprintf(os.Stderr, fmtStr, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -57,11 +57,11 @@ func (err ErrExternalLoginUserNotExist) Unwrap() error {
|
||||
|
||||
// ExternalLoginUser makes the connecting between some existing user and additional external login sources
|
||||
type ExternalLoginUser struct {
|
||||
ExternalID string `xorm:"pk NOT NULL"`
|
||||
UserID int64 `xorm:"INDEX NOT NULL"`
|
||||
LoginSourceID int64 `xorm:"pk NOT NULL"`
|
||||
RawData map[string]interface{} `xorm:"TEXT JSON"`
|
||||
Provider string `xorm:"index VARCHAR(25)"`
|
||||
ExternalID string `xorm:"pk NOT NULL"`
|
||||
UserID int64 `xorm:"INDEX NOT NULL"`
|
||||
LoginSourceID int64 `xorm:"pk NOT NULL"`
|
||||
RawData map[string]any `xorm:"TEXT JSON"`
|
||||
Provider string `xorm:"index VARCHAR(25)"`
|
||||
Email string
|
||||
Name string
|
||||
FirstName string
|
||||
|
||||
@@ -64,6 +64,10 @@ func NewUserRedirect(ctx context.Context, ID int64, oldUserName, newUserName str
|
||||
oldUserName = strings.ToLower(oldUserName)
|
||||
newUserName = strings.ToLower(newUserName)
|
||||
|
||||
if err := DeleteUserRedirect(ctx, oldUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := DeleteUserRedirect(ctx, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func (t *HookTask) AfterLoad() {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *HookTask) simpleMarshalJSON(v interface{}) string {
|
||||
func (t *HookTask) simpleMarshalJSON(v any) string {
|
||||
p, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
log.Error("Marshal [%d]: %v", t.ID, err)
|
||||
|
||||
@@ -29,12 +29,28 @@ const (
|
||||
)
|
||||
|
||||
func WriteLogs(ctx context.Context, filename string, offset int64, rows []*runnerv1.LogRow) ([]int, error) {
|
||||
flag := os.O_WRONLY
|
||||
if offset == 0 {
|
||||
// Create file only if offset is 0, or it could result in content holes if the file doesn't exist.
|
||||
flag |= os.O_CREATE
|
||||
}
|
||||
name := DBFSPrefix + filename
|
||||
f, err := dbfs.OpenFile(ctx, name, os.O_WRONLY|os.O_CREATE)
|
||||
f, err := dbfs.OpenFile(ctx, name, flag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dbfs OpenFile %q: %w", name, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dbfs Stat %q: %w", name, err)
|
||||
}
|
||||
if stat.Size() < offset {
|
||||
// If the size is less than offset, refuse to write, or it could result in content holes.
|
||||
// However, if the size is greater than offset, we can still write to overwrite the content.
|
||||
return nil, fmt.Errorf("size of %q is less than offset", name)
|
||||
}
|
||||
|
||||
if _, err := f.Seek(offset, io.SeekStart); err != nil {
|
||||
return nil, fmt.Errorf("dbfs Seek %q: %w", name, err)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
model.OnDecodeNodeError = func(node yaml.Node, out interface{}, err error) {
|
||||
model.OnDecodeNodeError = func(node yaml.Node, out any, err error) {
|
||||
// Log the error instead of panic or fatal.
|
||||
// It will be a big job to refactor act/pkg/model to return decode error,
|
||||
// so we just log the error and return empty value, and improve it later.
|
||||
@@ -321,44 +321,47 @@ func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *j
|
||||
}
|
||||
|
||||
func matchPullRequestEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
|
||||
// with no special filter parameters
|
||||
if len(evt.Acts()) == 0 {
|
||||
acts := evt.Acts()
|
||||
activityTypeMatched := false
|
||||
matchTimes := 0
|
||||
|
||||
if vals, ok := acts["types"]; !ok {
|
||||
// defaultly, only pull request `opened`, `reopened` and `synchronized` will trigger workflow
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
|
||||
return prPayload.Action == api.HookIssueSynchronized || prPayload.Action == api.HookIssueOpened || prPayload.Action == api.HookIssueReOpened
|
||||
activityTypeMatched = prPayload.Action == api.HookIssueSynchronized || prPayload.Action == api.HookIssueOpened || prPayload.Action == api.HookIssueReOpened
|
||||
} else {
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
|
||||
// Actions with the same name:
|
||||
// opened, edited, closed, reopened, assigned, unassigned
|
||||
// Actions need to be converted:
|
||||
// synchronized -> synchronize
|
||||
// label_updated -> labeled
|
||||
// label_cleared -> unlabeled
|
||||
// Unsupported activity types:
|
||||
// converted_to_draft, ready_for_review, locked, unlocked, review_requested, review_request_removed, auto_merge_enabled, auto_merge_disabled
|
||||
|
||||
action := prPayload.Action
|
||||
switch action {
|
||||
case api.HookIssueSynchronized:
|
||||
action = "synchronize"
|
||||
case api.HookIssueLabelUpdated:
|
||||
action = "labeled"
|
||||
case api.HookIssueLabelCleared:
|
||||
action = "unlabeled"
|
||||
}
|
||||
log.Trace("matching pull_request %s with %v", action, vals)
|
||||
for _, val := range vals {
|
||||
if glob.MustCompile(val, '/').Match(string(action)) {
|
||||
activityTypeMatched = true
|
||||
matchTimes++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matchTimes := 0
|
||||
// all acts conditions should be satisfied
|
||||
for cond, vals := range evt.Acts() {
|
||||
for cond, vals := range acts {
|
||||
switch cond {
|
||||
case "types":
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
|
||||
// Actions with the same name:
|
||||
// opened, edited, closed, reopened, assigned, unassigned
|
||||
// Actions need to be converted:
|
||||
// synchronized -> synchronize
|
||||
// label_updated -> labeled
|
||||
// label_cleared -> unlabeled
|
||||
// Unsupported activity types:
|
||||
// converted_to_draft, ready_for_review, locked, unlocked, review_requested, review_request_removed, auto_merge_enabled, auto_merge_disabled
|
||||
|
||||
action := prPayload.Action
|
||||
switch action {
|
||||
case api.HookIssueSynchronized:
|
||||
action = "synchronize"
|
||||
case api.HookIssueLabelUpdated:
|
||||
action = "labeled"
|
||||
case api.HookIssueLabelCleared:
|
||||
action = "unlabeled"
|
||||
}
|
||||
log.Trace("matching pull_request %s with %v", action, vals)
|
||||
for _, val := range vals {
|
||||
if glob.MustCompile(val, '/').Match(string(action)) {
|
||||
matchTimes++
|
||||
break
|
||||
}
|
||||
}
|
||||
case "branches":
|
||||
refName := git.RefName(prPayload.PullRequest.Base.Ref)
|
||||
patterns, err := workflowpattern.CompilePatterns(vals...)
|
||||
@@ -407,7 +410,7 @@ func matchPullRequestEvent(commit *git.Commit, prPayload *api.PullRequestPayload
|
||||
log.Warn("pull request event unsupported condition %q", cond)
|
||||
}
|
||||
}
|
||||
return matchTimes == len(evt.Acts())
|
||||
return activityTypeMatched && matchTimes == len(evt.Acts())
|
||||
}
|
||||
|
||||
func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
|
||||
|
||||
@@ -57,6 +57,25 @@ func TestDetectMatched(t *testing.T) {
|
||||
yamlOn: "on: pull_request",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequest(pull_request) `closed` action doesn't match GithubEventPullRequest(pull_request) with no activity type",
|
||||
triggedEvent: webhook_module.HookEventPullRequest,
|
||||
payload: &api.PullRequestPayload{Action: api.HookIssueClosed},
|
||||
yamlOn: "on: pull_request",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequest(pull_request) `closed` action doesn't match GithubEventPullRequest(pull_request) with branches",
|
||||
triggedEvent: webhook_module.HookEventPullRequest,
|
||||
payload: &api.PullRequestPayload{
|
||||
Action: api.HookIssueClosed,
|
||||
PullRequest: &api.PullRequest{
|
||||
Base: &api.PRBranchInfo{},
|
||||
},
|
||||
},
|
||||
yamlOn: "on:\n pull_request:\n branches: [main]",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequest(pull_request) `label_updated` action matches githubEventPullRequest(pull_request) with `label` activity type",
|
||||
triggedEvent: webhook_module.HookEventPullRequest,
|
||||
|
||||
@@ -215,8 +215,9 @@ func (l *LayeredFS) WatchLocalChanges(ctx context.Context, callback func()) {
|
||||
log.Error("Unable to list directories for asset local file-system %q: %v", layer.localPath, err)
|
||||
continue
|
||||
}
|
||||
layerDirs = append(layerDirs, ".")
|
||||
for _, dir := range layerDirs {
|
||||
if err = watcher.Add(util.FilePathJoinAbs(layer.localPath, dir)); err != nil {
|
||||
if err = watcher.Add(util.FilePathJoinAbs(layer.localPath, dir)); err != nil && !os.IsNotExist(err) {
|
||||
log.Error("Unable to watch directory %s: %v", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ const TimeLimitCodeLength = 12 + 6 + 40
|
||||
|
||||
// CreateTimeLimitCode create a time limit code
|
||||
// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
|
||||
func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string {
|
||||
func CreateTimeLimitCode(data string, minutes int, startInf any) string {
|
||||
format := "200601021504"
|
||||
|
||||
var start, end time.Time
|
||||
@@ -245,7 +245,7 @@ func SetupGiteaRoot() string {
|
||||
}
|
||||
|
||||
// FormatNumberSI format a number
|
||||
func FormatNumberSI(data interface{}) string {
|
||||
func FormatNumberSI(data any) string {
|
||||
var num int64
|
||||
if num1, ok := data.(int64); ok {
|
||||
num = num1
|
||||
|
||||
6
modules/cache/cache_redis.go
vendored
6
modules/cache/cache_redis.go
vendored
@@ -24,7 +24,7 @@ type RedisCacher struct {
|
||||
}
|
||||
|
||||
// toStr convert string/int/int64 interface to string. it's only used by the RedisCacher.Put internally
|
||||
func toStr(v interface{}) string {
|
||||
func toStr(v any) string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func toStr(v interface{}) string {
|
||||
|
||||
// Put puts value (string type) into cache with key and expire time.
|
||||
// If expired is 0, it lives forever.
|
||||
func (c *RedisCacher) Put(key string, val interface{}, expire int64) error {
|
||||
func (c *RedisCacher) Put(key string, val any, expire int64) error {
|
||||
// this function is not well-designed, it only puts string values into cache
|
||||
key = c.prefix + key
|
||||
if expire == 0 {
|
||||
@@ -65,7 +65,7 @@ func (c *RedisCacher) Put(key string, val interface{}, expire int64) error {
|
||||
}
|
||||
|
||||
// Get gets cached value by given key.
|
||||
func (c *RedisCacher) Get(key string) interface{} {
|
||||
func (c *RedisCacher) Get(key string) any {
|
||||
val, err := c.c.Get(graceful.GetManager().HammerContext(), c.prefix+key).Result()
|
||||
if err != nil {
|
||||
return nil
|
||||
|
||||
8
modules/cache/cache_twoqueue.go
vendored
8
modules/cache/cache_twoqueue.go
vendored
@@ -30,7 +30,7 @@ type TwoQueueCacheConfig struct {
|
||||
|
||||
// MemoryItem represents a memory cache item.
|
||||
type MemoryItem struct {
|
||||
Val interface{}
|
||||
Val any
|
||||
Created int64
|
||||
Timeout int64
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func (item *MemoryItem) hasExpired() bool {
|
||||
var _ mc.Cache = &TwoQueueCache{}
|
||||
|
||||
// Put puts value into cache with key and expire time.
|
||||
func (c *TwoQueueCache) Put(key string, val interface{}, timeout int64) error {
|
||||
func (c *TwoQueueCache) Put(key string, val any, timeout int64) error {
|
||||
item := &MemoryItem{
|
||||
Val: val,
|
||||
Created: time.Now().Unix(),
|
||||
@@ -56,7 +56,7 @@ func (c *TwoQueueCache) Put(key string, val interface{}, timeout int64) error {
|
||||
}
|
||||
|
||||
// Get gets cached value by given key.
|
||||
func (c *TwoQueueCache) Get(key string) interface{} {
|
||||
func (c *TwoQueueCache) Get(key string) any {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
cached, ok := c.cache.Get(key)
|
||||
@@ -146,7 +146,7 @@ func (c *TwoQueueCache) Flush() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TwoQueueCache) checkAndInvalidate(key interface{}) {
|
||||
func (c *TwoQueueCache) checkAndInvalidate(key any) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
cached, ok := c.cache.Peek(key)
|
||||
|
||||
@@ -90,7 +90,7 @@ Usage: %[1]s [-v] [-o output.go] ambiguous.json
|
||||
sort.Slice(tables, func(i, j int) bool {
|
||||
return tables[i].Locale < tables[j].Locale
|
||||
})
|
||||
data := map[string]interface{}{
|
||||
data := map[string]any{
|
||||
"Tables": tables,
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ Usage: %[1]s [-v] [-o output.go] ambiguous.json
|
||||
}
|
||||
}
|
||||
|
||||
func runTemplate(t *template.Template, filename string, data interface{}) error {
|
||||
func runTemplate(t *template.Template, filename string, data any) error {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
if err := t.Execute(buf, data); err != nil {
|
||||
return fmt.Errorf("unable to execute template: %w", err)
|
||||
@@ -172,17 +172,17 @@ var AmbiguousCharacters = map[string]*AmbiguousTable{
|
||||
|
||||
`))
|
||||
|
||||
func logf(format string, args ...interface{}) {
|
||||
func logf(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||
}
|
||||
|
||||
func verbosef(format string, args ...interface{}) {
|
||||
func verbosef(format string, args ...any) {
|
||||
if verbose {
|
||||
logf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func fatalf(format string, args ...interface{}) {
|
||||
func fatalf(format string, args ...any) {
|
||||
logf("fatal: "+format+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user