mirror of
https://github.com/go-gitea/gitea
synced 2026-02-08 00:50:53 +00:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ceb78caad | ||
|
|
4dccac3dbf | ||
|
|
73e70f3c44 | ||
|
|
499257d81e | ||
|
|
84fa30e3d5 | ||
|
|
f1a0b64109 | ||
|
|
bfdbc626cb | ||
|
|
3abbf5fc21 | ||
|
|
d9d3f5234e | ||
|
|
7d7ba76c08 | ||
|
|
e76b3f72b2 | ||
|
|
4bc6bfb476 | ||
|
|
5999349ce7 | ||
|
|
e301e26d7a | ||
|
|
d2efd2bf73 | ||
|
|
89297c9355 | ||
|
|
d2328c4051 | ||
|
|
af5d66b341 | ||
|
|
912a418920 | ||
|
|
cc7a4f17e0 | ||
|
|
5f82011b7c | ||
|
|
1bbbeb24ef | ||
|
|
1254a8271e | ||
|
|
ef3e3afc05 | ||
|
|
b1094ff28c | ||
|
|
8044d87c18 | ||
|
|
1b8e36587e | ||
|
|
a2f52f3561 | ||
|
|
65de747b13 | ||
|
|
7e86dffc35 | ||
|
|
7297cceda7 | ||
|
|
077160b838 | ||
|
|
da4448421e | ||
|
|
5ccb626cda | ||
|
|
b00f7c3c54 | ||
|
|
51fd730147 | ||
|
|
7117355169 | ||
|
|
d5f2c9d74d | ||
|
|
95c2cb4b79 | ||
|
|
7d717e22a8 | ||
|
|
dc66ceadac | ||
|
|
8cd5483e8a | ||
|
|
2e6e5bc9c9 | ||
|
|
f134229bf2 | ||
|
|
3d3c740636 | ||
|
|
c4f569b9a5 | ||
|
|
03b6e7900b | ||
|
|
463e144d97 | ||
|
|
2b32f8b95f | ||
|
|
94fbd44bac | ||
|
|
494e373292 | ||
|
|
10f93995e9 | ||
|
|
67a73dd05f | ||
|
|
893c97dd71 |
+8
-8
@@ -1162,7 +1162,7 @@ steps:
|
||||
pull: always
|
||||
settings:
|
||||
auto_tag: false
|
||||
tags: dev-linux-amd64
|
||||
tags: nightly-linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1184,7 +1184,7 @@ steps:
|
||||
settings:
|
||||
dockerfile: Dockerfile.rootless
|
||||
auto_tag: false
|
||||
tags: dev-linux-amd64-rootless
|
||||
tags: nightly-linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1233,7 +1233,7 @@ steps:
|
||||
pull: always
|
||||
settings:
|
||||
auto_tag: false
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64
|
||||
tags: ${DRONE_BRANCH##release/v}-nightly-linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1255,7 +1255,7 @@ steps:
|
||||
settings:
|
||||
dockerfile: Dockerfile.rootless
|
||||
auto_tag: false
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64-rootless
|
||||
tags: ${DRONE_BRANCH##release/v}-nightlf-linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1487,7 +1487,7 @@ steps:
|
||||
pull: always
|
||||
settings:
|
||||
auto_tag: false
|
||||
tags: dev-linux-arm64
|
||||
tags: nightly-linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1509,7 +1509,7 @@ steps:
|
||||
settings:
|
||||
dockerfile: Dockerfile.rootless
|
||||
auto_tag: false
|
||||
tags: dev-linux-arm64-rootless
|
||||
tags: nightly-linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1558,7 +1558,7 @@ steps:
|
||||
pull: always
|
||||
settings:
|
||||
auto_tag: false
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64
|
||||
tags: ${DRONE_BRANCH##release/v}-nightly-linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1580,7 +1580,7 @@ steps:
|
||||
settings:
|
||||
dockerfile: Dockerfile.rootless
|
||||
auto_tag: false
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64-rootless
|
||||
tags: ${DRONE_BRANCH##release/v}-nightly-linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
|
||||
@@ -4,6 +4,66 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.19.3](https://github.com/go-gitea/gitea/releases/tag/1.19.3) - 2023-05-03
|
||||
|
||||
* SECURITY
|
||||
* Use golang 1.20.4 to fix CVE-2023-24539, CVE-2023-24540, and CVE-2023-29400
|
||||
* ENHANCEMENTS
|
||||
* Enable whitespace rendering on selection in Monaco (#24444) (#24485)
|
||||
* Improve milestone filter on issues page (#22423) (#24440)
|
||||
* BUGFIXES
|
||||
* Fix api error message if fork exists (#24487) (#24493)
|
||||
* Fix user-cards format (#24428) (#24431)
|
||||
* Fix incorrect CurrentUser check for docker rootless (#24435)
|
||||
* Getting the tag list does not require being signed in (#24413) (#24416)
|
||||
|
||||
## [1.19.2](https://github.com/go-gitea/gitea/releases/tag/1.19.2) - 2023-04-26
|
||||
|
||||
* SECURITY
|
||||
* Require repo scope for PATs for private repos and basic authentication (#24362) (#24364)
|
||||
* Only delete secrets belonging to its owner (#24284) (#24286)
|
||||
* API
|
||||
* Fix typo in API route (#24310) (#24332)
|
||||
* Fix access token issue on some public endpoints (#24194) (#24259)
|
||||
* ENHANCEMENTS
|
||||
* Fix broken clone script on an empty archived repo (#24339) (#24348)
|
||||
* Fix Monaco IOS keyboard button (#24341) (#24347)
|
||||
* Don't set meta `theme-color` by default (#24340) (#24346)
|
||||
* Wrap too long push mirror addresses (#21120) (#24334)
|
||||
* Add --font-weight-bold and set previous bold to 601 (#24307) (#24331)
|
||||
* Unify nightly naming across binaries and docker images (#24116) (#24308)
|
||||
* Fix footer display (#24251) (#24269)
|
||||
* Fix label color, fix divider in dropdown (#24215) (#24244)
|
||||
* Vertical widths of containers removed (#24184) (#24211)
|
||||
* Use correct locale key for forks page (#24172) (#24175)
|
||||
* Sort repo topic labels by name (#24123) (#24153)
|
||||
* Highlight selected file in the PR file tree (#23947) (#24126)
|
||||
* BUGFIXES
|
||||
* Fix auth check bug (#24382) (#24387)
|
||||
* Add tags list for repos whose release setting is disabled (#23465) (#24369)
|
||||
* Fix wrong error info in RepoRefForAPI (#24344) (#24351)
|
||||
* Fix no edit/close/delete button in org repo project view page (#24349)
|
||||
* Respect the REGISTER_MANUAL_CONFIRM setting when registering via OIDC (#24035) (#24333)
|
||||
* Remove org users who belong to no teams (#24247) (#24313)
|
||||
* Fix bug when deleting wiki with no code write permission (#24274) (#24295)
|
||||
* Handle canceled workflow as a warning instead of a fail (#24282) (#24292)
|
||||
* Load reviewer for comments when dismissing a review (#24281) (#24288)
|
||||
* Show commit history for closed/merged PRs (#24238) (#24261)
|
||||
* Fix owner team access mode value in team_unit table (#24224)
|
||||
* Fix issue attachment handling (#24202) (#24221)
|
||||
* Fix incorrect CORS default values (#24206) (#24217)
|
||||
* Fix template error in pull request with deleted head repo (#24192) (#24216)
|
||||
* Don't list root repository on compare page if pulls not allowed (#24183) (#24210)
|
||||
* Fix calReleaseNumCommitsBehind (#24148) (#24197)
|
||||
* Fix Org edit page bugs: renaming detection, maxlength (#24161) (#24171)
|
||||
* Update redis library to support redis v7 (#24114) (#24156)
|
||||
* Use 1.18's aria role for dropdown menus (#24144) (#24155)
|
||||
* Fix 2-dot direct compare to use the right base commit (#24133) (#24150)
|
||||
* Fix incorrect server error content in RunnersList (#24118) (#24121)
|
||||
* Fix mismatch between hook events and github event types (#24048) (#24091)
|
||||
* BUILD
|
||||
* Support converting varchar to nvarchar for mssql database (#24105) (#24168)
|
||||
|
||||
## [1.19.1](https://github.com/go-gitea/gitea/releases/tag/v1.19.1) - 2023-04-12
|
||||
|
||||
* BREAKING
|
||||
|
||||
@@ -97,6 +97,11 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
# if version = "main" then update version to "nightly"
|
||||
ifeq ($(VERSION),main)
|
||||
VERSION := main-nightly
|
||||
endif
|
||||
|
||||
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
||||
|
||||
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
||||
|
||||
Generated
+5
-5
File diff suppressed because one or more lines are too long
+16
-11
@@ -17,7 +17,7 @@ import (
|
||||
var CmdConvert = cli.Command{
|
||||
Name: "convert",
|
||||
Usage: "Convert the database",
|
||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar",
|
||||
Action: runConvert,
|
||||
}
|
||||
|
||||
@@ -35,17 +35,22 @@ func runConvert(ctx *cli.Context) error {
|
||||
log.Info("Log path: %s", setting.Log.RootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
|
||||
if !setting.Database.Type.IsMySQL() {
|
||||
fmt.Println("This command can only be used with a MySQL database")
|
||||
return nil
|
||||
switch {
|
||||
case setting.Database.Type.IsMySQL():
|
||||
if err := db.ConvertUtf8ToUtf8mb4(); err != nil {
|
||||
log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err)
|
||||
return err
|
||||
}
|
||||
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
||||
case setting.Database.Type.IsMSSQL():
|
||||
if err := db.ConvertVarcharToNVarchar(); err != nil {
|
||||
log.Fatal("Failed to convert database from varchar to nvarchar: %v", err)
|
||||
return err
|
||||
}
|
||||
fmt.Println("Converted successfully, please confirm your database's all columns character is NVARCHAR now")
|
||||
default:
|
||||
fmt.Println("This command can only be used with a MySQL or MSSQL database")
|
||||
}
|
||||
|
||||
if err := db.ConvertUtf8ToUtf8mb4(); err != nil {
|
||||
log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1191,10 +1191,9 @@ ROUTER = console
|
||||
;; Number of line of codes shown for a code comment
|
||||
;CODE_COMMENT_LINES = 4
|
||||
;;
|
||||
;; Value of `theme-color` meta tag, used by Android >= 5.0
|
||||
;; An invalid color like "none" or "disable" will have the default style
|
||||
;; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
|
||||
;THEME_COLOR_META_TAG = `#6cc644`
|
||||
;; Value of `theme-color` meta tag, used by some mobile browers for chrome and
|
||||
;; out-of-viewport areas. Default is unset which uses body color.
|
||||
;THEME_COLOR_META_TAG =
|
||||
;;
|
||||
;; Max size of files to be displayed (default is 8MiB)
|
||||
;MAX_DISPLAY_FILE_SIZE = 8388608
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-rootless
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-rootless
|
||||
{{#if build.tags}}
|
||||
{{#unless (contains "-rc" build.tag)}}
|
||||
tags:
|
||||
@@ -10,12 +10,12 @@ tags:
|
||||
{{/if}}
|
||||
manifests:
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64-rootless
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-amd64-rootless
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64-rootless
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-arm64-rootless
|
||||
platform:
|
||||
architecture: arm64
|
||||
os: linux
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}
|
||||
{{#if build.tags}}
|
||||
{{#unless (contains "-rc" build.tag)}}
|
||||
tags:
|
||||
@@ -10,12 +10,12 @@ tags:
|
||||
{{/if}}
|
||||
manifests:
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-amd64
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-arm64
|
||||
platform:
|
||||
architecture: arm64
|
||||
os: linux
|
||||
|
||||
@@ -220,7 +220,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
- `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page.
|
||||
- `THEMES`: **auto,gitea,arc-green**: All available themes. Allow users select personalized themes.
|
||||
regardless of the value of `DEFAULT_THEME`.
|
||||
- `THEME_COLOR_META_TAG`: **#6cc644**: Value of `theme-color` meta tag, used by Android >= 5.0. An invalid color like "none" or "disable" will have the default style. More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
|
||||
- `THEME_COLOR_META_TAG`: **\<empty\>**: Value of `theme-color` meta tag, used by some mobile browers for chrome and out-of-viewport areas. Default is unset which uses body color.
|
||||
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
|
||||
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
|
||||
Values can be emoji alias (:smile:) or a unicode emoji.
|
||||
|
||||
@@ -44,7 +44,6 @@ require (
|
||||
github.com/go-git/go-billy/v5 v5.4.1
|
||||
github.com/go-git/go-git/v5 v5.5.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/go-sql-driver/mysql v1.7.0
|
||||
github.com/go-swagger/go-swagger v0.30.3
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.8.1
|
||||
@@ -88,8 +87,9 @@ require (
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.1.1
|
||||
github.com/sergi/go-diff v1.2.0
|
||||
github.com/redis/go-redis/v9 v9.0.3
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.2.0
|
||||
github.com/sergi/go-diff v1.3.1
|
||||
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
@@ -155,7 +155,7 @@ require (
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudflare/circl v1.2.0 // indirect
|
||||
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
|
||||
github.com/couchbase/gomemcached v0.1.2 // indirect
|
||||
@@ -230,6 +230,8 @@ require (
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/gomega v1.18.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
@@ -285,7 +287,7 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
|
||||
|
||||
replace github.com/blevesearch/zapx/v15 v15.3.6 => github.com/zeripath/zapx/v15 v15.3.6-alignment-fix
|
||||
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.243.3-0.20230407083103-5c4a96bcb797
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.243.4
|
||||
|
||||
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsi
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||
gitea.com/gitea/act v0.243.3-0.20230407083103-5c4a96bcb797 h1:QdQ+pHxpbIi2qsgZbYVxqYV7trfW3P5M/T4AfpoM7iw=
|
||||
gitea.com/gitea/act v0.243.3-0.20230407083103-5c4a96bcb797/go.mod h1:mabw6AZAiDgxGlK83orWLrNERSPvgBJzEUS3S7u2bHI=
|
||||
gitea.com/gitea/act v0.243.4 h1:MuBHBLCJfpa6mzwwvs4xqQynrSP2RRzpHpWfTV16PmI=
|
||||
gitea.com/gitea/act v0.243.4/go.mod h1:mabw6AZAiDgxGlK83orWLrNERSPvgBJzEUS3S7u2bHI=
|
||||
gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681 h1:MMSPgnVULVwV9kEBgvyEUhC9v/uviZ55hPJEMjpbNR4=
|
||||
gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc=
|
||||
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0=
|
||||
@@ -229,6 +229,8 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
|
||||
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
|
||||
github.com/bufbuild/connect-go v1.3.1 h1:doJP6Q8Ypg6haUT2IAZJPWHUN9rAUp+F9MfK7yhu1zs=
|
||||
github.com/bufbuild/connect-go v1.3.1/go.mod h1:9iNvh/NOsfhNBUH5CtvXeVUskQO1xsrEviH7ZArwZ3I=
|
||||
github.com/buildkite/terminal-to-html/v3 v3.7.0 h1:chdLUSpiOj/A4v3dzxyOqixXI6aw7IDA6Dk77FXsvNU=
|
||||
@@ -244,8 +246,9 @@ github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/
|
||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chi-middleware/proxy v1.1.1 h1:4HaXUp8o2+bhHr1OhVy+VjN0+L7/07JDcn6v7YrTjrQ=
|
||||
github.com/chi-middleware/proxy v1.1.1/go.mod h1:jQwMEJct2tz9VmtCELxvnXoMfa+SOdikvbVJVHv/M+0=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
@@ -463,8 +466,6 @@ github.com/go-openapi/validate v0.22.0 h1:b0QecH6VslW/TxtpKgzpO1SNG7GU2FsaqKdP1E
|
||||
github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
|
||||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
@@ -475,6 +476,7 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP
|
||||
github.com/go-swagger/go-swagger v0.30.3 h1:HuzvdMRed/9Q8vmzVcfNBQByZVtT79DNZxZ18OprdoI=
|
||||
github.com/go-swagger/go-swagger v0.30.3/go.mod h1:neDPes8r8PCz2JPvHRDj8BTULLh4VJUt7n6MpQqxhHM=
|
||||
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
|
||||
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.8.1 h1:uonwvepqRvSgddcrReZQhojTlWlmOlHkYAb9ZaOMWgU=
|
||||
@@ -621,6 +623,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
@@ -984,6 +987,7 @@ github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9l
|
||||
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
@@ -1000,13 +1004,18 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
@@ -1096,6 +1105,8 @@ github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw
|
||||
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.0.3 h1:+7mmR26M0IvyLxGZUHxu4GiBkJkVDid0Un+j4ScYu4k=
|
||||
github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rhysd/actionlint v1.6.23 h1:041VOXgZddfvSJa9Il+WT3Iwuo/j0Nmu4bhpAScrds4=
|
||||
@@ -1127,12 +1138,12 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.1.1 h1:lEOLY2vyGIqKWUI9nzsOJRV3mb3WC9dXYORsLEUcoeY=
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.1.1/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.2.0 h1:WCcC4vZDS1tYNxjWlwRJZQy28r8CMoggKnxNzxsVDMQ=
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.2.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
@@ -1445,6 +1456,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210501142056-aec3718b3fa0/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@@ -1562,6 +1574,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1695,6 +1708,7 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
|
||||
@@ -42,6 +42,33 @@ func ConvertUtf8ToUtf8mb4() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConvertVarcharToNVarchar converts database and tables from varchar to nvarchar if it's mssql
|
||||
func ConvertVarcharToNVarchar() error {
|
||||
if x.Dialect().URI().DBType != schemas.MSSQL {
|
||||
return nil
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
res, err := sess.QuerySliceString(`SELECT 'ALTER TABLE ' + OBJECT_NAME(SC.object_id) + ' MODIFY SC.name NVARCHAR(' + CONVERT(VARCHAR(5),SC.max_length) + ')'
|
||||
FROM SYS.columns SC
|
||||
JOIN SYS.types ST
|
||||
ON SC.system_type_id = ST.system_type_id
|
||||
AND SC.user_type_id = ST.user_type_id
|
||||
WHERE ST.name ='varchar'`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, row := range res {
|
||||
if len(row) == 1 {
|
||||
if _, err = sess.Exec(row[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Cell2Int64 converts a xorm.Cell type to int64,
|
||||
// and handles possible irregular cases.
|
||||
func Cell2Int64(val xorm.Cell) int64 {
|
||||
|
||||
@@ -25,7 +25,7 @@ func TestIterate(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 83, repoCnt)
|
||||
assert.EqualValues(t, 88, repoCnt)
|
||||
|
||||
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
|
||||
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
|
||||
|
||||
@@ -35,11 +35,11 @@ func TestFind(t *testing.T) {
|
||||
var repoUnits []repo_model.RepoUnit
|
||||
err := db.Find(db.DefaultContext, &opts, &repoUnits)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 83, len(repoUnits))
|
||||
assert.EqualValues(t, 88, len(repoUnits))
|
||||
|
||||
cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 83, cnt)
|
||||
assert.EqualValues(t, 88, cnt)
|
||||
|
||||
repoUnits = make([]repo_model.RepoUnit, 0, 10)
|
||||
newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
|
||||
|
||||
+1
-1
@@ -31,5 +31,5 @@ const (
|
||||
const (
|
||||
// Which means a condition to filter the records which don't match any id.
|
||||
// It's different from zero which means the condition could be ignored.
|
||||
NoneID = -1
|
||||
NoConditionID = -1
|
||||
)
|
||||
|
||||
@@ -66,3 +66,45 @@
|
||||
is_prerelease: true
|
||||
is_tag: false
|
||||
created_unix: 946684800
|
||||
|
||||
- id: 6
|
||||
repo_id: 57
|
||||
publisher_id: 2
|
||||
tag_name: "v1.0"
|
||||
lower_tag_name: "v1.0"
|
||||
target: "main"
|
||||
title: "v1.0"
|
||||
sha1: "a8a700e8c644c783ba2c6e742bb81bf91e244bff"
|
||||
num_commits: 3
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684801
|
||||
|
||||
- id: 7
|
||||
repo_id: 57
|
||||
publisher_id: 2
|
||||
tag_name: "v1.1"
|
||||
lower_tag_name: "v1.1"
|
||||
target: "main"
|
||||
title: "v1.1"
|
||||
sha1: "cef06e48f2642cd0dc9597b4bea09f4b3f74aad6"
|
||||
num_commits: 5
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684802
|
||||
|
||||
- id: 8
|
||||
repo_id: 57
|
||||
publisher_id: 2
|
||||
tag_name: "v2.0"
|
||||
lower_tag_name: "v2.0"
|
||||
target: "main"
|
||||
title: "v2.0"
|
||||
sha1: "7197b56fdc75b453f47c9110938cb46a303579fd"
|
||||
num_commits: 6
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684803
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# See models/unit/unit.go for the meaning of the type
|
||||
-
|
||||
id: 1
|
||||
repo_id: 1
|
||||
@@ -569,3 +570,29 @@
|
||||
type: 3
|
||||
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}"
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 85
|
||||
repo_id: 57
|
||||
type: 1
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 86
|
||||
repo_id: 57
|
||||
type: 2
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 87
|
||||
repo_id: 57
|
||||
type: 3
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 88
|
||||
repo_id: 57
|
||||
type: 4
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 89
|
||||
repo_id: 57
|
||||
type: 5
|
||||
created_unix: 946684810
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# don't forget to add fixtures in repo_unit.yml
|
||||
-
|
||||
id: 1
|
||||
owner_id: 2
|
||||
@@ -1634,3 +1635,16 @@
|
||||
is_private: true
|
||||
num_issues: 1
|
||||
status: 0
|
||||
|
||||
-
|
||||
id: 57
|
||||
owner_id: 2
|
||||
owner_name: user2
|
||||
lower_name: repo-release
|
||||
name: repo-release
|
||||
default_branch: main
|
||||
is_empty: false
|
||||
is_archived: false
|
||||
is_private: false
|
||||
status: 0
|
||||
num_issues: 0
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
num_followers: 2
|
||||
num_following: 1
|
||||
num_stars: 2
|
||||
num_repos: 11
|
||||
num_repos: 12
|
||||
num_teams: 0
|
||||
num_members: 0
|
||||
visibility: 0
|
||||
|
||||
+70
-77
@@ -52,84 +52,61 @@ func (err ErrCommentNotExist) Unwrap() error {
|
||||
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
|
||||
type CommentType int
|
||||
|
||||
// define unknown comment type
|
||||
const (
|
||||
CommentTypeUnknown CommentType = -1
|
||||
)
|
||||
// CommentTypeUndefined is used to search for comments of any type
|
||||
const CommentTypeUndefined CommentType = -1
|
||||
|
||||
// Enumerate all the comment types
|
||||
const (
|
||||
// 0 Plain comment, can be associated with a commit (CommitID > 0) and a line (LineNum > 0)
|
||||
CommentTypeComment CommentType = iota
|
||||
CommentTypeReopen // 1
|
||||
CommentTypeClose // 2
|
||||
CommentTypeComment CommentType = iota // 0 Plain comment, can be associated with a commit (CommitID > 0) and a line (LineNum > 0)
|
||||
|
||||
CommentTypeReopen // 1
|
||||
CommentTypeClose // 2
|
||||
|
||||
CommentTypeIssueRef // 3 References.
|
||||
CommentTypeCommitRef // 4 Reference from a commit (not part of a pull request)
|
||||
CommentTypeCommentRef // 5 Reference from a comment
|
||||
CommentTypePullRef // 6 Reference from a pull request
|
||||
|
||||
CommentTypeLabel // 7 Labels changed
|
||||
CommentTypeMilestone // 8 Milestone changed
|
||||
CommentTypeAssignees // 9 Assignees changed
|
||||
CommentTypeChangeTitle // 10 Change Title
|
||||
CommentTypeDeleteBranch // 11 Delete Branch
|
||||
|
||||
CommentTypeStartTracking // 12 Start a stopwatch for time tracking
|
||||
CommentTypeStopTracking // 13 Stop a stopwatch for time tracking
|
||||
CommentTypeAddTimeManual // 14 Add time manual for time tracking
|
||||
CommentTypeCancelTracking // 15 Cancel a stopwatch for time tracking
|
||||
CommentTypeAddedDeadline // 16 Added a due date
|
||||
CommentTypeModifiedDeadline // 17 Modified the due date
|
||||
CommentTypeRemovedDeadline // 18 Removed a due date
|
||||
|
||||
CommentTypeAddDependency // 19 Dependency added
|
||||
CommentTypeRemoveDependency // 20 Dependency removed
|
||||
|
||||
CommentTypeCode // 21 Comment a line of code
|
||||
CommentTypeReview // 22 Reviews a pull request by giving general feedback
|
||||
|
||||
CommentTypeLock // 23 Lock an issue, giving only collaborators access
|
||||
CommentTypeUnlock // 24 Unlocks a previously locked issue
|
||||
|
||||
CommentTypeChangeTargetBranch // 25 Change pull request's target branch
|
||||
|
||||
CommentTypeDeleteTimeManual // 26 Delete time manual for time tracking
|
||||
|
||||
CommentTypeReviewRequest // 27 add or remove Request from one
|
||||
CommentTypeMergePull // 28 merge pull request
|
||||
CommentTypePullRequestPush // 29 push to PR head branch
|
||||
|
||||
CommentTypeProject // 30 Project changed
|
||||
CommentTypeProjectBoard // 31 Project board changed
|
||||
|
||||
CommentTypeDismissReview // 32 Dismiss Review
|
||||
|
||||
CommentTypeChangeIssueRef // 33 Change issue ref
|
||||
|
||||
CommentTypePRScheduledToAutoMerge // 34 pr was scheduled to auto merge when checks succeed
|
||||
CommentTypePRUnScheduledToAutoMerge // 35 pr was un scheduled to auto merge when checks succeed
|
||||
|
||||
// 3 References.
|
||||
CommentTypeIssueRef
|
||||
// 4 Reference from a commit (not part of a pull request)
|
||||
CommentTypeCommitRef
|
||||
// 5 Reference from a comment
|
||||
CommentTypeCommentRef
|
||||
// 6 Reference from a pull request
|
||||
CommentTypePullRef
|
||||
// 7 Labels changed
|
||||
CommentTypeLabel
|
||||
// 8 Milestone changed
|
||||
CommentTypeMilestone
|
||||
// 9 Assignees changed
|
||||
CommentTypeAssignees
|
||||
// 10 Change Title
|
||||
CommentTypeChangeTitle
|
||||
// 11 Delete Branch
|
||||
CommentTypeDeleteBranch
|
||||
// 12 Start a stopwatch for time tracking
|
||||
CommentTypeStartTracking
|
||||
// 13 Stop a stopwatch for time tracking
|
||||
CommentTypeStopTracking
|
||||
// 14 Add time manual for time tracking
|
||||
CommentTypeAddTimeManual
|
||||
// 15 Cancel a stopwatch for time tracking
|
||||
CommentTypeCancelTracking
|
||||
// 16 Added a due date
|
||||
CommentTypeAddedDeadline
|
||||
// 17 Modified the due date
|
||||
CommentTypeModifiedDeadline
|
||||
// 18 Removed a due date
|
||||
CommentTypeRemovedDeadline
|
||||
// 19 Dependency added
|
||||
CommentTypeAddDependency
|
||||
// 20 Dependency removed
|
||||
CommentTypeRemoveDependency
|
||||
// 21 Comment a line of code
|
||||
CommentTypeCode
|
||||
// 22 Reviews a pull request by giving general feedback
|
||||
CommentTypeReview
|
||||
// 23 Lock an issue, giving only collaborators access
|
||||
CommentTypeLock
|
||||
// 24 Unlocks a previously locked issue
|
||||
CommentTypeUnlock
|
||||
// 25 Change pull request's target branch
|
||||
CommentTypeChangeTargetBranch
|
||||
// 26 Delete time manual for time tracking
|
||||
CommentTypeDeleteTimeManual
|
||||
// 27 add or remove Request from one
|
||||
CommentTypeReviewRequest
|
||||
// 28 merge pull request
|
||||
CommentTypeMergePull
|
||||
// 29 push to PR head branch
|
||||
CommentTypePullRequestPush
|
||||
// 30 Project changed
|
||||
CommentTypeProject
|
||||
// 31 Project board changed
|
||||
CommentTypeProjectBoard
|
||||
// 32 Dismiss Review
|
||||
CommentTypeDismissReview
|
||||
// 33 Change issue ref
|
||||
CommentTypeChangeIssueRef
|
||||
// 34 pr was scheduled to auto merge when checks succeed
|
||||
CommentTypePRScheduledToAutoMerge
|
||||
// 35 pr was un scheduled to auto merge when checks succeed
|
||||
CommentTypePRUnScheduledToAutoMerge
|
||||
)
|
||||
|
||||
var commentStrings = []string{
|
||||
@@ -181,7 +158,23 @@ func AsCommentType(typeName string) CommentType {
|
||||
return CommentType(index)
|
||||
}
|
||||
}
|
||||
return CommentTypeUnknown
|
||||
return CommentTypeUndefined
|
||||
}
|
||||
|
||||
func (t CommentType) HasContentSupport() bool {
|
||||
switch t {
|
||||
case CommentTypeComment, CommentTypeCode, CommentTypeReview:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t CommentType) HasAttachmentSupport() bool {
|
||||
switch t {
|
||||
case CommentTypeComment, CommentTypeCode, CommentTypeReview:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RoleDescriptor defines comment tag type
|
||||
@@ -1039,7 +1032,7 @@ func (opts *FindCommentsOptions) ToConds() builder.Cond {
|
||||
if opts.Before > 0 {
|
||||
cond = cond.And(builder.Lte{"comment.updated_unix": opts.Before})
|
||||
}
|
||||
if opts.Type != CommentTypeUnknown {
|
||||
if opts.Type != CommentTypeUndefined {
|
||||
cond = cond.And(builder.Eq{"comment.type": opts.Type})
|
||||
}
|
||||
if opts.Line != 0 {
|
||||
|
||||
@@ -56,7 +56,7 @@ func (comments CommentList) getLabelIDs() []int64 {
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (comments CommentList) loadLabels(ctx context.Context) error { //nolint
|
||||
func (comments CommentList) loadLabels(ctx context.Context) error {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -415,7 +415,7 @@ func (comments CommentList) getReviewIDs() []int64 {
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
||||
func (comments CommentList) loadReviews(ctx context.Context) error {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -453,6 +453,14 @@ func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
||||
|
||||
for _, comment := range comments {
|
||||
comment.Review = reviews[comment.ReviewID]
|
||||
|
||||
// If the comment dismisses a review, we need to load the reviewer to show whose review has been dismissed.
|
||||
// Otherwise, the reviewer is the poster of the comment, so we don't need to load it.
|
||||
if comment.Type == CommentTypeDismissReview {
|
||||
if err := comment.Review.LoadReviewer(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -64,8 +64,9 @@ func TestFetchCodeComments(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAsCommentType(t *testing.T) {
|
||||
assert.Equal(t, issues_model.CommentTypeUnknown, issues_model.AsCommentType(""))
|
||||
assert.Equal(t, issues_model.CommentTypeUnknown, issues_model.AsCommentType("nonsense"))
|
||||
assert.Equal(t, issues_model.CommentType(0), issues_model.CommentTypeComment)
|
||||
assert.Equal(t, issues_model.CommentTypeUndefined, issues_model.AsCommentType(""))
|
||||
assert.Equal(t, issues_model.CommentTypeUndefined, issues_model.AsCommentType("nonsense"))
|
||||
assert.Equal(t, issues_model.CommentTypeComment, issues_model.AsCommentType("comment"))
|
||||
assert.Equal(t, issues_model.CommentTypePRUnScheduledToAutoMerge, issues_model.AsCommentType("pull_cancel_scheduled_merge"))
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
func (issue *Issue) loadComments(ctx context.Context) (err error) {
|
||||
return issue.loadCommentsByType(ctx, CommentTypeUnknown)
|
||||
return issue.loadCommentsByType(ctx, CommentTypeUndefined)
|
||||
}
|
||||
|
||||
// LoadDiscussComments loads discuss comments
|
||||
@@ -1266,7 +1266,9 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
|
||||
applySubscribedCondition(sess, opts.SubscriberID)
|
||||
}
|
||||
|
||||
if len(opts.MilestoneIDs) > 0 {
|
||||
if len(opts.MilestoneIDs) == 1 && opts.MilestoneIDs[0] == db.NoConditionID {
|
||||
sess.And("issue.milestone_id = 0")
|
||||
} else if len(opts.MilestoneIDs) > 0 {
|
||||
sess.In("issue.milestone_id", opts.MilestoneIDs)
|
||||
}
|
||||
|
||||
@@ -1280,7 +1282,7 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
|
||||
if opts.ProjectID > 0 {
|
||||
sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id").
|
||||
And("project_issue.project_id=?", opts.ProjectID)
|
||||
} else if opts.ProjectID == db.NoneID { // show those that are in no project
|
||||
} else if opts.ProjectID == db.NoConditionID { // show those that are in no project
|
||||
sess.And(builder.NotIn("issue.id", builder.Select("issue_id").From("project_issue")))
|
||||
}
|
||||
|
||||
@@ -1680,6 +1682,8 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
|
||||
|
||||
if opts.MilestoneID > 0 {
|
||||
sess.And("issue.milestone_id = ?", opts.MilestoneID)
|
||||
} else if opts.MilestoneID == db.NoConditionID {
|
||||
sess.And("issue.milestone_id = 0")
|
||||
}
|
||||
|
||||
if opts.ProjectID > 0 {
|
||||
|
||||
+13
-4
@@ -418,6 +418,12 @@ func DeleteTeam(t *organization.Team) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tm := range t.Members {
|
||||
if err := removeInvalidOrgUser(ctx, tm.ID, t.OrgID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update organization number of teams.
|
||||
if _, err := db.Exec(ctx, "UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
|
||||
return err
|
||||
@@ -567,16 +573,19 @@ func removeTeamMember(ctx context.Context, team *organization.Team, userID int64
|
||||
}
|
||||
}
|
||||
|
||||
return removeInvalidOrgUser(ctx, userID, team.OrgID)
|
||||
}
|
||||
|
||||
func removeInvalidOrgUser(ctx context.Context, userID, orgID int64) error {
|
||||
// Check if the user is a member of any team in the organization.
|
||||
if count, err := e.Count(&organization.TeamUser{
|
||||
if count, err := db.GetEngine(ctx).Count(&organization.TeamUser{
|
||||
UID: userID,
|
||||
OrgID: team.OrgID,
|
||||
OrgID: orgID,
|
||||
}); err != nil {
|
||||
return err
|
||||
} else if count == 0 {
|
||||
return removeOrgUser(ctx, team.OrgID, userID)
|
||||
return removeOrgUser(ctx, orgID, userID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -338,9 +338,10 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
|
||||
units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
|
||||
for _, tp := range unit.AllRepoUnitTypes {
|
||||
units = append(units, TeamUnit{
|
||||
OrgID: org.ID,
|
||||
TeamID: t.ID,
|
||||
Type: tp,
|
||||
OrgID: org.ID,
|
||||
TeamID: t.ID,
|
||||
Type: tp,
|
||||
AccessMode: perm.AccessModeOwner,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -235,12 +235,12 @@ func TestSearchRepository(t *testing.T) {
|
||||
{
|
||||
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
|
||||
count: 29,
|
||||
count: 30,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
|
||||
count: 34,
|
||||
count: 35,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
||||
@@ -255,7 +255,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
{
|
||||
name: "AllPublic/PublicRepositoriesOfOrganization",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
|
||||
count: 29,
|
||||
count: 30,
|
||||
},
|
||||
{
|
||||
name: "AllTemplates",
|
||||
|
||||
@@ -194,14 +194,16 @@ func (opts *FindTopicOptions) toConds() builder.Cond {
|
||||
// FindTopics retrieves the topics via FindTopicOptions
|
||||
func FindTopics(opts *FindTopicOptions) ([]*Topic, int64, error) {
|
||||
sess := db.GetEngine(db.DefaultContext).Select("topic.*").Where(opts.toConds())
|
||||
orderBy := "topic.repo_count DESC"
|
||||
if opts.RepoID > 0 {
|
||||
sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id")
|
||||
orderBy = "topic.name" // when render topics for a repo, it's better to sort them by name, to get consistent result
|
||||
}
|
||||
if opts.PageSize != 0 && opts.Page != 0 {
|
||||
sess = db.SetSessionPagination(sess, opts)
|
||||
}
|
||||
topics := make([]*Topic, 0, 10)
|
||||
total, err := sess.Desc("topic.repo_count").FindAndCount(&topics)
|
||||
total, err := sess.OrderBy(orderBy).FindAndCount(&topics)
|
||||
return topics, total, err
|
||||
}
|
||||
|
||||
|
||||
+257
-25
@@ -99,40 +99,60 @@ func detectMatched(commit *git.Commit, triggedEvent webhook_module.HookEventType
|
||||
}
|
||||
|
||||
switch triggedEvent {
|
||||
case webhook_module.HookEventCreate,
|
||||
case // events with no activity types
|
||||
webhook_module.HookEventCreate,
|
||||
webhook_module.HookEventDelete,
|
||||
webhook_module.HookEventFork,
|
||||
webhook_module.HookEventIssueAssign,
|
||||
webhook_module.HookEventIssueLabel,
|
||||
webhook_module.HookEventIssueMilestone,
|
||||
webhook_module.HookEventPullRequestAssign,
|
||||
webhook_module.HookEventPullRequestLabel,
|
||||
webhook_module.HookEventPullRequestMilestone,
|
||||
webhook_module.HookEventPullRequestComment,
|
||||
webhook_module.HookEventPullRequestReviewApproved,
|
||||
webhook_module.HookEventPullRequestReviewRejected,
|
||||
webhook_module.HookEventPullRequestReviewComment,
|
||||
webhook_module.HookEventWiki,
|
||||
webhook_module.HookEventRepository,
|
||||
webhook_module.HookEventRelease,
|
||||
webhook_module.HookEventPackage:
|
||||
// FIXME: `wiki` event should match `gollum` event
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#gollum
|
||||
webhook_module.HookEventWiki:
|
||||
if len(evt.Acts()) != 0 {
|
||||
log.Warn("Ignore unsupported %s event arguments %v", triggedEvent, evt.Acts())
|
||||
}
|
||||
// no special filter parameters for these events, just return true if name matched
|
||||
return true
|
||||
|
||||
case webhook_module.HookEventPush:
|
||||
case // push
|
||||
webhook_module.HookEventPush:
|
||||
return matchPushEvent(commit, payload.(*api.PushPayload), evt)
|
||||
|
||||
case webhook_module.HookEventIssues:
|
||||
case // issues
|
||||
webhook_module.HookEventIssues,
|
||||
webhook_module.HookEventIssueAssign,
|
||||
webhook_module.HookEventIssueLabel,
|
||||
webhook_module.HookEventIssueMilestone:
|
||||
return matchIssuesEvent(commit, payload.(*api.IssuePayload), evt)
|
||||
|
||||
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestSync:
|
||||
case // issue_comment
|
||||
webhook_module.HookEventIssueComment,
|
||||
// `pull_request_comment` is same as `issue_comment`
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment
|
||||
webhook_module.HookEventPullRequestComment:
|
||||
return matchIssueCommentEvent(commit, payload.(*api.IssueCommentPayload), evt)
|
||||
|
||||
case // pull_request
|
||||
webhook_module.HookEventPullRequest,
|
||||
webhook_module.HookEventPullRequestSync,
|
||||
webhook_module.HookEventPullRequestAssign,
|
||||
webhook_module.HookEventPullRequestLabel:
|
||||
return matchPullRequestEvent(commit, payload.(*api.PullRequestPayload), evt)
|
||||
|
||||
case webhook_module.HookEventIssueComment:
|
||||
return matchIssueCommentEvent(commit, payload.(*api.IssueCommentPayload), evt)
|
||||
case // pull_request_review
|
||||
webhook_module.HookEventPullRequestReviewApproved,
|
||||
webhook_module.HookEventPullRequestReviewRejected:
|
||||
return matchPullRequestReviewEvent(commit, payload.(*api.PullRequestPayload), evt)
|
||||
|
||||
case // pull_request_review_comment
|
||||
webhook_module.HookEventPullRequestReviewComment:
|
||||
return matchPullRequestReviewCommentEvent(commit, payload.(*api.PullRequestPayload), evt)
|
||||
|
||||
case // release
|
||||
webhook_module.HookEventRelease:
|
||||
return matchReleaseEvent(commit, payload.(*api.ReleasePayload), evt)
|
||||
|
||||
case // registry_package
|
||||
webhook_module.HookEventPackage:
|
||||
return matchPackageEvent(commit, payload.(*api.PackagePayload), evt)
|
||||
|
||||
default:
|
||||
log.Warn("unsupported event %q", triggedEvent)
|
||||
@@ -249,8 +269,24 @@ func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *j
|
||||
for cond, vals := range evt.Acts() {
|
||||
switch cond {
|
||||
case "types":
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issues
|
||||
// Actions with the same name:
|
||||
// opened, edited, closed, reopened, assigned, unassigned, milestoned, demilestoned
|
||||
// Actions need to be converted:
|
||||
// label_updated -> labeled
|
||||
// label_cleared -> unlabeled
|
||||
// Unsupported activity types:
|
||||
// deleted, transferred, pinned, unpinned, locked, unlocked
|
||||
|
||||
action := issuePayload.Action
|
||||
switch action {
|
||||
case api.HookIssueLabelUpdated:
|
||||
action = "labeled"
|
||||
case api.HookIssueLabelCleared:
|
||||
action = "unlabeled"
|
||||
}
|
||||
for _, val := range vals {
|
||||
if glob.MustCompile(val, '/').Match(string(issuePayload.Action)) {
|
||||
if glob.MustCompile(val, '/').Match(string(action)) {
|
||||
matchTimes++
|
||||
break
|
||||
}
|
||||
@@ -265,8 +301,9 @@ 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 {
|
||||
// defaultly, only pull request opened and synchronized will trigger workflow
|
||||
return prPayload.Action == api.HookIssueSynchronized || prPayload.Action == api.HookIssueOpened
|
||||
// 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
|
||||
}
|
||||
|
||||
matchTimes := 0
|
||||
@@ -274,9 +311,24 @@ func matchPullRequestEvent(commit *git.Commit, prPayload *api.PullRequestPayload
|
||||
for cond, vals := range evt.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
|
||||
if prPayload.Action == api.HookIssueSynchronized {
|
||||
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 {
|
||||
@@ -347,6 +399,14 @@ func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCo
|
||||
for cond, vals := range evt.Acts() {
|
||||
switch cond {
|
||||
case "types":
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment
|
||||
// Actions with the same name:
|
||||
// created, edited, deleted
|
||||
// Actions need to be converted:
|
||||
// NONE
|
||||
// Unsupported activity types:
|
||||
// NONE
|
||||
|
||||
for _, val := range vals {
|
||||
if glob.MustCompile(val, '/').Match(string(issueCommentPayload.Action)) {
|
||||
matchTimes++
|
||||
@@ -354,7 +414,179 @@ func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCo
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Warn("issue comment unsupported condition %q", cond)
|
||||
log.Warn("issue comment event unsupported condition %q", cond)
|
||||
}
|
||||
}
|
||||
return matchTimes == len(evt.Acts())
|
||||
}
|
||||
|
||||
func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
|
||||
// with no special filter parameters
|
||||
if len(evt.Acts()) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
matchTimes := 0
|
||||
// all acts conditions should be satisfied
|
||||
for cond, vals := range evt.Acts() {
|
||||
switch cond {
|
||||
case "types":
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review
|
||||
// Activity types with the same name:
|
||||
// NONE
|
||||
// Activity types need to be converted:
|
||||
// reviewed -> submitted
|
||||
// reviewed -> edited
|
||||
// Unsupported activity types:
|
||||
// dismissed
|
||||
|
||||
actions := make([]string, 0)
|
||||
if prPayload.Action == api.HookIssueReviewed {
|
||||
// the `reviewed` HookIssueAction can match the two activity types: `submitted` and `edited`
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review
|
||||
actions = append(actions, "submitted", "edited")
|
||||
}
|
||||
|
||||
matched := false
|
||||
for _, val := range vals {
|
||||
for _, action := range actions {
|
||||
if glob.MustCompile(val, '/').Match(action) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if matched {
|
||||
break
|
||||
}
|
||||
}
|
||||
if matched {
|
||||
matchTimes++
|
||||
}
|
||||
default:
|
||||
log.Warn("pull request review event unsupported condition %q", cond)
|
||||
}
|
||||
}
|
||||
return matchTimes == len(evt.Acts())
|
||||
}
|
||||
|
||||
func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
|
||||
// with no special filter parameters
|
||||
if len(evt.Acts()) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
matchTimes := 0
|
||||
// all acts conditions should be satisfied
|
||||
for cond, vals := range evt.Acts() {
|
||||
switch cond {
|
||||
case "types":
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review_comment
|
||||
// Activity types with the same name:
|
||||
// NONE
|
||||
// Activity types need to be converted:
|
||||
// reviewed -> created
|
||||
// reviewed -> edited
|
||||
// Unsupported activity types:
|
||||
// deleted
|
||||
|
||||
actions := make([]string, 0)
|
||||
if prPayload.Action == api.HookIssueReviewed {
|
||||
// the `reviewed` HookIssueAction can match the two activity types: `created` and `edited`
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review_comment
|
||||
actions = append(actions, "created", "edited")
|
||||
}
|
||||
|
||||
matched := false
|
||||
for _, val := range vals {
|
||||
for _, action := range actions {
|
||||
if glob.MustCompile(val, '/').Match(action) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if matched {
|
||||
break
|
||||
}
|
||||
}
|
||||
if matched {
|
||||
matchTimes++
|
||||
}
|
||||
default:
|
||||
log.Warn("pull request review comment event unsupported condition %q", cond)
|
||||
}
|
||||
}
|
||||
return matchTimes == len(evt.Acts())
|
||||
}
|
||||
|
||||
func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *jobparser.Event) bool {
|
||||
// with no special filter parameters
|
||||
if len(evt.Acts()) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
matchTimes := 0
|
||||
// all acts conditions should be satisfied
|
||||
for cond, vals := range evt.Acts() {
|
||||
switch cond {
|
||||
case "types":
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release
|
||||
// Activity types with the same name:
|
||||
// published
|
||||
// Activity types need to be converted:
|
||||
// updated -> edited
|
||||
// Unsupported activity types:
|
||||
// unpublished, created, deleted, prereleased, released
|
||||
|
||||
action := payload.Action
|
||||
switch action {
|
||||
case api.HookReleaseUpdated:
|
||||
action = "edited"
|
||||
}
|
||||
for _, val := range vals {
|
||||
if glob.MustCompile(val, '/').Match(string(action)) {
|
||||
matchTimes++
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Warn("release event unsupported condition %q", cond)
|
||||
}
|
||||
}
|
||||
return matchTimes == len(evt.Acts())
|
||||
}
|
||||
|
||||
func matchPackageEvent(commit *git.Commit, payload *api.PackagePayload, evt *jobparser.Event) bool {
|
||||
// with no special filter parameters
|
||||
if len(evt.Acts()) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
matchTimes := 0
|
||||
// all acts conditions should be satisfied
|
||||
for cond, vals := range evt.Acts() {
|
||||
switch cond {
|
||||
case "types":
|
||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#registry_package
|
||||
// Activity types with the same name:
|
||||
// NONE
|
||||
// Activity types need to be converted:
|
||||
// created -> published
|
||||
// Unsupported activity types:
|
||||
// updated
|
||||
|
||||
action := payload.Action
|
||||
switch action {
|
||||
case api.HookPackageCreated:
|
||||
action = "published"
|
||||
}
|
||||
for _, val := range vals {
|
||||
if glob.MustCompile(val, '/').Match(string(action)) {
|
||||
matchTimes++
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Warn("package event unsupported condition %q", cond)
|
||||
}
|
||||
}
|
||||
return matchTimes == len(evt.Acts())
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||
|
||||
"github.com/nektos/act/pkg/jobparser"
|
||||
"github.com/nektos/act/pkg/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDetectMatched(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
commit *git.Commit
|
||||
triggedEvent webhook_module.HookEventType
|
||||
payload api.Payloader
|
||||
yamlOn string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "HookEventCreate(create) matches githubEventCreate(create)",
|
||||
triggedEvent: webhook_module.HookEventCreate,
|
||||
payload: nil,
|
||||
yamlOn: "on: create",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "HookEventIssues(issues) `opened` action matches githubEventIssues(issues)",
|
||||
triggedEvent: webhook_module.HookEventIssues,
|
||||
payload: &api.IssuePayload{Action: api.HookIssueOpened},
|
||||
yamlOn: "on: issues",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "HookEventIssues(issues) `milestoned` action matches githubEventIssues(issues)",
|
||||
triggedEvent: webhook_module.HookEventIssues,
|
||||
payload: &api.IssuePayload{Action: api.HookIssueMilestoned},
|
||||
yamlOn: "on: issues",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequestSync(pull_request_sync) matches githubEventPullRequest(pull_request)",
|
||||
triggedEvent: webhook_module.HookEventPullRequestSync,
|
||||
payload: &api.PullRequestPayload{Action: api.HookIssueSynchronized},
|
||||
yamlOn: "on: pull_request",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequest(pull_request) `label_updated` action doesn't match githubEventPullRequest(pull_request) with no activity type",
|
||||
triggedEvent: webhook_module.HookEventPullRequest,
|
||||
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
|
||||
yamlOn: "on: pull_request",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequest(pull_request) `label_updated` action matches githubEventPullRequest(pull_request) with `label` activity type",
|
||||
triggedEvent: webhook_module.HookEventPullRequest,
|
||||
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
|
||||
yamlOn: "on:\n pull_request:\n types: [labeled]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequestReviewComment(pull_request_review_comment) matches githubEventPullRequestReviewComment(pull_request_review_comment)",
|
||||
triggedEvent: webhook_module.HookEventPullRequestReviewComment,
|
||||
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
|
||||
yamlOn: "on:\n pull_request_review_comment:\n types: [created]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPullRequestReviewRejected(pull_request_review_rejected) doesn't match githubEventPullRequestReview(pull_request_review) with `dismissed` activity type (we don't support `dismissed` at present)",
|
||||
triggedEvent: webhook_module.HookEventPullRequestReviewRejected,
|
||||
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
|
||||
yamlOn: "on:\n pull_request_review:\n types: [dismissed]",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "HookEventRelease(release) `published` action matches githubEventRelease(release) with `published` activity type",
|
||||
triggedEvent: webhook_module.HookEventRelease,
|
||||
payload: &api.ReleasePayload{Action: api.HookReleasePublished},
|
||||
yamlOn: "on:\n release:\n types: [published]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "HookEventPackage(package) `created` action doesn't match githubEventRegistryPackage(registry_package) with `updated` activity type",
|
||||
triggedEvent: webhook_module.HookEventPackage,
|
||||
payload: &api.PackagePayload{Action: api.HookPackageCreated},
|
||||
yamlOn: "on:\n registry_package:\n types: [updated]",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
workflow, err := model.ReadWorkflow(bytes.NewReader([]byte(tc.yamlOn)))
|
||||
assert.NoError(t, err)
|
||||
evts, err := jobparser.ParseRawOn(&workflow.RawOn)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, evts, 1)
|
||||
assert.Equal(t, tc.expected, detectMatched(tc.commit, tc.triggedEvent, tc.payload, evts[0]))
|
||||
})
|
||||
}
|
||||
}
|
||||
Vendored
+1
-1
@@ -12,7 +12,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/nosql"
|
||||
|
||||
"gitea.com/go-chi/cache"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// RedisCacher represents a redis cache adapter implementation.
|
||||
|
||||
@@ -337,7 +337,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
|
||||
if git.IsErrNotExist(err) {
|
||||
ctx.NotFound()
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBlobByPath", err)
|
||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
@@ -106,3 +110,32 @@ func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
|
||||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
|
||||
}
|
||||
}
|
||||
|
||||
// RequireRepoScopedToken check whether personal access token has repo scope
|
||||
func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository) {
|
||||
if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true {
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
|
||||
if ok { // it's a personal access token but not oauth2 token
|
||||
var scopeMatched bool
|
||||
scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("HasScope", err)
|
||||
return
|
||||
}
|
||||
if !scopeMatched && !repo.IsPrivate {
|
||||
scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopePublicRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("HasScope", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if !scopeMatched {
|
||||
ctx.Error(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var replacer = strings.NewReplacer("_", "", "-", "")
|
||||
@@ -193,10 +193,6 @@ func getRedisOptions(uri *url.URL) *redis.UniversalOptions {
|
||||
opts.MinIdleConns, _ = strconv.Atoi(v[0])
|
||||
case "pooltimeout":
|
||||
opts.PoolTimeout = valToTimeDuration(v)
|
||||
case "idletimeout":
|
||||
opts.IdleTimeout = valToTimeDuration(v)
|
||||
case "idlecheckfrequency":
|
||||
opts.IdleCheckFrequency = valToTimeDuration(v)
|
||||
case "maxredirects":
|
||||
opts.MaxRedirects, _ = strconv.Atoi(v[0])
|
||||
case "readonly":
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -101,6 +102,9 @@ func TestChannelQueue_Batch(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestChannelQueue_Pause(t *testing.T) {
|
||||
if os.Getenv("CI") != "" {
|
||||
t.Skip("Skipping because test is flaky on CI")
|
||||
}
|
||||
lock := sync.Mutex{}
|
||||
var queue Queue
|
||||
var err error
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/nosql"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// RedisQueueType is the type for redis queue
|
||||
|
||||
@@ -5,6 +5,7 @@ package queue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -16,6 +17,9 @@ import (
|
||||
)
|
||||
|
||||
func TestPersistableChannelUniqueQueue(t *testing.T) {
|
||||
if os.Getenv("CI") != "" {
|
||||
t.Skip("Skipping because test is flaky on CI")
|
||||
}
|
||||
tmpDir := t.TempDir()
|
||||
fmt.Printf("TempDir %s\n", tmpDir)
|
||||
_ = log.NewLogger(1000, "console", "console", `{"level":"warn","stacktracelevel":"NONE","stderr":true}`)
|
||||
|
||||
@@ -6,7 +6,7 @@ package queue
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// RedisUniqueQueueType is the type for redis queue
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/nosql"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// RedisStore represents a redis session store implementation.
|
||||
|
||||
@@ -21,9 +21,10 @@ var CORSConfig = struct {
|
||||
Headers []string
|
||||
XFrameOptions string
|
||||
}{
|
||||
Enabled: false,
|
||||
MaxAge: 10 * time.Minute,
|
||||
AllowDomain: []string{"*"},
|
||||
Methods: []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
||||
Headers: []string{"Content-Type", "User-Agent"},
|
||||
MaxAge: 10 * time.Minute,
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
}
|
||||
|
||||
|
||||
@@ -282,6 +282,9 @@ func loadCommonSettingsFrom(cfg ConfigProvider) {
|
||||
loadLogFrom(cfg)
|
||||
loadServerFrom(cfg)
|
||||
loadSSHFrom(cfg)
|
||||
|
||||
mustCurrentRunUserMatch(cfg) // it depends on the SSH config, only non-builtin SSH server requires this check
|
||||
|
||||
loadOAuth2From(cfg)
|
||||
loadSecurityFrom(cfg)
|
||||
loadAttachmentFrom(cfg)
|
||||
@@ -314,14 +317,6 @@ func loadRunModeFrom(rootCfg ConfigProvider) {
|
||||
RunMode = rootSec.Key("RUN_MODE").MustString("prod")
|
||||
}
|
||||
IsProd = strings.EqualFold(RunMode, "prod")
|
||||
// Does not check run user when the install lock is off.
|
||||
installLock := rootCfg.Section("security").Key("INSTALL_LOCK").MustBool(false)
|
||||
if installLock {
|
||||
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
|
||||
if !match {
|
||||
log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser)
|
||||
}
|
||||
}
|
||||
|
||||
// check if we run as root
|
||||
if os.Getuid() == 0 {
|
||||
@@ -333,6 +328,17 @@ func loadRunModeFrom(rootCfg ConfigProvider) {
|
||||
}
|
||||
}
|
||||
|
||||
func mustCurrentRunUserMatch(rootCfg ConfigProvider) {
|
||||
// Does not check run user when the "InstallLock" is off.
|
||||
installLock := rootCfg.Section("security").Key("INSTALL_LOCK").MustBool(false)
|
||||
if installLock {
|
||||
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
|
||||
if !match {
|
||||
log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOrAppendToCustomConf creates or updates the custom config.
|
||||
// Use the callback to set individual values.
|
||||
func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) {
|
||||
|
||||
@@ -77,7 +77,7 @@ var UI = struct {
|
||||
GraphMaxCommitNum: 100,
|
||||
CodeCommentLines: 4,
|
||||
ReactionMaxUserNum: 10,
|
||||
ThemeColorMetaTag: `#6cc644`,
|
||||
ThemeColorMetaTag: ``,
|
||||
MaxDisplayFileSize: 8388608,
|
||||
DefaultTheme: `auto`,
|
||||
Themes: []string{`auto`, `gitea`, `arc-green`},
|
||||
|
||||
@@ -30,8 +30,8 @@ type OrganizationPermissions struct {
|
||||
// CreateOrgOption options for creating an organization
|
||||
type CreateOrgOption struct {
|
||||
// required: true
|
||||
UserName string `json:"username" binding:"Required"`
|
||||
FullName string `json:"full_name"`
|
||||
UserName string `json:"username" binding:"Required;Username;MaxSize(40)"`
|
||||
FullName string `json:"full_name" binding:"MaxSize(100)"`
|
||||
Description string `json:"description" binding:"MaxSize(255)"`
|
||||
Website string `json:"website" binding:"ValidUrl;MaxSize(255)"`
|
||||
Location string `json:"location" binding:"MaxSize(50)"`
|
||||
@@ -45,7 +45,7 @@ type CreateOrgOption struct {
|
||||
|
||||
// EditOrgOption options for editing an organization
|
||||
type EditOrgOption struct {
|
||||
FullName string `json:"full_name"`
|
||||
FullName string `json:"full_name" binding:"MaxSize(100)"`
|
||||
Description string `json:"description" binding:"MaxSize(255)"`
|
||||
Website string `json:"website" binding:"ValidUrl;MaxSize(255)"`
|
||||
Location string `json:"location" binding:"MaxSize(50)"`
|
||||
|
||||
@@ -1310,7 +1310,10 @@ issues.filter_label = Label
|
||||
issues.filter_label_exclude = `Use <code>alt</code> + <code>click/enter</code> to exclude labels`
|
||||
issues.filter_label_no_select = All labels
|
||||
issues.filter_milestone = Milestone
|
||||
issues.filter_milestone_no_select = All milestones
|
||||
issues.filter_milestone_all = All milestones
|
||||
issues.filter_milestone_none = No milestones
|
||||
issues.filter_milestone_open = Open milestones
|
||||
issues.filter_milestone_closed = Closed milestones
|
||||
issues.filter_project = Project
|
||||
issues.filter_project_all = All projects
|
||||
issues.filter_project_none = No project
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@@ -35,6 +36,32 @@ import (
|
||||
|
||||
func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
if ctx.Data["IsApiToken"] == true {
|
||||
scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
|
||||
if ok { // it's a personal access token but not oauth2 token
|
||||
scopeMatched := false
|
||||
var err error
|
||||
if accessMode == perm.AccessModeRead {
|
||||
scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeReadPackage)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "HasScope", err.Error())
|
||||
return
|
||||
}
|
||||
} else if accessMode == perm.AccessModeWrite {
|
||||
scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeWritePackage)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "HasScope", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
if !scopeMatched {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea Package API"`)
|
||||
ctx.Error(http.StatusUnauthorized, "reqPackageAccess", "user should have specific permission or be a site admin")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Package.AccessMode < accessMode && !ctx.IsUserSiteAdmin() {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea Package API"`)
|
||||
ctx.Error(http.StatusUnauthorized, "reqPackageAccess", "user should have specific permission or be a site admin")
|
||||
|
||||
@@ -145,7 +145,7 @@ func EditHook(ctx *context.APIContext) {
|
||||
|
||||
// DeleteHook delete a system hook
|
||||
func DeleteHook(ctx *context.APIContext) {
|
||||
// swagger:operation DELETE /amdin/hooks/{id} admin adminDeleteHook
|
||||
// swagger:operation DELETE /admin/hooks/{id} admin adminDeleteHook
|
||||
// ---
|
||||
// summary: Delete a hook
|
||||
// produces:
|
||||
|
||||
@@ -1178,12 +1178,12 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
m.Get("/{org}/permissions", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetUserOrgsPermissions)
|
||||
}, context_service.UserAssignmentAPI())
|
||||
m.Post("/orgs", reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateOrgOption{}), org.Create)
|
||||
m.Get("/orgs", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetAll)
|
||||
m.Get("/orgs", org.GetAll)
|
||||
m.Group("/orgs/{org}", func() {
|
||||
m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.Get).
|
||||
m.Combo("").Get(org.Get).
|
||||
Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.Delete)
|
||||
m.Combo("/repos").Get(reqToken(auth_model.AccessTokenScopeReadOrg), user.ListOrgRepos).
|
||||
m.Combo("/repos").Get(user.ListOrgRepos).
|
||||
Post(reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
|
||||
m.Group("/members", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListMembers)
|
||||
@@ -1191,8 +1191,8 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteMember)
|
||||
})
|
||||
m.Group("/public_members", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListPublicMembers)
|
||||
m.Combo("/{username}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.IsPublicMember).
|
||||
m.Get("", org.ListPublicMembers)
|
||||
m.Combo("/{username}").Get(org.IsPublicMember).
|
||||
Put(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.PublicizeMember).
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.ConcealMember)
|
||||
})
|
||||
@@ -1202,7 +1202,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
m.Get("/search", reqToken(auth_model.AccessTokenScopeReadOrg), org.SearchTeam)
|
||||
}, reqOrgMembership())
|
||||
m.Group("/labels", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListLabels)
|
||||
m.Get("", org.ListLabels)
|
||||
m.Post("", reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
|
||||
m.Combo("/{id}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetLabel).
|
||||
Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditLabelOption{}), org.EditLabel).
|
||||
|
||||
@@ -141,7 +141,7 @@ func CreateFork(ctx *context.APIContext) {
|
||||
Description: repo.Description,
|
||||
})
|
||||
if err != nil {
|
||||
if repo_model.IsErrReachLimitOfRepo(err) || repo_model.IsErrRepoAlreadyExist(err) {
|
||||
if repo_service.IsErrForkAlreadyExist(err) || repo_model.IsErrRepoAlreadyExist(err) || repo_model.IsErrReachLimitOfRepo(err) {
|
||||
ctx.Error(http.StatusConflict, "ForkRepository", err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "ForkRepository", err)
|
||||
|
||||
@@ -173,7 +173,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) {
|
||||
IssueID: issue.ID,
|
||||
Since: since,
|
||||
Before: before,
|
||||
Type: issues_model.CommentTypeUnknown,
|
||||
Type: issues_model.CommentTypeUndefined,
|
||||
}
|
||||
|
||||
comments, err := issues_model.FindComments(ctx, opts)
|
||||
@@ -549,7 +549,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
|
||||
return
|
||||
}
|
||||
|
||||
if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeReview && comment.Type != issues_model.CommentTypeCode {
|
||||
if !comment.Type.HasContentSupport() {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -963,7 +963,7 @@ func SignInOAuthCallback(ctx *context.Context) {
|
||||
}
|
||||
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm),
|
||||
IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm && !setting.Service.RegisterManualConfirm),
|
||||
}
|
||||
|
||||
source := authSource.Cfg.(*oauth2.Source)
|
||||
|
||||
@@ -43,6 +43,8 @@ func SecretsPost(ctx *context.Context) {
|
||||
func SecretsDelete(ctx *context.Context) {
|
||||
shared.PerformSecretsDelete(
|
||||
ctx,
|
||||
ctx.ContextUser.ID,
|
||||
0,
|
||||
ctx.Org.OrgLink+"/settings/secrets",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ type ViewResponse struct {
|
||||
Run struct {
|
||||
Link string `json:"link"`
|
||||
Title string `json:"title"`
|
||||
Status string `json:"status"`
|
||||
CanCancel bool `json:"canCancel"`
|
||||
Done bool `json:"done"`
|
||||
Jobs []*ViewJob `json:"jobs"`
|
||||
@@ -109,6 +110,7 @@ func ViewPost(ctx *context_module.Context) {
|
||||
resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
|
||||
resp.State.Run.Done = run.Status.IsDone()
|
||||
resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json
|
||||
resp.State.Run.Status = run.Status.String()
|
||||
for _, v := range jobs {
|
||||
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &ViewJob{
|
||||
ID: v.ID,
|
||||
|
||||
@@ -110,6 +110,11 @@ func GetAttachment(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
} else { // If we have the repository we check access
|
||||
context.CheckRepoScopedToken(ctx, repository)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err.Error())
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
@@ -23,10 +22,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
tplBlame base.TplName = "repo/home"
|
||||
)
|
||||
|
||||
type blameRow struct {
|
||||
RowNumber int
|
||||
Avatar gotemplate.HTML
|
||||
@@ -140,7 +135,7 @@ func RefBlame(ctx *context.Context) {
|
||||
|
||||
renderBlame(ctx, blameParts, commitNames, previousCommits)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplBlame)
|
||||
ctx.HTML(http.StatusOK, tplRepoHome)
|
||||
}
|
||||
|
||||
func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[string]*user_model.UserCommit, map[string]string) {
|
||||
|
||||
@@ -459,7 +459,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
|
||||
rootRepo.ID != ci.HeadRepo.ID &&
|
||||
rootRepo.ID != baseRepo.ID {
|
||||
canRead := access_model.CheckRepoUnitUser(ctx, rootRepo, ctx.Doer, unit.TypeCode)
|
||||
if canRead {
|
||||
if canRead && rootRepo.AllowsPulls() {
|
||||
ctx.Data["RootRepo"] = rootRepo
|
||||
if !fileOnly {
|
||||
branches, tags, err := getBranchesAndTagsForRepo(ctx, rootRepo)
|
||||
@@ -551,7 +551,11 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
|
||||
ctx.ServerError("GetCompareInfo", err)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["BeforeCommitID"] = ci.CompareInfo.MergeBase
|
||||
if ci.DirectComparison {
|
||||
ctx.Data["BeforeCommitID"] = ci.CompareInfo.BaseCommitID
|
||||
} else {
|
||||
ctx.Data["BeforeCommitID"] = ci.CompareInfo.MergeBase
|
||||
}
|
||||
|
||||
return ci
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"time"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
@@ -164,13 +164,18 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||
return
|
||||
}
|
||||
|
||||
context.CheckRepoScopedToken(ctx, repo)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.IsBasicAuth && ctx.Data["IsApiToken"] != true && ctx.Data["IsActionsToken"] != true {
|
||||
_, err = auth.GetTwoFactorByUID(ctx.Doer.ID)
|
||||
_, err = auth_model.GetTwoFactorByUID(ctx.Doer.ID)
|
||||
if err == nil {
|
||||
// TODO: This response should be changed to "invalid credentials" for security reasons once the expectation behind it (creating an app token to authenticate) is properly documented
|
||||
ctx.PlainText(http.StatusUnauthorized, "Users with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password. Please create and use a personal access token on the user settings page")
|
||||
return
|
||||
} else if !auth.IsErrTwoFactorNotEnrolled(err) {
|
||||
} else if !auth_model.IsErrTwoFactorNotEnrolled(err) {
|
||||
ctx.ServerError("IsErrTwoFactorNotEnrolled", err)
|
||||
return
|
||||
}
|
||||
|
||||
+46
-23
@@ -237,7 +237,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
||||
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5)
|
||||
|
||||
var mileIDs []int64
|
||||
if milestoneID > 0 {
|
||||
if milestoneID > 0 || milestoneID == db.NoConditionID { // -1 to get those issues which have no any milestone assigned
|
||||
mileIDs = []int64{milestoneID}
|
||||
}
|
||||
|
||||
@@ -438,14 +438,8 @@ func Issues(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
// Get milestones
|
||||
ctx.Data["Milestones"], _, err = issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
State: api.StateType(ctx.FormString("state")),
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("GetAllRepoMilestones", err)
|
||||
renderMilestones(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -454,6 +448,29 @@ func Issues(ctx *context.Context) {
|
||||
ctx.HTML(http.StatusOK, tplIssues)
|
||||
}
|
||||
|
||||
func renderMilestones(ctx *context.Context) {
|
||||
// Get milestones
|
||||
milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
State: api.StateAll,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("GetAllRepoMilestones", err)
|
||||
return
|
||||
}
|
||||
|
||||
openMilestones, closedMilestones := issues_model.MilestoneList{}, issues_model.MilestoneList{}
|
||||
for _, milestone := range milestones {
|
||||
if milestone.IsClosed {
|
||||
closedMilestones = append(closedMilestones, milestone)
|
||||
} else {
|
||||
openMilestones = append(openMilestones, milestone)
|
||||
}
|
||||
}
|
||||
ctx.Data["OpenMilestones"] = openMilestones
|
||||
ctx.Data["ClosedMilestones"] = closedMilestones
|
||||
}
|
||||
|
||||
// RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository
|
||||
func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.Repository) {
|
||||
var err error
|
||||
@@ -1563,7 +1580,7 @@ func ViewIssue(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if comment.Type == issues_model.CommentTypeCode || comment.Type == issues_model.CommentTypeReview || comment.Type == issues_model.CommentTypeDismissReview {
|
||||
} else if comment.Type.HasContentSupport() {
|
||||
comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
|
||||
URLPrefix: ctx.Repo.RepoLink,
|
||||
Metas: ctx.Repo.Repository.ComposeMetas(),
|
||||
@@ -1627,8 +1644,10 @@ func ViewIssue(ctx *context.Context) {
|
||||
comment.Type == issues_model.CommentTypeStopTracking {
|
||||
// drop error since times could be pruned from DB..
|
||||
_ = comment.LoadTime()
|
||||
} else if comment.Type == issues_model.CommentTypeClose {
|
||||
// record ID of latest closed comment.
|
||||
}
|
||||
|
||||
if comment.Type == issues_model.CommentTypeClose || comment.Type == issues_model.CommentTypeMergePull {
|
||||
// record ID of the latest closed/merged comment.
|
||||
// if PR is closed, the comments whose type is CommentTypePullRequestPush(29) after latestCloseCommentID won't be rendered.
|
||||
latestCloseCommentID = comment.ID
|
||||
}
|
||||
@@ -2800,7 +2819,7 @@ func UpdateCommentContent(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeReview && comment.Type != issues_model.CommentTypeCode {
|
||||
if !comment.Type.HasContentSupport() {
|
||||
ctx.Error(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
@@ -2864,7 +2883,7 @@ func DeleteComment(ctx *context.Context) {
|
||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
||||
ctx.Error(http.StatusForbidden)
|
||||
return
|
||||
} else if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeCode {
|
||||
} else if !comment.Type.HasContentSupport() {
|
||||
ctx.Error(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
@@ -3010,7 +3029,7 @@ func ChangeCommentReaction(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeCode && comment.Type != issues_model.CommentTypeReview {
|
||||
if !comment.Type.HasContentSupport() {
|
||||
ctx.Error(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
@@ -3126,15 +3145,19 @@ func GetCommentAttachments(ctx *context.Context) {
|
||||
ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !comment.Type.HasAttachmentSupport() {
|
||||
ctx.ServerError("GetCommentAttachments", fmt.Errorf("comment type %v does not support attachments", comment.Type))
|
||||
return
|
||||
}
|
||||
|
||||
attachments := make([]*api.Attachment, 0)
|
||||
if comment.Type == issues_model.CommentTypeComment {
|
||||
if err := comment.LoadAttachments(ctx); err != nil {
|
||||
ctx.ServerError("LoadAttachments", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < len(comment.Attachments); i++ {
|
||||
attachments = append(attachments, convert.ToAttachment(comment.Attachments[i]))
|
||||
}
|
||||
if err := comment.LoadAttachments(ctx); err != nil {
|
||||
ctx.ServerError("LoadAttachments", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < len(comment.Attachments); i++ {
|
||||
attachments = append(attachments, convert.ToAttachment(comment.Attachments[i]))
|
||||
}
|
||||
ctx.JSON(http.StatusOK, attachments)
|
||||
}
|
||||
|
||||
+15
-20
@@ -29,21 +29,17 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
tplReleases base.TplName = "repo/release/list"
|
||||
tplReleaseNew base.TplName = "repo/release/new"
|
||||
tplReleasesList base.TplName = "repo/release/list"
|
||||
tplReleaseNew base.TplName = "repo/release/new"
|
||||
tplTagsList base.TplName = "repo/tag/list"
|
||||
)
|
||||
|
||||
// calReleaseNumCommitsBehind calculates given release has how many commits behind release target.
|
||||
func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model.Release, countCache map[string]int64) error {
|
||||
// Fast return if release target is same as default branch.
|
||||
if repoCtx.BranchName == release.Target {
|
||||
release.NumCommitsBehind = repoCtx.CommitsCount - release.NumCommits
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get count if not exists
|
||||
if _, ok := countCache[release.Target]; !ok {
|
||||
if repoCtx.GitRepo.IsBranchExist(release.Target) {
|
||||
// short-circuit for the default branch
|
||||
if repoCtx.Repository.DefaultBranch == release.Target || repoCtx.GitRepo.IsBranchExist(release.Target) {
|
||||
commit, err := repoCtx.GitRepo.GetBranchCommit(release.Target)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetBranchCommit: %w", err)
|
||||
@@ -63,16 +59,19 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model
|
||||
|
||||
// Releases render releases list page
|
||||
func Releases(ctx *context.Context) {
|
||||
ctx.Data["PageIsReleaseList"] = true
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.releases")
|
||||
releasesOrTags(ctx, false)
|
||||
}
|
||||
|
||||
// TagsList render tags list page
|
||||
func TagsList(ctx *context.Context) {
|
||||
ctx.Data["PageIsTagList"] = true
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.tags")
|
||||
releasesOrTags(ctx, true)
|
||||
}
|
||||
|
||||
func releasesOrTags(ctx *context.Context, isTagList bool) {
|
||||
ctx.Data["PageIsReleaseList"] = true
|
||||
ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
|
||||
ctx.Data["IsViewBranch"] = false
|
||||
ctx.Data["IsViewTag"] = true
|
||||
@@ -80,14 +79,6 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
|
||||
ctx.Data["CanCreateBranch"] = false
|
||||
ctx.Data["HideBranchesInDropdown"] = true
|
||||
|
||||
if isTagList {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.tags")
|
||||
ctx.Data["PageIsTagList"] = true
|
||||
} else {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.releases")
|
||||
ctx.Data["PageIsTagList"] = false
|
||||
}
|
||||
|
||||
listOptions := db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: ctx.FormInt("limit"),
|
||||
@@ -197,7 +188,11 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
|
||||
pager.SetDefaultParams(ctx)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplReleases)
|
||||
if isTagList {
|
||||
ctx.HTML(http.StatusOK, tplTagsList)
|
||||
} else {
|
||||
ctx.HTML(http.StatusOK, tplReleasesList)
|
||||
}
|
||||
}
|
||||
|
||||
// ReleasesFeedRSS get feeds for releases in RSS format
|
||||
@@ -275,7 +270,7 @@ func SingleRelease(ctx *context.Context) {
|
||||
}
|
||||
|
||||
ctx.Data["Releases"] = []*repo_model.Release{release}
|
||||
ctx.HTML(http.StatusOK, tplReleases)
|
||||
ctx.HTML(http.StatusOK, tplReleasesList)
|
||||
}
|
||||
|
||||
// LatestRelease redirects to the latest release
|
||||
|
||||
@@ -41,6 +41,8 @@ func SecretsPost(ctx *context.Context) {
|
||||
func DeleteSecret(ctx *context.Context) {
|
||||
shared.PerformSecretsDelete(
|
||||
ctx,
|
||||
0,
|
||||
ctx.Repo.Repository.ID,
|
||||
ctx.Repo.RepoLink+"/settings/secrets",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1010,7 +1010,7 @@ func Stars(ctx *context.Context) {
|
||||
|
||||
// Forks render repository's forked users
|
||||
func Forks(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repos.forks")
|
||||
ctx.Data["Title"] = ctx.Tr("repo.forks")
|
||||
|
||||
page := ctx.FormInt("page")
|
||||
if page <= 0 {
|
||||
|
||||
@@ -22,13 +22,13 @@ import (
|
||||
func RunnersList(ctx *context.Context, tplName base.TplName, opts actions_model.FindRunnerOptions) {
|
||||
count, err := actions_model.CountRunners(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.ServerError("AdminRunners", err)
|
||||
ctx.ServerError("CountRunners", err)
|
||||
return
|
||||
}
|
||||
|
||||
runners, err := actions_model.FindRunners(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.ServerError("AdminRunners", err)
|
||||
ctx.ServerError("FindRunners", err)
|
||||
return
|
||||
}
|
||||
if err := runners.LoadAttributes(ctx); err != nil {
|
||||
|
||||
@@ -38,10 +38,10 @@ func PerformSecretsPost(ctx *context.Context, ownerID, repoID int64, redirectURL
|
||||
ctx.Redirect(redirectURL)
|
||||
}
|
||||
|
||||
func PerformSecretsDelete(ctx *context.Context, redirectURL string) {
|
||||
func PerformSecretsDelete(ctx *context.Context, ownerID, repoID int64, redirectURL string) {
|
||||
id := ctx.FormInt64("id")
|
||||
|
||||
if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil {
|
||||
if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id, OwnerID: ownerID, RepoID: repoID}); err != nil {
|
||||
log.Error("Delete secret %d failed: %v", id, err)
|
||||
ctx.Flash.Error(ctx.Tr("secrets.deletion.failed"))
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,8 @@ func SecretsPost(ctx *context.Context) {
|
||||
func SecretsDelete(ctx *context.Context) {
|
||||
shared.PerformSecretsDelete(
|
||||
ctx,
|
||||
ctx.Doer.ID,
|
||||
0,
|
||||
setting.AppSubURL+"/user/settings/secrets",
|
||||
)
|
||||
}
|
||||
|
||||
+7
-3
@@ -1215,7 +1215,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
|
||||
}, reqSignIn, context.RepoAssignment, context.UnitTypes())
|
||||
|
||||
// Releases
|
||||
// Tags
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Group("/tags", func() {
|
||||
m.Get("", repo.TagsList)
|
||||
@@ -1224,6 +1224,12 @@ func RegisterRoutes(m *web.Route) {
|
||||
}, func(ctx *context.Context) {
|
||||
ctx.Data["EnableFeed"] = setting.EnableFeed
|
||||
}, repo.MustBeNotEmpty, reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag, true))
|
||||
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
|
||||
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
|
||||
}, ignSignIn, context.RepoAssignment, context.UnitTypes())
|
||||
|
||||
// Releases
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/", repo.Releases)
|
||||
m.Get("/tag/*", repo.SingleRelease)
|
||||
@@ -1241,8 +1247,6 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Post("/attachments", repo.UploadReleaseAttachment)
|
||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, context.RepoRef())
|
||||
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
|
||||
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/edit/*", repo.EditRelease)
|
||||
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
|
||||
|
||||
@@ -137,8 +137,10 @@ func toCommitStatus(status actions_model.Status) api.CommitStatusState {
|
||||
switch status {
|
||||
case actions_model.StatusSuccess, actions_model.StatusSkipped:
|
||||
return api.CommitStatusSuccess
|
||||
case actions_model.StatusFailure, actions_model.StatusCancelled:
|
||||
case actions_model.StatusFailure:
|
||||
return api.CommitStatusFailure
|
||||
case actions_model.StatusCancelled:
|
||||
return api.CommitStatusWarning
|
||||
case actions_model.StatusWaiting, actions_model.StatusBlocked:
|
||||
return api.CommitStatusPending
|
||||
case actions_model.StatusRunning:
|
||||
|
||||
@@ -102,6 +102,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
|
||||
}
|
||||
|
||||
store.GetData()["IsApiToken"] = true
|
||||
store.GetData()["ApiTokenScope"] = token.Scope
|
||||
return u, nil
|
||||
} else if !auth_model.IsErrAccessTokenNotExist(err) && !auth_model.IsErrAccessTokenEmpty(err) {
|
||||
log.Error("GetAccessTokenBySha: %v", err)
|
||||
|
||||
@@ -90,8 +90,7 @@ func CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_m
|
||||
|
||||
// UpdateComment updates information of comment.
|
||||
func UpdateComment(ctx context.Context, c *issues_model.Comment, doer *user_model.User, oldContent string) error {
|
||||
needsContentHistory := c.Content != oldContent &&
|
||||
(c.Type == issues_model.CommentTypeComment || c.Type == issues_model.CommentTypeReview || c.Type == issues_model.CommentTypeCode)
|
||||
needsContentHistory := c.Content != oldContent && c.Type.HasContentSupport()
|
||||
if needsContentHistory {
|
||||
hasContentHistory, err := issues_model.HasIssueContentHistory(ctx, c.IssueID, c.ID)
|
||||
if err != nil {
|
||||
|
||||
@@ -58,6 +58,11 @@ func GetListLockHandler(ctx *context.Context) {
|
||||
}
|
||||
repository.MustOwner(ctx)
|
||||
|
||||
context.CheckRepoScopedToken(ctx, repository)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
authenticated := authenticate(ctx, repository, rv.Authorization, true, false)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
@@ -145,6 +150,11 @@ func PostLockHandler(ctx *context.Context) {
|
||||
}
|
||||
repository.MustOwner(ctx)
|
||||
|
||||
context.CheckRepoScopedToken(ctx, repository)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
authenticated := authenticate(ctx, repository, authorization, true, true)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
@@ -212,6 +222,11 @@ func VerifyLockHandler(ctx *context.Context) {
|
||||
}
|
||||
repository.MustOwner(ctx)
|
||||
|
||||
context.CheckRepoScopedToken(ctx, repository)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
authenticated := authenticate(ctx, repository, authorization, true, true)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
@@ -278,6 +293,11 @@ func UnLockHandler(ctx *context.Context) {
|
||||
}
|
||||
repository.MustOwner(ctx)
|
||||
|
||||
context.CheckRepoScopedToken(ctx, repository)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
authenticated := authenticate(ctx, repository, authorization, true, true)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
|
||||
@@ -423,6 +423,11 @@ func getAuthenticatedRepository(ctx *context.Context, rc *requestContext, requir
|
||||
return nil
|
||||
}
|
||||
|
||||
context.CheckRepoScopedToken(ctx, repository)
|
||||
if ctx.Written() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return repository
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,13 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
|
||||
if err := git.Push(gitRepo.Ctx, basePath, git.PushOptions{
|
||||
Remote: DefaultRemote,
|
||||
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, DefaultBranch),
|
||||
Env: repo_module.PushingEnvironment(doer, repo),
|
||||
Env: repo_module.FullPushingEnvironment(
|
||||
doer,
|
||||
doer,
|
||||
repo,
|
||||
repo.Name+".wiki",
|
||||
0,
|
||||
),
|
||||
}); err != nil {
|
||||
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
|
||||
return err
|
||||
|
||||
@@ -1,36 +1,34 @@
|
||||
<footer role="group" aria-label="{{.locale.Tr "aria.footer"}}">
|
||||
<div class="ui container">
|
||||
<div class="ui left" role="contentinfo" aria-label="{{.locale.Tr "aria.footer.software"}}">
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://gitea.io">{{.locale.Tr "powered_by" "Gitea"}}</a>
|
||||
{{if (or .ShowFooterVersion .PageIsAdmin)}}
|
||||
{{.locale.Tr "version"}}:
|
||||
{{if .IsAdmin}}
|
||||
<a href="{{AppSubUrl}}/admin/config">{{AppVer}}</a>
|
||||
{{else}}
|
||||
{{AppVer}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if and .TemplateLoadTimes ShowFooterTemplateLoadTime}}
|
||||
{{.locale.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong>
|
||||
{{.locale.Tr "template"}}{{if .TemplateName}} {{.TemplateName}}{{end}}: <strong>{{call .TemplateLoadTimes}}</strong>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="ui right links" role="group" aria-label="{{.locale.Tr "aria.footer.links"}}">
|
||||
{{if .ShowFooterBranding}}
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">{{svg "octicon-mark-github"}}<span class="sr-only">GitHub</span></a>
|
||||
<div class="ui left" role="contentinfo" aria-label="{{.locale.Tr "aria.footer.software"}}">
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://gitea.io">{{.locale.Tr "powered_by" "Gitea"}}</a>
|
||||
{{if (or .ShowFooterVersion .PageIsAdmin)}}
|
||||
{{.locale.Tr "version"}}:
|
||||
{{if .IsAdmin}}
|
||||
<a href="{{AppSubUrl}}/admin/config">{{AppVer}}</a>
|
||||
{{else}}
|
||||
{{AppVer}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if and .TemplateLoadTimes ShowFooterTemplateLoadTime}}
|
||||
{{.locale.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong>
|
||||
{{.locale.Tr "template"}}{{if .TemplateName}} {{.TemplateName}}{{end}}: <strong>{{call .TemplateLoadTimes}}</strong>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="ui right links" role="group" aria-label="{{.locale.Tr "aria.footer.links"}}">
|
||||
{{if .ShowFooterBranding}}
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">{{svg "octicon-mark-github"}}<span class="sr-only">GitHub</span></a>
|
||||
{{end}}
|
||||
<div class="ui language bottom floating slide up dropdown link item">
|
||||
{{svg "octicon-globe"}}
|
||||
<span>{{.locale.LangName}}</span>
|
||||
<div class="menu language-menu">
|
||||
{{range .AllLangs}}
|
||||
<a lang="{{.Lang}}" data-url="{{AppSubUrl}}/?lang={{.Lang}}" class="item {{if eq $.locale.Lang .Lang}}active selected{{end}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="menu language-menu">
|
||||
{{range .AllLangs}}
|
||||
<a lang="{{.Lang}}" data-url="{{AppSubUrl}}/?lang={{.Lang}}" class="item {{if eq $.locale.Lang .Lang}}active selected{{end}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<a href="{{AssetUrlPrefix}}/js/licenses.txt">{{.locale.Tr "licenses"}}</a>
|
||||
{{if .EnableSwagger}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}}
|
||||
{{template "custom/extra_links_footer" .}}
|
||||
</div>
|
||||
<a href="{{AssetUrlPrefix}}/js/licenses.txt">{{.locale.Tr "licenses"}}</a>
|
||||
{{if .EnableSwagger}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}}
|
||||
{{template "custom/extra_links_footer" .}}
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
|
||||
{{if .ManifestData}}<link rel="manifest" href="data:{{.ManifestData}}">{{end}}
|
||||
<meta name="theme-color" content="{{ThemeColorMetaTag}}">
|
||||
{{if ThemeColorMetaTag}}<meta name="theme-color" content="{{ThemeColorMetaTag}}">{{end}}
|
||||
<meta name="default-theme" content="{{DefaultTheme}}">
|
||||
<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}">
|
||||
<meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{{template "base/alert" .}}
|
||||
<div class="inline required field {{if .Err_OrgName}}error{{end}}">
|
||||
<label for="org_name">{{.locale.Tr "org.org_name_holder"}}</label>
|
||||
<input id="org_name" name="org_name" value="{{.org_name}}" autofocus required>
|
||||
<input id="org_name" name="org_name" value="{{.org_name}}" autofocus required maxlength="40">
|
||||
<span class="help">{{.locale.Tr "org.org_name_helper"}}</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -14,26 +14,27 @@
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="required field {{if .Err_Name}}error{{end}}">
|
||||
<label for="org_name">{{.locale.Tr "org.org_name_holder"}}
|
||||
<span class="text red gt-hidden" id="org-name-change-prompt"> {{.locale.Tr "org.settings.change_orgname_prompt"}}</span>
|
||||
<span class="text red gt-hidden" id="org-name-change-redirect-prompt"> {{.locale.Tr "org.settings.change_orgname_redirect_prompt"}}</span>
|
||||
<span class="text red gt-hidden" id="org-name-change-prompt">
|
||||
<br>{{.locale.Tr "org.settings.change_orgname_prompt"}}<br>{{.locale.Tr "org.settings.change_orgname_redirect_prompt"}}
|
||||
</span>
|
||||
</label>
|
||||
<input id="org_name" name="name" value="{{.Org.Name}}" data-org-name="{{.Org.Name}}" autofocus required>
|
||||
<input id="org_name" name="name" value="{{.Org.Name}}" data-org-name="{{.Org.Name}}" autofocus required maxlength="40">
|
||||
</div>
|
||||
<div class="field {{if .Err_FullName}}error{{end}}">
|
||||
<label for="full_name">{{.locale.Tr "org.org_full_name_holder"}}</label>
|
||||
<input id="full_name" name="full_name" value="{{.Org.FullName}}">
|
||||
<input id="full_name" name="full_name" value="{{.Org.FullName}}" maxlength="100">
|
||||
</div>
|
||||
<div class="field {{if .Err_Description}}error{{end}}">
|
||||
<label for="description">{{$.locale.Tr "org.org_desc"}}</label>
|
||||
<textarea id="description" name="description" rows="2">{{.Org.Description}}</textarea>
|
||||
<textarea id="description" name="description" rows="2" maxlength="255">{{.Org.Description}}</textarea>
|
||||
</div>
|
||||
<div class="field {{if .Err_Website}}error{{end}}">
|
||||
<label for="website">{{.locale.Tr "org.settings.website"}}</label>
|
||||
<input id="website" name="website" type="url" value="{{.Org.Website}}">
|
||||
<input id="website" name="website" type="url" value="{{.Org.Website}}" maxlength="255">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="location">{{.locale.Tr "org.settings.location"}}</label>
|
||||
<input id="location" name="location" value="{{.Org.Location}}">
|
||||
<input id="location" name="location" value="{{.Org.Location}}" maxlength="50">
|
||||
</div>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
@@ -50,13 +50,13 @@ git push -u origin {{.Repository.DefaultBranch}}</code></pre>
|
||||
git push -u origin {{.Repository.DefaultBranch}}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
{{template "repo/clone_script" .}}
|
||||
{{end}}
|
||||
{{else}}
|
||||
<div class="ui segment center">
|
||||
{{.locale.Tr "repo.empty_message"}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{template "repo/clone_script" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Milestone -->
|
||||
<div class="ui {{if not .Milestones}}disabled{{end}} dropdown jump item">
|
||||
<div class="ui {{if not (or .OpenMilestones .ClosedMilestones)}}disabled{{end}} dropdown jump item">
|
||||
<span class="text">
|
||||
{{.locale.Tr "repo.issues.filter_milestone"}}
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
@@ -73,9 +73,28 @@
|
||||
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
|
||||
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestone"}}">
|
||||
</div>
|
||||
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_milestone_no_select"}}</a>
|
||||
{{range .Milestones}}
|
||||
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected{{end}}{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.Name}}</a>
|
||||
<div class="divider"></div>
|
||||
<a class="{{if not $.MilestoneID}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=0&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_milestone_all"}}</a>
|
||||
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID -1}}active selected {{end}}{{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=-1&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_milestone_none"}}</a>
|
||||
{{if .OpenMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">{{.locale.Tr "repo.issues.filter_milestone_open"}}</div>
|
||||
{{range .OpenMilestones}}
|
||||
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">
|
||||
{{svg "octicon-milestone" 16 "mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .ClosedMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">{{.locale.Tr "repo.issues.filter_milestone_closed"}}</div>
|
||||
{{range .ClosedMilestones}}
|
||||
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">
|
||||
{{svg "octicon-milestone" 16 "mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_milestone_title"}}</div>
|
||||
{{if or .OpenMilestones .ClosedMilestones}}
|
||||
<div class="ui icon search input">
|
||||
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
|
||||
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestones"}}">
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
{{end}}
|
||||
<div class="no-select item">{{.locale.Tr "repo.issues.new.clear_milestone"}}</div>
|
||||
{{if and (not .OpenMilestones) (not .ClosedMilestones)}}
|
||||
<div class="header" style="text-transform: none;font-size:14px;">
|
||||
{{.locale.Tr "repo.issues.new.no_items"}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{if .OpenMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">
|
||||
{{.locale.Tr "repo.issues.new.open_milestone"}}
|
||||
</div>
|
||||
{{range .OpenMilestones}}
|
||||
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
|
||||
{{svg "octicon-milestone" 16 "gt-mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .ClosedMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">
|
||||
{{.locale.Tr "repo.issues.new.closed_milestone"}}
|
||||
</div>
|
||||
{{range .ClosedMilestones}}
|
||||
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
|
||||
{{svg "octicon-milestone" 16 "gt-mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -93,44 +93,7 @@
|
||||
{{end}}
|
||||
</span>
|
||||
<div class="menu">
|
||||
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_milestone_title"}}</div>
|
||||
{{if or .OpenMilestones .ClosedMilestones}}
|
||||
<div class="ui icon search input">
|
||||
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
|
||||
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestones"}}">
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="no-select item">{{.locale.Tr "repo.issues.new.clear_milestone"}}</div>
|
||||
{{if and (not .OpenMilestones) (not .ClosedMilestones)}}
|
||||
<div class="header" style="text-transform: none;font-size:14px;">
|
||||
{{.locale.Tr "repo.issues.new.no_items"}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{if .OpenMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">
|
||||
{{.locale.Tr "repo.issues.new.open_milestone"}}
|
||||
</div>
|
||||
{{range .OpenMilestones}}
|
||||
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
|
||||
{{svg "octicon-milestone" 16 "gt-mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .ClosedMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">
|
||||
{{.locale.Tr "repo.issues.new.closed_milestone"}}
|
||||
</div>
|
||||
{{range .ClosedMilestones}}
|
||||
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
|
||||
{{svg "octicon-milestone" 16 "gt-mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{template "repo/issue/milestone/select_menu" .}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui select-milestone list">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<div class="dropzone-attachments">
|
||||
{{if .Attachments}}
|
||||
<div class="ui clearing divider"></div>
|
||||
<div class="ui divider"></div>
|
||||
{{end}}
|
||||
<div class="ui middle aligned padded grid">
|
||||
{{$hasThumbnails := false}}
|
||||
{{- range .Attachments -}}
|
||||
<div class="twelve wide column" style="padding: 6px;">
|
||||
{{$hasThumbnails := false}}
|
||||
{{- range .Attachments -}}
|
||||
<div class="gt-df">
|
||||
<div class="gt-f1 gt-p-3">
|
||||
<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}" title='{{$.ctx.locale.Tr "repo.issues.attachment.open_tab" .Name}}'>
|
||||
{{if FilenameIsImage .Name}}
|
||||
{{if not (containGeneric $.Content .UUID)}}
|
||||
@@ -18,14 +18,14 @@
|
||||
<span><strong>{{.Name}}</strong></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="four wide column" style="padding: 0px;">
|
||||
<div class="gt-p-3 gt-df gt-ac">
|
||||
<span class="ui text grey right">{{.Size | FileSize}}</span>
|
||||
</div>
|
||||
{{end -}}
|
||||
</div>
|
||||
</div>
|
||||
{{end -}}
|
||||
|
||||
{{if $hasThumbnails}}
|
||||
<div class="ui clearing divider"></div>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui small thumbnails">
|
||||
{{- range .Attachments -}}
|
||||
{{if FilenameIsImage .Name}}
|
||||
|
||||
@@ -161,44 +161,7 @@
|
||||
{{end}}
|
||||
</a>
|
||||
<div class="menu" data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/milestone">
|
||||
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_milestone_title"}}</div>
|
||||
{{if or .OpenMilestones .ClosedMilestones}}
|
||||
<div class="ui icon search input">
|
||||
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
|
||||
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestones"}}">
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="no-select item">{{.locale.Tr "repo.issues.new.clear_milestone"}}</div>
|
||||
{{if and (not .OpenMilestones) (not .ClosedMilestones)}}
|
||||
<div class="header" style="text-transform: none;font-size:14px;">
|
||||
{{.locale.Tr "repo.issues.new.no_items"}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{if .OpenMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">
|
||||
{{.locale.Tr "repo.issues.new.open_milestone"}}
|
||||
</div>
|
||||
{{range .OpenMilestones}}
|
||||
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
|
||||
{{svg "octicon-milestone" 16 "gt-mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .ClosedMilestones}}
|
||||
<div class="divider"></div>
|
||||
<div class="header">
|
||||
{{.locale.Tr "repo.issues.new.closed_milestone"}}
|
||||
</div>
|
||||
{{range .ClosedMilestones}}
|
||||
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
|
||||
{{svg "octicon-milestone" 16 "gt-mr-2"}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{template "repo/issue/milestone/select_menu" .}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui select-milestone list">
|
||||
@@ -704,7 +667,7 @@
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if and .Issue.IsPull .IsIssuePoster (not .Issue.IsClosed)}}
|
||||
{{if and .Issue.IsPull .IsIssuePoster (not .Issue.IsClosed) .Issue.PullRequest.HeadRepo}}
|
||||
{{if and (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) .CanWriteToHeadRepo}}
|
||||
<div class="ui divider"></div>
|
||||
<div class="inline field">
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<h2 class="project-title">{{$.Project.Title}}</h2>
|
||||
<div class="content project-description">{{$.Project.RenderedContent|Str2html}}</div>
|
||||
</div>
|
||||
{{if and (or $.CanWriteIssues $.CanWritePulls) (not $.Repository.IsArchived)}}
|
||||
{{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
|
||||
<div class="column right aligned">
|
||||
<div class="ui compact right small menu">
|
||||
<a class="item" href="{{$.RepoLink}}/projects/{{.Project.ID}}/edit?redirect=project" data-id={{$.Project.ID}} data-title={{$.Project.Title}}>
|
||||
@@ -267,7 +267,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
{{if or .CanWriteIssues .CanWritePulls}}
|
||||
{{if .CanWriteProjects}}
|
||||
<div class="ui small basic delete modal">
|
||||
<div class="ui icon header">
|
||||
{{svg "octicon-trash"}}
|
||||
|
||||
@@ -1,73 +1,15 @@
|
||||
{{template "base/head" .}}
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content repository release">
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content repository releases">
|
||||
{{template "repo/header" .}}
|
||||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<h2 class="ui compact small menu header">
|
||||
{{if .Permission.CanRead $.UnitTypeReleases}}
|
||||
<a class="{{if (not .PageIsTagList)}}active {{end}}item" href="{{.RepoLink}}/releases">{{.locale.Tr "repo.release.releases"}}</a>
|
||||
{{end}}
|
||||
{{if .Permission.CanRead $.UnitTypeCode}}
|
||||
<a class="{{if .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/tags">{{.locale.Tr "repo.release.tags"}}</a>
|
||||
{{end}}
|
||||
</h2>
|
||||
{{if .EnableFeed}}
|
||||
<a href="{{.RepoLink}}/{{if .PageIsTagList}}tags{{else}}releases{{end}}.rss"><i class="ui grey icon tooltip gt-ml-3" data-content="{{.locale.Tr "rss_feed"}}" data-position="top center">{{svg "octicon-rss" 18}}</i></a>
|
||||
{{end}}
|
||||
{{if (and .CanCreateRelease (not .PageIsTagList))}}
|
||||
{{template "repo/sub_menu_release_tag" .}}
|
||||
|
||||
{{if .CanCreateRelease}}
|
||||
<a class="ui right small green button" href="{{$.RepoLink}}/releases/new">
|
||||
{{.locale.Tr "repo.release.new_release"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .PageIsTagList}}
|
||||
<div class="ui divider"></div>
|
||||
{{if gt .ReleasesNum 0}}
|
||||
<h4 class="ui top attached header">
|
||||
<div class="five wide column gt-df gt-ac">
|
||||
{{svg "octicon-tag" 16 "gt-mr-2"}}{{.locale.Tr "repo.release.tags"}}
|
||||
</div>
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped fixed table single line" id="tags-table">
|
||||
<thead></thead>
|
||||
<tbody class="tag-list">
|
||||
{{range $idx, $release := .Releases}}
|
||||
<tr>
|
||||
<td class="tag">
|
||||
<h3 class="release-tag-name gt-mb-3">
|
||||
<a class="gt-df gt-ac" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
|
||||
</h3>
|
||||
<div class="download gt-df gt-ac">
|
||||
{{if $.Permission.CanRead $.UnitTypeCode}}
|
||||
{{if .CreatedUnix}}
|
||||
<span class="gt-mr-3">{{svg "octicon-clock" 16 "gt-mr-2"}}{{TimeSinceUnix .CreatedUnix $.locale}}</span>
|
||||
{{end}}
|
||||
<a class="gt-mr-3 gt-mono muted" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a>
|
||||
{{if not $.DisableDownloadSourceArchives}}
|
||||
<a class="archive-link gt-mr-3 muted" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "gt-mr-2"}}ZIP</a>
|
||||
<a class="archive-link gt-mr-3 muted" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow">{{svg "octicon-file-zip" 16 "gt-mr-2"}}TAR.GZ</a>
|
||||
{{end}}
|
||||
{{if (and $.CanCreateRelease $release.IsTag)}}
|
||||
<a class="gt-mr-3 muted" href="{{$.RepoLink}}/releases/new?tag={{.TagName}}">{{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.new_release"}}</a>
|
||||
{{end}}
|
||||
{{if (and ($.Permission.CanWrite $.UnitTypeCode) $release.IsTag)}}
|
||||
<a class="ui delete-button gt-mr-3 muted" data-url="{{$.RepoLink}}/tags/delete" data-id="{{.ID}}">
|
||||
{{svg "octicon-trash" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.delete_tag"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if (not $release.IsTag)}}
|
||||
<a class="gt-mr-3 muted" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}">{{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.detail"}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<ul id="release-list">
|
||||
{{range $idx, $release := .Releases}}
|
||||
<li class="ui grid">
|
||||
@@ -196,7 +138,7 @@
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
|
||||
{{template "base/paginate" .}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
{{range .PushMirrors}}
|
||||
<tr>
|
||||
{{$address := MirrorRemoteAddress $.Context $.Repository .GetRemoteName true}}
|
||||
<td>{{$address.Address}}</td>
|
||||
<td class="gt-word-break">{{$address.Address}}</td>
|
||||
<td>{{$.locale.Tr "repo.settings.mirror_settings.direction.push"}}</td>
|
||||
<td>{{if .LastUpdateUnix}}<time data-format="date-time" datetime="{{.LastUpdateUnix.FormatLong}}">{{.LastUpdateUnix.AsTime}}</time>{{else}}{{$.locale.Tr "never"}}{{end}} {{if .LastError}}<div class="ui red label tooltip" data-content="{{.LastError}}">{{$.locale.Tr "error"}}</div>{{end}}</td>
|
||||
<td class="right aligned">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<a class="ui" href="{{.RepoLink}}/branches">{{svg "octicon-git-branch"}} <b>{{.BranchesCount}}</b> {{.locale.TrN .BranchesCount "repo.branch" "repo.branches"}}</a>
|
||||
</div>
|
||||
{{if $.Permission.CanRead $.UnitTypeCode}}
|
||||
<div class="item">
|
||||
<div class="item{{if .PageIsTagList}} active{{end}}">
|
||||
<a class="ui" href="{{.RepoLink}}/tags">{{svg "octicon-tag"}} <b>{{.NumTags}}</b> {{.locale.TrN .NumTags "repo.tag" "repo.tags"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{{$canReadReleases := $.Permission.CanRead $.UnitTypeReleases}}
|
||||
{{$canReadCode := $.Permission.CanRead $.UnitTypeCode}}
|
||||
|
||||
{{if $canReadReleases}}
|
||||
<h2 class="ui compact small menu header">
|
||||
<a class="{{if .PageIsReleaseList}}active {{end}}item" href="{{.RepoLink}}/releases">{{.locale.Tr "repo.release.releases"}}</a>
|
||||
{{if $canReadCode}}
|
||||
<a class="{{if .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/tags">{{.locale.Tr "repo.release.tags"}}</a>
|
||||
{{end}}
|
||||
</h2>
|
||||
|
||||
{{if .EnableFeed}}
|
||||
<a href="{{.RepoLink}}/{{if .PageIsTagList}}tags{{else}}releases{{end}}.rss"><i class="ui grey icon gt-ml-3" data-tooltip-content="{{.locale.Tr "rss_feed"}}">{{svg "octicon-rss" 18}}</i></a>
|
||||
{{end}}
|
||||
{{else if $canReadCode}}
|
||||
{{template "repo/sub_menu" .}}
|
||||
{{end}}
|
||||
@@ -0,0 +1,85 @@
|
||||
{{template "base/head" .}}
|
||||
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content repository tags">
|
||||
{{template "repo/header" .}}
|
||||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
{{template "repo/sub_menu_release_tag" .}}
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
<div class="five wide column gt-df gt-ac">
|
||||
{{svg "octicon-tag" 16 "gt-mr-2"}}{{.locale.Tr "repo.release.tags"}}
|
||||
</div>
|
||||
</h4>
|
||||
|
||||
{{$canReadReleases := $.Permission.CanRead $.UnitTypeReleases}}
|
||||
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped fixed table single line" id="tags-table">
|
||||
<tbody class="tag-list">
|
||||
{{range $idx, $release := .Releases}}
|
||||
<tr>
|
||||
<td class="tag">
|
||||
<h3 class="release-tag-name gt-mb-3">
|
||||
{{if $canReadReleases}}
|
||||
<a class="gt-df gt-ac" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
|
||||
{{else}}
|
||||
<a class="gt-df gt-ac" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
|
||||
{{end}}
|
||||
</h3>
|
||||
<div class="download gt-df gt-ac">
|
||||
{{if $.Permission.CanRead $.UnitTypeCode}}
|
||||
{{if .CreatedUnix}}
|
||||
<span class="gt-mr-3">{{svg "octicon-clock" 16 "gt-mr-2"}}{{TimeSinceUnix .CreatedUnix $.locale}}</span>
|
||||
{{end}}
|
||||
|
||||
<a class="gt-mr-3 gt-mono muted" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a>
|
||||
|
||||
{{if not $.DisableDownloadSourceArchives}}
|
||||
<a class="archive-link gt-mr-3 muted" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "gt-mr-2"}}ZIP</a>
|
||||
<a class="archive-link gt-mr-3 muted" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow">{{svg "octicon-file-zip" 16 "gt-mr-2"}}TAR.GZ</a>
|
||||
{{end}}
|
||||
|
||||
{{if (and $canReadReleases $.CanCreateRelease $release.IsTag)}}
|
||||
<a class="gt-mr-3 muted" href="{{$.RepoLink}}/releases/new?tag={{.TagName}}">{{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.new_release"}}</a>
|
||||
{{end}}
|
||||
|
||||
{{if (and ($.Permission.CanWrite $.UnitTypeCode) $release.IsTag)}}
|
||||
<a class="ui delete-button gt-mr-3 muted" data-url="{{$.RepoLink}}/tags/delete" data-id="{{.ID}}">
|
||||
{{svg "octicon-trash" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.delete_tag"}}
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
{{if and $canReadReleases (not $release.IsTag)}}
|
||||
<a class="gt-mr-3 muted" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}">{{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.detail"}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{template "base/paginate" .}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if $.Permission.CanWrite $.UnitTypeCode}}
|
||||
<div class="ui small basic delete modal">
|
||||
<div class="ui header">
|
||||
{{svg "octicon-trash" 16 "gt-mr-2"}}
|
||||
{{.locale.Tr "repo.release.delete_tag"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{.locale.Tr "repo.release.deletion_tag_desc"}}</p>
|
||||
</div>
|
||||
{{template "base/delete_modal_actions" .}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{template "base/footer" .}}
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="ui container user-cards">
|
||||
<div class="user-cards">
|
||||
{{if .CardsTitle}}
|
||||
<h2 class="ui dividing header">
|
||||
{{.CardsTitle}}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{{template "base/head" .}}
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content repository watchers">
|
||||
{{template "repo/header" .}}
|
||||
{{template "repo/user_cards" .}}
|
||||
<div class="ui container">
|
||||
{{template "repo/user_cards" .}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
|
||||
@@ -223,6 +223,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "Delete a hook",
|
||||
"operationId": "adminDeleteHook",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "id of the hook to delete",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"$ref": "#/responses/empty"
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
@@ -731,33 +756,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/amdin/hooks/{id}": {
|
||||
"delete": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "Delete a hook",
|
||||
"operationId": "adminDeleteHook",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "id of the hook to delete",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"$ref": "#/responses/empty"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/markdown": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ref: refs/heads/main
|
||||
@@ -0,0 +1,4 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = true
|
||||
@@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||
:
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use IPC::Open2;
|
||||
|
||||
# An example hook script to integrate Watchman
|
||||
# (https://facebook.github.io/watchman/) with git to speed up detecting
|
||||
# new and modified files.
|
||||
#
|
||||
# The hook is passed a version (currently 2) and last update token
|
||||
# formatted as a string and outputs to stdout a new update token and
|
||||
# all files that have been modified since the update token. Paths must
|
||||
# be relative to the root of the working tree and separated by a single NUL.
|
||||
#
|
||||
# To enable this hook, rename this file to "query-watchman" and set
|
||||
# 'git config core.fsmonitor .git/hooks/query-watchman'
|
||||
#
|
||||
my ($version, $last_update_token) = @ARGV;
|
||||
|
||||
# Uncomment for debugging
|
||||
# print STDERR "$0 $version $last_update_token\n";
|
||||
|
||||
# Check the hook interface version
|
||||
if ($version ne 2) {
|
||||
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
||||
"Falling back to scanning...\n";
|
||||
}
|
||||
|
||||
my $git_work_tree = get_working_dir();
|
||||
|
||||
my $retry = 1;
|
||||
|
||||
my $json_pkg;
|
||||
eval {
|
||||
require JSON::XS;
|
||||
$json_pkg = "JSON::XS";
|
||||
1;
|
||||
} or do {
|
||||
require JSON::PP;
|
||||
$json_pkg = "JSON::PP";
|
||||
};
|
||||
|
||||
launch_watchman();
|
||||
|
||||
sub launch_watchman {
|
||||
my $o = watchman_query();
|
||||
if (is_work_tree_watched($o)) {
|
||||
output_result($o->{clock}, @{$o->{files}});
|
||||
}
|
||||
}
|
||||
|
||||
sub output_result {
|
||||
my ($clockid, @files) = @_;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# binmode $fh, ":utf8";
|
||||
# print $fh "$clockid\n@files\n";
|
||||
# close $fh;
|
||||
|
||||
binmode STDOUT, ":utf8";
|
||||
print $clockid;
|
||||
print "\0";
|
||||
local $, = "\0";
|
||||
print @files;
|
||||
}
|
||||
|
||||
sub watchman_clock {
|
||||
my $response = qx/watchman clock "$git_work_tree"/;
|
||||
die "Failed to get clock id on '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub watchman_query {
|
||||
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
|
||||
or die "open2() failed: $!\n" .
|
||||
"Falling back to scanning...\n";
|
||||
|
||||
# In the query expression below we're asking for names of files that
|
||||
# changed since $last_update_token but not from the .git folder.
|
||||
#
|
||||
# To accomplish this, we're using the "since" generator to use the
|
||||
# recency index to select candidate nodes and "fields" to limit the
|
||||
# output to file names only. Then we're using the "expression" term to
|
||||
# further constrain the results.
|
||||
my $last_update_line = "";
|
||||
if (substr($last_update_token, 0, 1) eq "c") {
|
||||
$last_update_token = "\"$last_update_token\"";
|
||||
$last_update_line = qq[\n"since": $last_update_token,];
|
||||
}
|
||||
my $query = <<" END";
|
||||
["query", "$git_work_tree", {$last_update_line
|
||||
"fields": ["name"],
|
||||
"expression": ["not", ["dirname", ".git"]]
|
||||
}]
|
||||
END
|
||||
|
||||
# Uncomment for debugging the watchman query
|
||||
# open (my $fh, ">", ".git/watchman-query.json");
|
||||
# print $fh $query;
|
||||
# close $fh;
|
||||
|
||||
print CHLD_IN $query;
|
||||
close CHLD_IN;
|
||||
my $response = do {local $/; <CHLD_OUT>};
|
||||
|
||||
# Uncomment for debugging the watch response
|
||||
# open ($fh, ">", ".git/watchman-response.json");
|
||||
# print $fh $response;
|
||||
# close $fh;
|
||||
|
||||
die "Watchman: command returned no output.\n" .
|
||||
"Falling back to scanning...\n" if $response eq "";
|
||||
die "Watchman: command returned invalid output: $response\n" .
|
||||
"Falling back to scanning...\n" unless $response =~ /^\{/;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub is_work_tree_watched {
|
||||
my ($output) = @_;
|
||||
my $error = $output->{error};
|
||||
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
|
||||
$retry--;
|
||||
my $response = qx/watchman watch "$git_work_tree"/;
|
||||
die "Failed to make watchman watch '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
$output = $json_pkg->new->utf8->decode($response);
|
||||
$error = $output->{error};
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# close $fh;
|
||||
|
||||
# Watchman will always return all files on the first query so
|
||||
# return the fast "everything is dirty" flag to git and do the
|
||||
# Watchman query just to get it over with now so we won't pay
|
||||
# the cost in git to look up each individual file.
|
||||
my $o = watchman_clock();
|
||||
$error = $output->{error};
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
output_result($o->{clock}, ("/"));
|
||||
$last_update_token = $o->{clock};
|
||||
|
||||
eval { launch_watchman() };
|
||||
return 0;
|
||||
}
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub get_working_dir {
|
||||
my $working_dir;
|
||||
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
|
||||
$working_dir = Win32::GetCwd();
|
||||
$working_dir =~ tr/\\/\//;
|
||||
} else {
|
||||
require Cwd;
|
||||
$working_dir = Cwd::cwd();
|
||||
}
|
||||
|
||||
return $working_dir;
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare a packed repository for use over
|
||||
# dumb transports.
|
||||
#
|
||||
# To enable this hook, rename this file to "post-update".
|
||||
|
||||
exec git update-server-info
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||
:
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=$(git hash-object -t tree /dev/null)
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git merge" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message to
|
||||
# stderr if it wants to stop the merge commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-merge-commit".
|
||||
|
||||
. git-sh-setup
|
||||
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||
exec "$GIT_DIR/hooks/pre-commit"
|
||||
:
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
# An example hook script to verify what is about to be pushed. Called by "git
|
||||
# push" after it has checked the remote status, but before anything has been
|
||||
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# This hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- Name of the remote to which the push is being done
|
||||
# $2 -- URL to which the push is being done
|
||||
#
|
||||
# If pushing without using a named remote those arguments will be equal.
|
||||
#
|
||||
# Information about the commits which are being pushed is supplied as lines to
|
||||
# the standard input in the form:
|
||||
#
|
||||
# <local ref> <local oid> <remote ref> <remote oid>
|
||||
#
|
||||
# This sample shows how to prevent push of commits where the log message starts
|
||||
# with "WIP" (work in progress).
|
||||
|
||||
remote="$1"
|
||||
url="$2"
|
||||
|
||||
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||
|
||||
while read local_ref local_oid remote_ref remote_oid
|
||||
do
|
||||
if test "$local_oid" = "$zero"
|
||||
then
|
||||
# Handle delete
|
||||
:
|
||||
else
|
||||
if test "$remote_oid" = "$zero"
|
||||
then
|
||||
# New branch, examine all commits
|
||||
range="$local_oid"
|
||||
else
|
||||
# Update to existing branch, examine new commits
|
||||
range="$remote_oid..$local_oid"
|
||||
fi
|
||||
|
||||
# Check for WIP commit
|
||||
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||
if test -n "$commit"
|
||||
then
|
||||
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user