mirror of
https://github.com/go-gitea/gitea.git
synced 2024-09-01 14:56:30 +00:00
Merge branch 'main' into pacman-packages
This commit is contained in:
commit
e22a3c7bb1
15
assets/go-licenses.json
generated
15
assets/go-licenses.json
generated
@ -409,6 +409,11 @@
|
|||||||
"path": "github.com/go-chi/cors/LICENSE",
|
"path": "github.com/go-chi/cors/LICENSE",
|
||||||
"licenseText": "Copyright (c) 2014 Olivier Poitrey \u003crs@dailymotion.com\u003e\nCopyright (c) 2016-Present https://github.com/go-chi authors\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
"licenseText": "Copyright (c) 2014 Olivier Poitrey \u003crs@dailymotion.com\u003e\nCopyright (c) 2016-Present https://github.com/go-chi authors\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "github.com/go-co-op/gocron",
|
||||||
|
"path": "github.com/go-co-op/gocron/LICENSE",
|
||||||
|
"licenseText": "MIT License\n\nCopyright (c) 2014, 辣椒面\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "github.com/go-enry/go-enry/v2",
|
"name": "github.com/go-enry/go-enry/v2",
|
||||||
"path": "github.com/go-enry/go-enry/v2/LICENSE",
|
"path": "github.com/go-enry/go-enry/v2/LICENSE",
|
||||||
@ -484,11 +489,6 @@
|
|||||||
"path": "github.com/gogs/chardet/LICENSE",
|
"path": "github.com/gogs/chardet/LICENSE",
|
||||||
"licenseText": "Copyright (c) 2012 chardet Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nPartial of the Software is derived from ICU project. See icu-license.html for\nlicense of the derivative portions.\n"
|
"licenseText": "Copyright (c) 2012 chardet Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nPartial of the Software is derived from ICU project. See icu-license.html for\nlicense of the derivative portions.\n"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "github.com/gogs/cron",
|
|
||||||
"path": "github.com/gogs/cron/LICENSE",
|
|
||||||
"licenseText": "Copyright (C) 2012 Rob Figueiredo\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "github.com/gogs/go-gogs-client",
|
"name": "github.com/gogs/go-gogs-client",
|
||||||
"path": "github.com/gogs/go-gogs-client/LICENSE",
|
"path": "github.com/gogs/go-gogs-client/LICENSE",
|
||||||
@ -909,6 +909,11 @@
|
|||||||
"path": "github.com/robfig/cron/LICENSE",
|
"path": "github.com/robfig/cron/LICENSE",
|
||||||
"licenseText": "Copyright (C) 2012 Rob Figueiredo\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
"licenseText": "Copyright (C) 2012 Rob Figueiredo\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "github.com/robfig/cron/v3",
|
||||||
|
"path": "github.com/robfig/cron/v3/LICENSE",
|
||||||
|
"licenseText": "Copyright (C) 2012 Rob Figueiredo\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "github.com/rs/xid",
|
"name": "github.com/rs/xid",
|
||||||
"path": "github.com/rs/xid/LICENSE",
|
"path": "github.com/rs/xid/LICENSE",
|
||||||
|
14
cmd/admin.go
14
cmd/admin.go
@ -5,6 +5,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -297,10 +298,12 @@ var (
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "force-smtps",
|
Name: "force-smtps",
|
||||||
Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.",
|
Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "skip-verify",
|
Name: "skip-verify",
|
||||||
Usage: "Skip TLS verify.",
|
Usage: "Skip TLS verify.",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "helo-hostname",
|
Name: "helo-hostname",
|
||||||
@ -310,6 +313,7 @@ var (
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "disable-helo",
|
Name: "disable-helo",
|
||||||
Usage: "Disable SMTP helo.",
|
Usage: "Disable SMTP helo.",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "allowed-domains",
|
Name: "allowed-domains",
|
||||||
@ -319,10 +323,12 @@ var (
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "skip-local-2fa",
|
Name: "skip-local-2fa",
|
||||||
Usage: "Skip 2FA to log on.",
|
Usage: "Skip 2FA to log on.",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "active",
|
Name: "active",
|
||||||
Usage: "This Authentication Source is Activated.",
|
Usage: "This Authentication Source is Activated.",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,7 +379,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
oldnum, err := getReleaseCount(repo.ID)
|
oldnum, err := getReleaseCount(ctx, repo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(" GetReleaseCountByRepoID: %v", err)
|
log.Warn(" GetReleaseCountByRepoID: %v", err)
|
||||||
}
|
}
|
||||||
@ -385,7 +391,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err = getReleaseCount(repo.ID)
|
count, err = getReleaseCount(ctx, repo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(" GetReleaseCountByRepoID: %v", err)
|
log.Warn(" GetReleaseCountByRepoID: %v", err)
|
||||||
gitRepo.Close()
|
gitRepo.Close()
|
||||||
@ -401,9 +407,9 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReleaseCount(id int64) (int64, error) {
|
func getReleaseCount(ctx context.Context, id int64) (int64, error) {
|
||||||
return repo_model.GetReleaseCountByRepoID(
|
return repo_model.GetReleaseCountByRepoID(
|
||||||
db.DefaultContext,
|
ctx,
|
||||||
id,
|
id,
|
||||||
repo_model.FindReleasesOptions{
|
repo_model.FindReleasesOptions{
|
||||||
IncludeTags: true,
|
IncludeTags: true,
|
||||||
|
@ -117,6 +117,7 @@ var (
|
|||||||
Name: "rotate",
|
Name: "rotate",
|
||||||
Aliases: []string{"r"},
|
Aliases: []string{"r"},
|
||||||
Usage: "Rotate logs",
|
Usage: "Rotate logs",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
Name: "max-size",
|
Name: "max-size",
|
||||||
@ -127,6 +128,7 @@ var (
|
|||||||
Name: "daily",
|
Name: "daily",
|
||||||
Aliases: []string{"d"},
|
Aliases: []string{"d"},
|
||||||
Usage: "Rotate logs daily",
|
Usage: "Rotate logs daily",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "max-days",
|
Name: "max-days",
|
||||||
@ -137,6 +139,7 @@ var (
|
|||||||
Name: "compress",
|
Name: "compress",
|
||||||
Aliases: []string{"z"},
|
Aliases: []string{"z"},
|
||||||
Usage: "Compress rotated logs",
|
Usage: "Compress rotated logs",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "compression-level",
|
Name: "compression-level",
|
||||||
|
3
go.mod
3
go.mod
@ -41,6 +41,7 @@ require (
|
|||||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||||
github.com/go-chi/chi/v5 v5.0.8
|
github.com/go-chi/chi/v5 v5.0.8
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
|
github.com/go-co-op/gocron v1.30.1
|
||||||
github.com/go-enry/go-enry/v2 v2.8.4
|
github.com/go-enry/go-enry/v2 v2.8.4
|
||||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
|
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
|
||||||
github.com/go-git/go-billy/v5 v5.4.1
|
github.com/go-git/go-billy/v5 v5.4.1
|
||||||
@ -52,7 +53,6 @@ require (
|
|||||||
github.com/go-webauthn/webauthn v0.8.6
|
github.com/go-webauthn/webauthn v0.8.6
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||||
github.com/google/go-github/v53 v53.2.0
|
github.com/google/go-github/v53 v53.2.0
|
||||||
@ -253,6 +253,7 @@ require (
|
|||||||
github.com/rhysd/actionlint v1.6.25 // indirect
|
github.com/rhysd/actionlint v1.6.25 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/robfig/cron v1.2.0 // indirect
|
github.com/robfig/cron v1.2.0 // indirect
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
github.com/rs/xid v1.5.0 // indirect
|
github.com/rs/xid v1.5.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
10
go.sum
10
go.sum
@ -371,6 +371,8 @@ github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
|
|||||||
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||||
|
github.com/go-co-op/gocron v1.30.1 h1:tjWUvJl5KrcwpkEkSXFSQFr4F9h5SfV/m4+RX0cV2fs=
|
||||||
|
github.com/go-co-op/gocron v1.30.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
|
||||||
github.com/go-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs=
|
github.com/go-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs=
|
||||||
github.com/go-enry/go-enry/v2 v2.8.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
github.com/go-enry/go-enry/v2 v2.8.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
||||||
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
|
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
|
||||||
@ -496,8 +498,6 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8=
|
|
||||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
|
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
@ -787,6 +787,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
|||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
@ -1038,10 +1039,14 @@ github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
|||||||
github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
|
github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
|
||||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
@ -1250,6 +1255,7 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
|
@ -195,6 +195,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
|||||||
}
|
}
|
||||||
|
|
||||||
runJobs := make([]*ActionRunJob, 0, len(jobs))
|
runJobs := make([]*ActionRunJob, 0, len(jobs))
|
||||||
|
var hasWaiting bool
|
||||||
for _, v := range jobs {
|
for _, v := range jobs {
|
||||||
id, job := v.Job()
|
id, job := v.Job()
|
||||||
needs := job.Needs()
|
needs := job.Needs()
|
||||||
@ -205,6 +206,8 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
|||||||
status := StatusWaiting
|
status := StatusWaiting
|
||||||
if len(needs) > 0 || run.NeedApproval {
|
if len(needs) > 0 || run.NeedApproval {
|
||||||
status = StatusBlocked
|
status = StatusBlocked
|
||||||
|
} else {
|
||||||
|
hasWaiting = true
|
||||||
}
|
}
|
||||||
job.Name, _ = util.SplitStringAtByteN(job.Name, 255)
|
job.Name, _ = util.SplitStringAtByteN(job.Name, 255)
|
||||||
runJobs = append(runJobs, &ActionRunJob{
|
runJobs = append(runJobs, &ActionRunJob{
|
||||||
@ -225,6 +228,13 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there is a job in the waiting status, increase tasks version.
|
||||||
|
if hasWaiting {
|
||||||
|
if err := IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return commiter.Commit()
|
return commiter.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,13 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col
|
|||||||
return affected, nil
|
return affected, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if affected != 0 && util.SliceContains(cols, "status") && job.Status.IsWaiting() {
|
||||||
|
// if the status of job changes to waiting again, increase tasks version.
|
||||||
|
if err := IncreaseTaskVersion(ctx, job.OwnerID, job.RepoID); err != nil {
|
||||||
|
return affected, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if job.RunID == 0 {
|
if job.RunID == 0 {
|
||||||
var err error
|
var err error
|
||||||
if job, err = GetRunJobByID(ctx, job.ID); err != nil {
|
if job, err = GetRunJobByID(ctx, job.ID); err != nil {
|
||||||
|
@ -215,12 +215,11 @@ func GetRunningTaskByToken(ctx context.Context, token string) (*ActionTask, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask, bool, error) {
|
func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask, bool, error) {
|
||||||
dbCtx, commiter, err := db.TxContext(ctx)
|
ctx, commiter, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
defer commiter.Close()
|
defer commiter.Close()
|
||||||
ctx = dbCtx.WithContext(ctx)
|
|
||||||
|
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
|
105
models/actions/tasks_version.go
Normal file
105
models/actions/tasks_version.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ActionTasksVersion
|
||||||
|
// If both ownerID and repoID is zero, its scope is global.
|
||||||
|
// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currrently).
|
||||||
|
// If ownerID is zero and repoID is not zero, its scope is repo.
|
||||||
|
type ActionTasksVersion struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
OwnerID int64 `xorm:"UNIQUE(owner_repo)"`
|
||||||
|
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo)"`
|
||||||
|
Version int64
|
||||||
|
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
||||||
|
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db.RegisterModel(new(ActionTasksVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTasksVersionByScope(ctx context.Context, ownerID, repoID int64) (int64, error) {
|
||||||
|
var tasksVersion ActionTasksVersion
|
||||||
|
has, err := db.GetEngine(ctx).Where("owner_id = ? AND repo_id = ?", ownerID, repoID).Get(&tasksVersion)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if !has {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return tasksVersion.Version, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertTasksVersion(ctx context.Context, ownerID, repoID int64) (*ActionTasksVersion, error) {
|
||||||
|
tasksVersion := &ActionTasksVersion{
|
||||||
|
OwnerID: ownerID,
|
||||||
|
RepoID: repoID,
|
||||||
|
Version: 1,
|
||||||
|
}
|
||||||
|
if _, err := db.GetEngine(ctx).Insert(tasksVersion); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tasksVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func increaseTasksVersionByScope(ctx context.Context, ownerID, repoID int64) error {
|
||||||
|
result, err := db.GetEngine(ctx).Exec("UPDATE action_tasks_version SET version = version + 1 WHERE owner_id = ? AND repo_id = ?", ownerID, repoID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
affected, err := result.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if affected == 0 {
|
||||||
|
// if update sql does not affect any rows, the database may be broken,
|
||||||
|
// so re-insert the row of version data here.
|
||||||
|
if _, err := insertTasksVersion(ctx, ownerID, repoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error {
|
||||||
|
ctx, commiter, err := db.TxContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer commiter.Close()
|
||||||
|
|
||||||
|
// 1. increase global
|
||||||
|
if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil {
|
||||||
|
log.Error("IncreaseTasksVersionByScope(Global): %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. increase owner
|
||||||
|
if ownerID > 0 {
|
||||||
|
if err := increaseTasksVersionByScope(ctx, ownerID, 0); err != nil {
|
||||||
|
log.Error("IncreaseTasksVersionByScope(Owner): %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. increase repo
|
||||||
|
if repoID > 0 {
|
||||||
|
if err := increaseTasksVersionByScope(ctx, 0, repoID); err != nil {
|
||||||
|
log.Error("IncreaseTasksVersionByScope(Repo): %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commiter.Commit()
|
||||||
|
}
|
@ -515,6 +515,8 @@ var migrations = []Migration{
|
|||||||
NewMigration("Alter Actions Artifact table", v1_21.AlterActionArtifactTable),
|
NewMigration("Alter Actions Artifact table", v1_21.AlterActionArtifactTable),
|
||||||
// v266 -> v267
|
// v266 -> v267
|
||||||
NewMigration("Reduce commit status", v1_21.ReduceCommitStatus),
|
NewMigration("Reduce commit status", v1_21.ReduceCommitStatus),
|
||||||
|
// v267 -> v268
|
||||||
|
NewMigration("Add action_tasks_version table", v1_21.CreateActionTasksVersionTable),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
23
models/migrations/v1_21/v267.go
Normal file
23
models/migrations/v1_21/v267.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_21 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateActionTasksVersionTable(x *xorm.Engine) error {
|
||||||
|
type ActionTasksVersion struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
OwnerID int64 `xorm:"UNIQUE(owner_repo)"`
|
||||||
|
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo)"`
|
||||||
|
Version int64
|
||||||
|
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
||||||
|
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.Sync(new(ActionTasksVersion))
|
||||||
|
}
|
@ -150,11 +150,13 @@ func CloseProvidedListeners() error {
|
|||||||
return returnableError
|
return returnableError
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListener obtains a listener for the local network address. The network must be
|
// DefaultGetListener obtains a listener for the local network address. The network must be
|
||||||
// a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". It
|
// a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". It
|
||||||
// returns an provided net.Listener for the matching network and address, or
|
// returns an provided net.Listener for the matching network and address, or
|
||||||
// creates a new one using net.Listen.
|
// creates a new one using net.Listen. This function can be replaced by changing the
|
||||||
func GetListener(network, address string) (net.Listener, error) {
|
// GetListener variable at the top of this file, for example to listen on an onion service using
|
||||||
|
// github.com/cretz/bine
|
||||||
|
func DefaultGetListener(network, address string) (net.Listener, error) {
|
||||||
// Add a deferral to say that we've tried to grab a listener
|
// Add a deferral to say that we've tried to grab a listener
|
||||||
defer GetManager().InformCleanup()
|
defer GetManager().InformCleanup()
|
||||||
switch network {
|
switch network {
|
||||||
|
@ -9,9 +9,11 @@ package graceful
|
|||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
|
|
||||||
// GetListener obtains a listener for the local network address.
|
// DefaultGetListener obtains a listener for the local network address.
|
||||||
// On windows this is basically just a shim around net.Listen.
|
// On windows this is basically just a shim around net.Listen. This function
|
||||||
func GetListener(network, address string) (net.Listener, error) {
|
// can be replaced by changing the GetListener variable at the top of this file,
|
||||||
|
// for example to listen on an onion service using github.com/cretz/bine
|
||||||
|
func DefaultGetListener(network, address string) (net.Listener, error) {
|
||||||
// Add a deferral to say that we've tried to grab a listener
|
// Add a deferral to say that we've tried to grab a listener
|
||||||
defer GetManager().InformCleanup()
|
defer GetManager().InformCleanup()
|
||||||
|
|
||||||
|
@ -33,6 +33,14 @@ var (
|
|||||||
PerWriteWriteTimeoutKbTime = 10 * time.Second
|
PerWriteWriteTimeoutKbTime = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetListener returns a listener from a GetListener function, which must have the
|
||||||
|
// signature: `func FunctioName(network, address string) (net.Listener, error)`.
|
||||||
|
// This determines the implementation of net.Listener which the server will use.`
|
||||||
|
// It is implemented in this way so that downstreams may specify the type of listener
|
||||||
|
// they want to provide Gitea on by default, such as with a hidden service or a p2p network
|
||||||
|
// No need to worry about "breaking" if there would be a refactoring for the Listeners. No compatibility-guarantee for this mechanism
|
||||||
|
var GetListener = DefaultGetListener
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
|
DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/util/rotatingfilewriter"
|
"code.gitea.io/gitea/modules/util/rotatingfilewriter"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ type WriterFileOption struct {
|
|||||||
|
|
||||||
type eventWriterFile struct {
|
type eventWriterFile struct {
|
||||||
*EventWriterBaseImpl
|
*EventWriterBaseImpl
|
||||||
fileWriter *rotatingfilewriter.RotatingFileWriter
|
fileWriter io.WriteCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ EventWriter = (*eventWriterFile)(nil)
|
var _ EventWriter = (*eventWriterFile)(nil)
|
||||||
@ -37,7 +39,10 @@ func NewEventWriterFile(name string, mode WriterMode) EventWriter {
|
|||||||
CompressionLevel: opt.CompressionLevel,
|
CompressionLevel: opt.CompressionLevel,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// if the log file can't be opened, what should it do? panic/exit? ignore logs? fallback to stderr?
|
||||||
|
// it seems that "fallback to stderr" is slightly better than others ....
|
||||||
FallbackErrorf("unable to open log file %q: %v", opt.FileName, err)
|
FallbackErrorf("unable to open log file %q: %v", opt.FileName, err)
|
||||||
|
w.fileWriter = nopCloser{Writer: LoggerToWriter(FallbackErrorf)}
|
||||||
}
|
}
|
||||||
w.OutputWriteCloser = w.fileWriter
|
w.OutputWriteCloser = w.fileWriter
|
||||||
return w
|
return w
|
||||||
|
@ -640,7 +640,7 @@ update_language_success = Language has been updated.
|
|||||||
update_profile_success = Your profile has been updated.
|
update_profile_success = Your profile has been updated.
|
||||||
change_username = Your username has been changed.
|
change_username = Your username has been changed.
|
||||||
change_username_prompt = Note: username changes also change your account URL.
|
change_username_prompt = Note: username changes also change your account URL.
|
||||||
change_username_redirect_prompt = The old username will redirect until it is claimed.
|
change_username_redirect_prompt = The old username will redirect until someone claims it.
|
||||||
continue = Continue
|
continue = Continue
|
||||||
cancel = Cancel
|
cancel = Cancel
|
||||||
language = Language
|
language = Language
|
||||||
@ -2545,7 +2545,7 @@ settings.visibility.private_shortname = Private
|
|||||||
|
|
||||||
settings.update_settings = Update Settings
|
settings.update_settings = Update Settings
|
||||||
settings.update_setting_success = Organization settings have been updated.
|
settings.update_setting_success = Organization settings have been updated.
|
||||||
settings.change_orgname_prompt = Note: changing the organization name also changes the organization's URL.
|
settings.change_orgname_prompt = Note: Changing the organization name will also change your organization's URL and free the old name.
|
||||||
settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed.
|
settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed.
|
||||||
settings.update_avatar_success = The organization's avatar has been updated.
|
settings.update_avatar_success = The organization's avatar has been updated.
|
||||||
settings.delete = Delete Organization
|
settings.delete = Delete Organization
|
||||||
@ -2627,10 +2627,13 @@ teams.invite.description = Please click the button below to join the team.
|
|||||||
|
|
||||||
[admin]
|
[admin]
|
||||||
dashboard = Dashboard
|
dashboard = Dashboard
|
||||||
|
identity_access = Identity & Access
|
||||||
users = User Accounts
|
users = User Accounts
|
||||||
organizations = Organizations
|
organizations = Organizations
|
||||||
|
assets = Code Assets
|
||||||
repositories = Repositories
|
repositories = Repositories
|
||||||
hooks = Webhooks
|
hooks = Webhooks
|
||||||
|
integrations = Integrations
|
||||||
authentication = Authentication Sources
|
authentication = Authentication Sources
|
||||||
emails = User Emails
|
emails = User Emails
|
||||||
config = Configuration
|
config = Configuration
|
||||||
|
@ -1673,7 +1673,7 @@ pulls.is_empty=As modificações feitas neste ramo já existem no ramo de destin
|
|||||||
pulls.required_status_check_failed=Algumas das verificações obrigatórias não foram bem sucedidas.
|
pulls.required_status_check_failed=Algumas das verificações obrigatórias não foram bem sucedidas.
|
||||||
pulls.required_status_check_missing=Estão faltando algumas verificações necessárias.
|
pulls.required_status_check_missing=Estão faltando algumas verificações necessárias.
|
||||||
pulls.required_status_check_administrator=Uma vez que é administrador, ainda pode realizar a integração deste pedido.
|
pulls.required_status_check_administrator=Uma vez que é administrador, ainda pode realizar a integração deste pedido.
|
||||||
pulls.blocked_by_approvals=Este pedido de integração ainda não tem aprovações suficientes. Já foram concedidas %d de um total de%d aprovações.
|
pulls.blocked_by_approvals=Este pedido de integração ainda não tem aprovações suficientes. Já foram concedidas %d de um total de %d aprovações.
|
||||||
pulls.blocked_by_rejection=Este pedido de integração tem modificações solicitadas por um revisor oficial.
|
pulls.blocked_by_rejection=Este pedido de integração tem modificações solicitadas por um revisor oficial.
|
||||||
pulls.blocked_by_official_review_requests=Este pedido de integração tem pedidos de revisão oficiais.
|
pulls.blocked_by_official_review_requests=Este pedido de integração tem pedidos de revisão oficiais.
|
||||||
pulls.blocked_by_outdated_branch=Este pedido de integração foi bloqueado por ser obsoleto.
|
pulls.blocked_by_outdated_branch=Este pedido de integração foi bloqueado por ser obsoleto.
|
||||||
|
@ -127,20 +127,39 @@ func (s *Service) Declare(
|
|||||||
// FetchTask assigns a task to the runner
|
// FetchTask assigns a task to the runner
|
||||||
func (s *Service) FetchTask(
|
func (s *Service) FetchTask(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
_ *connect.Request[runnerv1.FetchTaskRequest],
|
req *connect.Request[runnerv1.FetchTaskRequest],
|
||||||
) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
||||||
runner := GetRunner(ctx)
|
runner := GetRunner(ctx)
|
||||||
|
|
||||||
var task *runnerv1.Task
|
var task *runnerv1.Task
|
||||||
if t, ok, err := pickTask(ctx, runner); err != nil {
|
tasksVersion := req.Msg.TasksVersion // task version from runner
|
||||||
log.Error("pick task failed: %v", err)
|
latestVersion, err := actions_model.GetTasksVersionByScope(ctx, runner.OwnerID, runner.RepoID)
|
||||||
return nil, status.Errorf(codes.Internal, "pick task: %v", err)
|
if err != nil {
|
||||||
} else if ok {
|
return nil, status.Errorf(codes.Internal, "query tasks version failed: %v", err)
|
||||||
task = t
|
} else if latestVersion == 0 {
|
||||||
|
if err := actions_model.IncreaseTaskVersion(ctx, runner.OwnerID, runner.RepoID); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "fail to increase task version: %v", err)
|
||||||
|
}
|
||||||
|
// if we don't increase the value of `latestVersion` here,
|
||||||
|
// the response of FetchTask will return tasksVersion as zero.
|
||||||
|
// and the runner will treat it as an old version of Gitea.
|
||||||
|
latestVersion++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tasksVersion != latestVersion {
|
||||||
|
// if the task version in request is not equal to the version in db,
|
||||||
|
// it means there may still be some tasks not be assgined.
|
||||||
|
// try to pick a task for the runner that send the request.
|
||||||
|
if t, ok, err := pickTask(ctx, runner); err != nil {
|
||||||
|
log.Error("pick task failed: %v", err)
|
||||||
|
return nil, status.Errorf(codes.Internal, "pick task: %v", err)
|
||||||
|
} else if ok {
|
||||||
|
task = t
|
||||||
|
}
|
||||||
|
}
|
||||||
res := connect.NewResponse(&runnerv1.FetchTaskResponse{
|
res := connect.NewResponse(&runnerv1.FetchTaskResponse{
|
||||||
Task: task,
|
Task: task,
|
||||||
|
TasksVersion: latestVersion,
|
||||||
})
|
})
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func SearchPackages(ctx *context.Context) {
|
|||||||
// EnumeratePackages lists all package names
|
// EnumeratePackages lists all package names
|
||||||
// https://packagist.org/apidoc#list-packages
|
// https://packagist.org/apidoc#list-packages
|
||||||
func EnumeratePackages(ctx *context.Context) {
|
func EnumeratePackages(ctx *context.Context) {
|
||||||
ps, err := packages_model.GetPackagesByType(db.DefaultContext, ctx.Package.Owner.ID, packages_model.TypeComposer)
|
ps, err := packages_model.GetPackagesByType(ctx, ctx.Package.Owner.ID, packages_model.TypeComposer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package conan
|
package conan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
std_ctx "context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -602,69 +603,64 @@ func DeletePackageV2(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeReference, ignoreRecipeRevision bool, pref *conan_module.PackageReference, ignorePackageRevision bool) error {
|
func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeReference, ignoreRecipeRevision bool, pref *conan_module.PackageReference, ignorePackageRevision bool) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
var pd *packages_model.PackageDescriptor
|
||||||
if err != nil {
|
versionDeleted := false
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, apictx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
err := db.WithTx(apictx, func(ctx std_ctx.Context) error {
|
||||||
if err != nil {
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, apictx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
|
||||||
pd, err := packages_model.GetPackageDescriptor(ctx, pv)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
filter := map[string]string{
|
|
||||||
conan_module.PropertyRecipeUser: rref.User,
|
|
||||||
conan_module.PropertyRecipeChannel: rref.Channel,
|
|
||||||
}
|
|
||||||
if !ignoreRecipeRevision {
|
|
||||||
filter[conan_module.PropertyRecipeRevision] = rref.RevisionOrDefault()
|
|
||||||
}
|
|
||||||
if pref != nil {
|
|
||||||
filter[conan_module.PropertyPackageReference] = pref.Reference
|
|
||||||
if !ignorePackageRevision {
|
|
||||||
filter[conan_module.PropertyPackageRevision] = pref.RevisionOrDefault()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
|
pd, err = packages_model.GetPackageDescriptor(ctx, pv)
|
||||||
VersionID: pv.ID,
|
if err != nil {
|
||||||
Properties: filter,
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := map[string]string{
|
||||||
|
conan_module.PropertyRecipeUser: rref.User,
|
||||||
|
conan_module.PropertyRecipeChannel: rref.Channel,
|
||||||
|
}
|
||||||
|
if !ignoreRecipeRevision {
|
||||||
|
filter[conan_module.PropertyRecipeRevision] = rref.RevisionOrDefault()
|
||||||
|
}
|
||||||
|
if pref != nil {
|
||||||
|
filter[conan_module.PropertyPackageReference] = pref.Reference
|
||||||
|
if !ignorePackageRevision {
|
||||||
|
filter[conan_module.PropertyPackageRevision] = pref.RevisionOrDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
|
||||||
|
VersionID: pv.ID,
|
||||||
|
Properties: filter,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(pfs) == 0 {
|
||||||
|
return conan_model.ErrPackageReferenceNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pf := range pfs {
|
||||||
|
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has, err := packages_model.HasVersionFileReferences(ctx, pv.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !has {
|
||||||
|
versionDeleted = true
|
||||||
|
|
||||||
|
return packages_service.DeletePackageVersionAndReferences(ctx, pv)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(pfs) == 0 {
|
|
||||||
return conan_model.ErrPackageReferenceNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pf := range pfs {
|
|
||||||
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
versionDeleted := false
|
|
||||||
has, err := packages_model.HasVersionFileReferences(ctx, pv.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !has {
|
|
||||||
versionDeleted = true
|
|
||||||
|
|
||||||
if err := packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := committer.Commit(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if versionDeleted {
|
if versionDeleted {
|
||||||
notification.NotifyPackageDelete(apictx, apictx.Doer, pd)
|
notification.NotifyPackageDelete(apictx, apictx.Doer, pd)
|
||||||
|
@ -26,19 +26,19 @@ var uploadVersionMutex sync.Mutex
|
|||||||
|
|
||||||
// saveAsPackageBlob creates a package blob from an upload
|
// saveAsPackageBlob creates a package blob from an upload
|
||||||
// The uploaded blob gets stored in a special upload version to link them to the package/image
|
// The uploaded blob gets stored in a special upload version to link them to the package/image
|
||||||
func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pci *packages_service.PackageCreationInfo) (*packages_model.PackageBlob, error) {
|
func saveAsPackageBlob(ctx context.Context, hsr packages_module.HashedSizeReader, pci *packages_service.PackageCreationInfo) (*packages_model.PackageBlob, error) {
|
||||||
pb := packages_service.NewPackageBlob(hsr)
|
pb := packages_service.NewPackageBlob(hsr)
|
||||||
|
|
||||||
exists := false
|
exists := false
|
||||||
|
|
||||||
contentStore := packages_module.NewContentStore()
|
contentStore := packages_module.NewContentStore()
|
||||||
|
|
||||||
uploadVersion, err := getOrCreateUploadVersion(&pci.PackageInfo)
|
uploadVersion, err := getOrCreateUploadVersion(ctx, &pci.PackageInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
err = db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
if err := packages_service.CheckSizeQuotaExceeded(ctx, pci.Creator, pci.Owner, packages_model.TypeContainer, hsr.Size()); err != nil {
|
if err := packages_service.CheckSizeQuotaExceeded(ctx, pci.Creator, pci.Owner, packages_model.TypeContainer, hsr.Size()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -79,24 +79,24 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pci *packages_servi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mountBlob mounts the specific blob to a different package
|
// mountBlob mounts the specific blob to a different package
|
||||||
func mountBlob(pi *packages_service.PackageInfo, pb *packages_model.PackageBlob) error {
|
func mountBlob(ctx context.Context, pi *packages_service.PackageInfo, pb *packages_model.PackageBlob) error {
|
||||||
uploadVersion, err := getOrCreateUploadVersion(pi)
|
uploadVersion, err := getOrCreateUploadVersion(ctx, pi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
return createFileForBlob(ctx, uploadVersion, pb)
|
return createFileForBlob(ctx, uploadVersion, pb)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrCreateUploadVersion(pi *packages_service.PackageInfo) (*packages_model.PackageVersion, error) {
|
func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageInfo) (*packages_model.PackageVersion, error) {
|
||||||
var uploadVersion *packages_model.PackageVersion
|
var uploadVersion *packages_model.PackageVersion
|
||||||
|
|
||||||
// FIXME: Replace usage of mutex with database transaction
|
// FIXME: Replace usage of mutex with database transaction
|
||||||
// https://github.com/go-gitea/gitea/pull/21862
|
// https://github.com/go-gitea/gitea/pull/21862
|
||||||
uploadVersionMutex.Lock()
|
uploadVersionMutex.Lock()
|
||||||
err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
err := db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
created := true
|
created := true
|
||||||
p := &packages_model.Package{
|
p := &packages_model.Package{
|
||||||
OwnerID: pi.Owner.ID,
|
OwnerID: pi.Owner.ID,
|
||||||
@ -172,8 +172,8 @@ func createFileForBlob(ctx context.Context, pv *packages_model.PackageVersion, p
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteBlob(ownerID int64, image, digest string) error {
|
func deleteBlob(ctx context.Context, ownerID int64, image, digest string) error {
|
||||||
return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
pfds, err := container_model.GetContainerBlobs(ctx, &container_model.BlobSearchOptions{
|
pfds, err := container_model.GetContainerBlobs(ctx, &container_model.BlobSearchOptions{
|
||||||
OwnerID: ownerID,
|
OwnerID: ownerID,
|
||||||
Image: image,
|
Image: image,
|
||||||
|
@ -210,7 +210,7 @@ func InitiateUploadBlob(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if accessible {
|
if accessible {
|
||||||
if err := mountBlob(&packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil {
|
if err := mountBlob(ctx, &packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func InitiateUploadBlob(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := saveAsPackageBlob(
|
if _, err := saveAsPackageBlob(ctx,
|
||||||
buf,
|
buf,
|
||||||
&packages_service.PackageCreationInfo{
|
&packages_service.PackageCreationInfo{
|
||||||
PackageInfo: packages_service.PackageInfo{
|
PackageInfo: packages_service.PackageInfo{
|
||||||
@ -384,7 +384,7 @@ func EndUploadBlob(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := saveAsPackageBlob(
|
if _, err := saveAsPackageBlob(ctx,
|
||||||
uploader,
|
uploader,
|
||||||
&packages_service.PackageCreationInfo{
|
&packages_service.PackageCreationInfo{
|
||||||
PackageInfo: packages_service.PackageInfo{
|
PackageInfo: packages_service.PackageInfo{
|
||||||
@ -502,7 +502,7 @@ func DeleteBlob(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := deleteBlob(ctx.Package.Owner.ID, ctx.Params("image"), d); err != nil {
|
if err := deleteBlob(ctx, ctx.Package.Owner.ID, ctx.Params("image"), d); err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -543,7 +543,7 @@ func UploadManifest(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
digest, err := processManifest(mci, buf)
|
digest, err := processManifest(ctx, mci, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var namedError *namedError
|
var namedError *namedError
|
||||||
if errors.As(err, &namedError) {
|
if errors.As(err, &namedError) {
|
||||||
|
@ -50,7 +50,7 @@ type manifestCreationInfo struct {
|
|||||||
Properties map[string]string
|
Properties map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func processManifest(mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) {
|
func processManifest(ctx context.Context, mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) {
|
||||||
var index oci.Index
|
var index oci.Index
|
||||||
if err := json.NewDecoder(buf).Decode(&index); err != nil {
|
if err := json.NewDecoder(buf).Decode(&index); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -72,14 +72,14 @@ func processManifest(mci *manifestCreationInfo, buf *packages_module.HashedBuffe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isImageManifestMediaType(mci.MediaType) {
|
if isImageManifestMediaType(mci.MediaType) {
|
||||||
return processImageManifest(mci, buf)
|
return processImageManifest(ctx, mci, buf)
|
||||||
} else if isImageIndexMediaType(mci.MediaType) {
|
} else if isImageIndexMediaType(mci.MediaType) {
|
||||||
return processImageManifestIndex(mci, buf)
|
return processImageManifestIndex(ctx, mci, buf)
|
||||||
}
|
}
|
||||||
return "", errManifestInvalid
|
return "", errManifestInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func processImageManifest(mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) {
|
func processImageManifest(ctx context.Context, mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) {
|
||||||
manifestDigest := ""
|
manifestDigest := ""
|
||||||
|
|
||||||
err := func() error {
|
err := func() error {
|
||||||
@ -92,7 +92,7 @@ func processImageManifest(mci *manifestCreationInfo, buf *packages_module.Hashed
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ func processImageManifest(mci *manifestCreationInfo, buf *packages_module.Hashed
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := notifyPackageCreate(mci.Creator, pv); err != nil {
|
if err := notifyPackageCreate(ctx, mci.Creator, pv); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ func processImageManifest(mci *manifestCreationInfo, buf *packages_module.Hashed
|
|||||||
return manifestDigest, nil
|
return manifestDigest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) {
|
func processImageManifestIndex(ctx context.Context, mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) {
|
||||||
manifestDigest := ""
|
manifestDigest := ""
|
||||||
|
|
||||||
err := func() error {
|
err := func() error {
|
||||||
@ -209,7 +209,7 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -285,7 +285,7 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := notifyPackageCreate(mci.Creator, pv); err != nil {
|
if err := notifyPackageCreate(ctx, mci.Creator, pv); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,13 +300,13 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H
|
|||||||
return manifestDigest, nil
|
return manifestDigest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func notifyPackageCreate(doer *user_model.User, pv *packages_model.PackageVersion) error {
|
func notifyPackageCreate(ctx context.Context, doer *user_model.User, pv *packages_model.PackageVersion) error {
|
||||||
pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
|
pd, err := packages_model.GetPackageDescriptor(ctx, pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.NotifyPackageCreate(db.DefaultContext, doer, pd)
|
notification.NotifyPackageCreate(ctx, doer, pd)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ package npm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
std_ctx "context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -222,7 +223,7 @@ func UploadPackage(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range npmPackage.DistTags {
|
for _, tag := range npmPackage.DistTags {
|
||||||
if err := setPackageTag(tag, pv, false); err != nil {
|
if err := setPackageTag(ctx, tag, pv, false); err != nil {
|
||||||
if err == errInvalidTagName {
|
if err == errInvalidTagName {
|
||||||
apiError(ctx, http.StatusBadRequest, err)
|
apiError(ctx, http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
@ -345,7 +346,7 @@ func AddPackageTag(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := setPackageTag(ctx.Params("tag"), pv, false); err != nil {
|
if err := setPackageTag(ctx, ctx.Params("tag"), pv, false); err != nil {
|
||||||
if err == errInvalidTagName {
|
if err == errInvalidTagName {
|
||||||
apiError(ctx, http.StatusBadRequest, err)
|
apiError(ctx, http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
@ -366,7 +367,7 @@ func DeletePackageTag(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(pvs) != 0 {
|
if len(pvs) != 0 {
|
||||||
if err := setPackageTag(ctx.Params("tag"), pvs[0], true); err != nil {
|
if err := setPackageTag(ctx, ctx.Params("tag"), pvs[0], true); err != nil {
|
||||||
if err == errInvalidTagName {
|
if err == errInvalidTagName {
|
||||||
apiError(ctx, http.StatusBadRequest, err)
|
apiError(ctx, http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
@ -377,7 +378,7 @@ func DeletePackageTag(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly bool) error {
|
func setPackageTag(ctx std_ctx.Context, tag string, pv *packages_model.PackageVersion, deleteOnly bool) error {
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
return errInvalidTagName
|
return errInvalidTagName
|
||||||
}
|
}
|
||||||
@ -386,47 +387,42 @@ func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly boo
|
|||||||
return errInvalidTagName
|
return errInvalidTagName
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
return db.WithTx(ctx, func(ctx std_ctx.Context) error {
|
||||||
if err != nil {
|
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
|
||||||
return err
|
PackageID: pv.PackageID,
|
||||||
}
|
Properties: map[string]string{
|
||||||
defer committer.Close()
|
npm_module.TagProperty: tag,
|
||||||
|
},
|
||||||
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
|
IsInternal: util.OptionalBoolFalse,
|
||||||
PackageID: pv.PackageID,
|
})
|
||||||
Properties: map[string]string{
|
|
||||||
npm_module.TagProperty: tag,
|
|
||||||
},
|
|
||||||
IsInternal: util.OptionalBoolFalse,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pvs) == 1 {
|
|
||||||
pvps, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeVersion, pvs[0].ID, npm_module.TagProperty)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pvp := range pvps {
|
if len(pvs) == 1 {
|
||||||
if pvp.Value == tag {
|
pvps, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeVersion, pvs[0].ID, npm_module.TagProperty)
|
||||||
if err := packages_model.DeletePropertyByID(ctx, pvp.ID); err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pvp := range pvps {
|
||||||
|
if pvp.Value == tag {
|
||||||
|
if err := packages_model.DeletePropertyByID(ctx, pvp.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !deleteOnly {
|
if !deleteOnly {
|
||||||
_, err = packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, npm_module.TagProperty, tag)
|
_, err = packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, npm_module.TagProperty, tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return nil
|
||||||
|
})
|
||||||
return committer.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func PackageSearch(ctx *context.Context) {
|
func PackageSearch(ctx *context.Context) {
|
||||||
|
@ -312,6 +312,8 @@ func DeleteUser(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
// "403":
|
// "403":
|
||||||
// "$ref": "#/responses/forbidden"
|
// "$ref": "#/responses/forbidden"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/notFound"
|
||||||
// "422":
|
// "422":
|
||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
@ -31,7 +30,7 @@ func appendPrivateInformation(ctx std_ctx.Context, apiKey *api.PublicKey, key *a
|
|||||||
if defaultUser.ID == key.OwnerID {
|
if defaultUser.ID == key.OwnerID {
|
||||||
apiKey.Owner = convert.ToUser(ctx, defaultUser, defaultUser)
|
apiKey.Owner = convert.ToUser(ctx, defaultUser, defaultUser)
|
||||||
} else {
|
} else {
|
||||||
user, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID)
|
user, err := user_model.GetUserByID(ctx, key.OwnerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiKey, err
|
return apiKey, err
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ func Packages(ctx *context.Context) {
|
|||||||
|
|
||||||
// DeletePackageVersion deletes a package version
|
// DeletePackageVersion deletes a package version
|
||||||
func DeletePackageVersion(ctx *context.Context) {
|
func DeletePackageVersion(ctx *context.Context) {
|
||||||
pv, err := packages_model.GetVersionByID(db.DefaultContext, ctx.FormInt64("id"))
|
pv, err := packages_model.GetVersionByID(ctx, ctx.FormInt64("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetRepositoryByID", err)
|
ctx.ServerError("GetRepositoryByID", err)
|
||||||
return
|
return
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package healthcheck
|
package healthcheck
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
@ -72,7 +73,7 @@ func Check(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
statuses := make([]status, 0)
|
statuses := make([]status, 0)
|
||||||
if setting.InstallLock {
|
if setting.InstallLock {
|
||||||
statuses = append(statuses, checkDatabase(rsp.Checks))
|
statuses = append(statuses, checkDatabase(r.Context(), rsp.Checks))
|
||||||
statuses = append(statuses, checkCache(rsp.Checks))
|
statuses = append(statuses, checkCache(rsp.Checks))
|
||||||
}
|
}
|
||||||
for _, s := range statuses {
|
for _, s := range statuses {
|
||||||
@ -89,9 +90,9 @@ func Check(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// database checks gitea database status
|
// database checks gitea database status
|
||||||
func checkDatabase(checks checks) status {
|
func checkDatabase(ctx context.Context, checks checks) status {
|
||||||
st := componentStatus{}
|
st := componentStatus{}
|
||||||
if err := db.GetEngine(db.DefaultContext).Ping(); err != nil {
|
if err := db.GetEngine(ctx).Ping(); err != nil {
|
||||||
st.Status = fail
|
st.Status = fail
|
||||||
st.Time = getCheckTime()
|
st.Time = getCheckTime()
|
||||||
log.Error("database ping failed with error: %v", err)
|
log.Error("database ping failed with error: %v", err)
|
||||||
|
@ -198,7 +198,7 @@ type fileInfo struct {
|
|||||||
st typesniffer.SniffedType
|
st typesniffer.SniffedType
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileReader(repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileInfo, error) {
|
func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileInfo, error) {
|
||||||
dataRc, err := blob.DataAsync()
|
dataRc, err := blob.DataAsync()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
@ -221,7 +221,7 @@ func getFileReader(repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileIn
|
|||||||
return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil
|
return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := git_model.GetLFSMetaObjectByOid(db.DefaultContext, repoID, pointer.Oid)
|
meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid)
|
||||||
if err != nil && err != git_model.ErrLFSObjectNotExist { // fallback to plain file
|
if err != nil && err != git_model.ErrLFSObjectNotExist { // fallback to plain file
|
||||||
return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil
|
return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr
|
|||||||
ctx.Data["ReadmeExist"] = true
|
ctx.Data["ReadmeExist"] = true
|
||||||
ctx.Data["FileIsSymlink"] = readmeFile.IsLink()
|
ctx.Data["FileIsSymlink"] = readmeFile.IsLink()
|
||||||
|
|
||||||
buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, target.Blob())
|
buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, target.Blob())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("getFileReader", err)
|
ctx.ServerError("getFileReader", err)
|
||||||
return
|
return
|
||||||
@ -328,7 +328,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
|||||||
ctx.Data["IsViewFile"] = true
|
ctx.Data["IsViewFile"] = true
|
||||||
ctx.Data["HideRepoInfo"] = true
|
ctx.Data["HideRepoInfo"] = true
|
||||||
blob := entry.Blob()
|
blob := entry.Blob()
|
||||||
buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, blob)
|
buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("getFileReader", err)
|
ctx.ServerError("getFileReader", err)
|
||||||
return
|
return
|
||||||
|
@ -14,10 +14,10 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/sync"
|
"code.gitea.io/gitea/modules/sync"
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
|
|
||||||
"github.com/gogs/cron"
|
"github.com/go-co-op/gocron"
|
||||||
)
|
)
|
||||||
|
|
||||||
var c = cron.New()
|
var scheduler = gocron.NewScheduler(time.Local)
|
||||||
|
|
||||||
// Prevent duplicate running tasks.
|
// Prevent duplicate running tasks.
|
||||||
var taskStatusTable = sync.NewStatusTable()
|
var taskStatusTable = sync.NewStatusTable()
|
||||||
@ -39,11 +39,11 @@ func NewContext(original context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Start()
|
scheduler.StartAsync()
|
||||||
started = true
|
started = true
|
||||||
lock.Unlock()
|
lock.Unlock()
|
||||||
graceful.GetManager().RunAtShutdown(context.Background(), func() {
|
graceful.GetManager().RunAtShutdown(context.Background(), func() {
|
||||||
c.Stop()
|
scheduler.Stop()
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
started = false
|
started = false
|
||||||
lock.Unlock()
|
lock.Unlock()
|
||||||
@ -77,13 +77,20 @@ type TaskTable []*TaskTableRow
|
|||||||
|
|
||||||
// ListTasks returns all running cron tasks.
|
// ListTasks returns all running cron tasks.
|
||||||
func ListTasks() TaskTable {
|
func ListTasks() TaskTable {
|
||||||
entries := c.Entries()
|
jobs := scheduler.Jobs()
|
||||||
eMap := map[string]*cron.Entry{}
|
jobMap := map[string]*gocron.Job{}
|
||||||
for _, e := range entries {
|
for _, job := range jobs {
|
||||||
eMap[e.Description] = e
|
// the first tag is the task name
|
||||||
|
tags := job.Tags()
|
||||||
|
if len(tags) == 0 { // should never happen
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
jobMap[job.Tags()[0]] = job
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
|
|
||||||
tTable := make([]*TaskTableRow, 0, len(tasks))
|
tTable := make([]*TaskTableRow, 0, len(tasks))
|
||||||
for _, task := range tasks {
|
for _, task := range tasks {
|
||||||
spec := "-"
|
spec := "-"
|
||||||
@ -91,10 +98,13 @@ func ListTasks() TaskTable {
|
|||||||
next time.Time
|
next time.Time
|
||||||
prev time.Time
|
prev time.Time
|
||||||
)
|
)
|
||||||
if e, ok := eMap[task.Name]; ok {
|
if e, ok := jobMap[task.Name]; ok {
|
||||||
spec = e.Spec
|
tags := e.Tags()
|
||||||
next = e.Next
|
if len(tags) > 1 {
|
||||||
prev = e.Prev
|
spec = tags[1] // the second tag is the task spec
|
||||||
|
}
|
||||||
|
next = e.NextRun()
|
||||||
|
prev = e.PreviousRun()
|
||||||
}
|
}
|
||||||
task.lock.Lock()
|
task.lock.Lock()
|
||||||
tTable = append(tTable, &TaskTableRow{
|
tTable = append(tTable, &TaskTableRow{
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -176,8 +177,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo
|
|||||||
|
|
||||||
if config.IsEnabled() {
|
if config.IsEnabled() {
|
||||||
// We cannot use the entry return as there is no way to lock it
|
// We cannot use the entry return as there is no way to lock it
|
||||||
if _, err = c.AddJob(name, config.GetSchedule(), task); err != nil {
|
if err := addTaskToScheduler(task); err != nil {
|
||||||
log.Error("Unable to register cron task with name: %s Error: %v", name, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,3 +199,21 @@ func RegisterTaskFatal(name string, config Config, fun func(context.Context, *us
|
|||||||
log.Fatal("Unable to register cron task %s Error: %v", name, err)
|
log.Fatal("Unable to register cron task %s Error: %v", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addTaskToScheduler(task *Task) error {
|
||||||
|
tags := []string{task.Name, task.config.GetSchedule()} // name and schedule can't be get from job, so we add them as tag
|
||||||
|
if scheduleHasSeconds(task.config.GetSchedule()) {
|
||||||
|
scheduler = scheduler.CronWithSeconds(task.config.GetSchedule())
|
||||||
|
} else {
|
||||||
|
scheduler = scheduler.Cron(task.config.GetSchedule())
|
||||||
|
}
|
||||||
|
if _, err := scheduler.Tag(tags...).Do(task.Run); err != nil {
|
||||||
|
log.Error("Unable to register cron task with name: %s Error: %v", task.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scheduleHasSeconds(schedule string) bool {
|
||||||
|
return len(strings.Fields(schedule)) >= 6
|
||||||
|
}
|
||||||
|
61
services/cron/tasks_test.go
Normal file
61
services/cron/tasks_test.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddTaskToScheduler(t *testing.T) {
|
||||||
|
assert.Len(t, scheduler.Jobs(), 0)
|
||||||
|
defer scheduler.Clear()
|
||||||
|
|
||||||
|
// no seconds
|
||||||
|
err := addTaskToScheduler(&Task{
|
||||||
|
Name: "task 1",
|
||||||
|
config: &BaseConfig{
|
||||||
|
Schedule: "5 4 * * *",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, scheduler.Jobs(), 1)
|
||||||
|
assert.Equal(t, "task 1", scheduler.Jobs()[0].Tags()[0])
|
||||||
|
assert.Equal(t, "5 4 * * *", scheduler.Jobs()[0].Tags()[1])
|
||||||
|
|
||||||
|
// with seconds
|
||||||
|
err = addTaskToScheduler(&Task{
|
||||||
|
Name: "task 2",
|
||||||
|
config: &BaseConfig{
|
||||||
|
Schedule: "30 5 4 * * *",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, scheduler.Jobs(), 2)
|
||||||
|
assert.Equal(t, "task 2", scheduler.Jobs()[1].Tags()[0])
|
||||||
|
assert.Equal(t, "30 5 4 * * *", scheduler.Jobs()[1].Tags()[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScheduleHasSeconds(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
schedule string
|
||||||
|
hasSecond bool
|
||||||
|
}{
|
||||||
|
{"* * * * * *", true},
|
||||||
|
{"* * * * *", false},
|
||||||
|
{"5 4 * * *", false},
|
||||||
|
{"5 4 * * *", false},
|
||||||
|
{"5,8 4 * * *", false},
|
||||||
|
{"* * * * * *", true},
|
||||||
|
{"5,8 4 * * *", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
assert.Equal(t, test.hasSecond, scheduleHasSeconds(test.schedule))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -4,35 +4,60 @@
|
|||||||
<a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/admin">
|
<a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/admin">
|
||||||
{{.locale.Tr "admin.dashboard"}}
|
{{.locale.Tr "admin.dashboard"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminUsers}}active {{end}}item" href="{{AppSubUrl}}/admin/users">
|
<details class="item toggleable-item" {{if or .PageIsAdminUsers .PageIsAdminEmails .PageIsAdminOrganizations .PageIsAdminAuthentications}}open{{end}}>
|
||||||
{{.locale.Tr "admin.users"}}
|
<summary>{{.locale.Tr "admin.identity_access"}}</summary>
|
||||||
</a>
|
<div class="menu">
|
||||||
<a class="{{if .PageIsAdminOrganizations}}active {{end}}item" href="{{AppSubUrl}}/admin/orgs">
|
<a class="{{if .PageIsAdminAuthentications}}active {{end}}item" href="{{AppSubUrl}}/admin/auths">
|
||||||
{{.locale.Tr "admin.organizations"}}
|
{{.locale.Tr "admin.authentication"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminRepositories}}active {{end}}item" href="{{AppSubUrl}}/admin/repos">
|
<a class="{{if .PageIsAdminOrganizations}}active {{end}}item" href="{{AppSubUrl}}/admin/orgs">
|
||||||
{{.locale.Tr "admin.repositories"}}
|
{{.locale.Tr "admin.organizations"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .EnablePackages}}
|
<a class="{{if .PageIsAdminUsers}}active {{end}}item" href="{{AppSubUrl}}/admin/users">
|
||||||
<a class="{{if .PageIsAdminPackages}}active {{end}}item" href="{{AppSubUrl}}/admin/packages">
|
{{.locale.Tr "admin.users"}}
|
||||||
{{.locale.Tr "packages.title"}}
|
</a>
|
||||||
</a>
|
<a class="{{if .PageIsAdminEmails}}active {{end}}item" href="{{AppSubUrl}}/admin/emails">
|
||||||
{{end}}
|
{{.locale.Tr "admin.emails"}}
|
||||||
{{if not DisableWebhooks}}
|
</a>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<details class="item toggleable-item" {{if or .PageIsAdminRepositories (and .EnablePackages .PageIsAdminPackages)}}open{{end}}>
|
||||||
|
<summary>{{.locale.Tr "admin.assets"}}</summary>
|
||||||
|
<div class="menu">
|
||||||
|
{{if .EnablePackages}}
|
||||||
|
<a class="{{if .PageIsAdminPackages}}active {{end}}item" href="{{AppSubUrl}}/admin/packages">
|
||||||
|
{{.locale.Tr "packages.title"}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
<a class="{{if .PageIsAdminRepositories}}active {{end}}item" href="{{AppSubUrl}}/admin/repos">
|
||||||
|
{{.locale.Tr "admin.repositories"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<!-- Webhooks and OAuth can be both disabled here, so add this if statement to display different ui -->
|
||||||
|
{{if and (not DisableWebhooks) .EnableOAuth2}}
|
||||||
|
<details class="item toggleable-item" {{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks .PageIsAdminApplications}}open{{end}}>
|
||||||
|
<summary>{{.locale.Tr "admin.integrations"}}</summary>
|
||||||
|
<div class="menu">
|
||||||
|
<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/admin/applications">
|
||||||
|
{{.locale.Tr "settings.applications"}}
|
||||||
|
</a>
|
||||||
|
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/admin/hooks">
|
||||||
|
{{.locale.Tr "admin.hooks"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
{{else}}
|
||||||
|
{{if not DisableWebhooks}}
|
||||||
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/admin/hooks">
|
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/admin/hooks">
|
||||||
{{.locale.Tr "admin.hooks"}}
|
{{.locale.Tr "admin.hooks"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsAdminAuthentications}}active {{end}}item" href="{{AppSubUrl}}/admin/auths">
|
{{if .EnableOAuth2}}
|
||||||
{{.locale.Tr "admin.authentication"}}
|
<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/admin/applications">
|
||||||
</a>
|
{{.locale.Tr "settings.applications"}}
|
||||||
<a class="{{if .PageIsAdminEmails}}active {{end}}item" href="{{AppSubUrl}}/admin/emails">
|
</a>
|
||||||
{{.locale.Tr "admin.emails"}}
|
{{end}}
|
||||||
</a>
|
|
||||||
{{if .EnableOAuth2}}
|
|
||||||
<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/admin/applications">
|
|
||||||
{{.locale.Tr "settings.applications"}}
|
|
||||||
</a>
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .EnableActions}}
|
{{if .EnableActions}}
|
||||||
<details class="item toggleable-item" {{if .PageIsSharedSettingsRunners}}open{{end}}>
|
<details class="item toggleable-item" {{if .PageIsSharedSettingsRunners}}open{{end}}>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
{{$referenceUrl = printf "%s/files#%s" .ctxData.Issue.Link .item.HashTag}}
|
{{$referenceUrl = printf "%s/files#%s" .ctxData.Issue.Link .item.HashTag}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="item context js-aria-clickable" data-clipboard-text-type="url" data-clipboard-text="{{AppSubUrl}}{{$referenceUrl}}">{{.ctxData.locale.Tr "repo.issues.context.copy_link"}}</div>
|
<div class="item context js-aria-clickable" data-clipboard-text-type="url" data-clipboard-text="{{$referenceUrl}}">{{.ctxData.locale.Tr "repo.issues.context.copy_link"}}</div>
|
||||||
<div class="item context js-aria-clickable quote-reply {{if .diff}}quote-reply-diff{{end}}" data-target="{{.item.HashTag}}-raw">{{.ctxData.locale.Tr "repo.issues.context.quote_reply"}}</div>
|
<div class="item context js-aria-clickable quote-reply {{if .diff}}quote-reply-diff{{end}}" data-target="{{.item.HashTag}}-raw">{{.ctxData.locale.Tr "repo.issues.context.quote_reply"}}</div>
|
||||||
{{if not .ctxData.UnitIssuesGlobalDisabled}}
|
{{if not .ctxData.UnitIssuesGlobalDisabled}}
|
||||||
<div class="item context js-aria-clickable reference-issue" data-target="{{.item.HashTag}}-raw" data-modal="#reference-issue-modal" data-poster="{{.item.Poster.GetDisplayName}}" data-poster-username="{{.item.Poster.Name}}" data-reference="{{$referenceUrl}}">{{.ctxData.locale.Tr "repo.issues.context.reference_issue"}}</div>
|
<div class="item context js-aria-clickable reference-issue" data-target="{{.item.HashTag}}-raw" data-modal="#reference-issue-modal" data-poster="{{.item.Poster.GetDisplayName}}" data-poster-username="{{.item.Poster.Name}}" data-reference="{{$referenceUrl}}">{{.ctxData.locale.Tr "repo.issues.context.reference_issue"}}</div>
|
||||||
|
3
templates/swagger/v1_json.tmpl
generated
3
templates/swagger/v1_json.tmpl
generated
@ -620,6 +620,9 @@
|
|||||||
"403": {
|
"403": {
|
||||||
"$ref": "#/responses/forbidden"
|
"$ref": "#/responses/forbidden"
|
||||||
},
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/notFound"
|
||||||
|
},
|
||||||
"422": {
|
"422": {
|
||||||
"$ref": "#/responses/validationError"
|
"$ref": "#/responses/validationError"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user