Compare commits
No commits in common. "master" and "docker_compose" have entirely different histories.
master
...
docker_com
|
@ -1,68 +0,0 @@
|
|||
version: 2
|
||||
name: gitlink正式环境
|
||||
description: ""
|
||||
global:
|
||||
concurrent: 1
|
||||
workflow:
|
||||
- ref: start
|
||||
name: 开始
|
||||
task: start
|
||||
- ref: git_clone_0
|
||||
name: git clone
|
||||
on-failure: ignore
|
||||
task: git_clone@1.2.6
|
||||
input:
|
||||
remote_url: '"https://gitlink.org.cn/Gitlink/gitea_hat.git"'
|
||||
ref: '"refs/heads/master"'
|
||||
commit_id: '""'
|
||||
depth: 1
|
||||
needs:
|
||||
- start
|
||||
- ref: end
|
||||
name: 结束
|
||||
task: end
|
||||
needs:
|
||||
- gitlink_ssh_cmd_0
|
||||
- ref: gitlink_scp_resource_0
|
||||
name: scp复制文件(支持跳板机)
|
||||
on-failure: ignore
|
||||
task: yystopf/gitlink_scp_resource@0.0.7
|
||||
input:
|
||||
ssh_private_key: ((ssh.siyao))
|
||||
remote_host: '"10.9.117.109"'
|
||||
remote_port: '"22"'
|
||||
remote_user: '"root"'
|
||||
remote_file: '"/root/gitea"'
|
||||
local_file: golang_build_node_0.bin_dir
|
||||
gateway_host: '"123.59.135.93"'
|
||||
gateway_port: '"51123"'
|
||||
gateway_user: '"pdl"'
|
||||
temp_file: '"/home/pdl/gitea"'
|
||||
needs:
|
||||
- golang_build_node_0
|
||||
- ref: golang_build_node_0
|
||||
name: golang_build_node
|
||||
on-failure: ignore
|
||||
task: yystopf/golang_build_node@0.0.2
|
||||
input:
|
||||
workspace: git_clone_0.git_path
|
||||
out_bin_name: '"gitea"'
|
||||
goos: '"linux"'
|
||||
goarch: '"amd64"'
|
||||
needs:
|
||||
- git_clone_0
|
||||
- ref: gitlink_ssh_cmd_0
|
||||
name: ssh执行命令(支持跳板机)
|
||||
task: yystopf/gitlink_ssh_cmd@0.0.6
|
||||
input:
|
||||
ssh_private_key: ((ssh.siyao))
|
||||
remote_host: '"10.9.117.109"'
|
||||
remote_port: '"22"'
|
||||
remote_user: '"root"'
|
||||
gateway_host: '"123.59.135.93"'
|
||||
gateway_port: '"51123"'
|
||||
gateway_user: '"pdl"'
|
||||
ssh_cmd: '"sh update.sh"'
|
||||
needs:
|
||||
- gitlink_scp_resource_0
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
version: 2
|
||||
name: test
|
||||
description: ""
|
||||
global:
|
||||
concurrent: 1
|
||||
trigger:
|
||||
webhook: gitlink@1.0.0
|
||||
event:
|
||||
- ref: push
|
||||
ruleset-operator: AND
|
||||
workflow:
|
||||
- ref: start
|
||||
name: 开始
|
||||
task: start
|
||||
- ref: git_clone_0
|
||||
name: git clone
|
||||
task: git_clone@1.2.9
|
||||
input:
|
||||
remote_url: '""'
|
||||
ref: '"refs/heads/master"'
|
||||
commit_id: '""'
|
||||
depth: 1
|
||||
needs:
|
||||
- start
|
||||
- ref: golong_build_122_0
|
||||
name: golang build 1.22
|
||||
task: dagege/golong_build_122@1.0.4
|
||||
input:
|
||||
workspace: git_clone_0.git_path
|
||||
out_bin_name: catpaw
|
||||
GOOS: '"linux"'
|
||||
GOARCH: '"amd64"'
|
||||
needs:
|
||||
- git_clone_0
|
||||
- ref: end
|
||||
name: 结束
|
||||
task: end
|
||||
needs:
|
||||
- golong_build_122_0
|
||||
|
|
@ -42,10 +42,6 @@
|
|||
|
||||
## 编译
|
||||
|
||||
```
|
||||
sh build.sh
|
||||
```
|
||||
|
||||
类Linux平台,在项目根目录运行:
|
||||
```shell
|
||||
# 编译Linux 64位可执行程序
|
||||
|
|
174
app.ini.example
174
app.ini.example
|
@ -1,174 +0,0 @@
|
|||
APP_NAME = Gitea: Git with a cup of tea
|
||||
RUN_USER = git
|
||||
RUN_MODE = prod
|
||||
WORK_PATH = /usr/local/bin
|
||||
|
||||
[nacos]
|
||||
SERVER = 127.0.0.1
|
||||
PORT = 8848
|
||||
WEIGHT = 10
|
||||
|
||||
[oauth2]
|
||||
JWT_SECRET = pyD-ZA6zwykBhVCWdF5FsdRGDtM6kg16JLhcCu8uLPM
|
||||
|
||||
[security]
|
||||
INTERNAL_TOKEN = eyDDbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE1NzQyMzU3OTN9.w7RDQaNanZHdC2XIrr9kAntPIjhfkXXOiBnNTbEdqQ8
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = K4DDaucPzKQnTf7WQxKFIoFNtIlsWVacoN5Ss3VDypQBUes7Ncy96UU735sfGOar
|
||||
REVERSE_PROXY_LIMIT = 1
|
||||
REVERSE_PROXY_TRUSTED_PROXIES = *
|
||||
PASSWORD_HASH_ALGO = pbkdf2
|
||||
|
||||
[database]
|
||||
PATH = /data/gitea/gitea.db
|
||||
DB_TYPE = mysql
|
||||
HOST = 127.0.0.1:3306
|
||||
NAME = gitea_hat
|
||||
USER = root
|
||||
PASSWD = `123456`
|
||||
MYSQL_CHARSET = utf8
|
||||
SSL_MODE = disable
|
||||
CONN_MAX_LIFE_TIME=180
|
||||
MAX_IDLE_CONNS=5
|
||||
MAX_OPEN_CONNS=200
|
||||
LOG_SQL =false
|
||||
|
||||
[repository]
|
||||
ROOT = /data/gitea-repositories
|
||||
DEFAULT_BRANCH = master
|
||||
DEFAULT_FORK_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages,repo.actions
|
||||
DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages,repo.actions
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
||||
[repository.upload]
|
||||
TEMP_PATH = /data/gitea/uploads
|
||||
|
||||
[repository.pull-request]
|
||||
DEFAULT_MERGE_STYLE = merge
|
||||
|
||||
[repository.signing]
|
||||
DEFAULT_TRUST_MODEL = committer
|
||||
|
||||
[lfs]
|
||||
PATH = /data/git/lfs
|
||||
|
||||
[server]
|
||||
APP_DATA_PATH = /data/gitea
|
||||
DOMAIN = 172.20.32.201
|
||||
SSH_DOMAIN = 172.20.32.201
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL = http://172.20.32.201:10082/
|
||||
DISABLE_SSH = false
|
||||
SSH_PORT = 2022
|
||||
SSH_LISTEN_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = n2kib4qdArULO57JW0jD2Ygm3z1ehzI8Y4zVfbxouyY
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[service]
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
DISABLE_REGISTRATION = true
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = noreply.example.org
|
||||
SHOW_REGISTRATION_BUTTON = false
|
||||
|
||||
[webhook]
|
||||
ALLOWED_HOST_LIST = *
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
PROVIDER = file
|
||||
|
||||
[picture]
|
||||
DISABLE_GRAVATAR = true
|
||||
ENABLE_FEDERATED_AVATAR = false
|
||||
|
||||
[attachment]
|
||||
PATH = /data/gitea/attachments
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
ENABLE_OPENID_SIGNUP = true
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
|
||||
[log]
|
||||
MODE = file
|
||||
LEVEL = Trace
|
||||
ROOT_PATH = /data/gitea/log
|
||||
REDIRECT_MACARON_LOG = true
|
||||
ENABLE_ACCESS_LOG = true
|
||||
|
||||
[api]
|
||||
DEFAULT_PAGING_NUM = 200
|
||||
MAX_RESPONSE_ITEMS = 200
|
||||
|
||||
[git]
|
||||
PATH =
|
||||
DISABLE_DIFF_HIGHLIGHT = false
|
||||
MAX_GIT_DIFF_LINES = 1000
|
||||
MAX_GIT_DIFF_LINE_CHARACTERS = 5000
|
||||
MAX_GIT_DIFF_FILES = 100
|
||||
GC_ARGS =
|
||||
EnableAutoGitWireProtocol = true
|
||||
COMMITS_RANGE_SIZE = 50
|
||||
|
||||
; Operation timeout in seconds
|
||||
[git.timeout]
|
||||
DEFAULT = 1800
|
||||
MIGRATE = 21600
|
||||
MIRROR = 1800
|
||||
CLONE = 1800
|
||||
PULL = 1800
|
||||
GC = 60
|
||||
|
||||
[cache]
|
||||
ENABLED = true
|
||||
ADAPTER = memory
|
||||
INTERVAL = 60
|
||||
HOST =
|
||||
ITEM_TTL = 16h
|
||||
|
||||
[cache.last_commit]
|
||||
ENABLED = true
|
||||
ITEM_TTL = 24h
|
||||
COMMITS_COUNT = 1000
|
||||
|
||||
[migrations]
|
||||
ALLOW_LOCALNETWORKS = true
|
||||
|
||||
#[cron.update_mirrors]
|
||||
#SCHEDULE = @every 24h
|
||||
|
||||
[cron.delete_repo_archives]
|
||||
ENABLED = true
|
||||
RUN_AT_START = true
|
||||
SCHEDULE = @every 72h
|
||||
OLDER_THAN = 8h
|
||||
|
||||
[cron.update_checker]
|
||||
ENABLED = false
|
||||
|
||||
[storage.repo-archive]
|
||||
PATH = /data/repo-archive
|
||||
|
||||
[mirror]
|
||||
ENABLED = true
|
||||
|
||||
[ssh.minimum_key_sizes]
|
||||
RSA = 2048
|
2
build.sh
2
build.sh
|
@ -12,4 +12,4 @@ go run build/generate-bindata.go public public vendor/code.gitea.io/gitea/module
|
|||
go run build/generate-bindata.go templates templates vendor/code.gitea.io/gitea/modules/templates/bindata.go
|
||||
|
||||
echo "go build -tags 'bindata' -o gitea_hat main.go..."
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -tags 'bindata' -o gitea_hat main.go
|
||||
go build -tags 'bindata' -o gitea_hat main.go
|
||||
|
|
55
cmd/web.go
55
cmd/web.go
|
@ -27,9 +27,6 @@ import (
|
|||
"code.gitea.io/gitea/routers/install"
|
||||
hat_routers "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers"
|
||||
"github.com/felixge/fgprof"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
@ -213,7 +210,8 @@ func serveInstalled(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
// Set up Chi routes
|
||||
webRoutes := hat_routers.NormalRoutes()
|
||||
webRoutes := routers.NormalRoutes()
|
||||
hat_routers.InitHatRouters(graceful.GetManager().HammerContext(), webRoutes)
|
||||
|
||||
err := listen(webRoutes, true)
|
||||
<-graceful.GetManager().Done()
|
||||
|
@ -238,55 +236,6 @@ func runWeb(ctx *cli.Context) error {
|
|||
}
|
||||
}()
|
||||
|
||||
rootCfg := setting.CfgProvider
|
||||
nacosServer := rootCfg.Section("nacos").Key("SERVER").String()
|
||||
nacosPort := rootCfg.Section("nacos").Key("PORT").MustInt64()
|
||||
nacosWeight := rootCfg.Section("nacos").Key("WEIGHT").MustInt64()
|
||||
if nacosWeight == 0 {
|
||||
nacosWeight = 10
|
||||
}
|
||||
if nacosServer != "" && nacosPort != 0 {
|
||||
//create ServerConfig
|
||||
sc := []constant.ServerConfig{
|
||||
*constant.NewServerConfig(nacosServer, uint64(nacosPort), constant.WithContextPath("/nacos")),
|
||||
}
|
||||
|
||||
//create ClientConfig
|
||||
cc := *constant.NewClientConfig(
|
||||
constant.WithNamespaceId(""),
|
||||
constant.WithTimeoutMs(5000),
|
||||
constant.WithNotLoadCacheAtStart(true),
|
||||
constant.WithLogDir("/tmp/nacos/log"),
|
||||
constant.WithCacheDir("/tmp/nacos/cache"),
|
||||
constant.WithLogLevel("debug"),
|
||||
)
|
||||
|
||||
// create naming client
|
||||
client, err := clients.NewNamingClient(
|
||||
vo.NacosClientParam{
|
||||
ClientConfig: &cc,
|
||||
ServerConfigs: sc,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//Register
|
||||
_, err = client.RegisterInstance(vo.RegisterInstanceParam{
|
||||
Ip: nacosServer,
|
||||
Port: uint64(nacosPort),
|
||||
ServiceName: "gitea_hat",
|
||||
Weight: float64(nacosWeight),
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
})
|
||||
|
||||
log.Info("Nacos: Register Gitea Web Finished")
|
||||
}
|
||||
|
||||
managerCtx, cancel := context.WithCancel(context.Background())
|
||||
graceful.InitManager(managerCtx)
|
||||
defer cancel()
|
||||
|
|
29
go.mod
29
go.mod
|
@ -7,21 +7,15 @@ toolchain go1.21.4
|
|||
require (
|
||||
code.gitea.io/gitea v1.21.0
|
||||
gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669
|
||||
gitea.com/go-chi/captcha v0.0.0-20230415143339-2c0754df4384
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/caddyserver/certmagic v0.19.2
|
||||
github.com/felixge/fgprof v0.9.3
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/klauspost/cpuid/v2 v2.2.6
|
||||
github.com/nacos-group/nacos-sdk-go/v2 v2.2.7
|
||||
github.com/nektos/act v0.2.52
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
golang.org/x/net v0.23.0
|
||||
golang.org/x/net v0.18.0
|
||||
golang.org/x/text v0.14.0
|
||||
xorm.io/builder v0.3.13
|
||||
xorm.io/xorm v1.3.4
|
||||
|
@ -54,6 +48,7 @@ require (
|
|||
dario.cat/mergo v1.0.0 // indirect
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||
gitea.com/go-chi/cache v0.2.0 // indirect
|
||||
gitea.com/go-chi/captcha v0.0.0-20230415143339-2c0754df4384 // indirect
|
||||
gitea.com/go-chi/session v0.0.0-20230613035928-39541325faa3 // indirect
|
||||
gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 // indirect
|
||||
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 // indirect
|
||||
|
@ -63,16 +58,11 @@ require (
|
|||
github.com/ClickHouse/clickhouse-go/v2 v2.15.0 // indirect
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect
|
||||
github.com/RoaringBitmap/roaring v1.6.0 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.11.1 // indirect
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect
|
||||
github.com/alibabacloud-go/tea v1.1.17 // indirect
|
||||
github.com/alibabacloud-go/tea-utils v1.4.4 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.2.2 // indirect
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7 // indirect
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
|
@ -97,7 +87,6 @@ require (
|
|||
github.com/blevesearch/zapx/v15 v15.3.13 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/buildkite/terminal-to-html/v3 v3.9.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chi-middleware/proxy v1.1.1 // indirect
|
||||
|
@ -126,6 +115,7 @@ require (
|
|||
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.10 // indirect
|
||||
github.com/go-co-op/gocron v1.36.0 // indirect
|
||||
github.com/go-enry/go-enry/v2 v2.8.6 // indirect
|
||||
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
||||
|
@ -147,7 +137,6 @@ require (
|
|||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-github/v53 v53.2.0 // indirect
|
||||
|
@ -167,7 +156,6 @@ require (
|
|||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
|
@ -198,6 +186,7 @@ require (
|
|||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/msteinert/pam v1.2.0 // indirect
|
||||
github.com/nektos/act v0.2.52 // indirect
|
||||
github.com/niklasfasching/go-org v1.7.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
|
@ -210,6 +199,7 @@ require (
|
|||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pquerna/otp v1.4.0 // indirect
|
||||
github.com/prometheus/client_golang v1.17.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
|
@ -251,20 +241,19 @@ require (
|
|||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/crypto v0.15.0 // indirect
|
||||
golang.org/x/image v0.14.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/oauth2 v0.14.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/time v0.4.0 // indirect
|
||||
golang.org/x/tools v0.15.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
61
go.sum
61
go.sum
|
@ -76,8 +76,6 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2
|
|||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0=
|
||||
github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw=
|
||||
|
@ -111,19 +109,6 @@ github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk
|
|||
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
|
||||
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50=
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
|
||||
github.com/alibabacloud-go/tea v1.1.17 h1:05R5DnaJXe9sCNIe8KUgWHC/z6w/VZIwczgUwzRnul8=
|
||||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.4 h1:lxCDvNCdTo9FaXKKq45+4vGETQUKNOW/qKTcX9Sk53o=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.4/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 h1:ie/8RxBOfKZWcrbYSJi2Z8uX8TcOlSMwPlEJh83OeOw=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.2.2 h1:rWkH6D2XlXb/Y+tNAQROxBzp3a0p92ni+pXcaHBe/WI=
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.2.2/go.mod h1:GDtq+Kw+v0fO+j5BrrWiUHbBq7L+hfpzpPfXKOZMFE0=
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7 h1:olLiPI2iM8Hqq6vKnSxpM3awCrm9/BeOgHpzQkOYnI4=
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7/go.mod h1:oDg1j4kFxnhgftaiLJABkGeSvuEvSF5Lo6UmRAMruX4=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
|
@ -200,8 +185,6 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
|||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg=
|
||||
github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/buildkite/terminal-to-html/v3 v3.9.1 h1:8SOCKFK9ntpYvPE3yUAXHiZYdQI4xf9o9S3wOX7x12A=
|
||||
github.com/buildkite/terminal-to-html/v3 v3.9.1/go.mod h1:Nsx19oOIo6MZM/cEPookXi/nrQQmnSJFLZL1KS05t+A=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
|
@ -390,7 +373,6 @@ github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7w
|
|||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
|
@ -416,8 +398,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -585,17 +565,10 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
|
|||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jhillyerd/enmime v1.0.1 h1:y6RyqIgBOI2hIinOXIzmeB+ITRVls0zTJIm5GwgXnjE=
|
||||
github.com/jhillyerd/enmime v1.0.1/go.mod h1:LMMbm6oTlzWHghPavqHtOrP/NosVv3l42CUrZjn03/Q=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
|
@ -715,8 +688,6 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
|
@ -729,8 +700,6 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
|||
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||
github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE=
|
||||
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
|
||||
github.com/nacos-group/nacos-sdk-go/v2 v2.2.7 h1:wCC1f3/VzIR1WD30YKeJGZAOchYCK/35mLC8qWt6Q6o=
|
||||
github.com/nacos-group/nacos-sdk-go/v2 v2.2.7/go.mod h1:VYlyDPlQchPC31PmfBustu81vsOkdpCuO5k0dRdQcFc=
|
||||
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
|
||||
github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o=
|
||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
|
@ -926,7 +895,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
|
||||
|
@ -985,7 +953,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
|
@ -1002,8 +969,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
|
|||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -1036,7 +1003,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
|
@ -1074,7 +1040,6 @@ golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
|
@ -1085,8 +1050,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -1154,9 +1119,7 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -1177,8 +1140,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -1188,8 +1151,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
||||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -1264,7 +1227,6 @@ golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4X
|
|||
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
|
@ -1363,8 +1325,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
|||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -1379,11 +1341,8 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkp
|
|||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
|
|
2
main.go
2
main.go
|
@ -22,7 +22,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
Version = "v2.7, by v1.21.0 "
|
||||
Version = "development"
|
||||
Tags = ""
|
||||
MakeVersion = ""
|
||||
)
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
gitea_actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
gitea_repo_model "code.gitea.io/gitea/models/repo"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func InsertRun(ctx context.Context, run *gitea_actions_model.ActionRun, jobs []*gitea_actions_model.ActionRunJob) error {
|
||||
ctx, commiter, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer commiter.Close()
|
||||
|
||||
index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
run.Index = index
|
||||
run.ID = 0
|
||||
|
||||
if err := db.Insert(ctx, run); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if run.Repo == nil {
|
||||
repo, err := gitea_repo_model.GetRepositoryByID(ctx, run.RepoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
run.Repo = repo
|
||||
}
|
||||
|
||||
if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runJobs := make([]*gitea_actions_model.ActionRunJob, 0, len(jobs))
|
||||
for _, job := range jobs {
|
||||
runJobs = append(runJobs, &gitea_actions_model.ActionRunJob{
|
||||
RunID: run.ID,
|
||||
RepoID: run.RepoID,
|
||||
OwnerID: run.OwnerID,
|
||||
CommitSHA: run.CommitSHA,
|
||||
IsForkPullRequest: run.IsForkPullRequest,
|
||||
Name: job.Name,
|
||||
WorkflowPayload: job.WorkflowPayload,
|
||||
JobID: job.JobID,
|
||||
Needs: job.Needs,
|
||||
RunsOn: job.RunsOn,
|
||||
Status: gitea_actions_model.StatusWaiting,
|
||||
})
|
||||
|
||||
}
|
||||
if err := db.Insert(ctx, runJobs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gitea_actions_model.IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return commiter.Commit()
|
||||
}
|
||||
|
||||
func updateRepoRunsNumbers(ctx context.Context, repo *gitea_repo_model.Repository) error {
|
||||
_, err := db.GetEngine(ctx).ID(repo.ID).
|
||||
SetExpr("num_action_runs",
|
||||
builder.Select("count(*)").From("action_run").
|
||||
Where(builder.Eq{"repo_id": repo.ID}),
|
||||
).
|
||||
SetExpr("num_closed_action_runs",
|
||||
builder.Select("count(*)").From("action_run").
|
||||
Where(builder.Eq{
|
||||
"repo_id": repo.ID,
|
||||
}.And(
|
||||
builder.In("status",
|
||||
gitea_actions_model.StatusSuccess,
|
||||
gitea_actions_model.StatusFailure,
|
||||
gitea_actions_model.StatusCancelled,
|
||||
gitea_actions_model.StatusSkipped,
|
||||
),
|
||||
),
|
||||
),
|
||||
).
|
||||
Update(repo)
|
||||
return err
|
||||
}
|
|
@ -2,18 +2,15 @@ package convert
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/repo"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/webhook"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
gitea_convert "code.gitea.io/gitea/services/convert"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
||||
)
|
||||
|
||||
|
@ -95,28 +92,3 @@ func ToHookTask(t *webhook.HookTask) *api.HookTask {
|
|||
ResponseContent: responseContent,
|
||||
}
|
||||
}
|
||||
|
||||
func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit string) *api.ChangedFile {
|
||||
|
||||
file := &api.ChangedFile{
|
||||
Filename: f.GetDiffFileName(),
|
||||
OldName: f.OldName,
|
||||
Index: f.Index,
|
||||
Type: f.Type,
|
||||
IsBin: f.IsBin,
|
||||
IsCreated: f.IsCreated,
|
||||
IsDeleted: f.IsDeleted,
|
||||
IsLFSFile: f.IsLFSFile,
|
||||
IsRenamed: f.IsRenamed,
|
||||
IsSubmodule: f.IsSubmodule,
|
||||
Additions: f.Addition,
|
||||
Deletions: f.Deletion,
|
||||
Changes: f.Addition + f.Deletion,
|
||||
Sha: commit,
|
||||
HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
|
||||
ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit),
|
||||
RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package git
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -38,8 +36,8 @@ func GetFirstAndLastCommitByPath(repo *gitea_git.Repository, revision, relpath s
|
|||
}
|
||||
|
||||
// CommitsByFileAndRange return the commits according revision file and the page
|
||||
func AllCommitsByFileAndRange(repo *gitea_git.Repository, opts gitea_git.CommitsByFileAndRangeOptions, keyword string, pageSize int) ([]*gitea_git.Commit, error) {
|
||||
skip := (opts.Page - 1) * pageSize
|
||||
func CommitsByFileAndRange(repo *gitea_git.Repository, revision, file string, page, pageSize int) ([]*gitea_git.Commit, error) {
|
||||
skip := (page - 1) * pageSize
|
||||
|
||||
stdoutReader, stdoutWriter := io.Pipe()
|
||||
defer func() {
|
||||
|
@ -48,68 +46,35 @@ func AllCommitsByFileAndRange(repo *gitea_git.Repository, opts gitea_git.Commits
|
|||
}()
|
||||
go func() {
|
||||
stderr := strings.Builder{}
|
||||
gitCmd := gitea_git.NewCommand(repo.Ctx, "rev-list").
|
||||
AddOptionFormat("--max-count=%d", pageSize*opts.Page).
|
||||
AddOptionFormat("--skip=%d", skip).
|
||||
AddOptionFormat("--grep=%s", keyword)
|
||||
gitCmd.AddDynamicArguments(opts.Revision)
|
||||
|
||||
if opts.Not != "" {
|
||||
gitCmd.AddOptionValues("--not", opts.Not)
|
||||
}
|
||||
|
||||
gitCmd.AddArguments("--all")
|
||||
|
||||
// gitCmd.AddDashesAndList(opts.File)
|
||||
gitCmd := gitea_git.NewCommand(repo.Ctx, "log", prettyLogFormat, "--follow").AddDynamicArguments("--max-count=" + strconv.Itoa(pageSize))
|
||||
gitCmd.AddDynamicArguments(revision)
|
||||
gitCmd.AddDynamicArguments("--" + file)
|
||||
err := gitCmd.Run(&gitea_git.RunOpts{
|
||||
Dir: repo.Path,
|
||||
Stdout: stdoutWriter,
|
||||
Stderr: &stderr,
|
||||
})
|
||||
if err != nil {
|
||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
||||
_ = stdoutWriter.CloseWithError(gitea_git.ConcatenateError(err, (&stderr).String()))
|
||||
} else {
|
||||
_ = stdoutWriter.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
commits := []*gitea_git.Commit{}
|
||||
shaline := [41]byte{}
|
||||
var sha1 gitea_git.SHA1
|
||||
for {
|
||||
n, err := io.ReadFull(stdoutReader, shaline[:])
|
||||
if err != nil || n < 40 {
|
||||
if skip > 0 {
|
||||
_, err := io.CopyN(io.Discard, stdoutReader, int64(skip*41))
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
return []*gitea_git.Commit{}, nil
|
||||
}
|
||||
return commits, err
|
||||
}
|
||||
n, err = hex.Decode(sha1[:], shaline[0:40])
|
||||
if n != 20 {
|
||||
err = fmt.Errorf("invalid sha %q", string(shaline[:40]))
|
||||
}
|
||||
if err != nil {
|
||||
_ = stdoutReader.CloseWithError(err)
|
||||
return nil, err
|
||||
}
|
||||
commit, err := repo.GetCommit(sha1.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commits = append(commits, commit)
|
||||
}
|
||||
}
|
||||
|
||||
func GetAllCommitsCount(repo *gitea_git.Repository, keyword string) (int64, error) {
|
||||
cmd := gitea_git.NewCommand(repo.Ctx, "rev-list").
|
||||
AddOptionFormat("--grep=%s", keyword)
|
||||
cmd.AddArguments("--exclude=" + "refs/pull/" + "*")
|
||||
|
||||
cmd.AddArguments("--all", "--count")
|
||||
|
||||
stdout, _, err := cmd.RunStdString(&gitea_git.RunOpts{Dir: repo.Path})
|
||||
stdout, err := io.ReadAll(stdoutReader)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
|
||||
return parsePrettyFormatLogToList(repo, stdout)
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ func GetRepoContributorsNew(repo *gitea_git.Repository, page, pageSize int) (int
|
|||
return err
|
||||
}
|
||||
name := l[strings.Index(l, "\t")+1 : strings.Index(l, " <")]
|
||||
email := strings.ToLower(l[strings.Index(l, "<")+1 : strings.Index(l, ">")])
|
||||
email := l[strings.Index(l, "<")+1 : strings.Index(l, ">")]
|
||||
totalContributions += commitsInt
|
||||
// committer is not system user
|
||||
if existedContributorInfo, ok := contributorInfoHash[email]; ok {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package structs
|
||||
|
||||
type RestoreBranchOption struct {
|
||||
BranchID int64 `json:"branch_id"`
|
||||
BranchName string `json:"name"`
|
||||
}
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
type CreateHookOption struct {
|
||||
// required: true
|
||||
// enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,jianmu,softbot,reposync
|
||||
// enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,jianmu,softbot
|
||||
Type string `json:"type" binding:"Required"`
|
||||
// required: true
|
||||
Config gitea_api.CreateHookOptionConfig `json:"config" binding:"Required"`
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"time"
|
||||
|
||||
gitea_api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
)
|
||||
|
||||
type PullRequest struct {
|
||||
|
@ -40,23 +39,3 @@ type PullRequest struct {
|
|||
CommitNum int `json:"commit_num"`
|
||||
ChangedFiles int `json:"changed_files"`
|
||||
}
|
||||
|
||||
type ChangedFile struct {
|
||||
Filename string `json:"filename"`
|
||||
OldName string `json:"old_name"`
|
||||
Index int `json:"index"`
|
||||
Type gitdiff.DiffFileType `json:"type"`
|
||||
IsBin bool `json:"is_bin"`
|
||||
IsCreated bool `json:"is_created"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
IsLFSFile bool `json:"is_lfs_file"`
|
||||
IsRenamed bool `json:"is_renamed"`
|
||||
IsSubmodule bool `json:"is_submodule"`
|
||||
Additions int `json:"additions"`
|
||||
Deletions int `json:"deletions"`
|
||||
Changes int `json:"changes"`
|
||||
Sha string `json:"sha"`
|
||||
HTMLURL string `json:"html_url,omitempty"`
|
||||
ContentsURL string `json:"contents_url,omitempty"`
|
||||
RawURL string `json:"raw_url,omitempty"`
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
package structs
|
||||
|
||||
import (
|
||||
gitea_api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
type Branch struct {
|
||||
*gitea_api.Branch
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
DeletedUnix int `json:"deleted_unix"`
|
||||
ID int64 `json:"id"`
|
||||
DeletedBy *BranchDeleteUser `json:"deleted_by"`
|
||||
}
|
||||
|
||||
type BranchDeleteUser struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
本协议是您(如下也称“用户”)与国防科技大学计算机学院国产基础软件工程研究中心(以下简称“中心”),关于麒麟如意内核软件(以下简称“本软件”)的协议,请认真阅读。
|
||||
1.申请使用本软件的用户均需填写本协议,并遵守本协议各项条件的约束。
|
||||
2.用户须在本平台内使用本软件,不得以拷贝、刻录等方式将本软件传播至本平台以外的任何第三方平台或主体。若需要向本平台以外的第三方平台或主体传播,用户需向中心提出申请并获书面授权。
|
||||
3.对于未签署本协议的第三者,一旦申请使用本软件,即表示第三者同意接受本协议各项条件的约束。如果第三者不同意本协议的条件,则不能获得使用本软件的权利。
|
||||
4.用户有权提出对软件的使用反馈及意见,用户可以发表对软件的使用体验及感受,但不得随意诽谤、中伤。
|
||||
5.用户可以在软件上添加、修改源代码,但必须遵守本软件的开源许可协议的规定。
|
||||
6.用户须保证其添加、修改的代码内容所涉及的知识产权均为其个体所有,或经过知识产权所有者的授权,用户须保证其对于前述代码内容造成的侵权并不知情。若用户提供的代码内容涉及其它第三方开源平台,用户需保证其传播方式满足该开源平台的相关约定。
|
||||
7.本中心/本协议鼓励用户将开发成果返回至开发团队,或在如意内核软件中开源,开发者将在代码中署名。
|
||||
8.未经本中心书面许可,用户不得将该软件用于商业用途;若该软件被用户用于学术研究,则相关学术成果中应明示引用如意内核软件。
|
||||
9.您获得的只是对于本软件非商业用途的使用权。本软件仅限中华人民共和国公民申请使用。
|
||||
10.本协议的最终解释权归中心。
|
|
@ -1,6 +1,7 @@
|
|||
package hat
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -29,7 +30,6 @@ import (
|
|||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/admin"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/org"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo/actions"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/user"
|
||||
"github.com/go-chi/cors"
|
||||
)
|
||||
|
@ -95,7 +95,7 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
|
|||
}
|
||||
}
|
||||
|
||||
func Routers() *web.Route {
|
||||
func Routers(ctx gocontext.Context) *web.Route {
|
||||
m := web.NewRoute()
|
||||
|
||||
m.Use(securityHeaders())
|
||||
|
@ -123,17 +123,6 @@ func Routers() *web.Route {
|
|||
m.Post("/create_pr_version", bind(gitea_api.PullRequestPayload{}), repo.CreatePrVersion)
|
||||
m.Group("/repos", func() {
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Combo("").Delete(reqToken(), reqOwner(), repo.Delete)
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", context.ReferencesGitRepo(), actions.ListActions)
|
||||
m.Post("/disable", reqAdmin(), actions.DisableWorkflowFile)
|
||||
m.Post("/enable", reqAdmin(), actions.EnableWorkflowFile)
|
||||
m.Post("/runs/{run}/jobs/{job}", context.ReferencesGitRepo(), bind(actions.ViewRequest{}), actions.ListJobs)
|
||||
m.Post("/runs/{run}/jobs/{job}/rerun", reqRepoWriter(unit_model.TypeActions), actions.Rerun)
|
||||
m.Get("/runs/{run}/jobs/{job}/logs", actions.Logs)
|
||||
m.Post("/runs/{run}/rerun", reqRepoWriter(unit_model.TypeActions), actions.Rerun)
|
||||
m.Post("/runs", context.ReferencesGitRepo(), reqRepoWriter(unit_model.TypeActions), actions.Run)
|
||||
}, reqRepoReader(unit_model.TypeActions))
|
||||
m.Post("/transfer", reqOwner(), bind(gitea_api.TransferRepoOption{}), repo.Transfer)
|
||||
m.Get("/branch_name_set", context.ReferencesGitRepo(), repo.BranchNameSet)
|
||||
m.Get("/tag_name_set", context.ReferencesGitRepo(), repo.TagNameSet)
|
||||
|
@ -141,45 +130,25 @@ func Routers() *web.Route {
|
|||
m.Group("/branches", func() {
|
||||
m.Get("", context.ReferencesGitRepo(), repo.ListBranches)
|
||||
m.Get("/branches_slice", context.ReferencesGitRepo(), repo.ListBranchesSlice)
|
||||
m.Post("/restore", context.ReferencesGitRepo(), bind(hat_api.RestoreBranchOption{}), repo.RestoreBranch)
|
||||
}, reqRepoReader(unit_model.TypeCode))
|
||||
m.Group("/commits", func() {
|
||||
m.Get("/{sha}/diff", repo.GetCommitDiff)
|
||||
m.Group("/{sha}/files", func() {
|
||||
m.Get("", repo.GetCommitFiles)
|
||||
m.Get("/*", repo.GetCommitFilesByPath)
|
||||
})
|
||||
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
|
||||
m.Group("/tags", func() {
|
||||
m.Get("", repo.ListTags)
|
||||
m.Get("/*", repo.GetTag)
|
||||
}, reqRepoReader(unit_model.TypeCode), context.ReferencesGitRepo(true))
|
||||
m.Group("/wiki", func() {
|
||||
m.Get("/page_names", repo.ListWikiPageNames)
|
||||
})
|
||||
m.Group("/readme", func() {
|
||||
m.Get("", repo.GetReadmeContents)
|
||||
m.Get("/*", repo.GetReadmeContentsByPath)
|
||||
})
|
||||
m.Get("/commits_slice", repo.GetAllCommitsSliceByTime)
|
||||
m.Get("/recent_commits", context.ReferencesGitRepo(), repo.GetRecentCommits)
|
||||
m.Get("/compare/*", reqRepoReader(unit_model.TypeCode), repo.CompareDiff)
|
||||
// m.Group("/compare/{shaFrom}...{shaTo}", func() {
|
||||
// m.Get("", repo.CompareDiff)
|
||||
// m.Group("/files", func() {
|
||||
// m.Get("", repo.CompareFiles)
|
||||
// m.Get("/*", repo.CompareFilesByPath)
|
||||
// })
|
||||
// }, reqRepoReader(unit_model.TypeCode))
|
||||
m.Group("/pulls", func() {
|
||||
m.Group("/{index}", func() {
|
||||
m.Combo("").Get(repo.GetPullRequest).
|
||||
Patch(bind(gitea_api.EditPullRequestOption{}), repo.EditPullRequest)
|
||||
m.Get("/commits", context.ReferencesGitRepo(), repo.GetPullCommits)
|
||||
m.Group("/files", func() {
|
||||
m.Get("", repo.GetPullFiles)
|
||||
m.Get("/*", repo.GetPullFilesByPath)
|
||||
}, context.ReferencesGitRepo())
|
||||
m.Get("/files", context.ReferencesGitRepo(), repo.GetPullFiles)
|
||||
m.Group("/versions", func() {
|
||||
m.Get("", repo.ListPullRequestVersions)
|
||||
m.Get("/{versionId}/diff", context.ReferencesGitRepo(), repo.GetPullRequestVersionDiff)
|
||||
|
|
|
@ -1,686 +0,0 @@
|
|||
package actions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
stdCtx "context"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/actions"
|
||||
actions_module "code.gitea.io/gitea/modules/actions"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/web/repo"
|
||||
actions_service "code.gitea.io/gitea/services/actions"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
hat_actions_model "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/actions"
|
||||
jobparser "github.com/nektos/act/pkg/jobparser"
|
||||
"github.com/nektos/act/pkg/model"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func Run(ctx *context.APIContext) {
|
||||
workflow := ctx.FormString("workflow")
|
||||
ref := ctx.FormString("ref")
|
||||
|
||||
if ref == "" {
|
||||
ref = ctx.Repo.Repository.DefaultBranch
|
||||
}
|
||||
|
||||
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
entries, err := ListWorkflowsByWorkflow(commit, workflow)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "ListWorkflowsByWorkflow", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
workflows := make([]*actions_module.DetectedWorkflow, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
content, err := actions_module.GetContentFromEntry(entry)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetContentFromEntry", err.Error())
|
||||
return
|
||||
}
|
||||
dwf := &actions_module.DetectedWorkflow{
|
||||
EntryName: entry.Name(),
|
||||
Content: content,
|
||||
}
|
||||
workflows = append(workflows, dwf)
|
||||
}
|
||||
|
||||
for _, dwf := range workflows {
|
||||
run := &actions_model.ActionRun{
|
||||
Title: strings.SplitN(commit.CommitMessage, "\n", 2)[0],
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
OwnerID: ctx.Repo.Repository.OwnerID,
|
||||
WorkflowID: dwf.EntryName,
|
||||
TriggerUserID: ctx.Doer.ID,
|
||||
Ref: ref,
|
||||
CommitSHA: commit.ID.String(),
|
||||
Status: actions_model.StatusWaiting,
|
||||
}
|
||||
|
||||
jobs, err := jobparser.Parse(dwf.Content)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "jobparser.Parse", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := actions_model.InsertRun(ctx, run, jobs); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "InsertRun", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
alljobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: run.ID})
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "FindRunJobs", err.Error())
|
||||
return
|
||||
}
|
||||
actions_service.CreateCommitStatus(ctx, alljobs...)
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func ListWorkflowsByWorkflow(commit *git.Commit, workflow string) (git.Entries, error) {
|
||||
tree, err := commit.SubTree(".gitea/workflows")
|
||||
if _, ok := err.(git.ErrNotExist); ok {
|
||||
tree, err = commit.SubTree(".github/workflows")
|
||||
}
|
||||
if _, ok := err.(git.ErrNotExist); ok {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entries, err := tree.ListEntriesRecursiveFast()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make(git.Entries, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
if workflow == entry.Name() && (strings.HasSuffix(entry.Name(), ".yml") || strings.HasSuffix(entry.Name(), ".yaml")) {
|
||||
ret = append(ret, entry)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type Workflow struct {
|
||||
Name string
|
||||
ErrMsg string
|
||||
}
|
||||
|
||||
type ResponseAction struct {
|
||||
Workflows []Workflow
|
||||
CurWorkflow string
|
||||
ActionsConfig *repo_model.ActionsConfig
|
||||
AllowDisableOrEnableWorkflow bool
|
||||
CurWorkflowDisabled bool
|
||||
CurActor int64
|
||||
CurStatus int
|
||||
IsFiltered bool
|
||||
Runs actions_model.RunList
|
||||
Actors []*user.User
|
||||
StatusInfoList []actions_model.StatusInfo
|
||||
}
|
||||
|
||||
func ListActions(ctx *context.APIContext) {
|
||||
|
||||
workflow := ctx.FormString("workflow")
|
||||
actorID := ctx.FormInt64("actor")
|
||||
status := ctx.FormInt("status")
|
||||
|
||||
var workflows []Workflow
|
||||
if empty, err := ctx.Repo.GitRepo.IsEmpty(); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "IsEmpty", err.Error())
|
||||
return
|
||||
} else if !empty {
|
||||
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBranchCommit", err.Error())
|
||||
return
|
||||
}
|
||||
entries, err := actions.ListWorkflows(commit)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "ListWorkflows", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
opts := actions_model.FindRunnerOptions{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
WithAvailable: true,
|
||||
}
|
||||
runners, err := actions_model.FindRunners(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "FindRunners", err.Error())
|
||||
}
|
||||
|
||||
allRunnerLabels := make(container.Set[string])
|
||||
for _, r := range runners {
|
||||
allRunnerLabels.AddMultiple(r.AgentLabels...)
|
||||
}
|
||||
|
||||
workflows = make([]Workflow, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
workflow := Workflow{Name: entry.Name()}
|
||||
content, err := actions.GetContentFromEntry(entry)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetContentFromEntry", err.Error())
|
||||
return
|
||||
}
|
||||
wf, err := model.ReadWorkflow(bytes.NewReader(content))
|
||||
if err != nil {
|
||||
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", err.Error())
|
||||
workflows = append(workflows, workflow)
|
||||
continue
|
||||
}
|
||||
// Check whether have matching runner
|
||||
for _, j := range wf.Jobs {
|
||||
runsOnList := j.RunsOn()
|
||||
for _, ro := range runsOnList {
|
||||
if strings.Contains(ro, "${{") {
|
||||
// Skip if it contains expressions.
|
||||
// The expressions could be very complex and could not be evaluated here,
|
||||
// so just skip it, it's OK since it's just a tooltip message.
|
||||
continue
|
||||
}
|
||||
if !allRunnerLabels.Contains(ro) {
|
||||
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_runner_helper", ro)
|
||||
break
|
||||
}
|
||||
}
|
||||
if workflow.ErrMsg != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
workflows = append(workflows, workflow)
|
||||
}
|
||||
}
|
||||
responseAction := ResponseAction{}
|
||||
responseAction.Workflows = workflows
|
||||
page := ctx.FormInt("page")
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
responseAction.CurWorkflow = workflow
|
||||
|
||||
actionsConfig := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions).ActionsConfig()
|
||||
responseAction.ActionsConfig = actionsConfig
|
||||
|
||||
if len(workflow) > 0 && ctx.Repo.IsAdmin() {
|
||||
responseAction.AllowDisableOrEnableWorkflow = true
|
||||
responseAction.CurWorkflowDisabled = actionsConfig.IsWorkflowDisabled(workflow)
|
||||
}
|
||||
|
||||
responseAction.CurActor = actorID
|
||||
responseAction.CurStatus = status
|
||||
if actorID > 0 && status > int(actions_model.StatusUnknown) {
|
||||
responseAction.IsFiltered = true
|
||||
}
|
||||
|
||||
opts := actions_model.FindRunOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: page,
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
},
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
WorkflowID: workflow,
|
||||
TriggerUserID: actorID,
|
||||
}
|
||||
|
||||
if actions_model.Status(status) != actions_model.StatusUnknown {
|
||||
opts.Status = []actions_model.Status{actions_model.Status(status)}
|
||||
}
|
||||
|
||||
runs, total, err := actions_model.FindRuns(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "FindRuns", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, run := range runs {
|
||||
run.Repo = ctx.Repo.Repository
|
||||
}
|
||||
|
||||
if err := runs.LoadTriggerUser(ctx); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadTriggerUser", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
responseAction.Runs = runs
|
||||
|
||||
actors, err := actions_model.GetActors(ctx, ctx.Repo.Repository.ID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetActors", err.Error())
|
||||
return
|
||||
}
|
||||
responseAction.Actors = repo.MakeSelfOnTop(ctx.Doer, actors)
|
||||
responseAction.StatusInfoList = actions_model.GetStatusInfoList(ctx)
|
||||
ctx.SetLinkHeader(int(total), ctx.FormInt("limit"))
|
||||
ctx.SetTotalCountHeader(total)
|
||||
ctx.JSON(http.StatusOK, responseAction)
|
||||
}
|
||||
|
||||
type ViewRequest struct {
|
||||
LogCursors []struct {
|
||||
Step int `json:"step"`
|
||||
Cursor int64 `json:"cursor"`
|
||||
Expanded bool `json:"expanded"`
|
||||
} `json:"logCursors"`
|
||||
}
|
||||
|
||||
type ViewResponse struct {
|
||||
State struct {
|
||||
Run struct {
|
||||
Link string `json:"link"`
|
||||
Title string `json:"title"`
|
||||
Status string `json:"status"`
|
||||
CanCancel bool `json:"canCancel"`
|
||||
CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve
|
||||
CanRerun bool `json:"canRerun"`
|
||||
Done bool `json:"done"`
|
||||
Jobs []*ViewJob `json:"jobs"`
|
||||
Commit ViewCommit `json:"commit"`
|
||||
} `json:"run"`
|
||||
CurrentJob struct {
|
||||
Title string `json:"title"`
|
||||
Detail string `json:"detail"`
|
||||
Steps []*ViewJobStep `json:"steps"`
|
||||
} `json:"currentJob"`
|
||||
} `json:"state"`
|
||||
Logs struct {
|
||||
StepsLog []*ViewStepLog `json:"stepsLog"`
|
||||
} `json:"logs"`
|
||||
}
|
||||
|
||||
type ViewJob struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
CanRerun bool `json:"canRerun"`
|
||||
Duration string `json:"duration"`
|
||||
}
|
||||
|
||||
type ViewCommit struct {
|
||||
LocaleCommit string `json:"localeCommit"`
|
||||
LocalePushedBy string `json:"localePushedBy"`
|
||||
ShortSha string `json:"shortSHA"`
|
||||
Link string `json:"link"`
|
||||
Pusher ViewUser `json:"pusher"`
|
||||
Branch ViewBranch `json:"branch"`
|
||||
}
|
||||
|
||||
type ViewUser struct {
|
||||
DisplayName string `json:"displayName"`
|
||||
Link string `json:"link"`
|
||||
}
|
||||
|
||||
type ViewBranch struct {
|
||||
Name string `json:"name"`
|
||||
Link string `json:"link"`
|
||||
}
|
||||
|
||||
type ViewJobStep struct {
|
||||
Summary string `json:"summary"`
|
||||
Duration string `json:"duration"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type ViewStepLog struct {
|
||||
Step int `json:"step"`
|
||||
Cursor int64 `json:"cursor"`
|
||||
Lines []*ViewStepLogLine `json:"lines"`
|
||||
Started int64 `json:"started"`
|
||||
}
|
||||
|
||||
type ViewStepLogLine struct {
|
||||
Index int64 `json:"index"`
|
||||
Message string `json:"message"`
|
||||
Timestamp float64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func ListJobs(ctx *context.APIContext) {
|
||||
req := web.GetForm(ctx).(*ViewRequest)
|
||||
|
||||
runIndex := ctx.ParamsInt64("run")
|
||||
jobIndex := ctx.ParamsInt64("job")
|
||||
|
||||
current, jobs := getRunJobs(ctx, runIndex, jobIndex)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
run := current.Run
|
||||
if err := run.LoadAttributes(ctx); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
resp := &ViewResponse{}
|
||||
resp.State.Run.Title = run.Title
|
||||
resp.State.Run.Link = run.Link()
|
||||
resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
|
||||
resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions)
|
||||
resp.State.Run.CanRerun = 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,
|
||||
Name: v.Name,
|
||||
Status: v.Status.String(),
|
||||
CanRerun: v.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions),
|
||||
Duration: v.Duration().String(),
|
||||
})
|
||||
}
|
||||
|
||||
pusher := ViewUser{
|
||||
DisplayName: run.TriggerUser.GetDisplayName(),
|
||||
Link: run.TriggerUser.HomeLink(),
|
||||
}
|
||||
branch := ViewBranch{
|
||||
Name: run.PrettyRef(),
|
||||
Link: run.RefLink(),
|
||||
}
|
||||
resp.State.Run.Commit = ViewCommit{
|
||||
LocaleCommit: ctx.Tr("actions.runs.commit"),
|
||||
LocalePushedBy: ctx.Tr("actions.runs.pushed_by"),
|
||||
ShortSha: base.ShortSha(run.CommitSHA),
|
||||
Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA),
|
||||
Pusher: pusher,
|
||||
Branch: branch,
|
||||
}
|
||||
|
||||
var task *actions_model.ActionTask
|
||||
if current.TaskID > 0 {
|
||||
var err error
|
||||
task, err = actions_model.GetTaskByID(ctx, current.TaskID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetTaskByID", err.Error())
|
||||
return
|
||||
}
|
||||
task.Job = current
|
||||
if err := task.LoadAttributes(ctx); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resp.State.CurrentJob.Title = current.Name
|
||||
resp.State.CurrentJob.Detail = current.Status.LocaleString(ctx.Locale)
|
||||
if run.NeedApproval {
|
||||
resp.State.CurrentJob.Detail = ctx.Locale.Tr("actions.need_approval_desc")
|
||||
}
|
||||
resp.State.CurrentJob.Steps = make([]*ViewJobStep, 0) // marshal to '[]' instead fo 'null' in json
|
||||
resp.Logs.StepsLog = make([]*ViewStepLog, 0) // marshal to '[]' instead fo 'null' in json
|
||||
if task != nil {
|
||||
steps := actions.FullSteps(task)
|
||||
|
||||
for _, v := range steps {
|
||||
resp.State.CurrentJob.Steps = append(resp.State.CurrentJob.Steps, &ViewJobStep{
|
||||
Summary: v.Name,
|
||||
Duration: v.Duration().String(),
|
||||
Status: v.Status.String(),
|
||||
})
|
||||
}
|
||||
|
||||
for _, cursor := range req.LogCursors {
|
||||
if !cursor.Expanded {
|
||||
continue
|
||||
}
|
||||
|
||||
step := steps[cursor.Step]
|
||||
|
||||
logLines := make([]*ViewStepLogLine, 0) // marshal to '[]' instead fo 'null' in json
|
||||
|
||||
index := step.LogIndex + cursor.Cursor
|
||||
validCursor := cursor.Cursor >= 0 &&
|
||||
// !(cursor.Cursor < step.LogLength) when the frontend tries to fetch next line before it's ready.
|
||||
// So return the same cursor and empty lines to let the frontend retry.
|
||||
cursor.Cursor < step.LogLength &&
|
||||
// !(index < task.LogIndexes[index]) when task data is older than step data.
|
||||
// It can be fixed by making sure write/read tasks and steps in the same transaction,
|
||||
// but it's easier to just treat it as fetching the next line before it's ready.
|
||||
index < int64(len(task.LogIndexes))
|
||||
|
||||
if validCursor {
|
||||
length := step.LogLength - cursor.Cursor
|
||||
offset := task.LogIndexes[index]
|
||||
var err error
|
||||
logRows, err := actions.ReadLogs(ctx, task.LogInStorage, task.LogFilename, offset, length)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "ReadLogs", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for i, row := range logRows {
|
||||
logLines = append(logLines, &ViewStepLogLine{
|
||||
Index: cursor.Cursor + int64(i) + 1, // start at 1
|
||||
Message: row.Content,
|
||||
Timestamp: float64(row.Time.AsTime().UnixNano()) / float64(time.Second),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
resp.Logs.StepsLog = append(resp.Logs.StepsLog, &ViewStepLog{
|
||||
Step: cursor.Step,
|
||||
Cursor: cursor.Cursor + int64(len(logLines)),
|
||||
Lines: logLines,
|
||||
Started: int64(step.Started),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func Rerun(ctx *context.APIContext) {
|
||||
runIndex := ctx.ParamsInt64("run")
|
||||
jobIndex := ctx.ParamsInt64("job")
|
||||
|
||||
run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetRunByIndex", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// can not rerun job when workflow is disabled
|
||||
cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions)
|
||||
cfg := cfgUnit.ActionsConfig()
|
||||
if cfg.IsWorkflowDisabled(run.WorkflowID) {
|
||||
ctx.Error(http.StatusInternalServerError, "IsWorkflowDisabled", ctx.Locale.Tr("actions.workflow.disabled"))
|
||||
return
|
||||
}
|
||||
|
||||
job, jobs := getRunJobs(ctx, runIndex, jobIndex)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if jobIndex != 0 {
|
||||
jobs = []*actions_model.ActionRunJob{job}
|
||||
}
|
||||
|
||||
// if err := hat_actions_model.InsertRun(ctx, run, jobs); err != nil {
|
||||
// ctx.Error(http.StatusInternalServerError, "InsertRun", err.Error())
|
||||
// return
|
||||
// }
|
||||
|
||||
// for _, j := range jobs {
|
||||
if err := newRerunJob(ctx, run, jobs); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "rerunJob", err.Error())
|
||||
return
|
||||
}
|
||||
// }
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func newRerunJob(ctx *context.APIContext, run *actions_model.ActionRun, jobs []*actions_model.ActionRunJob) error {
|
||||
if err := db.WithTx(ctx, func(ctx stdCtx.Context) error {
|
||||
err := hat_actions_model.InsertRun(ctx, run, jobs)
|
||||
return err
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actions_service.CreateCommitStatus(ctx, jobs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func rerunJob(ctx *context.APIContext, job *actions_model.ActionRunJob) error {
|
||||
status := job.Status
|
||||
if !status.IsDone() {
|
||||
return nil
|
||||
}
|
||||
|
||||
job.TaskID = 0
|
||||
job.Status = actions_model.StatusWaiting
|
||||
job.Started = 0
|
||||
job.Stopped = 0
|
||||
|
||||
if err := db.WithTx(ctx, func(ctx stdCtx.Context) error {
|
||||
_, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, "task_id", "status", "started", "stopped")
|
||||
return err
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actions_service.CreateCommitStatus(ctx, job)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Logs(ctx *context.APIContext) {
|
||||
runIndex := ctx.ParamsInt64("run")
|
||||
jobIndex := ctx.ParamsInt64("job")
|
||||
|
||||
job, _ := getRunJobs(ctx, runIndex, jobIndex)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
if job.TaskID == 0 {
|
||||
ctx.Error(http.StatusNotFound, "", "job is not started")
|
||||
return
|
||||
}
|
||||
|
||||
err := job.LoadRun(ctx)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadRun", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
task, err := actions_model.GetTaskByID(ctx, job.TaskID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetTaskByID", err.Error())
|
||||
return
|
||||
}
|
||||
if task.LogExpired {
|
||||
ctx.Error(http.StatusNotFound, "", "logs have been cleaned up")
|
||||
return
|
||||
}
|
||||
|
||||
reader, err := actions.OpenLogs(ctx, task.LogInStorage, task.LogFilename)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "OpenLogs", err.Error())
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
workflowName := job.Run.WorkflowID
|
||||
if p := strings.Index(workflowName, "."); p > 0 {
|
||||
workflowName = workflowName[0:p]
|
||||
}
|
||||
ctx.ServeContent(reader, &context.ServeHeaderOptions{
|
||||
Filename: fmt.Sprintf("%v-%v-%v.log", workflowName, job.Name, task.ID),
|
||||
ContentLength: &task.LogSize,
|
||||
ContentType: "text/plain",
|
||||
ContentTypeCharset: "utf-8",
|
||||
Disposition: "attachment",
|
||||
})
|
||||
}
|
||||
|
||||
func getRunJobs(ctx *context.APIContext, runIndex, jobIndex int64) (*actions_model.ActionRunJob, []*actions_model.ActionRunJob) {
|
||||
run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
|
||||
if err != nil {
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
ctx.Error(http.StatusNotFound, "GetRunByIndex", err.Error())
|
||||
return nil, nil
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "GetRunByIndex", err.Error())
|
||||
return nil, nil
|
||||
}
|
||||
run.Repo = ctx.Repo.Repository
|
||||
|
||||
jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetRunJobsByRunID", err.Error())
|
||||
return nil, nil
|
||||
}
|
||||
if len(jobs) == 0 {
|
||||
ctx.Error(http.StatusNotFound, "", err.Error())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, v := range jobs {
|
||||
v.Run = run
|
||||
}
|
||||
|
||||
if jobIndex >= 0 && jobIndex < int64(len(jobs)) {
|
||||
return jobs[jobIndex], jobs
|
||||
}
|
||||
return jobs[0], jobs
|
||||
}
|
||||
|
||||
func DisableWorkflowFile(ctx *context.APIContext) {
|
||||
disableOrEnableWorkflowFile(ctx, false)
|
||||
}
|
||||
|
||||
func EnableWorkflowFile(ctx *context.APIContext) {
|
||||
disableOrEnableWorkflowFile(ctx, true)
|
||||
}
|
||||
|
||||
func disableOrEnableWorkflowFile(ctx *context.APIContext, isEnable bool) {
|
||||
workflow := ctx.FormString("workflow")
|
||||
if len(workflow) == 0 {
|
||||
ctx.ServerError("workflow", nil)
|
||||
return
|
||||
}
|
||||
|
||||
cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions)
|
||||
cfg := cfgUnit.ActionsConfig()
|
||||
|
||||
if isEnable {
|
||||
cfg.EnableWorkflow(workflow)
|
||||
} else {
|
||||
cfg.DisableWorkflow(workflow)
|
||||
}
|
||||
|
||||
if err := repo_model.UpdateRepoUnit(cfgUnit); err != nil {
|
||||
ctx.ServerError("UpdateRepoUnit", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
|
@ -4,20 +4,17 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
gitea_git "code.gitea.io/gitea/modules/git"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
gitea_api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert"
|
||||
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
||||
hat_branch_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/convert"
|
||||
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git"
|
||||
|
||||
|
@ -26,7 +23,7 @@ import (
|
|||
|
||||
func ListBranches(ctx *context.APIContext) {
|
||||
var totalNumOfBranches int64
|
||||
var apiBranches []*hat_api.Branch
|
||||
var apiBranches []*gitea_api.Branch
|
||||
|
||||
searchName := ctx.FormString("name")
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
|
@ -35,20 +32,11 @@ func ListBranches(ctx *context.APIContext) {
|
|||
ctx.Error(http.StatusInternalServerError, "Load git repository failed", nil)
|
||||
return
|
||||
}
|
||||
var isDeleted util.OptionalBool
|
||||
switch ctx.FormString("state") {
|
||||
case "all":
|
||||
isDeleted = util.OptionalBoolNone
|
||||
case "deleted":
|
||||
isDeleted = util.OptionalBoolTrue
|
||||
default:
|
||||
isDeleted = util.OptionalBoolFalse
|
||||
}
|
||||
|
||||
branchOpts := git_model.FindBranchOptions{
|
||||
ListOptions: listOptions,
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
IsDeletedBranch: isDeleted,
|
||||
IsDeletedBranch: util.OptionalBoolFalse,
|
||||
Keyword: searchName,
|
||||
}
|
||||
|
||||
|
@ -58,8 +46,8 @@ func ListBranches(ctx *context.APIContext) {
|
|||
ctx.Error(http.StatusInternalServerError, "CountBranches", err)
|
||||
return
|
||||
}
|
||||
if totalNumOfBranches < 2 { // sync branches immediately because non-empty repository should have at least 1 branch
|
||||
_, err = repo_module.SyncRepoBranches(ctx, ctx.Repo.Repository.ID, 0)
|
||||
if totalNumOfBranches == 0 { // sync branches immediately because non-empty repository should have at least 1 branch
|
||||
totalNumOfBranches, err = repo_module.SyncRepoBranches(ctx, ctx.Repo.Repository.ID, 0)
|
||||
if err != nil {
|
||||
ctx.ServerError("SyncRepoBranches", err)
|
||||
return
|
||||
|
@ -78,14 +66,9 @@ func ListBranches(ctx *context.APIContext) {
|
|||
return
|
||||
}
|
||||
|
||||
apiBranches = make([]*hat_api.Branch, 0, len(branches))
|
||||
apiBranches = make([]*gitea_api.Branch, 0, len(branches))
|
||||
for i := range branches {
|
||||
err := branches[i].LoadDeletedBy(ctx)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadDeletedBy", err)
|
||||
return
|
||||
}
|
||||
c, err := ctx.Repo.GitRepo.GetCommit(branches[i].CommitID)
|
||||
c, err := ctx.Repo.GitRepo.GetBranchCommit(branches[i].Name)
|
||||
if err != nil {
|
||||
// Skip if this branch doesn't exist anymore.
|
||||
if gitea_git.IsErrNotExist(err) {
|
||||
|
@ -97,7 +80,7 @@ func ListBranches(ctx *context.APIContext) {
|
|||
}
|
||||
|
||||
branchProtection := rules.GetFirstMatched(branches[i].Name)
|
||||
apiBranch, err := hat_branch_convert.ToBranch(ctx, branches[i], c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
|
||||
apiBranch, err := convert.ToBranch(ctx, ctx.Repo.Repository, branches[i].Name, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
|
||||
return
|
||||
|
@ -206,48 +189,3 @@ func BranchesSliceByProtection(ctx *context.APIContext, branchList []*git.Branch
|
|||
}
|
||||
return branchSlice
|
||||
}
|
||||
|
||||
func RestoreBranch(ctx *context.APIContext) {
|
||||
|
||||
form := web.GetForm(ctx).(*hat_api.RestoreBranchOption)
|
||||
branchID := form.BranchID
|
||||
branchName := form.BranchName
|
||||
|
||||
deletedBranch, err := git_model.GetDeletedBranchByID(ctx, ctx.Repo.Repository.ID, branchID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetDeletedBranchByID: %v", err)
|
||||
return
|
||||
} else if deletedBranch == nil {
|
||||
ctx.Error(http.StatusInternalServerError, "RestoreBranch: Can't restore branch '%s', as it does not exist", branchName)
|
||||
return
|
||||
}
|
||||
|
||||
if err := gitea_git.Push(ctx, ctx.Repo.Repository.RepoPath(), gitea_git.PushOptions{
|
||||
Remote: ctx.Repo.Repository.RepoPath(),
|
||||
Branch: fmt.Sprintf("%s:%s%s", deletedBranch.CommitID, gitea_git.BranchPrefix, deletedBranch.Name),
|
||||
Env: repo_module.PushingEnvironment(ctx.Doer, ctx.Repo.Repository),
|
||||
}); err != nil {
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
ctx.Error(http.StatusInternalServerError, "RestoreBranch: Can't restore branch '%s', since one with same name already exist", deletedBranch.Name)
|
||||
return
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "RestoreBranch: CreateBranch: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := repo_service.PushUpdate(
|
||||
&repo_module.PushUpdateOptions{
|
||||
RefFullName: gitea_git.RefNameFromBranch(deletedBranch.Name),
|
||||
OldCommitID: gitea_git.EmptySHA,
|
||||
NewCommitID: deletedBranch.CommitID,
|
||||
PusherID: ctx.Doer.ID,
|
||||
PusherName: ctx.Doer.Name,
|
||||
RepoUserName: ctx.Repo.Owner.Name,
|
||||
RepoName: ctx.Repo.Repository.Name,
|
||||
}); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "RestoreBranch: Update: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusCreated)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import (
|
|||
"code.gitea.io/gitea/services/gitdiff"
|
||||
hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert"
|
||||
hat_git "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git"
|
||||
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
||||
)
|
||||
|
||||
func GetAllCommitsSliceByTime(ctx *context.APIContext) {
|
||||
|
@ -128,77 +127,6 @@ func toResponseCommit(ctx *context.APIContext, repo *repo.Repository, gitRepo *g
|
|||
}, nil
|
||||
}
|
||||
|
||||
func GetRecentCommits(ctx *context.APIContext) {
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.JSON(http.StatusConflict, api.APIError{
|
||||
Message: "Git Repository is empty",
|
||||
URL: setting.API.SwaggerURL,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
keyword := ctx.FormString("keyword")
|
||||
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
if listOptions.Page <= 0 {
|
||||
listOptions.Page = 1
|
||||
}
|
||||
if listOptions.PageSize > setting.Git.CommitsRangeSize {
|
||||
listOptions.PageSize = setting.Git.CommitsRangeSize
|
||||
}
|
||||
|
||||
var baseCommit *git.Commit
|
||||
var commitsCountTotal int64
|
||||
var err error
|
||||
head, err := ctx.Repo.GitRepo.GetHEADBranch()
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetHeadBranch", err)
|
||||
return
|
||||
}
|
||||
baseCommit, err = ctx.Repo.GitRepo.GetBranchCommit(head.Name)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
commitsCountTotal, err = hat_git.GetAllCommitsCount(ctx.Repo.GitRepo, keyword)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "CommitsCountFiles", err)
|
||||
return
|
||||
}
|
||||
pageCount := int(math.Ceil(float64(commitsCountTotal) / float64(listOptions.PageSize)))
|
||||
commits, err := hat_git.AllCommitsByFileAndRange(ctx.Repo.GitRepo,
|
||||
git.CommitsByFileAndRangeOptions{
|
||||
Revision: baseCommit.ID.String(),
|
||||
File: ".",
|
||||
Page: listOptions.Page,
|
||||
}, keyword, listOptions.PageSize)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
|
||||
return
|
||||
}
|
||||
|
||||
userCache := make(map[string]*user_model.User)
|
||||
apiCommits := make([]*api.Commit, len(commits))
|
||||
for i, commit := range commits {
|
||||
apiCommits[i], err = convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache, convert.ParseCommitOptions(ctx))
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "ToCommit", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Resp.Header().Set("X-Page", strconv.Itoa(listOptions.Page))
|
||||
ctx.Resp.Header().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
|
||||
ctx.Resp.Header().Set("X-Total", strconv.FormatInt(commitsCountTotal, 10))
|
||||
ctx.Resp.Header().Set("X-PageCount", strconv.Itoa(pageCount))
|
||||
ctx.Resp.Header().Set("X-HasMore", strconv.FormatBool(listOptions.Page < pageCount))
|
||||
|
||||
ctx.SetLinkHeader(int(commitsCountTotal), listOptions.PageSize)
|
||||
ctx.Resp.Header().Set("X-Total-Count", fmt.Sprintf("%d", commitsCountTotal))
|
||||
|
||||
ctx.JSON(http.StatusOK, apiCommits)
|
||||
}
|
||||
|
||||
func GetFileAllCommits(ctx *context.APIContext) {
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.JSON(http.StatusConflict, api.APIError{
|
||||
|
@ -255,12 +183,7 @@ func GetFileAllCommits(ctx *context.APIContext) {
|
|||
|
||||
}
|
||||
pageCount := int(math.Ceil(float64(commitsCountTotal) / float64(listOptions.PageSize)))
|
||||
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(
|
||||
git.CommitsByFileAndRangeOptions{
|
||||
Revision: baseCommit.ID.String(),
|
||||
File: treePath,
|
||||
Page: listOptions.Page,
|
||||
})
|
||||
commits, err := hat_git.CommitsByFileAndRange(ctx.Repo.GitRepo, baseCommit.ID.String(), treePath, listOptions.Page, listOptions.PageSize)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
|
||||
return
|
||||
|
@ -313,111 +236,6 @@ func GetSingleCommit(ctx *context.APIContext) {
|
|||
ctx.JSON(http.StatusOK, json)
|
||||
}
|
||||
|
||||
func GetCommitFiles(ctx *context.APIContext) {
|
||||
commitID := ctx.Params(":sha")
|
||||
gitRepo := ctx.Repo.GitRepo
|
||||
|
||||
commit, err := gitRepo.GetCommit(commitID)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
ctx.NotFound(commitID)
|
||||
return
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "gitRepo.GetCommit", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(commitID) != 40 {
|
||||
commitID = commit.ID.String()
|
||||
}
|
||||
|
||||
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
|
||||
AfterCommitID: commitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
})
|
||||
if err != nil {
|
||||
ctx.NotFound("GetDIff", err)
|
||||
return
|
||||
}
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
|
||||
totalNumberOfFiles := diff.NumFiles
|
||||
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
|
||||
|
||||
start, end := listOptions.GetStartEnd()
|
||||
|
||||
if end > totalNumberOfFiles {
|
||||
end = totalNumberOfFiles
|
||||
}
|
||||
|
||||
lenFiles := end - start
|
||||
if lenFiles < 0 {
|
||||
lenFiles = 0
|
||||
}
|
||||
|
||||
apiFiles := make([]*hat_api.ChangedFile, 0, lenFiles)
|
||||
for i := start; i < end; i++ {
|
||||
apiFiles = append(apiFiles, hat_convert.ToChangedFile(diff.Files[i], ctx.Repo.Repository, commitID))
|
||||
}
|
||||
ctx.SetLinkHeader(totalNumberOfFiles, listOptions.PageSize)
|
||||
ctx.SetTotalCountHeader(int64(totalNumberOfFiles))
|
||||
|
||||
ctx.RespHeader().Set("X-Page", strconv.Itoa(listOptions.Page))
|
||||
ctx.RespHeader().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
|
||||
ctx.RespHeader().Set("X-PageCount", strconv.Itoa(totalNumberOfPages))
|
||||
ctx.RespHeader().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages))
|
||||
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore")
|
||||
|
||||
ctx.JSON(http.StatusOK, struct {
|
||||
Files []*hat_api.ChangedFile `json:"files"`
|
||||
TotalAddition int `json:"total_addition"`
|
||||
TotalDeletion int `json:"total_deletion"`
|
||||
}{
|
||||
Files: apiFiles,
|
||||
TotalAddition: diff.TotalAddition,
|
||||
TotalDeletion: diff.TotalDeletion,
|
||||
})
|
||||
}
|
||||
|
||||
func GetCommitFilesByPath(ctx *context.APIContext) {
|
||||
commitID := ctx.Params(":sha")
|
||||
gitRepo := ctx.Repo.GitRepo
|
||||
path := ctx.Params("*")
|
||||
commit, err := gitRepo.GetCommit(commitID)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
ctx.NotFound(commitID)
|
||||
return
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "gitRepo.GetCommit", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(commitID) != 40 {
|
||||
commitID = commit.ID.String()
|
||||
}
|
||||
|
||||
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
|
||||
AfterCommitID: commitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
}, path)
|
||||
if err != nil {
|
||||
ctx.NotFound("GetDIff", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, &diff)
|
||||
|
||||
}
|
||||
|
||||
func GetCommitDiff(ctx *context.APIContext) {
|
||||
commitID := ctx.Params(":sha")
|
||||
gitRepo := ctx.Repo.GitRepo
|
||||
|
|
|
@ -1,614 +0,0 @@
|
|||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
gocontext "context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
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"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"github.com/go-chi/cors"
|
||||
)
|
||||
|
||||
func HTTPGitEnabledHandler(ctx *context.Context) {
|
||||
if setting.Repository.DisableHTTPGit {
|
||||
ctx.Resp.WriteHeader(http.StatusForbidden)
|
||||
_, _ = ctx.Resp.Write([]byte("Interacting with repositories by HTTP protocol is not allowed"))
|
||||
}
|
||||
}
|
||||
|
||||
func CorsHandler() func(next http.Handler) http.Handler {
|
||||
if setting.Repository.AccessControlAllowOrigin != "" {
|
||||
return cors.Handler(cors.Options{
|
||||
AllowedOrigins: []string{setting.Repository.AccessControlAllowOrigin},
|
||||
AllowedHeaders: []string{"Content-Type", "Authorization", "User-Agent"},
|
||||
})
|
||||
}
|
||||
return func(next http.Handler) http.Handler {
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
// httpBase implementation git smart HTTP protocol
|
||||
func httpBase(ctx *context.Context) *serviceHandler {
|
||||
username := ctx.Params(":username")
|
||||
reponame := strings.TrimSuffix(ctx.Params(":reponame"), ".git")
|
||||
|
||||
if ctx.FormString("go-get") == "1" {
|
||||
context.EarlyResponseForGoGetMeta(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
var isPull, receivePack bool
|
||||
service := ctx.FormString("service")
|
||||
if service == "git-receive-pack" ||
|
||||
strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
|
||||
isPull = false
|
||||
receivePack = true
|
||||
} else if service == "git-upload-pack" ||
|
||||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
|
||||
isPull = true
|
||||
} else if service == "git-upload-archive" ||
|
||||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") {
|
||||
isPull = true
|
||||
} else {
|
||||
isPull = ctx.Req.Method == "GET"
|
||||
}
|
||||
|
||||
var accessMode perm.AccessMode
|
||||
if isPull {
|
||||
accessMode = perm.AccessModeRead
|
||||
} else {
|
||||
accessMode = perm.AccessModeWrite
|
||||
}
|
||||
|
||||
isWiki := false
|
||||
unitType := unit.TypeCode
|
||||
var wikiRepoName string
|
||||
if strings.HasSuffix(reponame, ".wiki") {
|
||||
isWiki = true
|
||||
unitType = unit.TypeWiki
|
||||
wikiRepoName = reponame
|
||||
reponame = reponame[:len(reponame)-5]
|
||||
}
|
||||
|
||||
owner := ctx.ContextUser
|
||||
if !owner.IsOrganization() && !owner.IsActive {
|
||||
ctx.PlainText(http.StatusForbidden, "Repository cannot be accessed. You cannot push or open issues/pull-requests.")
|
||||
return nil
|
||||
}
|
||||
|
||||
repoExist := true
|
||||
repo, err := repo_model.GetRepositoryByName(owner.ID, reponame)
|
||||
if err != nil {
|
||||
if repo_model.IsErrRepoNotExist(err) {
|
||||
if redirectRepoID, err := repo_model.LookupRedirect(owner.ID, reponame); err == nil {
|
||||
context.RedirectToRepo(ctx.Base, redirectRepoID)
|
||||
return nil
|
||||
}
|
||||
repoExist = false
|
||||
} else {
|
||||
ctx.ServerError("GetRepositoryByName", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Don't allow pushing if the repo is archived
|
||||
if repoExist && repo.IsArchived && !isPull {
|
||||
ctx.PlainText(http.StatusForbidden, "This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only public pull don't need auth.
|
||||
isPublicPull := repoExist && !repo.IsPrivate && isPull
|
||||
var (
|
||||
askAuth = !isPublicPull || setting.Service.RequireSignInView
|
||||
environ []string
|
||||
)
|
||||
|
||||
// don't allow anonymous pulls if organization is not public
|
||||
if isPublicPull {
|
||||
if err := repo.LoadOwner(ctx); err != nil {
|
||||
ctx.ServerError("LoadOwner", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
askAuth = askAuth || (repo.Owner.Visibility != structs.VisibleTypePublic)
|
||||
}
|
||||
|
||||
// check access
|
||||
if askAuth {
|
||||
// rely on the results of Contexter
|
||||
if !ctx.IsSigned {
|
||||
// TODO: support digit auth - which would be Authorization header with digit
|
||||
//ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea"`)
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
|
||||
ctx.Error(http.StatusUnauthorized)
|
||||
return nil
|
||||
}
|
||||
|
||||
context.CheckRepoScopedToken(ctx, repo, auth_model.GetScopeLevelFromAccessMode(accessMode))
|
||||
if ctx.Written() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ctx.IsBasicAuth && ctx.Data["IsApiToken"] != true && ctx.Data["IsActionsToken"] != true {
|
||||
_, err = auth_model.GetTwoFactorByUID(ctx, 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 nil
|
||||
} else if !auth_model.IsErrTwoFactorNotEnrolled(err) {
|
||||
ctx.ServerError("IsErrTwoFactorNotEnrolled", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin {
|
||||
ctx.PlainText(http.StatusForbidden, "Your account is disabled.")
|
||||
return nil
|
||||
}
|
||||
|
||||
environ = []string{
|
||||
repo_module.EnvRepoUsername + "=" + username,
|
||||
repo_module.EnvRepoName + "=" + reponame,
|
||||
repo_module.EnvPusherName + "=" + ctx.Doer.Name,
|
||||
repo_module.EnvPusherID + fmt.Sprintf("=%d", ctx.Doer.ID),
|
||||
repo_module.EnvAppURL + "=" + setting.AppURL,
|
||||
}
|
||||
|
||||
if repoExist {
|
||||
// Because of special ref "refs/for" .. , need delay write permission check
|
||||
if git.SupportProcReceive {
|
||||
accessMode = perm.AccessModeRead
|
||||
}
|
||||
|
||||
if ctx.Data["IsActionsToken"] == true {
|
||||
taskID := ctx.Data["ActionsTaskID"].(int64)
|
||||
task, err := actions_model.GetTaskByID(ctx, taskID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetTaskByID", err)
|
||||
return nil
|
||||
}
|
||||
if task.RepoID != repo.ID {
|
||||
ctx.PlainText(http.StatusForbidden, "User permission denied")
|
||||
return nil
|
||||
}
|
||||
|
||||
if task.IsForkPullRequest {
|
||||
if accessMode > perm.AccessModeRead {
|
||||
ctx.PlainText(http.StatusForbidden, "User permission denied")
|
||||
return nil
|
||||
}
|
||||
environ = append(environ, fmt.Sprintf("%s=%d", repo_module.EnvActionPerm, perm.AccessModeRead))
|
||||
} else {
|
||||
if accessMode > perm.AccessModeWrite {
|
||||
ctx.PlainText(http.StatusForbidden, "User permission denied")
|
||||
return nil
|
||||
}
|
||||
environ = append(environ, fmt.Sprintf("%s=%d", repo_module.EnvActionPerm, perm.AccessModeWrite))
|
||||
}
|
||||
} else {
|
||||
p, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetUserRepoPermission", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !p.CanAccess(accessMode, unitType) {
|
||||
ctx.PlainText(http.StatusNotFound, "Repository not found")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if !isPull && repo.IsMirror {
|
||||
ctx.PlainText(http.StatusForbidden, "mirror repository is read-only")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if !ctx.Doer.KeepEmailPrivate {
|
||||
environ = append(environ, repo_module.EnvPusherEmail+"="+ctx.Doer.Email)
|
||||
}
|
||||
|
||||
if isWiki {
|
||||
environ = append(environ, repo_module.EnvRepoIsWiki+"=true")
|
||||
} else {
|
||||
environ = append(environ, repo_module.EnvRepoIsWiki+"=false")
|
||||
}
|
||||
}
|
||||
|
||||
if !repoExist {
|
||||
if !receivePack {
|
||||
ctx.PlainText(http.StatusNotFound, "Repository not found")
|
||||
return nil
|
||||
}
|
||||
|
||||
if isWiki { // you cannot send wiki operation before create the repository
|
||||
ctx.PlainText(http.StatusNotFound, "Repository not found")
|
||||
return nil
|
||||
}
|
||||
|
||||
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
|
||||
ctx.PlainText(http.StatusForbidden, "Push to create is not enabled for organizations.")
|
||||
return nil
|
||||
}
|
||||
if !owner.IsOrganization() && !setting.Repository.EnablePushCreateUser {
|
||||
ctx.PlainText(http.StatusForbidden, "Push to create is not enabled for users.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return dummy payload if GET receive-pack
|
||||
if ctx.Req.Method == http.MethodGet {
|
||||
dummyInfoRefs(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
repo, err = repo_service.PushCreateRepo(ctx, ctx.Doer, owner, reponame)
|
||||
if err != nil {
|
||||
log.Error("pushCreateRepo: %v", err)
|
||||
ctx.Status(http.StatusNotFound)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if isWiki {
|
||||
// Ensure the wiki is enabled before we allow access to it
|
||||
if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil {
|
||||
if repo_model.IsErrUnitTypeNotExist(err) {
|
||||
ctx.PlainText(http.StatusForbidden, "repository wiki is disabled")
|
||||
return nil
|
||||
}
|
||||
log.Error("Failed to get the wiki unit in %-v Error: %v", repo, err)
|
||||
ctx.ServerError("GetUnit(UnitTypeWiki) for "+repo.FullName(), err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
environ = append(environ, repo_module.EnvRepoID+fmt.Sprintf("=%d", repo.ID))
|
||||
|
||||
w := ctx.Resp
|
||||
r := ctx.Req
|
||||
cfg := &serviceConfig{
|
||||
UploadPack: true,
|
||||
ReceivePack: true,
|
||||
Env: environ,
|
||||
}
|
||||
|
||||
r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name
|
||||
|
||||
dir := repo_model.RepoPath(username, reponame)
|
||||
if isWiki {
|
||||
dir = repo_model.RepoPath(username, wikiRepoName)
|
||||
}
|
||||
|
||||
return &serviceHandler{cfg, w, r, dir, cfg.Env}
|
||||
}
|
||||
|
||||
var (
|
||||
infoRefsCache []byte
|
||||
infoRefsOnce sync.Once
|
||||
)
|
||||
|
||||
func dummyInfoRefs(ctx *context.Context) {
|
||||
infoRefsOnce.Do(func() {
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "gitea-info-refs-cache")
|
||||
if err != nil {
|
||||
log.Error("Failed to create temp dir for git-receive-pack cache: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := util.RemoveAll(tmpDir); err != nil {
|
||||
log.Error("RemoveAll: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := git.InitRepository(ctx, tmpDir, true); err != nil {
|
||||
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
refs, _, err := git.NewCommand(ctx, "receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Dir: tmpDir})
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
|
||||
}
|
||||
|
||||
log.Debug("populating infoRefsCache: \n%s", string(refs))
|
||||
infoRefsCache = refs
|
||||
})
|
||||
|
||||
ctx.RespHeader().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
|
||||
ctx.RespHeader().Set("Pragma", "no-cache")
|
||||
ctx.RespHeader().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
|
||||
ctx.RespHeader().Set("Content-Type", "application/x-git-receive-pack-advertisement")
|
||||
_, _ = ctx.Write(packetWrite("# service=git-receive-pack\n"))
|
||||
_, _ = ctx.Write([]byte("0000"))
|
||||
_, _ = ctx.Write(infoRefsCache)
|
||||
}
|
||||
|
||||
type serviceConfig struct {
|
||||
UploadPack bool
|
||||
ReceivePack bool
|
||||
Env []string
|
||||
}
|
||||
|
||||
type serviceHandler struct {
|
||||
cfg *serviceConfig
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
dir string
|
||||
environ []string
|
||||
}
|
||||
|
||||
func (h *serviceHandler) setHeaderNoCache() {
|
||||
h.w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
|
||||
h.w.Header().Set("Pragma", "no-cache")
|
||||
h.w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
|
||||
}
|
||||
|
||||
func (h *serviceHandler) setHeaderCacheForever() {
|
||||
now := time.Now().Unix()
|
||||
expires := now + 31536000
|
||||
h.w.Header().Set("Date", fmt.Sprintf("%d", now))
|
||||
h.w.Header().Set("Expires", fmt.Sprintf("%d", expires))
|
||||
h.w.Header().Set("Cache-Control", "public, max-age=31536000")
|
||||
}
|
||||
|
||||
func containsParentDirectorySeparator(v string) bool {
|
||||
if !strings.Contains(v, "..") {
|
||||
return false
|
||||
}
|
||||
for _, ent := range strings.FieldsFunc(v, isSlashRune) {
|
||||
if ent == ".." {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isSlashRune(r rune) bool { return r == '/' || r == '\\' }
|
||||
|
||||
func (h *serviceHandler) sendFile(contentType, file string) {
|
||||
if containsParentDirectorySeparator(file) {
|
||||
log.Error("request file path contains invalid path: %v", file)
|
||||
h.w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
reqFile := path.Join(h.dir, file)
|
||||
|
||||
fi, err := os.Stat(reqFile)
|
||||
if os.IsNotExist(err) {
|
||||
h.w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
h.w.Header().Set("Content-Type", contentType)
|
||||
h.w.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size()))
|
||||
h.w.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat))
|
||||
http.ServeFile(h.w, h.r, reqFile)
|
||||
}
|
||||
|
||||
// one or more key=value pairs separated by colons
|
||||
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
|
||||
|
||||
func prepareGitCmdWithAllowedService(service string, h *serviceHandler) (*git.Command, error) {
|
||||
if service == "receive-pack" && h.cfg.ReceivePack {
|
||||
return git.NewCommand(h.r.Context(), "receive-pack"), nil
|
||||
}
|
||||
if service == "upload-pack" && h.cfg.UploadPack {
|
||||
return git.NewCommand(h.r.Context(), "upload-pack"), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("service %q is not allowed", service)
|
||||
}
|
||||
|
||||
func serviceRPC(h *serviceHandler, service string) {
|
||||
defer func() {
|
||||
if err := h.r.Body.Close(); err != nil {
|
||||
log.Error("serviceRPC: Close: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
expectedContentType := fmt.Sprintf("application/x-git-%s-request", service)
|
||||
if h.r.Header.Get("Content-Type") != expectedContentType {
|
||||
log.Error("Content-Type (%q) doesn't match expected: %q", h.r.Header.Get("Content-Type"), expectedContentType)
|
||||
h.w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
cmd, err := prepareGitCmdWithAllowedService(service, h)
|
||||
if err != nil {
|
||||
log.Error("Failed to prepareGitCmdWithService: %v", err)
|
||||
h.w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service))
|
||||
|
||||
reqBody := h.r.Body
|
||||
|
||||
// Handle GZIP.
|
||||
if h.r.Header.Get("Content-Encoding") == "gzip" {
|
||||
reqBody, err = gzip.NewReader(reqBody)
|
||||
if err != nil {
|
||||
log.Error("Fail to create gzip reader: %v", err)
|
||||
h.w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// set this for allow pre-receive and post-receive execute
|
||||
h.environ = append(h.environ, "SSH_ORIGINAL_COMMAND="+service)
|
||||
|
||||
if protocol := h.r.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) {
|
||||
h.environ = append(h.environ, "GIT_PROTOCOL="+protocol)
|
||||
}
|
||||
|
||||
var stderr bytes.Buffer
|
||||
cmd.AddArguments("--stateless-rpc").AddDynamicArguments(h.dir)
|
||||
cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir))
|
||||
if err := cmd.Run(&git.RunOpts{
|
||||
Dir: h.dir,
|
||||
Env: append(os.Environ(), h.environ...),
|
||||
Stdout: h.w,
|
||||
Stdin: reqBody,
|
||||
Stderr: &stderr,
|
||||
UseContextTimeout: true,
|
||||
}); err != nil {
|
||||
if err.Error() != "signal: killed" {
|
||||
log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String())
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceUploadPack implements Git Smart HTTP protocol
|
||||
func ServiceUploadPack(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h != nil {
|
||||
serviceRPC(h, "upload-pack")
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceReceivePack implements Git Smart HTTP protocol
|
||||
func ServiceReceivePack(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h != nil {
|
||||
serviceRPC(h, "receive-pack")
|
||||
}
|
||||
}
|
||||
|
||||
func getServiceType(r *http.Request) string {
|
||||
serviceType := r.FormValue("service")
|
||||
if !strings.HasPrefix(serviceType, "git-") {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimPrefix(serviceType, "git-")
|
||||
}
|
||||
|
||||
func updateServerInfo(ctx gocontext.Context, dir string) []byte {
|
||||
out, _, err := git.NewCommand(ctx, "update-server-info").RunStdBytes(&git.RunOpts{Dir: dir})
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("%v - %s", err, string(out)))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func packetWrite(str string) []byte {
|
||||
s := strconv.FormatInt(int64(len(str)+4), 16)
|
||||
if len(s)%4 != 0 {
|
||||
s = strings.Repeat("0", 4-len(s)%4) + s
|
||||
}
|
||||
return []byte(s + str)
|
||||
}
|
||||
|
||||
// GetInfoRefs implements Git dumb HTTP
|
||||
func GetInfoRefs(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
h.setHeaderNoCache()
|
||||
service := getServiceType(h.r)
|
||||
cmd, err := prepareGitCmdWithAllowedService(service, h)
|
||||
if err == nil {
|
||||
if protocol := h.r.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) {
|
||||
h.environ = append(h.environ, "GIT_PROTOCOL="+protocol)
|
||||
}
|
||||
h.environ = append(os.Environ(), h.environ...)
|
||||
|
||||
refs, _, err := cmd.AddArguments("--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Env: h.environ, Dir: h.dir})
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
|
||||
}
|
||||
|
||||
h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service))
|
||||
h.w.WriteHeader(http.StatusOK)
|
||||
_, _ = h.w.Write(packetWrite("# service=git-" + service + "\n"))
|
||||
_, _ = h.w.Write([]byte("0000"))
|
||||
_, _ = h.w.Write(refs)
|
||||
} else {
|
||||
updateServerInfo(ctx, h.dir)
|
||||
h.sendFile("text/plain; charset=utf-8", "info/refs")
|
||||
}
|
||||
}
|
||||
|
||||
// GetTextFile implements Git dumb HTTP
|
||||
func GetTextFile(p string) func(*context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h != nil {
|
||||
h.setHeaderNoCache()
|
||||
file := ctx.Params("file")
|
||||
if file != "" {
|
||||
h.sendFile("text/plain", "objects/info/"+file)
|
||||
} else {
|
||||
h.sendFile("text/plain", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetInfoPacks implements Git dumb HTTP
|
||||
func GetInfoPacks(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h != nil {
|
||||
h.setHeaderCacheForever()
|
||||
h.sendFile("text/plain; charset=utf-8", "objects/info/packs")
|
||||
}
|
||||
}
|
||||
|
||||
// GetLooseObject implements Git dumb HTTP
|
||||
func GetLooseObject(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h != nil {
|
||||
h.setHeaderCacheForever()
|
||||
h.sendFile("application/x-git-loose-object", fmt.Sprintf("objects/%s/%s",
|
||||
ctx.Params("head"), ctx.Params("hash")))
|
||||
}
|
||||
}
|
||||
|
||||
// GetPackFile implements Git dumb HTTP
|
||||
func GetPackFile(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h != nil {
|
||||
h.setHeaderCacheForever()
|
||||
h.sendFile("application/x-git-packed-objects", "objects/pack/pack-"+ctx.Params("file")+".pack")
|
||||
}
|
||||
}
|
||||
|
||||
// GetIdxFile implements Git dumb HTTP
|
||||
func GetIdxFile(ctx *context.Context) {
|
||||
h := httpBase(ctx)
|
||||
if h != nil {
|
||||
h.setHeaderCacheForever()
|
||||
h.sendFile("application/x-git-packed-objects-toc", "objects/pack/pack-"+ctx.Params("file")+".idx")
|
||||
}
|
||||
}
|
|
@ -197,7 +197,7 @@ func isValidHookHttpMethod(name string) bool {
|
|||
|
||||
func isValidHookTaskType(name string) bool {
|
||||
// 建木devops
|
||||
if name == "jianmu" || name == "softbot" || name == "reposync" {
|
||||
if name == "jianmu" || name == "softbot" {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ package repo
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -16,7 +14,6 @@ import (
|
|||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
@ -31,7 +28,6 @@ import (
|
|||
notify_service "code.gitea.io/gitea/services/notify"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert"
|
||||
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
||||
hat_pull_service "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/pull"
|
||||
)
|
||||
|
||||
|
@ -391,119 +387,6 @@ func GetPullFiles(ctx *context.APIContext) {
|
|||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiff", err)
|
||||
return
|
||||
}
|
||||
isNew := ctx.FormString("isNew")
|
||||
if isNew != "" {
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
|
||||
totalNumberOfFiles := diff.NumFiles
|
||||
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
|
||||
|
||||
start, end := listOptions.GetStartEnd()
|
||||
|
||||
if end > totalNumberOfFiles {
|
||||
end = totalNumberOfFiles
|
||||
}
|
||||
|
||||
lenFiles := end - start
|
||||
if lenFiles < 0 {
|
||||
lenFiles = 0
|
||||
}
|
||||
apiFiles := make([]*hat_api.ChangedFile, 0, lenFiles)
|
||||
for i := start; i < end; i++ {
|
||||
apiFiles = append(apiFiles, hat_convert.ToChangedFile(diff.Files[i], ctx.Repo.Repository, headCommitID))
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(totalNumberOfFiles, listOptions.PageSize)
|
||||
ctx.SetTotalCountHeader(int64(totalNumberOfFiles))
|
||||
|
||||
ctx.RespHeader().Set("X-Page", strconv.Itoa(listOptions.Page))
|
||||
ctx.RespHeader().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
|
||||
ctx.RespHeader().Set("X-PageCount", strconv.Itoa(totalNumberOfPages))
|
||||
ctx.RespHeader().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages))
|
||||
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore")
|
||||
ctx.JSON(http.StatusOK, struct {
|
||||
Files []*hat_api.ChangedFile `json:"files"`
|
||||
TotalAddition int `json:"total_addition"`
|
||||
TotalDeletion int `json:"total_deletion"`
|
||||
}{
|
||||
Files: apiFiles,
|
||||
TotalAddition: diff.TotalAddition,
|
||||
TotalDeletion: diff.TotalDeletion,
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
fileDiff := struct {
|
||||
*gitdiff.Diff
|
||||
LatestSha string
|
||||
}{
|
||||
Diff: diff,
|
||||
LatestSha: endCommitID,
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, fileDiff)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GetPullFilesByPath(ctx *context.APIContext) {
|
||||
path := ctx.Params("*")
|
||||
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
||||
if err != nil {
|
||||
if issues_model.IsErrPullRequestNotExist(err) {
|
||||
ctx.NotFound()
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := pr.LoadBaseRepo(ctx); err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := pr.LoadHeadRepo(ctx); err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
baseGitRepo := ctx.Repo.GitRepo
|
||||
|
||||
var prInfo *git.CompareInfo
|
||||
if pr.HasMerged {
|
||||
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false)
|
||||
} else {
|
||||
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false)
|
||||
}
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCompareInfo", err)
|
||||
return
|
||||
}
|
||||
|
||||
headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRefCommitID", err)
|
||||
return
|
||||
}
|
||||
|
||||
startCommitID := prInfo.MergeBase
|
||||
endCommitID := headCommitID
|
||||
|
||||
diff, err := gitdiff.GetDiff(baseGitRepo, &gitdiff.DiffOptions{
|
||||
BeforeCommitID: startCommitID,
|
||||
AfterCommitID: endCommitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
}, path)
|
||||
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiff", err)
|
||||
return
|
||||
|
|
|
@ -2,9 +2,7 @@ package repo
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -17,15 +15,10 @@ import (
|
|||
"code.gitea.io/gitea/modules/git"
|
||||
gitea_git "code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert"
|
||||
hat_git "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git"
|
||||
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
||||
hat_repo_service "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/repository"
|
||||
)
|
||||
|
||||
func PrepareComapreDiff(
|
||||
|
@ -34,7 +27,7 @@ func PrepareComapreDiff(
|
|||
headRepo *repo_model.Repository,
|
||||
headGitRepo *gitea_git.Repository,
|
||||
compareInfo *gitea_git.CompareInfo,
|
||||
baseBranch, headBranch string, path ...string) bool {
|
||||
baseBranch, headBranch string) bool {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
@ -67,14 +60,12 @@ func PrepareComapreDiff(
|
|||
defer gitRepo.Close()
|
||||
|
||||
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
|
||||
BeforeCommitID: compareInfo.MergeBase,
|
||||
AfterCommitID: headCommitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
}, path...)
|
||||
BeforeCommitID: compareInfo.MergeBase,
|
||||
AfterCommitID: headCommitID,
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: setting.Git.MaxGitDiffFiles,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetDiff", err)
|
||||
|
@ -99,237 +90,13 @@ type CompareCommit struct {
|
|||
}
|
||||
|
||||
func CompareDiff(ctx *context.APIContext) {
|
||||
isFiles := ctx.FormString("isFiles")
|
||||
if isFiles == "" {
|
||||
// headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
|
||||
_, _, headGitRepo, compareInfo, _, _ := ParseCompareInfo(ctx)
|
||||
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
|
||||
// _ = PrepareComapreDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch)
|
||||
|
||||
result := make([]CompareCommit, 0)
|
||||
for _, commit := range compareInfo.Commits {
|
||||
compareCommit := CompareCommit{
|
||||
Commit: commit,
|
||||
Sha: commit.ID.String(),
|
||||
}
|
||||
for _, p := range commit.Parents {
|
||||
compareCommit.ParentShas = append(compareCommit.ParentShas, p.String())
|
||||
}
|
||||
result = append(result, compareCommit)
|
||||
}
|
||||
|
||||
different := struct {
|
||||
Commits []CompareCommit
|
||||
Diff interface{}
|
||||
CommitsCount int
|
||||
Latestsha string
|
||||
FilesCount int
|
||||
}{
|
||||
Commits: result,
|
||||
// Diff: ctx.Data["Diff"],
|
||||
}
|
||||
|
||||
different.CommitsCount = len(compareInfo.Commits)
|
||||
different.Latestsha = compareInfo.HeadCommitID
|
||||
different.FilesCount = compareInfo.NumFiles
|
||||
|
||||
ctx.JSON(http.StatusOK, different)
|
||||
} else {
|
||||
if ctx.FormString("filepath") == "" {
|
||||
headUser, headRepo, headGitRepo, compareInfo, _, headBranch := ParseCompareInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
|
||||
headCommitID := headBranch
|
||||
|
||||
repoPath := repo_model.RepoPath(headUser.Name, headRepo.Name)
|
||||
|
||||
gitRepo, _ := gitea_git.OpenRepository(ctx, repoPath)
|
||||
defer gitRepo.Close()
|
||||
|
||||
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
|
||||
BeforeCommitID: compareInfo.MergeBase,
|
||||
AfterCommitID: headCommitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetDiff", err)
|
||||
return
|
||||
}
|
||||
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
|
||||
totalNumberOfFiles := diff.NumFiles
|
||||
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
|
||||
|
||||
start, end := listOptions.GetStartEnd()
|
||||
|
||||
if end > totalNumberOfFiles {
|
||||
end = totalNumberOfFiles
|
||||
}
|
||||
|
||||
lenFiles := end - start
|
||||
if lenFiles < 0 {
|
||||
lenFiles = 0
|
||||
}
|
||||
|
||||
apiFiles := make([]*hat_api.ChangedFile, 0, lenFiles)
|
||||
for i := start; i < end; i++ {
|
||||
apiFiles = append(apiFiles, hat_convert.ToChangedFile(diff.Files[i], ctx.Repo.Repository, headCommitID))
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(totalNumberOfFiles, listOptions.PageSize)
|
||||
ctx.SetTotalCountHeader(int64(totalNumberOfFiles))
|
||||
|
||||
ctx.RespHeader().Set("X-Page", strconv.Itoa(listOptions.Page))
|
||||
ctx.RespHeader().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
|
||||
ctx.RespHeader().Set("X-PageCount", strconv.Itoa(totalNumberOfPages))
|
||||
ctx.RespHeader().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages))
|
||||
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore")
|
||||
|
||||
ctx.JSON(http.StatusOK, struct {
|
||||
Files []*hat_api.ChangedFile `json:"files"`
|
||||
TotalAddition int `json:"total_addition"`
|
||||
TotalDeletion int `json:"total_deletion"`
|
||||
}{
|
||||
Files: apiFiles,
|
||||
TotalAddition: diff.TotalAddition,
|
||||
TotalDeletion: diff.TotalDeletion,
|
||||
})
|
||||
} else {
|
||||
path := util.PathEscapeSegments(ctx.FormString("filepath"))
|
||||
headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
|
||||
_ = PrepareComapreDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch, path)
|
||||
|
||||
result := make([]CompareCommit, 0)
|
||||
for _, commit := range compareInfo.Commits {
|
||||
compareCommit := CompareCommit{
|
||||
Commit: commit,
|
||||
Sha: commit.ID.String(),
|
||||
}
|
||||
for _, p := range commit.Parents {
|
||||
compareCommit.ParentShas = append(compareCommit.ParentShas, p.String())
|
||||
}
|
||||
result = append(result, compareCommit)
|
||||
}
|
||||
|
||||
different := struct {
|
||||
Commits []CompareCommit
|
||||
Diff interface{}
|
||||
CommitsCount int
|
||||
Latestsha string
|
||||
}{
|
||||
Commits: result,
|
||||
Diff: ctx.Data["Diff"],
|
||||
}
|
||||
|
||||
different.CommitsCount = len(compareInfo.Commits)
|
||||
different.Latestsha = compareInfo.HeadCommitID
|
||||
|
||||
ctx.JSON(http.StatusOK, different)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func CompareFiles(ctx *context.APIContext) {
|
||||
headUser, headRepo, headGitRepo, compareInfo, _, headBranch := ParseCompareInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
|
||||
headCommitID := headBranch
|
||||
|
||||
repoPath := repo_model.RepoPath(headUser.Name, headRepo.Name)
|
||||
|
||||
gitRepo, _ := gitea_git.OpenRepository(ctx, repoPath)
|
||||
defer gitRepo.Close()
|
||||
|
||||
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
|
||||
BeforeCommitID: compareInfo.MergeBase,
|
||||
AfterCommitID: headCommitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetDiff", err)
|
||||
return
|
||||
}
|
||||
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
|
||||
totalNumberOfFiles := diff.NumFiles
|
||||
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
|
||||
|
||||
start, end := listOptions.GetStartEnd()
|
||||
|
||||
if end > totalNumberOfFiles {
|
||||
end = totalNumberOfFiles
|
||||
}
|
||||
|
||||
lenFiles := end - start
|
||||
if lenFiles < 0 {
|
||||
lenFiles = 0
|
||||
}
|
||||
|
||||
apiFiles := make([]*hat_api.ChangedFile, 0, lenFiles)
|
||||
for i := start; i < end; i++ {
|
||||
apiFiles = append(apiFiles, hat_convert.ToChangedFile(diff.Files[i], ctx.Repo.Repository, headCommitID))
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(totalNumberOfFiles, listOptions.PageSize)
|
||||
ctx.SetTotalCountHeader(int64(totalNumberOfFiles))
|
||||
|
||||
ctx.RespHeader().Set("X-Page", strconv.Itoa(listOptions.Page))
|
||||
ctx.RespHeader().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
|
||||
ctx.RespHeader().Set("X-PageCount", strconv.Itoa(totalNumberOfPages))
|
||||
ctx.RespHeader().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages))
|
||||
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore")
|
||||
|
||||
ctx.JSON(http.StatusOK, struct {
|
||||
Files []*hat_api.ChangedFile `json:"files"`
|
||||
TotalAddition int `json:"total_addition"`
|
||||
TotalDeletion int `json:"total_deletion"`
|
||||
}{
|
||||
Files: apiFiles,
|
||||
TotalAddition: diff.TotalAddition,
|
||||
TotalDeletion: diff.TotalDeletion,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func CompareFilesByPath(ctx *context.APIContext) {
|
||||
path := ctx.Params("*")
|
||||
headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
|
||||
_ = PrepareComapreDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch, path)
|
||||
_ = PrepareComapreDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch)
|
||||
|
||||
result := make([]CompareCommit, 0)
|
||||
for _, commit := range compareInfo.Commits {
|
||||
|
@ -845,29 +612,3 @@ func ListCodeStats(ctx *context.APIContext) {
|
|||
|
||||
ctx.JSON(http.StatusOK, stats)
|
||||
}
|
||||
|
||||
func Delete(ctx *context.APIContext) {
|
||||
owner := ctx.Repo.Owner
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
canDelete, err := repo_module.CanUserDelete(ctx, repo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "CanUserDelete", err)
|
||||
return
|
||||
} else if !canDelete {
|
||||
ctx.Error(http.StatusForbidden, "", "Given user is not owner of organization.")
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
ctx.Repo.GitRepo.Close()
|
||||
}
|
||||
|
||||
if err := hat_repo_service.DeleteRepository(ctx, ctx.Doer, repo, true); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "DeleteRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name)
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
|
|
@ -44,20 +44,6 @@ func ListTags(ctx *context.APIContext) {
|
|||
ctx.JSON(http.StatusOK, &apiTags)
|
||||
}
|
||||
|
||||
func GetTag(ctx *context.APIContext) {
|
||||
tagName := ctx.Params("*")
|
||||
tag, err := ctx.Repo.GitRepo.GetTag(tagName)
|
||||
if err != nil {
|
||||
ctx.NotFound(tagName)
|
||||
}
|
||||
|
||||
apiTag, err := hat_convert.ToTag(ctx.Repo.Repository, ctx.Repo.GitRepo, tag)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "hat_convert.ToTag", err)
|
||||
}
|
||||
ctx.JSON(http.StatusOK, apiTag)
|
||||
}
|
||||
|
||||
func BranchTagCount(ctx *context.APIContext) {
|
||||
_, tagsTotal, err := ctx.Repo.GitRepo.GetTagInfos(0, 0)
|
||||
if err != nil {
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
util "code.gitea.io/gitea/modules/util"
|
||||
wiki_service "code.gitea.io/gitea/services/wiki"
|
||||
)
|
||||
|
||||
func ListWikiPageNames(ctx *context.APIContext) {
|
||||
|
||||
wikiRepo, err := git.OpenRepository(ctx, ctx.Repo.Repository.WikiPath())
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) || err.Error() == "no such file or directory" {
|
||||
ctx.NotFound(err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
commit, err := wikiRepo.GetBranchCommit("master")
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
ctx.NotFound(err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBranchCommit", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if wikiRepo != nil {
|
||||
|
||||
defer wikiRepo.Close()
|
||||
}
|
||||
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
entries, err := commit.ListEntries()
|
||||
if err != nil {
|
||||
ctx.ServerError("ListEntries", err)
|
||||
return
|
||||
}
|
||||
|
||||
pages := make([]*api.WikiPageMetaData, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
if !entry.IsRegular() {
|
||||
continue
|
||||
}
|
||||
wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
|
||||
if err != nil {
|
||||
if repo_model.IsErrWikiInvalidFileName(err) {
|
||||
continue
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "WikiFilenameToName", err)
|
||||
return
|
||||
}
|
||||
subURL := string(wikiName)
|
||||
_, title := wiki_service.WebPathToUserTitle(wikiName)
|
||||
pages = append(pages, &api.WikiPageMetaData{
|
||||
Title: title,
|
||||
HTMLURL: util.URLJoin(ctx.Repo.Repository.HTMLURL(), "wiki", subURL),
|
||||
SubURL: subURL,
|
||||
})
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(int64(len(entries)))
|
||||
ctx.JSON(http.StatusOK, pages)
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/httpcache"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web/routing"
|
||||
)
|
||||
|
||||
func storageHandler(storageSetting *setting.Storage, prefix string, objStore storage.ObjectStorage) http.HandlerFunc {
|
||||
prefix = strings.Trim(prefix, "/")
|
||||
funcInfo := routing.GetFuncInfo(storageHandler, prefix)
|
||||
|
||||
if storageSetting.MinioConfig.ServeDirect {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "GET" && req.Method != "HEAD" {
|
||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
routing.UpdateFuncInfo(req.Context(), funcInfo)
|
||||
|
||||
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
|
||||
rPath = util.PathJoinRelX(rPath)
|
||||
|
||||
u, err := objStore.URL(rPath, path.Base(rPath))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
|
||||
log.Warn("Unable to find %s %s", prefix, rPath)
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
log.Error("Error whilst getting URL for %s %s. Error: %v", prefix, rPath, err)
|
||||
http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, req, u.String(), http.StatusTemporaryRedirect)
|
||||
})
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "GET" && req.Method != "HEAD" {
|
||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
routing.UpdateFuncInfo(req.Context(), funcInfo)
|
||||
|
||||
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
|
||||
rPath = util.PathJoinRelX(rPath)
|
||||
if rPath == "" || rPath == "." {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
fi, err := objStore.Stat(rPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
|
||||
log.Warn("Unable to find %s %s", prefix, rPath)
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err)
|
||||
http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
fr, err := objStore.Open(rPath)
|
||||
if err != nil {
|
||||
log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err)
|
||||
http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer fr.Close()
|
||||
httpcache.ServeContentWithCacheControl(w, req, path.Base(rPath), fi.ModTime(), fr)
|
||||
})
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/routers/web/repo"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
context_service "code.gitea.io/gitea/services/context"
|
||||
//"code.gitea.io/gitea/routers/web/repo"
|
||||
hat_repo "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo"
|
||||
)
|
||||
|
||||
func requireSignIn(ctx *context.Context) {
|
||||
if !setting.Service.RequireSignInView {
|
||||
return
|
||||
}
|
||||
|
||||
// rely on the results of Contexter
|
||||
if !ctx.IsSigned {
|
||||
// TODO: support digit auth - which would be Authorization header with digit
|
||||
//ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea"`)
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="."`)
|
||||
ctx.Error(http.StatusUnauthorized)
|
||||
}
|
||||
}
|
||||
|
||||
func gitHTTPRouters(m *web.Route) {
|
||||
m.Group("", func() {
|
||||
m.PostOptions("/git-upload-pack", repo.ServiceUploadPack)
|
||||
m.PostOptions("/git-receive-pack", repo.ServiceReceivePack)
|
||||
m.GetOptions("/info/refs", hat_repo.GetInfoRefs)
|
||||
m.GetOptions("/HEAD", repo.GetTextFile("HEAD"))
|
||||
m.GetOptions("/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
|
||||
m.GetOptions("/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
|
||||
m.GetOptions("/objects/info/packs", repo.GetInfoPacks)
|
||||
m.GetOptions("/objects/info/{file:[^/]*}", repo.GetTextFile(""))
|
||||
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
|
||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
||||
}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
func goGet(ctx *context.Context) {
|
||||
if ctx.Req.Method != "GET" || len(ctx.Req.URL.RawQuery) < 8 || ctx.FormString("go-get") != "1" {
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.SplitN(ctx.Req.URL.EscapedPath(), "/", 4)
|
||||
|
||||
if len(parts) < 3 {
|
||||
return
|
||||
}
|
||||
|
||||
ownerName := parts[1]
|
||||
repoName := parts[2]
|
||||
|
||||
// Quick responses appropriate go-get meta with status 200
|
||||
// regardless of if user have access to the repository,
|
||||
// or the repository does not exist at all.
|
||||
// This is particular a workaround for "go get" command which does not respect
|
||||
// .netrc file.
|
||||
|
||||
trimmedRepoName := strings.TrimSuffix(repoName, ".git")
|
||||
|
||||
if ownerName == "" || trimmedRepoName == "" {
|
||||
_, _ = ctx.Write([]byte(`<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
invalid import path
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
ctx.Status(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
branchName := setting.Repository.DefaultBranch
|
||||
|
||||
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName)
|
||||
if err == nil && len(repo.DefaultBranch) > 0 {
|
||||
branchName = repo.DefaultBranch
|
||||
}
|
||||
prefix := setting.AppURL + path.Join(url.PathEscape(ownerName), url.PathEscape(repoName), "src", "branch", util.PathEscapeSegments(branchName))
|
||||
|
||||
appURL, _ := url.Parse(setting.AppURL)
|
||||
|
||||
insecure := ""
|
||||
if appURL.Scheme == string(setting.HTTP) {
|
||||
insecure = "--insecure "
|
||||
}
|
||||
|
||||
goGetImport := context.ComposeGoGetImport(ownerName, trimmedRepoName)
|
||||
|
||||
var cloneURL string
|
||||
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
|
||||
cloneURL = repo_model.ComposeSSHCloneURL(ownerName, repoName)
|
||||
} else {
|
||||
cloneURL = repo_model.ComposeHTTPSCloneURL(ownerName, repoName)
|
||||
}
|
||||
goImportContent := fmt.Sprintf("%s git %s", goGetImport, cloneURL /*CloneLink*/)
|
||||
goSourceContent := fmt.Sprintf("%s _ %s %s", goGetImport, prefix+"{/dir}" /*GoDocDirectory*/, prefix+"{/dir}/{file}#L{line}" /*GoDocFile*/)
|
||||
goGetCli := fmt.Sprintf("go get %s%s", insecure, goGetImport)
|
||||
|
||||
res := fmt.Sprintf(`<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="go-import" content="%s">
|
||||
<meta name="go-source" content="%s">
|
||||
</head>
|
||||
<body>
|
||||
%s
|
||||
</body>
|
||||
</html>`, html.EscapeString(goImportContent), html.EscapeString(goSourceContent), html.EscapeString(goGetCli))
|
||||
|
||||
ctx.RespHeader().Set("Content-Type", "text/html")
|
||||
_, _ = ctx.Write([]byte(res))
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
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/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/sitemap"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
"code.gitea.io/gitea/routers/web/auth"
|
||||
"code.gitea.io/gitea/routers/web/user"
|
||||
)
|
||||
|
||||
const (
|
||||
// tplHome home page template
|
||||
tplHome base.TplName = "home"
|
||||
)
|
||||
|
||||
// Home render home page
|
||||
func Home(ctx *context.Context) {
|
||||
if ctx.IsSigned {
|
||||
if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||
ctx.HTML(http.StatusOK, auth.TplActivate)
|
||||
} else if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin {
|
||||
log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr())
|
||||
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
||||
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
|
||||
} else if ctx.Doer.MustChangePassword {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
||||
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
|
||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
||||
} else {
|
||||
user.Dashboard(ctx)
|
||||
}
|
||||
return
|
||||
// Check non-logged users landing page.
|
||||
} else if setting.LandingPageURL != setting.LandingPageHome {
|
||||
ctx.Redirect(setting.AppSubURL + string(setting.LandingPageURL))
|
||||
return
|
||||
}
|
||||
|
||||
// Check auto-login.
|
||||
uname := ctx.GetSiteCookie(setting.CookieUserName)
|
||||
if len(uname) != 0 {
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["PageIsHome"] = true
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
ctx.HTML(http.StatusOK, tplHome)
|
||||
}
|
||||
|
||||
// HomeSitemap renders the main sitemap
|
||||
func HomeSitemap(ctx *context.Context) {
|
||||
m := sitemap.NewSitemapIndex()
|
||||
if !setting.Service.Explore.DisableUsersPage {
|
||||
_, cnt, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{
|
||||
Type: user_model.UserTypeIndividual,
|
||||
ListOptions: db.ListOptions{PageSize: 1},
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
Visible: []structs.VisibleType{structs.VisibleTypePublic},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchUsers", err)
|
||||
return
|
||||
}
|
||||
count := int(cnt)
|
||||
idx := 1
|
||||
for i := 0; i < count; i += setting.UI.SitemapPagingNum {
|
||||
m.Add(sitemap.URL{URL: setting.AppURL + "explore/users/sitemap-" + strconv.Itoa(idx) + ".xml"})
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
_, cnt, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
PageSize: 1,
|
||||
},
|
||||
Actor: ctx.Doer,
|
||||
AllPublic: true,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepository", err)
|
||||
return
|
||||
}
|
||||
count := int(cnt)
|
||||
idx := 1
|
||||
for i := 0; i < count; i += setting.UI.SitemapPagingNum {
|
||||
m.Add(sitemap.URL{URL: setting.AppURL + "explore/repos/sitemap-" + strconv.Itoa(idx) + ".xml"})
|
||||
idx++
|
||||
}
|
||||
|
||||
ctx.Resp.Header().Set("Content-Type", "text/xml")
|
||||
if _, err := m.WriteTo(ctx.Resp); err != nil {
|
||||
log.Error("Failed writing sitemap: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// NotFound render 404 page
|
||||
func NotFound(ctx *context.Context) {
|
||||
ctx.Data["Title"] = "Page Not Found"
|
||||
ctx.NotFound("home.NotFound", nil)
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
// Metrics validate auth token and render prometheus metrics
|
||||
func Metrics(resp http.ResponseWriter, req *http.Request) {
|
||||
if setting.Metrics.Token == "" {
|
||||
promhttp.Handler().ServeHTTP(resp, req)
|
||||
return
|
||||
}
|
||||
header := req.Header.Get("Authorization")
|
||||
if header == "" {
|
||||
http.Error(resp, "", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
got := []byte(header)
|
||||
want := []byte("Bearer " + setting.Metrics.Token)
|
||||
if subtle.ConstantTimeCompare(got, want) != 1 {
|
||||
http.Error(resp, "", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
promhttp.Handler().ServeHTTP(resp, req)
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
type nodeInfoLinks struct {
|
||||
Links []nodeInfoLink `json:"links"`
|
||||
}
|
||||
|
||||
type nodeInfoLink struct {
|
||||
Href string `json:"href"`
|
||||
Rel string `json:"rel"`
|
||||
}
|
||||
|
||||
// NodeInfoLinks returns links to the node info endpoint
|
||||
func NodeInfoLinks(ctx *context.Context) {
|
||||
nodeinfolinks := &nodeInfoLinks{
|
||||
Links: []nodeInfoLink{{
|
||||
fmt.Sprintf("%sapi/v1/nodeinfo", setting.AppURL),
|
||||
"http://nodeinfo.diaspora.software/ns/schema/2.1",
|
||||
}},
|
||||
}
|
||||
ctx.JSON(http.StatusOK, nodeinfolinks)
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
)
|
||||
|
||||
// tplSwaggerV1Json swagger v1 json template
|
||||
const tplSwaggerV1Json base.TplName = "swagger/v1_json"
|
||||
|
||||
// SwaggerV1Json render swagger v1 json
|
||||
func SwaggerV1Json(ctx *context.Context) {
|
||||
t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json), nil)
|
||||
if err != nil {
|
||||
ctx.ServerError("unable to find template", err)
|
||||
return
|
||||
}
|
||||
ctx.Resp.Header().Set("Content-Type", "application/json")
|
||||
if err = t.Execute(ctx.Resp, ctx.Data); err != nil {
|
||||
ctx.ServerError("unable to execute template", err)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,121 +0,0 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-webfinger-14#section-4.4
|
||||
|
||||
type webfingerJRD struct {
|
||||
Subject string `json:"subject,omitempty"`
|
||||
Aliases []string `json:"aliases,omitempty"`
|
||||
Properties map[string]any `json:"properties,omitempty"`
|
||||
Links []*webfingerLink `json:"links,omitempty"`
|
||||
}
|
||||
|
||||
type webfingerLink struct {
|
||||
Rel string `json:"rel,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Href string `json:"href,omitempty"`
|
||||
Titles map[string]string `json:"titles,omitempty"`
|
||||
Properties map[string]any `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// WebfingerQuery returns information about a resource
|
||||
// https://datatracker.ietf.org/doc/html/rfc7565
|
||||
func WebfingerQuery(ctx *context.Context) {
|
||||
appURL, _ := url.Parse(setting.AppURL)
|
||||
|
||||
resource, err := url.Parse(ctx.FormTrim("resource"))
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var u *user_model.User
|
||||
|
||||
switch resource.Scheme {
|
||||
case "acct":
|
||||
// allow only the current host
|
||||
parts := strings.SplitN(resource.Opaque, "@", 2)
|
||||
if len(parts) != 2 {
|
||||
ctx.Error(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if parts[1] != appURL.Host {
|
||||
ctx.Error(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
u, err = user_model.GetUserByName(ctx, parts[0])
|
||||
case "mailto":
|
||||
u, err = user_model.GetUserByEmail(ctx, resource.Opaque)
|
||||
if u != nil && u.KeepEmailPrivate {
|
||||
err = user_model.ErrUserNotExist{}
|
||||
}
|
||||
default:
|
||||
ctx.Error(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.Error(http.StatusNotFound)
|
||||
} else {
|
||||
log.Error("Error getting user: %s Error: %v", resource.Opaque, err)
|
||||
ctx.Error(http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !user_model.IsUserVisibleToViewer(ctx, u, ctx.Doer) {
|
||||
ctx.Error(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
aliases := []string{
|
||||
u.HTMLURL(),
|
||||
appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(u.ID),
|
||||
}
|
||||
if !u.KeepEmailPrivate {
|
||||
aliases = append(aliases, fmt.Sprintf("mailto:%s", u.Email))
|
||||
}
|
||||
|
||||
links := []*webfingerLink{
|
||||
{
|
||||
Rel: "http://webfinger.net/rel/profile-page",
|
||||
Type: "text/html",
|
||||
Href: u.HTMLURL(),
|
||||
},
|
||||
{
|
||||
Rel: "http://webfinger.net/rel/avatar",
|
||||
Href: u.AvatarLink(ctx),
|
||||
},
|
||||
{
|
||||
Rel: "self",
|
||||
Type: "application/activity+json",
|
||||
Href: appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(u.ID),
|
||||
},
|
||||
{
|
||||
Rel: "http://openid.net/specs/connect/1.0/issuer",
|
||||
Href: appURL.String(),
|
||||
},
|
||||
}
|
||||
|
||||
ctx.Resp.Header().Add("Access-Control-Allow-Origin", "*")
|
||||
ctx.JSON(http.StatusOK, &webfingerJRD{
|
||||
Subject: fmt.Sprintf("acct:%s@%s", url.QueryEscape(u.Name), appURL.Host),
|
||||
Aliases: aliases,
|
||||
Links: links,
|
||||
})
|
||||
}
|
|
@ -10,17 +10,9 @@ import (
|
|||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
actions_router "code.gitea.io/gitea/routers/api/actions"
|
||||
packages_router "code.gitea.io/gitea/routers/api/packages"
|
||||
apiv1 "code.gitea.io/gitea/routers/api/v1"
|
||||
"code.gitea.io/gitea/routers/common"
|
||||
"code.gitea.io/gitea/routers/private"
|
||||
//web_routers "code.gitea.io/gitea/routers/web"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/models/migrations"
|
||||
api_hat "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat"
|
||||
web_routers "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/web"
|
||||
hat_pull_service "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/pull"
|
||||
)
|
||||
|
||||
|
@ -48,6 +40,12 @@ func GlobalInitInstalled(ctx context.Context) {
|
|||
|
||||
}
|
||||
|
||||
func InitHatRouters(ctx context.Context, e *web.Route) *web.Route {
|
||||
|
||||
e.Mount("/api/hat", api_hat.Routers(ctx))
|
||||
return e
|
||||
}
|
||||
|
||||
func InitDBEngine(ctx context.Context) (err error) {
|
||||
log.Info("Beginning hat ORM engine initialization.")
|
||||
for i := 0; i < setting.Database.DBConnectRetries; i++ {
|
||||
|
@ -69,37 +67,3 @@ func InitDBEngine(ctx context.Context) (err error) {
|
|||
db.HasEngine = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func NormalRoutes() *web.Route {
|
||||
_ = templates.HTMLRenderer()
|
||||
r := web.NewRoute()
|
||||
r.Use(common.ProtocolMiddlewares()...)
|
||||
|
||||
r.Mount("/", web_routers.Routes())
|
||||
r.Mount("/api/v1", apiv1.Routes())
|
||||
r.Mount("/api/hat", api_hat.Routers())
|
||||
|
||||
r.Mount("/api/internal", private.Routes())
|
||||
r.Post("/-/fetch-redirect", common.FetchRedirectDelegate)
|
||||
|
||||
if setting.Packages.Enabled {
|
||||
// This implements package support for most package managers
|
||||
r.Mount("/api/packages", packages_router.CommonRoutes())
|
||||
// This implements the OCI API (Note this is not preceded by /api but is instead /v2)
|
||||
r.Mount("/v2", packages_router.ContainerRoutes())
|
||||
}
|
||||
|
||||
if setting.Actions.Enabled {
|
||||
prefix := "/api/actions"
|
||||
r.Mount(prefix, actions_router.Routes(prefix))
|
||||
|
||||
// TODO: Pipeline api used for runner internal communication with gitea server. but only artifact is used for now.
|
||||
// In Github, it uses ACTIONS_RUNTIME_URL=https://pipelines.actions.githubusercontent.com/fLgcSHkPGySXeIFrg8W8OBSfeg3b5Fls1A1CwX566g8PayEGlg/
|
||||
// TODO: this prefix should be generated with a token string with runner ?
|
||||
prefix = "/api/actions_pipeline"
|
||||
r.Mount(prefix, actions_router.ArtifactsRoutes(prefix))
|
||||
}
|
||||
|
||||
return r
|
||||
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package convert
|
||||
|
||||
import (
|
||||
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
||||
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
gitea_convert "code.gitea.io/gitea/services/convert"
|
||||
)
|
||||
|
||||
func ToBranch(ctx *context.APIContext, branch *git_model.Branch, c *git.Commit, bp *git_model.ProtectedBranch, user *user_model.User, isRepoAdmin bool) (*hat_api.Branch, error) {
|
||||
gitea_api_branch, err := gitea_convert.ToBranch(ctx, ctx.Repo.Repository, branch.Name, c, bp, user, isRepoAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hat_api_branch := &hat_api.Branch{}
|
||||
hat_api_branch.Branch = gitea_api_branch
|
||||
hat_api_branch.IsDeleted = branch.IsDeleted
|
||||
hat_api_branch.DeletedUnix = int(branch.DeletedUnix)
|
||||
hat_api_branch.ID = branch.ID
|
||||
hat_api_branch.DeletedBy = &hat_api.BranchDeleteUser{
|
||||
Name: branch.DeletedBy.Name,
|
||||
Email: branch.DeletedBy.Email,
|
||||
}
|
||||
return hat_api_branch, nil
|
||||
}
|
|
@ -1,389 +0,0 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
admin_model "code.gitea.io/gitea/models/admin"
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
project_model "code.gitea.io/gitea/models/project"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
secret_model "code.gitea.io/gitea/models/secret"
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/models/webhook"
|
||||
actions_module "code.gitea.io/gitea/modules/actions"
|
||||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, repoID int64, ignoreOrgTeams ...bool) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
// Query the action tasks of this repo, they will be needed after they have been deleted to remove the logs
|
||||
tasks, err := actions_model.FindTasks(ctx, actions_model.FindTaskOptions{RepoID: repoID})
|
||||
if err != nil {
|
||||
return fmt.Errorf("find actions tasks of repo %v: %w", repoID, err)
|
||||
}
|
||||
|
||||
// Query the artifacts of this repo, they will be needed after they have been deleted to remove artifacts files in ObjectStorage
|
||||
artifacts, err := actions_model.ListArtifactsByRepoID(ctx, repoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err)
|
||||
}
|
||||
|
||||
// In case owner is a organization, we have to change repo specific teams
|
||||
// if ignoreOrgTeams is not true
|
||||
var org *user_model.User
|
||||
if len(ignoreOrgTeams) == 0 || !ignoreOrgTeams[0] {
|
||||
if org, err = user_model.GetUserByID(ctx, uid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
repo := &repo_model.Repository{OwnerID: uid}
|
||||
has, err := sess.ID(repoID).Get(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return repo_model.ErrRepoNotExist{
|
||||
ID: repoID,
|
||||
UID: uid,
|
||||
OwnerName: "",
|
||||
Name: "",
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Deploy Keys
|
||||
deployKeys, err := asymkey_model.ListDeployKeys(ctx, &asymkey_model.ListDeployKeysOptions{RepoID: repoID})
|
||||
if err != nil {
|
||||
return fmt.Errorf("listDeployKeys: %w", err)
|
||||
}
|
||||
needRewriteKeysFile := len(deployKeys) > 0
|
||||
for _, dKey := range deployKeys {
|
||||
if err := models.DeleteDeployKey(ctx, doer, dKey.ID); err != nil {
|
||||
return fmt.Errorf("deleteDeployKeys: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if cnt, err := sess.ID(repoID).Delete(&repo_model.Repository{}); err != nil {
|
||||
return err
|
||||
} else if cnt != 1 {
|
||||
return repo_model.ErrRepoNotExist{
|
||||
ID: repoID,
|
||||
UID: uid,
|
||||
OwnerName: "",
|
||||
Name: "",
|
||||
}
|
||||
}
|
||||
|
||||
if org != nil && org.IsOrganization() {
|
||||
teams, err := organization.FindOrgTeams(ctx, org.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, t := range teams {
|
||||
if !organization.HasTeamRepo(ctx, t.OrgID, t.ID, repoID) {
|
||||
continue
|
||||
} else if err = removeRepositoryFromTeam(ctx, t, repo, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attachments := make([]*repo_model.Attachment, 0, 20)
|
||||
if err = sess.Join("INNER", "`release`", "`release`.id = `attachment`.release_id").
|
||||
Where("`release`.repo_id = ?", repoID).
|
||||
Find(&attachments); err != nil {
|
||||
return err
|
||||
}
|
||||
releaseAttachments := make([]string, 0, len(attachments))
|
||||
for i := 0; i < len(attachments); i++ {
|
||||
releaseAttachments = append(releaseAttachments, attachments[i].RelativePath())
|
||||
}
|
||||
|
||||
if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars=num_stars-1 WHERE id IN (SELECT `uid` FROM `star` WHERE repo_id = ?)", repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if _, err := db.GetEngine(ctx).In("hook_id", builder.Select("id").From("webhook").Where(builder.Eq{"webhook.repo_id": repo.ID})).
|
||||
// Delete(&webhook.HookTask{}); err != nil {
|
||||
// return err
|
||||
// }
|
||||
if _, err := db.GetEngine(ctx).Exec("DELETE hook_task FROM hook_task INNER JOIN webhook ON webhook.id = hook_task.hook_id WHERE webhook.repo_id = ? ", repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := db.DeleteBeans(ctx,
|
||||
&access_model.Access{RepoID: repo.ID},
|
||||
&activities_model.Action{RepoID: repo.ID},
|
||||
&repo_model.Collaboration{RepoID: repoID},
|
||||
&issues_model.Comment{RefRepoID: repoID},
|
||||
&git_model.CommitStatus{RepoID: repoID},
|
||||
&git_model.Branch{RepoID: repoID},
|
||||
&git_model.LFSLock{RepoID: repoID},
|
||||
&repo_model.LanguageStat{RepoID: repoID},
|
||||
&issues_model.Milestone{RepoID: repoID},
|
||||
&repo_model.Mirror{RepoID: repoID},
|
||||
&activities_model.Notification{RepoID: repoID},
|
||||
&git_model.ProtectedBranch{RepoID: repoID},
|
||||
&git_model.ProtectedTag{RepoID: repoID},
|
||||
&repo_model.PushMirror{RepoID: repoID},
|
||||
&repo_model.Release{RepoID: repoID},
|
||||
&repo_model.RepoIndexerStatus{RepoID: repoID},
|
||||
&repo_model.Redirect{RedirectRepoID: repoID},
|
||||
&repo_model.RepoUnit{RepoID: repoID},
|
||||
&repo_model.Star{RepoID: repoID},
|
||||
&admin_model.Task{RepoID: repoID},
|
||||
&repo_model.Watch{RepoID: repoID},
|
||||
&webhook.Webhook{RepoID: repoID},
|
||||
&secret_model.Secret{RepoID: repoID},
|
||||
&actions_model.ActionTaskStep{RepoID: repoID},
|
||||
&actions_model.ActionTask{RepoID: repoID},
|
||||
&actions_model.ActionRunJob{RepoID: repoID},
|
||||
&actions_model.ActionRun{RepoID: repoID},
|
||||
&actions_model.ActionRunner{RepoID: repoID},
|
||||
&actions_model.ActionScheduleSpec{RepoID: repoID},
|
||||
&actions_model.ActionSchedule{RepoID: repoID},
|
||||
&actions_model.ActionArtifact{RepoID: repoID},
|
||||
); err != nil {
|
||||
return fmt.Errorf("deleteBeans: %w", err)
|
||||
}
|
||||
|
||||
// Delete Labels and related objects
|
||||
if err := issues_model.DeleteLabelsByRepoID(ctx, repoID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete Pulls and related objects
|
||||
if err := issues_model.DeletePullsByBaseRepoID(ctx, repoID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete Issues and related objects
|
||||
var attachmentPaths []string
|
||||
if attachmentPaths, err = issues_model.DeleteIssuesByRepoID(ctx, repoID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete issue index
|
||||
if err := db.DeleteResourceIndex(ctx, "issue_index", repoID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if repo.IsFork {
|
||||
if _, err := db.Exec(ctx, "UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkID); err != nil {
|
||||
return fmt.Errorf("decrease fork count: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := db.Exec(ctx, "UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", uid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(repo.Topics) > 0 {
|
||||
if err := repo_model.RemoveTopicsFromRepo(ctx, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := project_model.DeleteProjectByRepoID(ctx, repoID); err != nil {
|
||||
return fmt.Errorf("unable to delete projects for repo[%d]: %w", repoID, err)
|
||||
}
|
||||
|
||||
// Remove LFS objects
|
||||
var lfsObjects []*git_model.LFSMetaObject
|
||||
if err = sess.Where("repository_id=?", repoID).Find(&lfsObjects); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lfsPaths := make([]string, 0, len(lfsObjects))
|
||||
for _, v := range lfsObjects {
|
||||
count, err := db.CountByBean(ctx, &git_model.LFSMetaObject{Pointer: lfs.Pointer{Oid: v.Oid}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
lfsPaths = append(lfsPaths, v.RelativePath())
|
||||
}
|
||||
|
||||
if _, err := db.DeleteByBean(ctx, &git_model.LFSMetaObject{RepositoryID: repoID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove archives
|
||||
var archives []*repo_model.RepoArchiver
|
||||
if err = sess.Where("repo_id=?", repoID).Find(&archives); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
archivePaths := make([]string, 0, len(archives))
|
||||
for _, v := range archives {
|
||||
archivePaths = append(archivePaths, v.RelativePath())
|
||||
}
|
||||
|
||||
if _, err := db.DeleteByBean(ctx, &repo_model.RepoArchiver{RepoID: repoID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if repo.NumForks > 0 {
|
||||
if _, err = sess.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
|
||||
log.Error("reset 'fork_id' and 'is_fork': %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get all attachments with both issue_id and release_id are zero
|
||||
var newAttachments []*repo_model.Attachment
|
||||
if err := sess.Where(builder.Eq{
|
||||
"repo_id": repo.ID,
|
||||
"issue_id": 0,
|
||||
"release_id": 0,
|
||||
}).Find(&newAttachments); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newAttachmentPaths := make([]string, 0, len(newAttachments))
|
||||
for _, attach := range newAttachments {
|
||||
newAttachmentPaths = append(newAttachmentPaths, attach.RelativePath())
|
||||
}
|
||||
|
||||
if _, err := sess.Where("repo_id=?", repo.ID).Delete(new(repo_model.Attachment)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = committer.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
committer.Close()
|
||||
|
||||
if needRewriteKeysFile {
|
||||
if err := asymkey_model.RewriteAllPublicKeys(ctx); err != nil {
|
||||
log.Error("RewriteAllPublicKeys failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// We should always delete the files after the database transaction succeed. If
|
||||
// we delete the file but the database rollback, the repository will be broken.
|
||||
|
||||
// Remove repository files.
|
||||
repoPath := repo.RepoPath()
|
||||
system_model.RemoveAllWithNotice(ctx, "Delete repository files", repoPath)
|
||||
|
||||
// Remove wiki files
|
||||
if repo.HasWiki() {
|
||||
system_model.RemoveAllWithNotice(ctx, "Delete repository wiki", repo.WikiPath())
|
||||
}
|
||||
|
||||
// Remove archives
|
||||
for _, archive := range archivePaths {
|
||||
system_model.RemoveStorageWithNotice(ctx, storage.RepoArchives, "Delete repo archive file", archive)
|
||||
}
|
||||
|
||||
// Remove lfs objects
|
||||
for _, lfsObj := range lfsPaths {
|
||||
system_model.RemoveStorageWithNotice(ctx, storage.LFS, "Delete orphaned LFS file", lfsObj)
|
||||
}
|
||||
|
||||
// Remove issue attachment files.
|
||||
for _, attachment := range attachmentPaths {
|
||||
system_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", attachment)
|
||||
}
|
||||
|
||||
// Remove release attachment files.
|
||||
for _, releaseAttachment := range releaseAttachments {
|
||||
system_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete release attachment", releaseAttachment)
|
||||
}
|
||||
|
||||
// Remove attachment with no issue_id and release_id.
|
||||
for _, newAttachment := range newAttachmentPaths {
|
||||
system_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", newAttachment)
|
||||
}
|
||||
|
||||
if len(repo.Avatar) > 0 {
|
||||
if err := storage.RepoAvatars.Delete(repo.CustomAvatarRelativePath()); err != nil {
|
||||
return fmt.Errorf("Failed to remove %s: %w", repo.Avatar, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, delete action logs after the actions have already been deleted to avoid new log files
|
||||
for _, task := range tasks {
|
||||
err := actions_module.RemoveLogs(ctx, task.LogInStorage, task.LogFilename)
|
||||
if err != nil {
|
||||
log.Error("remove log file %q: %v", task.LogFilename, err)
|
||||
// go on
|
||||
}
|
||||
}
|
||||
|
||||
// delete actions artifacts in ObjectStorage after the repo have already been deleted
|
||||
for _, art := range artifacts {
|
||||
if err := storage.ActionsArtifacts.Delete(art.StoragePath); err != nil {
|
||||
log.Error("remove artifact file %q: %v", art.StoragePath, err)
|
||||
// go on
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeRepositoryFromTeam(ctx context.Context, t *organization.Team, repo *repo_model.Repository, recalculate bool) (err error) {
|
||||
e := db.GetEngine(ctx)
|
||||
if err = organization.RemoveTeamRepo(ctx, t.ID, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.NumRepos--
|
||||
if _, err = e.ID(t.ID).Cols("num_repos").Update(t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Don't need to recalculate when delete a repository from organization.
|
||||
if recalculate {
|
||||
if err = access_model.RecalculateTeamAccesses(ctx, repo, t.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
teamUsers, err := organization.GetTeamUsersByTeamID(ctx, t.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getTeamUsersByTeamID: %w", err)
|
||||
}
|
||||
for _, teamUser := range teamUsers {
|
||||
has, err := access_model.HasAccess(ctx, teamUser.UID, repo)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = repo_model.WatchRepo(ctx, teamUser.UID, repo.ID, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove all IssueWatches a user has subscribed to in the repositories
|
||||
if err := issues_model.RemoveIssueWatchersByRepoID(ctx, teamUser.UID, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
notify_service "code.gitea.io/gitea/services/notify"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
)
|
||||
|
||||
func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, notify bool) error {
|
||||
if err := pull_service.CloseRepoBranchesPulls(ctx, doer, repo); err != nil {
|
||||
log.Error("CloseRepoBranchesPulls failed: %v", err)
|
||||
}
|
||||
|
||||
if notify {
|
||||
// If the repo itself has webhooks, we need to trigger them before deleting it...
|
||||
notify_service.DeleteRepository(ctx, doer, repo)
|
||||
}
|
||||
|
||||
if err := DeleteRepositoryDirectly(ctx, doer, repo.OwnerID, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return packages_model.UnlinkRepositoryFromAllPackages(ctx, repo.ID)
|
||||
}
|
Loading…
Reference in New Issue