Merge branch 'main' into sync-issue-pr-and-more

This commit is contained in:
Chongyi Zheng 2023-09-24 02:47:56 -04:00
commit 99f91023ce
No known key found for this signature in database
GPG Key ID: E3C2287691E40E35
223 changed files with 1590 additions and 1168 deletions

View File

@ -44,7 +44,10 @@ steps:
image: techknowlogick/xgo:go-1.21.x
pull: always
commands:
- curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get -qqy install nodejs
- apt-get update && apt-get -qqy install ca-certificates curl gnupg
- mkdir -p /etc/apt/keyrings && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
- echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
- apt-get update && apt-get -qqy install nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:

View File

@ -11,7 +11,6 @@ parserOptions:
plugins:
- "@eslint-community/eslint-plugin-eslint-comments"
- eslint-plugin-array-func
- eslint-plugin-custom-elements
- eslint-plugin-import
- eslint-plugin-jquery
- eslint-plugin-no-jquery
@ -46,6 +45,9 @@ overrides:
- files: ["*.config.*"]
rules:
import/no-unused-modules: [0]
- files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"]
rules:
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
rules:
"@eslint-community/eslint-comments/disable-enable-pair": [2]
@ -85,19 +87,6 @@ rules:
consistent-this: [0]
constructor-super: [2]
curly: [0]
custom-elements/expose-class-on-global: [0]
custom-elements/extends-correct-class: [2]
custom-elements/file-name-matches-element: [2]
custom-elements/no-constructor: [2]
custom-elements/no-customized-built-in-elements: [2]
custom-elements/no-dom-traversal-in-attributechangedcallback: [2]
custom-elements/no-dom-traversal-in-connectedcallback: [2]
custom-elements/no-exports-with-element: [2]
custom-elements/no-method-prefixed-with-on: [2]
custom-elements/no-unchecked-define: [0]
custom-elements/one-element-per-file: [0]
custom-elements/tag-name-matches-class: [2]
custom-elements/valid-tag-name: [2]
default-case-last: [2]
default-case: [0]
default-param-last: [0]
@ -420,7 +409,7 @@ rules:
no-restricted-exports: [0]
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
no-restricted-imports: [0]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.js instead"}]
no-return-assign: [0]
no-script-url: [2]
no-self-assign: [2, {props: true}]
@ -737,14 +726,27 @@ rules:
valid-typeof: [2, {requireStringLiterals: true}]
vars-on-top: [0]
wc/attach-shadow-constructor: [2]
wc/define-tag-after-class-definition: [0]
wc/expose-class-on-global: [0]
wc/file-name-matches-element: [2]
wc/guard-define-call: [0]
wc/guard-super-call: [2]
wc/max-elements-per-file: [0]
wc/no-child-traversal-in-attributechangedcallback: [2]
wc/no-child-traversal-in-connectedcallback: [2]
wc/no-closed-shadow-root: [2]
wc/no-constructor-attributes: [2]
wc/no-constructor-params: [2]
wc/no-invalid-element-name: [0] # covered by custom-elements/valid-tag-name
wc/no-constructor: [2]
wc/no-customized-built-in-elements: [2]
wc/no-exports-with-element: [2]
wc/no-invalid-element-name: [2]
wc/no-invalid-extends: [2]
wc/no-method-prefixed-with-on: [2]
wc/no-self-class: [2]
wc/no-typos: [2]
wc/require-listener-teardown: [2]
wc/tag-name-matches-class: [2]
wrap-iife: [2, inside]
wrap-regex: [0]
yield-star-spacing: [2, after]

View File

@ -226,6 +226,7 @@ help:
@echo " - test-frontend test frontend files"
@echo " - test-backend test backend files"
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
@echo " - update update js and py dependencies"
@echo " - update-js update js dependencies"
@echo " - update-py update py dependencies"
@echo " - webpack build webpack files"
@ -924,6 +925,9 @@ node_modules: package-lock.json
poetry install
@touch .venv
.PHONY: update
update: update-js update-py
.PHONY: update-js
update-js: node-check | node_modules
npx updates -u -f package.json

View File

@ -95,7 +95,7 @@ Some lint rules and IDEs also have warnings if the returned Promise is not handl
### Fetching data
To fetch data, use the wrapper functions `GET`, `POST` etc. from `modules/fetch.js`. They
accept a `data` option for the content, will automatically set CSFR token and return a
accept a `data` option for the content, will automatically set CSRF token and return a
Promise for a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
### HTML Attributes and `dataset`

View File

@ -91,12 +91,6 @@ As a workaround, you can use [go-hashfiles](https://gitea.com/actions/go-hashfil
## Missing features
### Variables
See [Variables](https://docs.github.com/en/actions/learn-github-actions/variables).
It's under development.
### Problem Matchers
Problem Matchers are a way to scan the output of actions for a specified regex pattern and surface that information prominently in the UI.
@ -120,15 +114,17 @@ Pre and Post steps don't have their own section in the job log user interface.
### Downloading actions
Gitea Actions doesn't download actions from GitHub by default.
"By default" means that you don't specify the host in the `uses` field, like `uses: actions/checkout@v3`.
As a contrast, `uses: https://github.com/actions/checkout@v3` has specified host.
Previously (Pre 1.21.0), `[actions].DEFAULT_ACTIONS_URL` defaulted to `https://gitea.com`.
We have since restricted this option to only allow two values (`github` and `self`).
When set to `github`, the new default, Gitea will download non-fully-qualified actions from <https://github.com>.
For example, if you use `uses: actions/checkout@v3`, it will download the checkout repository from <https://github.com/actions/checkout.git>.
The missing host will be filled with `https://gitea.com` if you don't configure it.
That means `uses: actions/checkout@v3` will download the action from [gitea.com/actions/checkout](https://gitea.com/actions/checkout), instead of [github.com/actions/checkout](https://github.com/actions/checkout).
If you want to download an action from another git hoster, you can use an absolute URL, e.g. `uses: https://gitea.com/actions/checkout@v3`.
As mentioned, it's configurable.
If you want your runners to download actions from GitHub or your own Gitea instance by default, you can configure it by setting `[actions].DEFAULT_ACTIONS_URL`. See [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions).
If your Gitea instance is in an intranet or a restricted area, you can set the URL to `self` to only download actions from your own instance by default.
Of course, you can still use absolute URLs in workflows.
More details about the `[actions].DEFAULT_ACTIONS_URL` configuration can be found in the [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions)。
### Context availability

View File

@ -120,15 +120,13 @@ Gitea Actions目前不支持此功能。
### 下载Actions
Gitea Actions默认不从GitHub下载Actions。
"默认" 意味着您在`uses` 字段中不指定主机,如`uses: actions/checkout@v3`。
相反,`uses: https://github.com/actions/checkout@v3`是有指定主机的
`[actions].DEFAULT_ACTIONS_URL` 保持默认值为 `github`Gitea将会从 https://github.com 下载相对路径的actions。比如
果你使用 `uses: actions/checkout@v3`Gitea将会从 https://github.com/actions/checkout.git 下载这个 actions 项目
如果你想要从另外一个 Git服务下载actions你只需要使用绝对URL `uses: https://gitea.com/actions/checkout@v3` 来下载
如果您不进行配置,缺失的主机将填充为`https://gitea.com`。
这意味着`uses: actions/checkout@v3`将从[gitea.com/actions/checkout](https://gitea.com/actions/checkout)下载该Action而不是[github.com/actions/checkout](https://github.com/actions/checkout)。
如果你的 Gitea 实例是部署在一个互联网限制的网络中,有可以使用绝对地址来下载 actions。你也可以讲配置项修改为 `[actions].DEFAULT_ACTIONS_URL = self`。这样所有的相对路径的actions引用将不再会从 github.com 去下载,而会从这个 Gitea 实例自己的仓库中去下载。例如: `uses: actions/checkout@v3` 将会从 `[server].ROOT_URL`/actions/checkout.git 这个地址去下载 actions。
正如前面提到的,这是可配置的。
如果您希望您的运行程序默认从GitHub或您自己的Gitea实例下载动作您可以通过设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。
设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。
### 上下文可用性

View File

@ -180,3 +180,6 @@ For events supported only by GitHub, see GitHub's [documentation](https://docs.g
| pull_request_review_comment | `created`, `edited` |
| release | `published`, `edited` |
| registry_package | `published` |
> For `pull_request` events, in [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request), the `ref` is `refs/pull/:prNumber/merge`, which is a reference to the merge commit preview. However, Gitea has no such reference.
> Therefore, the `ref` in Gitea Actions is `refs/pull/:prNumber/head`, which points to the head of pull request rather than the preview of the merge commit.

View File

@ -180,3 +180,6 @@ defaults:
| pull_request_review_comment | `created`, `edited` |
| release | `published`, `edited` |
| registry_package | `published` |
> 对于 `pull_request` 事件,在 [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request) 中 `ref``refs/pull/:prNumber/merge`,它指向这个拉取请求合并提交的一个预览。但是 Gitea 没有这种 reference。
> 因此Gitea Actions 中 `ref``refs/pull/:prNumber/head`,它指向这个拉取请求的头分支而不是合并提交的预览。

2
go.mod
View File

@ -42,7 +42,7 @@ require (
github.com/go-chi/chi/v5 v5.0.10
github.com/go-chi/cors v1.2.1
github.com/go-co-op/gocron v1.31.1
github.com/go-enry/go-enry/v2 v2.8.4
github.com/go-enry/go-enry/v2 v2.8.5
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
github.com/go-git/go-billy/v5 v5.4.1
github.com/go-git/go-git/v5 v5.8.1

4
go.sum
View File

@ -347,8 +347,8 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-co-op/gocron v1.31.1 h1:LZAuBlU0t3SPGUMJGhrJ6VuCc3CsrYzkzicygvVWlfA=
github.com/go-co-op/gocron v1.31.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
github.com/go-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs=
github.com/go-enry/go-enry/v2 v2.8.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
github.com/go-enry/go-enry/v2 v2.8.5 h1:jtYXblst2+d9k7ZgEgkv6Q5hKRKPf0qHRjt715BZEX4=
github.com/go-enry/go-enry/v2 v2.8.5/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=

View File

@ -342,7 +342,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
// Published releases list
sess := releasesForActivityStatement(ctx, repoID, fromTime)
sess.OrderBy("release.created_unix DESC")
sess.OrderBy("`release`.created_unix DESC")
stats.PublishedReleases = make([]*repo_model.Release, 0)
if err = sess.Find(&stats.PublishedReleases); err != nil {
return err
@ -350,7 +350,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
// Published releases authors
sess = releasesForActivityStatement(ctx, repoID, fromTime)
if _, err = sess.Select("count(distinct release.publisher_id) as `count`").Table("release").Get(&count); err != nil {
if _, err = sess.Select("count(distinct `release`.publisher_id) as `count`").Table("release").Get(&count); err != nil {
return err
}
stats.PublishedReleaseAuthorCount = count
@ -359,7 +359,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
}
func releasesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
return db.GetEngine(ctx).Where("release.repo_id = ?", repoID).
And("release.is_draft = ?", false).
And("release.created_unix >= ?", fromTime.Unix())
return db.GetEngine(ctx).Where("`release`.repo_id = ?", repoID).
And("`release`.is_draft = ?", false).
And("`release`.created_unix >= ?", fromTime.Unix())
}

View File

@ -321,3 +321,20 @@
created_unix: 946684830
updated_unix: 978307200
is_locked: false
-
id: 20
repo_id: 23
index: 1
poster_id: 2
original_author_id: 0
name: issue for pr
content: content
milestone_id: 0
priority: 0
is_closed: false
is_pull: true
num_comments: 0
created_unix: 978307210
updated_unix: 978307210
is_locked: false

View File

@ -89,3 +89,12 @@
base_branch: main
merge_base: cbff181af4c9c7fee3cf6c106699e07d9a3f54e6
has_merged: false
-
id: 8
type: 0 # gitea pull request
status: 2 # mergable
issue_id: 20
index: 1
head_repo_id: 23
base_repo_id: 23

View File

@ -679,7 +679,7 @@
num_forks: 0
num_issues: 0
num_closed_issues: 0
num_pulls: 0
num_pulls: 1
num_closed_pulls: 0
num_milestones: 0
num_closed_milestones: 0

View File

@ -132,3 +132,41 @@
content: "singular review from org6 and final review for this pr"
updated_unix: 946684831
created_unix: 946684831
-
id: 16
type: 4
reviewer_id: 20
issue_id: 20
content: "review request for user20"
updated_unix: 946684832
created_unix: 946684832
-
id: 17
type: 1
reviewer_id: 20
issue_id: 20
content: "review approved by user20"
updated_unix: 946684833
created_unix: 946684833
-
id: 18
type: 4
reviewer_id: 0
reviewer_team_id: 5
issue_id: 20
content: "review request for team5"
updated_unix: 946684834
created_unix: 946684834
-
id: 19
type: 4
reviewer_id: 15
reviewer_team_id: 0
issue_id: 20
content: "review request for user15"
updated_unix: 946684835
created_unix: 946684835

View File

@ -93,7 +93,7 @@
name: review_team
authorize: 1 # read
num_repos: 1
num_members: 2
num_members: 3
includes_all_repositories: false
can_create_org_repo: false

View File

@ -123,3 +123,9 @@
org_id: 36
team_id: 20
uid: 5
-
id: 22
org_id: 17
team_id: 9
uid: 15

View File

@ -315,6 +315,11 @@ type WhitelistOptions struct {
// This function also performs check if whitelist user and team's IDs have been changed
// to avoid unnecessary whitelist delete and regenerate.
func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
}
if err = repo.LoadOwner(ctx); err != nil {
return fmt.Errorf("LoadOwner: %v", err)
}
@ -445,9 +450,14 @@ func updateTeamWhitelist(ctx context.Context, repo *repo_model.Repository, curre
}
// DeleteProtectedBranch removes ProtectedBranch relation between the user and repository.
func DeleteProtectedBranch(ctx context.Context, repoID, id int64) (err error) {
func DeleteProtectedBranch(ctx context.Context, repo *repo_model.Repository, id int64) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
}
protectedBranch := &ProtectedBranch{
RepoID: repoID,
RepoID: repo.ID,
ID: id,
}

View File

@ -362,14 +362,21 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64)
From("team_user").
Where(builder.Eq{"team_user.uid": reviewRequestedID})
// if the review is approved or rejected, it should not be shown in the review requested list
maxReview := builder.Select("MAX(r.id)").
From("review as r").
Where(builder.In("r.type", []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest})).
GroupBy("r.issue_id, r.reviewer_id, r.reviewer_team_id")
subQuery := builder.Select("review.issue_id").
From("review").
Where(builder.And(
builder.In("review.type", []ReviewType{ReviewTypeRequest, ReviewTypeReject, ReviewTypeApprove}),
builder.Eq{"review.type": ReviewTypeRequest},
builder.Or(
builder.Eq{"review.reviewer_id": reviewRequestedID},
builder.In("review.reviewer_team_id", existInTeamQuery),
),
builder.In("review.id", maxReview),
))
return sess.Where("issue.poster_id <> ?", reviewRequestedID).
And(builder.In("issue.id", subQuery))

View File

@ -403,7 +403,7 @@ func TestCountIssues(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{})
assert.NoError(t, err)
assert.EqualValues(t, 19, count)
assert.EqualValues(t, 20, count)
}
func TestIssueLoadAttributes(t *testing.T) {

View File

@ -15,7 +15,7 @@ import (
type IssueUser struct {
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"INDEX"` // User ID.
IssueID int64
IssueID int64 `xorm:"INDEX"`
IsRead bool
IsMentioned bool
}

View File

@ -534,6 +534,8 @@ var migrations = []Migration{
NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun),
// v276 -> v277
NewMigration("Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors),
// v277 -> v278
NewMigration("Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID),
}
// GetCurrentDBVersion returns the current db version

View File

@ -41,6 +41,8 @@ func migratePullMirrors(x *xorm.Engine) error {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
RemoteAddress string `xorm:"VARCHAR(2048)"`
RepoOwner string
RepoName string
}
sess := x.NewSession()
@ -59,7 +61,9 @@ func migratePullMirrors(x *xorm.Engine) error {
for {
var mirrors []Mirror
if err := sess.Limit(limit, start).Find(&mirrors); err != nil {
if err := sess.Select("mirror.id, mirror.repo_id, mirror.remote_address, repository.owner_name as repo_owner, repository.name as repo_name").
Join("INNER", "repository", "repository.id = mirror.repo_id").
Limit(limit, start).Find(&mirrors); err != nil {
return err
}
@ -69,7 +73,7 @@ func migratePullMirrors(x *xorm.Engine) error {
start += len(mirrors)
for _, m := range mirrors {
remoteAddress, err := getRemoteAddress(sess, m.RepoID, "origin")
remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, "origin")
if err != nil {
return err
}
@ -100,6 +104,8 @@ func migratePushMirrors(x *xorm.Engine) error {
RepoID int64 `xorm:"INDEX"`
RemoteName string
RemoteAddress string `xorm:"VARCHAR(2048)"`
RepoOwner string
RepoName string
}
sess := x.NewSession()
@ -118,7 +124,9 @@ func migratePushMirrors(x *xorm.Engine) error {
for {
var mirrors []PushMirror
if err := sess.Limit(limit, start).Find(&mirrors); err != nil {
if err := sess.Select("push_mirror.id, push_mirror.repo_id, push_mirror.remote_name, push_mirror.remote_address, repository.owner_name as repo_owner, repository.name as repo_name").
Join("INNER", "repository", "repository.id = push_mirror.repo_id").
Limit(limit, start).Find(&mirrors); err != nil {
return err
}
@ -128,7 +136,7 @@ func migratePushMirrors(x *xorm.Engine) error {
start += len(mirrors)
for _, m := range mirrors {
remoteAddress, err := getRemoteAddress(sess, m.RepoID, m.RemoteName)
remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, m.RemoteName)
if err != nil {
return err
}
@ -153,25 +161,12 @@ func migratePushMirrors(x *xorm.Engine) error {
return sess.Commit()
}
func getRemoteAddress(sess *xorm.Session, repoID int64, remoteName string) (string, error) {
var ownerName string
var repoName string
has, err := sess.
Table("repository").
Cols("owner_name", "lower_name").
Where("id=?", repoID).
Get(&ownerName, &repoName)
if err != nil {
return "", err
} else if !has {
return "", fmt.Errorf("repository [%v] not found", repoID)
}
func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(ownerName), strings.ToLower(repoName)+".git")
remoteURL, err := git.GetRemoteAddress(context.Background(), repoPath, remoteName)
if err != nil {
return "", err
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)
}
u, err := giturl.Parse(remoteURL)

View File

@ -0,0 +1,16 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21 //nolint
import (
"xorm.io/xorm"
)
func AddIndexToIssueUserIssueID(x *xorm.Engine) error {
type IssueUser struct {
IssueID int64 `xorm:"INDEX"`
}
return x.Sync(new(IssueUser))
}

View File

@ -47,6 +47,14 @@ func (err ErrUserDoesNotHaveAccessToRepo) Unwrap() error {
return util.ErrPermissionDenied
}
type ErrRepoIsArchived struct {
Repo *Repository
}
func (err ErrRepoIsArchived) Error() string {
return fmt.Sprintf("%s is archived", err.Repo.LogString())
}
var (
reservedRepoNames = []string{".", "..", "-"}
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
@ -660,6 +668,14 @@ func (repo *Repository) GetTrustModel() TrustModelType {
return trustModel
}
// MustNotBeArchived returns ErrRepoIsArchived if the repo is archived
func (repo *Repository) MustNotBeArchived() error {
if repo.IsArchived {
return ErrRepoIsArchived{Repo: repo}
}
return nil
}
// __________ .__ __
// \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__.
// | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | |

View File

@ -101,6 +101,12 @@ type APIRedirect struct{}
// swagger:response string
type APIString string
// APIRepoArchivedError is an error that is raised when an archived repo should be modified
// swagger:response repoArchivedError
type APIRepoArchivedError struct {
APIError
}
// ServerError responds with error message, status is 500
func (ctx *APIContext) ServerError(title string, err error) {
ctx.Error(http.StatusInternalServerError, title, err)

View File

@ -101,7 +101,7 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
},
// find releases without existing repository
genericOrphanCheck("Orphaned Releases without existing repository",
"release", "repository", "release.repo_id=repository.id"),
"release", "repository", "`release`.repo_id=repository.id"),
// find pulls without existing issues
genericOrphanCheck("Orphaned PullRequests without existing issue",
"pull_request", "issue", "pull_request.issue_id=issue.id"),

View File

@ -180,6 +180,21 @@ func searchIssueByID(t *testing.T) {
},
[]int64{11, 6, 5, 3, 2, 1},
},
{
// issue 20 request user 15 and team 5 which user 15 belongs to
// the review request number of issue 20 should be 1
SearchOptions{
ReviewRequestedID: int64Pointer(15),
},
[]int64{12, 20},
},
{
// user 20 approved the issue 20, so return nothing
SearchOptions{
ReviewRequestedID: int64Pointer(20),
},
[]int64{},
},
}
for _, test := range tests {
@ -206,7 +221,7 @@ func searchIssueIsPull(t *testing.T) {
SearchOptions{
IsPull: util.OptionalBoolTrue,
},
[]int64{12, 11, 19, 9, 8, 3, 2},
[]int64{12, 11, 20, 19, 9, 8, 3, 2},
},
}
for _, test := range tests {
@ -227,7 +242,7 @@ func searchIssueIsClosed(t *testing.T) {
SearchOptions{
IsClosed: util.OptionalBoolFalse,
},
[]int64{17, 16, 15, 14, 13, 12, 11, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1},
[]int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1},
},
{
SearchOptions{
@ -293,7 +308,7 @@ func searchIssueByLabelID(t *testing.T) {
SearchOptions{
ExcludedLabelIDs: []int64{1},
},
[]int64{17, 16, 15, 14, 13, 12, 11, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3},
[]int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3},
},
}
for _, test := range tests {
@ -317,7 +332,7 @@ func searchIssueByTime(t *testing.T) {
SearchOptions{
UpdatedAfterUnix: int64Pointer(0),
},
[]int64{17, 16, 15, 14, 13, 12, 11, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1},
[]int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1},
},
}
for _, test := range tests {
@ -338,7 +353,7 @@ func searchIssueWithOrder(t *testing.T) {
SearchOptions{
SortBy: internal.SortByCreatedAsc,
},
[]int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 11, 12, 13, 14, 15, 16, 17},
[]int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 20, 11, 12, 13, 14, 15, 16, 17},
},
}
for _, test := range tests {
@ -393,7 +408,7 @@ func searchIssueWithPaginator(t *testing.T) {
},
},
[]int64{17, 16, 15, 14, 13},
19,
20,
},
}
for _, test := range tests {

View File

@ -15,7 +15,7 @@ import (
// FilesystemClient is used to read LFS data from a filesystem path
type FilesystemClient struct {
lfsdir string
lfsDir string
}
// BatchSize returns the preferred size of batchs to process
@ -25,16 +25,12 @@ func (c *FilesystemClient) BatchSize() int {
func newFilesystemClient(endpoint *url.URL) *FilesystemClient {
path, _ := util.FileURLToPath(endpoint)
lfsdir := filepath.Join(path, "lfs", "objects")
client := &FilesystemClient{lfsdir}
return client
lfsDir := filepath.Join(path, "lfs", "objects")
return &FilesystemClient{lfsDir}
}
func (c *FilesystemClient) objectPath(oid string) string {
return filepath.Join(c.lfsdir, oid[0:2], oid[2:4], oid)
return filepath.Join(c.lfsDir, oid[0:2], oid[2:4], oid)
}
// Download reads the specific LFS object from the target path

View File

@ -8,6 +8,7 @@ import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
@ -17,7 +18,7 @@ import (
"code.gitea.io/gitea/modules/proxy"
)
const batchSize = 20
const httpBatchSize = 20
// HTTPClient is used to communicate with the LFS server
// https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
@ -29,7 +30,7 @@ type HTTPClient struct {
// BatchSize returns the preferred size of batchs to process
func (c *HTTPClient) BatchSize() int {
return batchSize
return httpBatchSize
}
func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient {
@ -43,28 +44,25 @@ func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient
Transport: httpTransport,
}
client := &HTTPClient{
client: hc,
endpoint: strings.TrimSuffix(endpoint.String(), "/"),
transfers: make(map[string]TransferAdapter),
}
basic := &BasicTransferAdapter{hc}
client.transfers[basic.Name()] = basic
client := &HTTPClient{
client: hc,
endpoint: strings.TrimSuffix(endpoint.String(), "/"),
transfers: map[string]TransferAdapter{
basic.Name(): basic,
},
}
return client
}
func (c *HTTPClient) transferNames() []string {
keys := make([]string, len(c.transfers))
i := 0
for k := range c.transfers {
keys[i] = k
i++
}
return keys
}
@ -74,7 +72,6 @@ func (c *HTTPClient) batch(ctx context.Context, operation string, objects []Poin
url := fmt.Sprintf("%s/objects/batch", c.endpoint)
request := &BatchRequest{operation, c.transferNames(), nil, objects}
payload := new(bytes.Buffer)
err := json.NewEncoder(payload).Encode(request)
if err != nil {
@ -82,32 +79,17 @@ func (c *HTTPClient) batch(ctx context.Context, operation string, objects []Poin
return nil, err
}
log.Trace("Calling: %s", url)
req, err := http.NewRequestWithContext(ctx, "POST", url, payload)
req, err := createRequest(ctx, http.MethodPost, url, map[string]string{"Content-Type": MediaType}, payload)
if err != nil {
log.Error("Error creating request: %v", err)
return nil, err
}
req.Header.Set("Content-type", MediaType)
req.Header.Set("Accept", MediaType)
res, err := c.client.Do(req)
res, err := performRequest(ctx, c.client, req)
if err != nil {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
log.Error("Error while processing request: %v", err)
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Unexpected server response: %s", res.Status)
}
var response BatchResponse
err = json.NewDecoder(res.Body).Decode(&response)
if err != nil {
@ -177,7 +159,7 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
link, ok := object.Actions["upload"]
if !ok {
log.Debug("%+v", object)
return errors.New("Missing action 'upload'")
return errors.New("missing action 'upload'")
}
content, err := uc(object.Pointer, nil)
@ -187,8 +169,6 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
err = transferAdapter.Upload(ctx, link, object.Pointer, content)
content.Close()
if err != nil {
return err
}
@ -203,7 +183,7 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
link, ok := object.Actions["download"]
if !ok {
log.Debug("%+v", object)
return errors.New("Missing action 'download'")
return errors.New("missing action 'download'")
}
content, err := transferAdapter.Download(ctx, link)
@ -219,3 +199,59 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
return nil
}
// createRequest creates a new request, and sets the headers.
func createRequest(ctx context.Context, method, url string, headers map[string]string, body io.Reader) (*http.Request, error) {
log.Trace("createRequest: %s", url)
req, err := http.NewRequestWithContext(ctx, method, url, body)
if err != nil {
log.Error("Error creating request: %v", err)
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
req.Header.Set("Accept", MediaType)
return req, nil
}
// performRequest sends a request, optionally performs a callback on the request and returns the response.
// If the status code is 200, the response is returned, and it will contain a non-nil Body.
// Otherwise, it will return an error, and the Body will be nil or closed.
func performRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
log.Trace("performRequest: %s", req.URL)
res, err := client.Do(req)
if err != nil {
select {
case <-ctx.Done():
return res, ctx.Err()
default:
}
log.Error("Error while processing request: %v", err)
return res, err
}
if res.StatusCode != http.StatusOK {
defer res.Body.Close()
return res, handleErrorResponse(res)
}
return res, nil
}
func handleErrorResponse(resp *http.Response) error {
var er ErrorResponse
err := json.NewDecoder(resp.Body).Decode(&er)
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
log.Error("Error decoding json: %v", err)
return err
}
log.Trace("ErrorResponse: %v", er)
return errors.New(er.Message)
}

View File

@ -177,7 +177,7 @@ func TestHTTPClientDownload(t *testing.T) {
// case 0
{
endpoint: "https://status-not-ok.io",
expectederror: "Unexpected server response: ",
expectederror: io.ErrUnexpectedEOF.Error(),
},
// case 1
{
@ -207,7 +207,7 @@ func TestHTTPClientDownload(t *testing.T) {
// case 6
{
endpoint: "https://empty-actions-map.io",
expectederror: "Missing action 'download'",
expectederror: "missing action 'download'",
},
// case 7
{
@ -217,27 +217,28 @@ func TestHTTPClientDownload(t *testing.T) {
// case 8
{
endpoint: "https://upload-actions-map.io",
expectederror: "Missing action 'download'",
expectederror: "missing action 'download'",
},
// case 9
{
endpoint: "https://verify-actions-map.io",
expectederror: "Missing action 'download'",
expectederror: "missing action 'download'",
},
// case 10
{
endpoint: "https://unknown-actions-map.io",
expectederror: "Missing action 'download'",
expectederror: "missing action 'download'",
},
}
for n, c := range cases {
client := &HTTPClient{
client: hc,
endpoint: c.endpoint,
transfers: make(map[string]TransferAdapter),
client: hc,
endpoint: c.endpoint,
transfers: map[string]TransferAdapter{
"dummy": dummy,
},
}
client.transfers["dummy"] = dummy
err := client.Download(context.Background(), []Pointer{p}, func(p Pointer, content io.ReadCloser, objectError error) error {
if objectError != nil {
@ -284,7 +285,7 @@ func TestHTTPClientUpload(t *testing.T) {
// case 0
{
endpoint: "https://status-not-ok.io",
expectederror: "Unexpected server response: ",
expectederror: io.ErrUnexpectedEOF.Error(),
},
// case 1
{
@ -319,7 +320,7 @@ func TestHTTPClientUpload(t *testing.T) {
// case 7
{
endpoint: "https://download-actions-map.io",
expectederror: "Missing action 'upload'",
expectederror: "missing action 'upload'",
},
// case 8
{
@ -329,22 +330,23 @@ func TestHTTPClientUpload(t *testing.T) {
// case 9
{
endpoint: "https://verify-actions-map.io",
expectederror: "Missing action 'upload'",
expectederror: "missing action 'upload'",
},
// case 10
{
endpoint: "https://unknown-actions-map.io",
expectederror: "Missing action 'upload'",
expectederror: "missing action 'upload'",
},
}
for n, c := range cases {
client := &HTTPClient{
client: hc,
endpoint: c.endpoint,
transfers: make(map[string]TransferAdapter),
client: hc,
endpoint: c.endpoint,
transfers: map[string]TransferAdapter{
"dummy": dummy,
},
}
client.transfers["dummy"] = dummy
err := client.Upload(context.Background(), []Pointer{p}, func(p Pointer, objectError error) (io.ReadCloser, error) {
return io.NopCloser(new(bytes.Buffer)), objectError

View File

@ -29,10 +29,10 @@ const (
var (
// ErrMissingPrefix occurs if the content lacks the LFS prefix
ErrMissingPrefix = errors.New("Content lacks the LFS prefix")
ErrMissingPrefix = errors.New("content lacks the LFS prefix")
// ErrInvalidStructure occurs if the content has an invalid structure
ErrInvalidStructure = errors.New("Content has an invalid structure")
ErrInvalidStructure = errors.New("content has an invalid structure")
// ErrInvalidOIDFormat occurs if the oid has an invalid format
ErrInvalidOIDFormat = errors.New("OID has an invalid format")

View File

@ -6,8 +6,6 @@ package lfs
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
@ -15,7 +13,7 @@ import (
"code.gitea.io/gitea/modules/log"
)
// TransferAdapter represents an adapter for downloading/uploading LFS objects
// TransferAdapter represents an adapter for downloading/uploading LFS objects.
type TransferAdapter interface {
Name() string
Download(ctx context.Context, l *Link) (io.ReadCloser, error)
@ -23,41 +21,48 @@ type TransferAdapter interface {
Verify(ctx context.Context, l *Link, p Pointer) error
}
// BasicTransferAdapter implements the "basic" adapter
// BasicTransferAdapter implements the "basic" adapter.
type BasicTransferAdapter struct {
client *http.Client
}
// Name returns the name of the adapter
// Name returns the name of the adapter.
func (a *BasicTransferAdapter) Name() string {
return "basic"
}
// Download reads the download location and downloads the data
// Download reads the download location and downloads the data.
func (a *BasicTransferAdapter) Download(ctx context.Context, l *Link) (io.ReadCloser, error) {
resp, err := a.performRequest(ctx, "GET", l, nil, nil)
req, err := createRequest(ctx, http.MethodGet, l.Href, l.Header, nil)
if err != nil {
return nil, err
}
resp, err := performRequest(ctx, a.client, req)
if err != nil {
return nil, err
}
return resp.Body, nil
}
// Upload sends the content to the LFS server
// Upload sends the content to the LFS server.
func (a *BasicTransferAdapter) Upload(ctx context.Context, l *Link, p Pointer, r io.Reader) error {
_, err := a.performRequest(ctx, "PUT", l, r, func(req *http.Request) {
if len(req.Header.Get("Content-Type")) == 0 {
req.Header.Set("Content-Type", "application/octet-stream")
}
if req.Header.Get("Transfer-Encoding") == "chunked" {
req.TransferEncoding = []string{"chunked"}
}
req.ContentLength = p.Size
})
req, err := createRequest(ctx, http.MethodPut, l.Href, l.Header, r)
if err != nil {
return err
}
if req.Header.Get("Content-Type") == "" {
req.Header.Set("Content-Type", "application/octet-stream")
}
if req.Header.Get("Transfer-Encoding") == "chunked" {
req.TransferEncoding = []string{"chunked"}
}
req.ContentLength = p.Size
res, err := performRequest(ctx, a.client, req)
if err != nil {
return err
}
defer res.Body.Close()
return nil
}
@ -69,66 +74,15 @@ func (a *BasicTransferAdapter) Verify(ctx context.Context, l *Link, p Pointer) e
return err
}
_, err = a.performRequest(ctx, "POST", l, bytes.NewReader(b), func(req *http.Request) {
req.Header.Set("Content-Type", MediaType)
})
req, err := createRequest(ctx, http.MethodPost, l.Href, l.Header, bytes.NewReader(b))
if err != nil {
return err
}
req.Header.Set("Content-Type", MediaType)
res, err := performRequest(ctx, a.client, req)
if err != nil {
return err
}
defer res.Body.Close()
return nil
}
func (a *BasicTransferAdapter) performRequest(ctx context.Context, method string, l *Link, body io.Reader, callback func(*http.Request)) (*http.Response, error) {
log.Trace("Calling: %s %s", method, l.Href)
req, err := http.NewRequestWithContext(ctx, method, l.Href, body)
if err != nil {
log.Error("Error creating request: %v", err)
return nil, err
}
for key, value := range l.Header {
req.Header.Set(key, value)
}
req.Header.Set("Accept", MediaType)
if callback != nil {
callback(req)
}
res, err := a.client.Do(req)
if err != nil {
select {
case <-ctx.Done():
return res, ctx.Err()
default:
}
log.Error("Error while processing request: %v", err)
return res, err
}
if res.StatusCode != http.StatusOK {
return res, handleErrorResponse(res)
}
return res, nil
}
func handleErrorResponse(resp *http.Response) error {
defer resp.Body.Close()
er, err := decodeResponseError(resp.Body)
if err != nil {
return fmt.Errorf("Request failed with status %s", resp.Status)
}
log.Trace("ErrorRespone: %v", er)
return errors.New(er.Message)
}
func decodeResponseError(r io.Reader) (ErrorResponse, error) {
var er ErrorResponse
err := json.NewDecoder(r).Decode(&er)
if err != nil {
log.Error("Error decoding json: %v", err)
}
return er, err
}

View File

@ -81,7 +81,6 @@ var (
StaticCacheTime time.Duration
EnableGzip bool
LandingPageURL LandingPage
LandingPageCustom string
UnixSocketPermission uint32
EnablePprof bool
PprofDataPath string
@ -103,7 +102,6 @@ var (
StaticURLPrefix string
AbsoluteAssetURL string
HasRobotsTxt bool
ManifestData string
)

View File

@ -3,6 +3,8 @@
package structs
import "time"
// CreatePushMirrorOption represents need information to create a push mirror of a repository.
type CreatePushMirrorOption struct {
RemoteAddress string `json:"remote_address"`
@ -15,12 +17,14 @@ type CreatePushMirrorOption struct {
// PushMirror represents information of a push mirror
// swagger:model
type PushMirror struct {
RepoName string `json:"repo_name"`
RemoteName string `json:"remote_name"`
RemoteAddress string `json:"remote_address"`
CreatedUnix string `json:"created"`
LastUpdateUnix string `json:"last_update"`
LastError string `json:"last_error"`
Interval string `json:"interval"`
SyncOnCommit bool `json:"sync_on_commit"`
RepoName string `json:"repo_name"`
RemoteName string `json:"remote_name"`
RemoteAddress string `json:"remote_address"`
// swagger:strfmt date-time
CreatedUnix time.Time `json:"created"`
// swagger:strfmt date-time
LastUpdateUnix *time.Time `json:"last_update"`
LastError string `json:"last_error"`
Interval string `json:"interval"`
SyncOnCommit bool `json:"sync_on_commit"`
}

View File

@ -225,6 +225,7 @@ func isOSWindows() bool {
var driveLetterRegexp = regexp.MustCompile("/[A-Za-z]:/")
// FileURLToPath extracts the path information from a file://... url.
// It returns an error only if the URL is not a file URL.
func FileURLToPath(u *url.URL) (string, error) {
if u.Scheme != "file" {
return "", errors.New("URL scheme is not 'file': " + u.String())

View File

@ -47,8 +47,6 @@ func GetContextData(c context.Context) ContextData {
func CommonTemplateContextData() ContextData {
return ContextData{
"IsLandingPageHome": setting.LandingPageURL == setting.LandingPageHome,
"IsLandingPageExplore": setting.LandingPageURL == setting.LandingPageExplore,
"IsLandingPageOrganizations": setting.LandingPageURL == setting.LandingPageOrganizations,
"ShowRegistrationButton": setting.Service.ShowRegistrationButton,

View File

@ -180,6 +180,7 @@ network_error=ネットワークエラー
[startpage]
app_desc=自分で立てる、超簡単 Git サービス
install=簡単インストール
install_desc=シンプルに、プラットフォームに応じて<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.com/installation/install-from-binary">バイナリを実行</a>したり、<a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>で動かしたり、<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.com/installation/install-from-package">パッケージ</a>を使うだけ。
platform=クロスプラットフォーム
platform_desc=Giteaは<a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a>でコンパイルできる環境ならどこでも動きます: Windows、macOS、Linux、ARM等々、好きなものを選んでください!
lightweight=軽量
@ -377,6 +378,7 @@ email_not_associate=このメールアドレスは、どのアカウントにも
send_reset_mail=アカウント回復メールを送信
reset_password=アカウントの回復
invalid_code=確認コードが無効か期限切れです。
invalid_code_forgot_password=確認コードは無効または期限切れです。 新しいセッションを開始するには<a href="%s">ここ</a>をクリックしてください。
invalid_password=アカウントの作成に使用されたパスワードと一致しません。
reset_password_helper=アカウント回復
reset_password_wrong_user=あなたは %s でサインイン中ですが、アカウント回復のリンクは %s のものです。
@ -678,6 +680,7 @@ choose_new_avatar=新しいアバターを選択
update_avatar=アバターを更新
delete_current_avatar=現在のアバターを削除
uploaded_avatar_not_a_image=アップロードしたファイルは画像ファイルではありません。
uploaded_avatar_is_too_big=アップロードされたファイルサイズ(%d KiB) が最大サイズ(%d KiB) を超えています。
update_avatar_success=アバターを更新しました。
update_user_avatar_success=ユーザーのアバターを更新しました。
@ -967,6 +970,7 @@ trust_model_helper_collaborator_committer=共同作業者+コミッター: 共
trust_model_helper_default=デフォルト: このシステムのデフォルトのトラストモデルを使用します
create_repo=リポジトリを作成
default_branch=デフォルトブランチ
default_branch_label=デフォルト
default_branch_helper=デフォルトブランチはプルリクエストとコードコミットのベースブランチとなります。
mirror_prune=Prune
mirror_prune_desc=不要になった古いリモートトラッキング参照を削除
@ -1466,9 +1470,18 @@ issues.ref_reopening_from=`<a href="%[3]s">が%[4]s、プルリクエストが
issues.ref_closed_from=`<a href="%[3]s">が%[4]s、このイシューをクローズ</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_reopened_from=`<a href="%[3]s">が%[4]s、このイシューを再オープン</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_from=` %[1]s にて`
issues.author=著作者
issues.author=作成者
issues.author_helper=このユーザーは作成者です。
issues.role.owner=オーナー
issues.role.owner_helper=このユーザーはこのリポジトリの所有者です。
issues.role.member=メンバー
issues.role.member_helper=このユーザーはこのリポジトリを所有している組織のメンバーです。
issues.role.collaborator=共同作業者
issues.role.collaborator_helper=このユーザーはリポジトリ上で共同作業するように招待されています。
issues.role.first_time_contributor=初めての貢献者
issues.role.first_time_contributor_helper=これは、このユーザーのリポジトリへの最初の貢献です。
issues.role.contributor=貢献者
issues.role.contributor_helper=このユーザーは以前にリポジトリにコミットしています。
issues.re_request_review=レビューを再依頼
issues.is_stale=このレビューのあと、このPRに変更がありました
issues.remove_request_review=レビュー依頼を取り消し
@ -1727,6 +1740,7 @@ pulls.rebase_conflict_summary=エラーメッセージ
pulls.unrelated_histories=マージ失敗: マージHEADとベースには共通する履歴がありません。 ヒント: 別のストラテジーを試してみてください
pulls.merge_out_of_date=マージ失敗: マージの生成中にベースが更新されました。 ヒント: もう一度試してみてください
pulls.head_out_of_date=マージ失敗: マージの生成中に head が更新されました。 ヒント: もう一度試してみてください
pulls.has_merged=失敗: プルリクエストはマージされていました。再度マージしたり、ターゲットブランチを変更することはできません。
pulls.push_rejected=マージ失敗: プッシュは拒否されました。 このリポジトリのGitフックを見直してください。
pulls.push_rejected_summary=拒否メッセージ全体:
pulls.push_rejected_no_message=マージ失敗: プッシュは拒否され、リモートからのメッセージはありません。<br>このリポジトリのGitフックを見直してください
@ -1792,6 +1806,8 @@ milestones.edit_success=マイルストーン "%s" を更新しました。
milestones.deletion=マイルストーンの削除
milestones.deletion_desc=マイルストーンを削除すると、関連するすべてのイシューから除去されます。 続行しますか?
milestones.deletion_success=マイルストーンを削除しました。
milestones.filter_sort.earliest_due_data=期日が早い順
milestones.filter_sort.latest_due_date=期日が遅い順
milestones.filter_sort.least_complete=消化率の低い順
milestones.filter_sort.most_complete=消化率の高い順
milestones.filter_sort.most_issues=イシューの多い順
@ -2289,6 +2305,7 @@ settings.tags.protection.allowed.teams=許可するチーム
settings.tags.protection.allowed.noone=なし
settings.tags.protection.create=タグを保護
settings.tags.protection.none=タグは保護されていません。
settings.tags.protection.pattern.description=ひとつのタグ名か、複数のタグにマッチするglobパターンまたは正規表現を使用できます。 詳しくは<a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/protected-tags">タグの保護ガイド</a> をご覧ください。
settings.bot_token=Botトークン
settings.chat_id=チャットID
settings.matrix.homeserver_url=ホームサーバー URL
@ -2680,6 +2697,7 @@ dashboard.reinit_missing_repos=レコードが存在するが見当たらない
dashboard.sync_external_users=外部ユーザーデータの同期
dashboard.cleanup_hook_task_table=hook_taskテーブルのクリーンアップ
dashboard.cleanup_packages=期限切れパッケージのクリーンアップ
dashboard.cleanup_actions=Actionsの期限切れのログとアーティファクトのクリーンアップ
dashboard.server_uptime=サーバーの稼働時間
dashboard.current_goroutine=現在のGoroutine数
dashboard.current_memory_usage=現在のメモリ使用量
@ -2717,6 +2735,7 @@ dashboard.gc_lfs=LFSメタオブジェクトのガベージコレクション
dashboard.stop_zombie_tasks=ゾンビタスクを停止
dashboard.stop_endless_tasks=終わらないタスクを停止
dashboard.cancel_abandoned_jobs=放置されたままのジョブをキャンセル
dashboard.start_schedule_tasks=スケジュールタスクを開始
users.user_manage_panel=ユーザーアカウント管理
users.new_account=ユーザーアカウントを作成
@ -2725,6 +2744,9 @@ users.full_name=フルネーム
users.activated=アクティベート済み
users.admin=管理者
users.restricted=制限あり
users.reserved=予約済み
users.bot=Bot
users.remote=リモート
users.2fa=2FA
users.repos=リポジトリ
users.created=作成日
@ -2771,6 +2793,7 @@ users.list_status_filter.is_prohibit_login=ログインを禁止
users.list_status_filter.not_prohibit_login=ログインを許可
users.list_status_filter.is_2fa_enabled=2要素認証有効
users.list_status_filter.not_2fa_enabled=2要素認証無効
users.details=ユーザーの詳細
emails.email_manage_panel=ユーザーメールアドレスの管理
emails.primary=プライマリー
@ -2806,6 +2829,7 @@ repos.size=サイズ
packages.package_manage_panel=パッケージ管理
packages.total_size=合計サイズ: %s
packages.unreferenced_size=非参照サイズ: %s
packages.cleanup=期限切れデータを掃除する
packages.owner=オーナー
packages.creator=作成者
packages.name=名前
@ -2816,10 +2840,12 @@ packages.size=サイズ
packages.published=配布
defaulthooks=デフォルトWebhook
defaulthooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義されたWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくは<a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">Webhooksガイド</a>をご覧下さい。
defaulthooks.add_webhook=デフォルトWebhookの追加
defaulthooks.update_webhook=デフォルトWebhookの更新
systemhooks=システムWebhook
systemhooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義したWebhookはシステム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくは<a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">Webhooksガイド</a>をご覧下さい。
systemhooks.add_webhook=システムWebhookを追加
systemhooks.update_webhook=システムWebhookを更新
@ -2912,6 +2938,7 @@ auths.sspi_default_language=ユーザーのデフォルトの言語
auths.sspi_default_language_helper=SSPI認証処理によって自動的に作成されるユーザーのデフォルトの言語です。 言語を自動検出する方が良い場合は空のままにしてください。
auths.tips=ヒント
auths.tips.oauth2.general=OAuth2認証
auths.tips.oauth2.general.tip=新しいOAuth2認証を登録するときは、コールバック/リダイレクトURLは以下になります:
auths.tip.oauth2_provider=OAuth2プロバイダー
auths.tip.bitbucket=新しいOAuthコンシューマーを https://bitbucket.org/account/user/<あなたのユーザー名>/oauth-consumers/new から登録し、"アカウント" に "読み取り" 権限を追加してください。
auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンスのメニュー "Settings -> Security -> OAuth 2.0 client" から登録してください。
@ -2923,6 +2950,7 @@ auths.tip.google_plus=OAuth2クライアント資格情報を、Google APIコン
auths.tip.openid_connect=OpenID Connect DiscoveryのURL (<server>/.well-known/openid-configuration) をエンドポイントとして指定してください
auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。
auths.tip.discord=新しいアプリケーションを https://discordapp.com/developers/applications/me から登録してください。
auths.tip.gitea=新しいOAuthアプリケーションを登録してください。 利用ガイドは https://docs.gitea.com/development/oauth2-provider にあります
auths.tip.yandex=`https://oauth.yandex.com/client/new で新しいアプリケーションを作成してください。 "Yandex.Passport API" セクションで次の項目を許可します: "Access to email address"、"Access to user avatar"、"Access to username, first name and surname, gender"`
auths.tip.mastodon=認証したいMastodonインスタンスのカスタムURLを入力してください (入力しない場合はデフォルトのURLを使用します)
auths.edit=認証ソースの編集
@ -2952,6 +2980,7 @@ config.disable_router_log=ルーターのログが無効
config.run_user=実行ユーザー名
config.run_mode=実行モード
config.git_version=Gitバージョン
config.app_data_path=Appデータパス
config.repo_root_path=リポジトリのルートパス
config.lfs_root_path=LFSルートパス
config.log_file_root_path=ログの保存先パス

1108
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,16 +4,16 @@
"node": ">= 18.0.0"
},
"dependencies": {
"@citation-js/core": "0.6.8",
"@citation-js/plugin-bibtex": "0.6.8",
"@citation-js/plugin-csl": "0.6.8",
"@citation-js/core": "0.6.9",
"@citation-js/plugin-bibtex": "0.6.9",
"@citation-js/plugin-csl": "0.6.9",
"@citation-js/plugin-software-formats": "0.6.1",
"@claviska/jquery-minicolors": "2.3.6",
"@github/markdown-toolbar-element": "2.2.0",
"@github/markdown-toolbar-element": "2.2.1",
"@github/relative-time-element": "4.3.0",
"@github/text-expander-element": "2.5.0",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.7.0",
"@primer/octicons": "19.8.0",
"@webcomponents/custom-elements": "1.6.0",
"add-asset-webpack-plugin": "2.0.1",
"ansi_up": "6.0.2",
@ -37,7 +37,7 @@
"pdfobject": "2.2.12",
"pretty-ms": "8.0.0",
"sortablejs": "1.15.0",
"swagger-ui-dist": "5.7.1",
"swagger-ui-dist": "5.7.2",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
@ -54,12 +54,11 @@
},
"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
"@playwright/test": "1.38.0",
"@playwright/test": "1.38.1",
"@stoplight/spectral-cli": "6.11.0",
"@vitejs/plugin-vue": "4.3.4",
"eslint": "8.49.0",
"eslint-plugin-array-func": "4.0.0",
"eslint-plugin-custom-elements": "0.0.8",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
@ -69,18 +68,18 @@
"eslint-plugin-unicorn": "48.0.1",
"eslint-plugin-vue": "9.17.0",
"eslint-plugin-vue-scoped-css": "2.5.0",
"eslint-plugin-wc": "1.5.0",
"eslint-plugin-wc": "2.0.3",
"jsdom": "22.1.0",
"markdownlint-cli": "0.35.0",
"markdownlint-cli": "0.37.0",
"postcss-html": "1.5.0",
"stylelint": "15.10.3",
"stylelint-declaration-block-no-ignored-properties": "2.7.0",
"stylelint-declaration-strict-value": "1.9.2",
"stylelint-stylistic": "0.4.3",
"svgo": "3.0.2",
"updates": "15.0.0",
"updates": "15.0.2",
"vite-string-plugin": "1.1.2",
"vitest": "0.34.4"
"vitest": "0.34.5"
},
"browserslist": [
"defaults",

18
poetry.lock generated
View File

@ -42,13 +42,13 @@ six = ">=1.13.0"
[[package]]
name = "djlint"
version = "1.32.1"
version = "1.34.0"
description = "HTML Template Linter and Formatter"
optional = false
python-versions = ">=3.8.0,<4.0.0"
files = [
{file = "djlint-1.32.1-py3-none-any.whl", hash = "sha256:8aaec6776376cfd41f3e742ed9f5e3c46dc7c6cd7646abf9e99860fb1ec9f19a"},
{file = "djlint-1.32.1.tar.gz", hash = "sha256:c1e2141acf1547d244af7ef8abd15fbbae2abcc7a03e2bf31f8a491de69a6c72"},
{file = "djlint-1.34.0-py3-none-any.whl", hash = "sha256:bdc26cc607dee8b46e262654eb0fbac7862c34d68172c8adc25a0b56fc7d8173"},
{file = "djlint-1.34.0.tar.gz", hash = "sha256:60b4f4ca99fd83106603bdd466f35314fda33776f3a6e70ea9d674da9d0ad053"},
]
[package.dependencies]
@ -149,7 +149,6 @@ files = [
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
@ -157,15 +156,8 @@ files = [
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
@ -182,7 +174,6 @@ files = [
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
@ -190,7 +181,6 @@ files = [
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
@ -356,4 +346,4 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"]
[metadata]
lock-version = "2.0"
python-versions = "^3.8"
content-hash = "d2c60da5736ff899675088560244f086265a777e8057eed9e347367373e1937c"
content-hash = "a2e2a44801f0da2cc5cc1d1a3f707853f51a4346fef725f98c67a074dcb223d6"

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-filter-remove" width="16" height="16" aria-hidden="true"><path d="M14.384 4.57a.752.752 0 0 0 1.061 0 .752.752 0 0 0 0-1.061l-.884-.884.883-.884A.75.75 0 0 0 14.384.68l-.884.884-.884-.884a.75.75 0 0 0-1.06 1.061l.883.884-.883.884a.75.75 0 0 0 1.06 1.061l.884-.884.884.884ZM.75 3a.75.75 0 0 0 0 1.5H9A.75.75 0 0 0 9 3H.75ZM3 7.75A.75.75 0 0 1 3.75 7h8.5a.75.75 0 0 1 0 1.5h-8.5A.75.75 0 0 1 3 7.75Zm3 4a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"/></svg>

After

Width:  |  Height:  |  Size: 560 B

View File

@ -8,7 +8,7 @@ authors = []
python = "^3.8"
[tool.poetry.group.dev.dependencies]
djlint = "1.32.1"
djlint = "1.34.0"
yamllint = "1.32.0"
[tool.djlint]

View File

@ -675,7 +675,7 @@ func mustEnableWiki(ctx *context.APIContext) {
func mustNotBeArchived(ctx *context.APIContext) {
if ctx.Repo.Repository.IsArchived {
ctx.NotFound()
ctx.Error(http.StatusLocked, "RepoArchived", fmt.Errorf("%s is archived", ctx.Repo.Repository.LogString()))
return
}
}
@ -1108,23 +1108,23 @@ func Routes() *web.Route {
m.Group("/branches", func() {
m.Get("", repo.ListBranches)
m.Get("/*", repo.GetBranch)
m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), repo.DeleteBranch)
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteBranch)
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
m.Group("/branch_protections", func() {
m.Get("", repo.ListBranchProtections)
m.Post("", bind(api.CreateBranchProtectionOption{}), repo.CreateBranchProtection)
m.Post("", bind(api.CreateBranchProtectionOption{}), mustNotBeArchived, repo.CreateBranchProtection)
m.Group("/{name}", func() {
m.Get("", repo.GetBranchProtection)
m.Patch("", bind(api.EditBranchProtectionOption{}), repo.EditBranchProtection)
m.Patch("", bind(api.EditBranchProtectionOption{}), mustNotBeArchived, repo.EditBranchProtection)
m.Delete("", repo.DeleteBranchProtection)
})
}, reqToken(), reqAdmin())
m.Group("/tags", func() {
m.Get("", repo.ListTags)
m.Get("/*", repo.GetTag)
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag)
m.Delete("/*", reqToken(), repo.DeleteTag)
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateTagOption{}), repo.CreateTag)
m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteTag)
}, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true))
m.Group("/keys", func() {
m.Combo("").Get(repo.ListDeployKeys).
@ -1245,15 +1245,15 @@ func Routes() *web.Route {
m.Get("/tags/{sha}", repo.GetAnnotatedTag)
m.Get("/notes/{sha}", repo.GetNote)
}, context.ReferencesGitRepo(true), reqRepoReader(unit.TypeCode))
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch)
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), mustNotBeArchived, repo.ApplyDiffPatch)
m.Group("/contents", func() {
m.Get("", repo.GetContentsList)
m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, repo.ChangeFiles)
m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.ChangeFiles)
m.Get("/*", repo.GetContents)
m.Group("/*", func() {
m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, repo.CreateFile)
m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, repo.UpdateFile)
m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, repo.DeleteFile)
m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.CreateFile)
m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.UpdateFile)
m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.DeleteFile)
}, reqToken())
}, reqRepoReader(unit.TypeCode))
m.Get("/signing-key.gpg", misc.SigningKey)

View File

@ -248,7 +248,7 @@ func CreateTeam(ctx *context.APIContext) {
return
}
apiTeam, err := convert.ToTeam(ctx, team)
apiTeam, err := convert.ToTeam(ctx, team, true)
if err != nil {
ctx.InternalServerError(err)
return

View File

@ -117,17 +117,13 @@ func DeleteBranch(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
if ctx.Repo.Repository.IsEmpty {
ctx.Error(http.StatusNotFound, "", "Git Repository is empty.")
return
}
if ctx.Repo.Repository.IsArchived {
ctx.Error(http.StatusForbidden, "", "Git Repository is archived.")
return
}
if ctx.Repo.Repository.IsMirror {
ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.")
return
@ -157,10 +153,6 @@ func DeleteBranch(ctx *context.APIContext) {
}
}
if ctx.Repo.Repository.IsArchived {
ctx.Error(http.StatusForbidden, "IsArchived", fmt.Errorf("can not delete branch of an archived repository"))
return
}
if ctx.Repo.Repository.IsMirror {
ctx.Error(http.StatusForbidden, "IsMirrored", fmt.Errorf("can not delete branch of an mirror repository"))
return
@ -216,17 +208,14 @@ func CreateBranch(ctx *context.APIContext) {
// description: The old branch does not exist.
// "409":
// description: The branch with the same name already exists.
// "423":
// "$ref": "#/responses/repoArchivedError"
if ctx.Repo.Repository.IsEmpty {
ctx.Error(http.StatusNotFound, "", "Git Repository is empty.")
return
}
if ctx.Repo.Repository.IsArchived {
ctx.Error(http.StatusForbidden, "", "Git Repository is archived.")
return
}
if ctx.Repo.Repository.IsMirror {
ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.")
return
@ -519,6 +508,8 @@ func CreateBranchProtection(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateBranchProtectionOption)
repo := ctx.Repo.Repository
@ -727,6 +718,8 @@ func EditBranchProtection(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.EditBranchProtectionOption)
repo := ctx.Repo.Repository
bpName := ctx.Params(":name")
@ -1004,7 +997,7 @@ func DeleteBranchProtection(ctx *context.APIContext) {
return
}
if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository.ID, bp.ID); err != nil {
if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository, bp.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "DeleteProtectedBranch", err)
return
}

View File

@ -450,6 +450,8 @@ func ChangeFiles(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
apiOpts := web.GetForm(ctx).(*api.ChangeFilesOptions)
@ -550,6 +552,8 @@ func CreateFile(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
apiOpts := web.GetForm(ctx).(*api.CreateFileOptions)
@ -646,6 +650,8 @@ func UpdateFile(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
apiOpts := web.GetForm(ctx).(*api.UpdateFileOptions)
if ctx.Repo.Repository.IsEmpty {
ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty"))
@ -806,6 +812,8 @@ func DeleteFile(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
apiOpts := web.GetForm(ctx).(*api.DeleteFileOptions)
if !canWriteFiles(ctx, apiOpts.BranchName) {

View File

@ -631,6 +631,8 @@ func CreateIssue(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateIssueOption)
var deadlineUnix timeutil.TimeStamp
if form.Deadline != nil && ctx.Repo.CanWrite(unit.TypeIssues) {

View File

@ -153,6 +153,8 @@ func CreateIssueAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
issue := getIssueFromContext(ctx)
if issue == nil {
@ -238,6 +240,8 @@ func EditIssueAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/Attachment"
// "404":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
attachment := getIssueAttachmentSafeWrite(ctx)
if attachment == nil {
@ -292,6 +296,8 @@ func DeleteIssueAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
attachment := getIssueAttachmentSafeWrite(ctx)
if attachment == nil {

View File

@ -358,6 +358,8 @@ func CreateIssueComment(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateIssueCommentOption)
issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
@ -486,7 +488,8 @@ func EditIssueComment(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.EditIssueCommentOption)
editIssueComment(ctx, *form)
}

View File

@ -156,6 +156,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
// Check if comment exists and load comment
comment := getIssueCommentSafe(ctx)
@ -245,7 +247,8 @@ func EditIssueCommentAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/Attachment"
// "404":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
attach := getIssueCommentAttachmentSafeWrite(ctx)
if attach == nil {
return
@ -297,7 +300,8 @@ func DeleteIssueCommentAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
attach := getIssueCommentAttachmentSafeWrite(ctx)
if attach == nil {
return

View File

@ -187,6 +187,8 @@ func CreateIssueDependency(ctx *context.APIContext) {
// "$ref": "#/responses/Issue"
// "404":
// description: the issue does not exist
// "423":
// "$ref": "#/responses/repoArchivedError"
// We want to make <:index> depend on <Form>, i.e. <:index> is the target
target := getParamsIssue(ctx)
@ -246,6 +248,8 @@ func RemoveIssueDependency(ctx *context.APIContext) {
// "$ref": "#/responses/Issue"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
// We want to make <:index> depend on <Form>, i.e. <:index> is the target
target := getParamsIssue(ctx)

View File

@ -47,6 +47,8 @@ func ApplyDiffPatch(ctx *context.APIContext) {
// "$ref": "#/responses/FileResponse"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
apiOpts := web.GetForm(ctx).(*api.ApplyDiffPatchFileOptions)
opts := &files.ApplyDiffPatchOptions{

View File

@ -282,6 +282,8 @@ func CreatePullRequest(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := *web.GetForm(ctx).(*api.CreatePullRequestOption)
if form.Head == form.Base {
@ -741,6 +743,8 @@ func MergePullRequest(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "409":
// "$ref": "#/responses/error"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*forms.MergePullRequestForm)
@ -1196,6 +1200,8 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
pullIndex := ctx.ParamsInt64(":index")
pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pullIndex)

View File

@ -184,6 +184,8 @@ func CreateTag(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "409":
// "$ref": "#/responses/conflict"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateTagOption)
// If target is not provided use default branch
@ -251,6 +253,8 @@ func DeleteTag(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "409":
// "$ref": "#/responses/conflict"
// "423":
// "$ref": "#/responses/repoArchivedError"
tagName := ctx.Params("*")
tag, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName)

View File

@ -52,6 +52,8 @@ func NewWikiPage(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateWikiPageOptions)
@ -128,6 +130,8 @@ func EditWikiPage(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateWikiPageOptions)
@ -234,6 +238,8 @@ func DeleteWikiPage(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
wikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw(":pageName"))

View File

@ -285,7 +285,7 @@ func DeleteProtectedBranchRulePost(ctx *context.Context) {
return
}
if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository.ID, ruleID); err != nil {
if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository, ruleID); err != nil {
ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", rule.RuleName))
ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
return

View File

@ -77,8 +77,9 @@ func userProfile(ctx *context.Context) {
func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGitRepo *git.Repository, profileReadme *git.Blob) {
// if there is a profile readme, default to "overview" page, otherwise, default to "repositories" page
// if there is not a profile readme, the overview tab should be treated as the repositories tab
tab := ctx.FormString("tab")
if tab == "" {
if tab == "" || tab == "overview" {
if profileReadme != nil {
tab = "overview"
} else {
@ -157,10 +158,10 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGi
switch tab {
case "followers":
ctx.Data["Cards"] = followers
total = int(count)
total = int(numFollowers)
case "following":
ctx.Data["Cards"] = following
total = int(count)
total = int(numFollowing)
case "activity":
date := ctx.FormString("date")
pagingNum = setting.UI.FeedPagingNum

View File

@ -22,7 +22,7 @@ import (
type Provider interface {
Name() string
DisplayName() string
IconHTML() template.HTML
IconHTML(size int) template.HTML
CustomURLSettings() *CustomURLSettings
}
@ -54,14 +54,16 @@ func (p *AuthSourceProvider) DisplayName() string {
return p.sourceName
}
func (p *AuthSourceProvider) IconHTML() template.HTML {
func (p *AuthSourceProvider) IconHTML(size int) template.HTML {
if p.iconURL != "" {
img := fmt.Sprintf(`<img class="gt-object-contain gt-mr-3" width="20" height="20" src="%s" alt="%s">`,
img := fmt.Sprintf(`<img class="gt-object-contain gt-mr-3" width="%d" height="%d" src="%s" alt="%s">`,
size,
size,
html.EscapeString(p.iconURL), html.EscapeString(p.DisplayName()),
)
return template.HTML(img)
}
return p.GothProvider.IconHTML()
return p.GothProvider.IconHTML(size)
}
// Providers contains the map of registered OAuth2 providers in Gitea (based on goth)

View File

@ -27,7 +27,7 @@ func (b *BaseProvider) DisplayName() string {
}
// IconHTML returns icon HTML for this provider
func (b *BaseProvider) IconHTML() template.HTML {
func (b *BaseProvider) IconHTML(size int) template.HTML {
svgName := "gitea-" + b.name
switch b.name {
case "gplus":
@ -35,10 +35,10 @@ func (b *BaseProvider) IconHTML() template.HTML {
case "github":
svgName = "octicon-mark-github"
}
svgHTML := svg.RenderHTML(svgName, 20, "gt-mr-3")
svgHTML := svg.RenderHTML(svgName, size, "gt-mr-3")
if svgHTML == "" {
log.Error("No SVG icon for oauth2 provider %q", b.name)
svgHTML = svg.RenderHTML("gitea-openid", 20, "gt-mr-3")
svgHTML = svg.RenderHTML("gitea-openid", size, "gt-mr-3")
}
return svgHTML
}

View File

@ -28,8 +28,8 @@ func (o *OpenIDProvider) DisplayName() string {
}
// IconHTML returns icon HTML for this provider
func (o *OpenIDProvider) IconHTML() template.HTML {
return svg.RenderHTML("gitea-openid", 20, "gt-mr-3")
func (o *OpenIDProvider) IconHTML(size int) template.HTML {
return svg.RenderHTML("gitea-openid", size, "gt-mr-3")
}
// CreateGothProvider creates a GothProvider from this Provider

View File

@ -15,8 +15,8 @@ func ToPushMirror(pm *repo_model.PushMirror) (*api.PushMirror, error) {
RepoName: repo.Name,
RemoteName: pm.RemoteName,
RemoteAddress: pm.RemoteAddress,
CreatedUnix: pm.CreatedUnix.FormatLong(),
LastUpdateUnix: pm.LastUpdateUnix.FormatLong(),
CreatedUnix: pm.CreatedUnix.AsTime(),
LastUpdateUnix: pm.LastUpdateUnix.AsTimePtr(),
LastError: pm.LastError,
Interval: pm.Interval.String(),
SyncOnCommit: pm.SyncOnCommit,

View File

@ -1343,7 +1343,7 @@ outer:
}
}
return diff, err
return diff, nil
}
// CommentAsDiff returns c.Patch as *Diff

View File

@ -25,6 +25,16 @@ import (
)
func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) {
err := rel.LoadAttributes(ctx)
if err != nil {
return false, err
}
err = rel.Repo.MustNotBeArchived()
if err != nil {
return false, err
}
var created bool
// Only actual create when publish.
if !rel.IsDraft {

View File

@ -29,6 +29,11 @@ import (
// CreateNewBranch creates a new repository branch
func CreateNewBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldBranchName, branchName string) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
}
// Check if branch name can be used
if err := checkBranchName(ctx, repo, branchName); err != nil {
return err
@ -246,6 +251,11 @@ func checkBranchName(ctx context.Context, repo *repo_model.Repository, name stri
// CreateNewBranchFromCommit creates a new repository branch
func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commit, branchName string) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
}
// Check if branch name can be used
if err := checkBranchName(ctx, repo, branchName); err != nil {
return err
@ -267,6 +277,11 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo
// RenameBranch rename a branch
func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, gitRepo *git.Repository, from, to string) (string, error) {
err := repo.MustNotBeArchived()
if err != nil {
return "", err
}
if from == to {
return "target_exist", nil
}
@ -315,6 +330,11 @@ var (
// DeleteBranch delete branch
func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string) error {
err := repo.MustNotBeArchived()
if err != nil {
return err
}
if branchName == repo.DefaultBranch {
return ErrBranchIsDefault
}

View File

@ -95,6 +95,11 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode
// ApplyDiffPatch applies a patch to the given repository
func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) {
err := repo.MustNotBeArchived()
if err != nil {
return nil, err
}
if err := opts.Validate(ctx, repo, doer); err != nil {
return nil, err
}

View File

@ -65,6 +65,11 @@ type RepoFileOptions struct {
// ChangeRepoFiles adds, updates or removes multiple files in the given repository
func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ChangeRepoFilesOptions) (*structs.FilesResponse, error) {
err := repo.MustNotBeArchived()
if err != nil {
return nil, err
}
// If no branch name is set, assume default branch
if opts.OldBranch == "" {
opts.OldBranch = repo.DefaultBranch

View File

@ -170,7 +170,7 @@ func (d *DingtalkPayload) Repository(p *api.RepositoryPayload) (api.Payloader, e
func (d *DingtalkPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true)
return createDingtalkPayload(text, text, "view release", p.Release.URL), nil
return createDingtalkPayload(text, text, "view release", p.Release.HTMLURL), nil
}
func createDingtalkPayload(title, text, singleTitle, singleURL string) *DingtalkPayload {

View File

@ -238,7 +238,7 @@ func TestDingTalkPayload(t *testing.T) {
assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Text)
assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Title)
assert.Equal(t, "view release", pl.(*DingtalkPayload).ActionCard.SingleTitle)
assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL))
assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL))
})
}

View File

@ -253,7 +253,7 @@ func (d *DiscordPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) {
func (d *DiscordPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
text, color := getReleasePayloadInfo(p, noneLinkFormatter, false)
return d.createPayload(p.Sender, text, p.Release.Note, p.Release.URL, color), nil
return d.createPayload(p.Sender, text, p.Release.Note, p.Release.HTMLURL, color), nil
}
// GetDiscordPayload converts a discord webhook into a DiscordPayload

View File

@ -270,7 +270,7 @@ func TestDiscordPayload(t *testing.T) {
assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
assert.Equal(t, "[test/repo] Release created: v1.0", pl.(*DiscordPayload).Embeds[0].Title)
assert.Equal(t, "Note of first stable release", pl.(*DiscordPayload).Embeds[0].Description)
assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*DiscordPayload).Embeds[0].URL)
assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", pl.(*DiscordPayload).Embeds[0].URL)
assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)

View File

@ -240,7 +240,7 @@ func pullReleaseTestPayload() *api.ReleasePayload {
Target: "master",
Title: "First stable release",
Note: "Note of first stable release",
URL: "http://localhost:3000/api/v1/repos/test/repo/releases/2",
HTMLURL: "http://localhost:3000/test/repo/releases/tag/v1.0",
},
}
}

View File

@ -177,7 +177,7 @@ func (m *MatrixPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, e
func (m *MatrixPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) {
senderLink := MatrixLinkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName)
title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)
titleLink := MatrixLinkFormatter(p.PullRequest.URL, title)
titleLink := MatrixLinkFormatter(p.PullRequest.HTMLURL, title)
repoLink := MatrixLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
var text string

View File

@ -290,7 +290,7 @@ func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
p.Sender,
title,
"",
p.Release.URL,
p.Release.HTMLURL,
color,
&MSTeamsFact{"Tag:", p.Release.TagName},
), nil

View File

@ -429,7 +429,7 @@ func TestMSTeamsPayload(t *testing.T) {
}
assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
})
}

View File

@ -223,7 +223,7 @@ func (s *SlackPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, er
attachments = append(attachments, SlackAttachment{
Color: fmt.Sprintf("%x", color),
Title: issueTitle,
TitleLink: p.PullRequest.URL,
TitleLink: p.PullRequest.HTMLURL,
Text: attachmentText,
})
}

View File

@ -79,6 +79,11 @@ func prepareGitPath(gitRepo *git.Repository, wikiPath WebPath) (bool, string, er
// updateWikiPage adds a new page or edits an existing page in repository wiki.
func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldWikiName, newWikiName WebPath, content, message string, isNew bool) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
}
if err = validateWebPath(newWikiName); err != nil {
return err
}
@ -238,6 +243,11 @@ func EditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.R
// DeleteWikiPage deletes a wiki page identified by its path.
func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, wikiName WebPath) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
}
wikiWorkingPool.CheckIn(fmt.Sprint(repo.ID))
defer wikiWorkingPool.CheckOut(fmt.Sprint(repo.ID))

View File

@ -168,7 +168,9 @@ func TestRepository_AddWikiPage(t *testing.T) {
assert.NoError(t, AddWikiPage(git.DefaultContext, doer, repo, webPath, wikiContent, commitMsg))
// Now need to show that the page has been added:
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath())
assert.NoError(t, err)
if !assert.NoError(t, err) {
return
}
defer gitRepo.Close()
masterTree, err := gitRepo.GetTree(DefaultBranch)
assert.NoError(t, err)
@ -238,7 +240,9 @@ func TestRepository_DeleteWikiPage(t *testing.T) {
// Now need to show that the page has been added:
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath())
assert.NoError(t, err)
if !assert.NoError(t, err) {
return
}
defer gitRepo.Close()
masterTree, err := gitRepo.GetTree(DefaultBranch)
assert.NoError(t, err)
@ -251,8 +255,10 @@ func TestPrepareWikiFileName(t *testing.T) {
unittest.PrepareTestEnv(t)
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath())
if !assert.NoError(t, err) {
return
}
defer gitRepo.Close()
assert.NoError(t, err)
tests := []struct {
name string
@ -303,8 +309,10 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) {
assert.NoError(t, err)
gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir)
if !assert.NoError(t, err) {
return
}
defer gitRepo.Close()
assert.NoError(t, err)
existence, newWikiPath, err := prepareGitPath(gitRepo, "Home")
assert.False(t, existence)

View File

@ -428,7 +428,7 @@
</div>
<div class="field">
<button class="ui green button">{{.locale.Tr "admin.auths.update"}}</button>
<button class="ui primary button">{{.locale.Tr "admin.auths.update"}}</button>
<button class="ui red button delete-button" data-url="{{$.Link}}/delete" data-id="{{.Source.ID}}">{{.locale.Tr "admin.auths.delete"}}</button>
</div>
</form>

View File

@ -73,7 +73,7 @@
</div>
<div class="field">
<button class="ui green button">{{.locale.Tr "admin.auths.new"}}</button>
<button class="ui primary button">{{.locale.Tr "admin.auths.new"}}</button>
</div>
</form>
</div>

View File

@ -9,8 +9,8 @@
<div class="ui dropdown type jump item gt-mr-0">
<span class="text">
{{.locale.Tr "repo.issues.filter_sort"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>

View File

@ -238,7 +238,7 @@
<div class="ui tiny input">
<input type="email" name="email" placeholder="{{.locale.Tr "admin.config.test_email_placeholder"}}" size="29" required>
</div>
<button class="ui tiny green button">{{.locale.Tr "admin.config.send_test_mail_submit"}}</button>
<button class="ui tiny primary button">{{.locale.Tr "admin.config.send_test_mail_submit"}}</button>
</form>
</dd>
{{end}}

View File

@ -20,7 +20,7 @@
<tbody>
{{range .Entries}}
<tr>
<td><button type="submit" class="ui green button" name="op" value="{{.Name}}" title="{{$.locale.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td>
<td><button type="submit" class="ui primary button" name="op" value="{{.Name}}" title="{{$.locale.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td>
<td>{{$.locale.Tr (printf "admin.dashboard.%s" .Name)}}</td>
<td>{{.Spec}}</td>
<td>{{DateTime "full" .Next}}</td>

View File

@ -15,55 +15,55 @@
<tbody>
<tr>
<td>{{.locale.Tr "admin.dashboard.delete_inactive_accounts"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="delete_inactive_accounts">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="delete_inactive_accounts">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.delete_repo_archives"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="delete_repo_archives">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="delete_repo_archives">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.delete_missing_repos"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="delete_missing_repos">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="delete_missing_repos">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.git_gc_repos"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="git_gc_repos">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="git_gc_repos">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
{{if and (not .SSH.Disabled) (not .SSH.StartBuiltinServer)}}
<tr>
<td>{{.locale.Tr "admin.dashboard.resync_all_sshkeys"}}<br>
{{.locale.Tr "admin.dashboard.resync_all_sshkeys.desc"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="resync_all_sshkeys">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="resync_all_sshkeys">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.resync_all_sshprincipals"}}<br>
{{.locale.Tr "admin.dashboard.resync_all_sshprincipals.desc"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="resync_all_sshprincipals">{{svg "octicon-play" 16}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="resync_all_sshprincipals">{{svg "octicon-play" 16}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
{{end}}
<tr>
<td>{{.locale.Tr "admin.dashboard.resync_all_hooks"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="resync_all_hooks">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="resync_all_hooks">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.reinit_missing_repos"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="reinit_missing_repos">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="reinit_missing_repos">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.sync_external_users"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="sync_external_users">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="sync_external_users">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.repo_health_check"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="repo_health_check">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="repo_health_check">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.delete_generated_repository_avatars"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="delete_generated_repository_avatars">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="delete_generated_repository_avatars">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
<tr>
<td>{{.locale.Tr "admin.dashboard.sync_repo_branches"}}</td>
<td class="text right"><button type="submit" class="ui green button" name="op" value="sync_repo_branches">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
<td class="text right"><button type="submit" class="ui primary button" name="op" value="sync_repo_branches">{{svg "octicon-play"}} {{.locale.Tr "admin.dashboard.operation_run"}}</button></td>
</tr>
</tbody>
</table>

View File

@ -15,8 +15,8 @@
<div class="ui dropdown type jump item gt-mr-0">
<span class="text">
{{.locale.Tr "repo.issues.filter_sort"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="{{if or (eq .SortType "email") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=email&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.email"}}</a>
<a class="{{if eq .SortType "reverseemail"}}active {{end}}item" href="{{$.Link}}?sort=reverseemail&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.email_reverse"}}</a>

View File

@ -9,8 +9,8 @@
<div class="ui dropdown type jump item gt-mr-0">
<span class="text">
{{.locale.Tr "repo.issues.filter_sort"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>

View File

@ -23,7 +23,7 @@
<div class="item gt-df gt-ac">
<span class="gt-f1"> {{svg "octicon-file-directory-fill"}} {{$dir}}</span>
<div>
<button class="ui button green show-modal gt-p-3" data-modal="#adopt-unadopted-modal-{{$dirI}}">{{svg "octicon-plus"}} {{$.locale.Tr "repo.adopt_preexisting_label"}}</button>
<button class="ui button primary show-modal gt-p-3" data-modal="#adopt-unadopted-modal-{{$dirI}}">{{svg "octicon-plus"}} {{$.locale.Tr "repo.adopt_preexisting_label"}}</button>
<div class="ui g-modal-confirm modal" id="adopt-unadopted-modal-{{$dirI}}">
<div class="header">
<span class="label">{{$.locale.Tr "repo.adopt_preexisting"}}</span>

View File

@ -4,7 +4,7 @@
{{.locale.Tr "admin.users.edit_account"}}
</h4>
<div class="ui attached segment">
<form class="ui form" action="{{.Link}}" method="post">
<form class="ui form" action="./edit" method="post">
{{template "base/disable_form_autofill"}}
{{.CsrfTokenHtml}}
<div class="field {{if .Err_UserName}}error{{end}}">
@ -147,7 +147,7 @@
<div class="divider"></div>
<div class="field">
<button class="ui green button">{{.locale.Tr "admin.users.update_profile"}}</button>
<button class="ui primary button">{{.locale.Tr "admin.users.update_profile"}}</button>
<button class="ui red button show-modal" data-modal="#delete-user-modal">{{.locale.Tr "admin.users.delete_account"}}</button>
</div>
</form>
@ -157,7 +157,7 @@
{{.locale.Tr "settings.avatar"}}
</h4>
<div class="ui attached segment">
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
<form class="ui form" action="./avatar" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}}
{{if not .DisableGravatar}}
<div class="inline field">
@ -185,8 +185,8 @@
</div>
<div class="field">
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
<button class="ui primary button">{{$.locale.Tr "settings.update_avatar"}}</button>
<button class="ui red button link-action" data-url="./avatar/delete">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
</div>
</form>
</div>
@ -197,7 +197,7 @@
{{svg "octicon-trash"}}
{{.locale.Tr "settings.delete_account_title"}}
</div>
<form class="ui form" method="post" action="{{.Link}}/delete">
<form class="ui form" method="post" action="./delete">
<div class="content">
<p>{{.locale.Tr "settings.delete_account_desc"}}</p>
{{$.CsrfTokenHtml}}

View File

@ -13,7 +13,8 @@
<div class="ui right floated secondary filter menu">
<!-- Status Filter Menu Item -->
<div class="ui dropdown type jump item">
<span class="text">{{.locale.Tr "admin.users.list_status_filter.menu_text"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}</span>
<span class="text">{{.locale.Tr "admin.users.list_status_filter.menu_text"}}</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="item j-reset-status-filter">{{.locale.Tr "admin.users.list_status_filter.reset"}}</a>
<div class="divider"></div>
@ -37,8 +38,9 @@
<!-- Sort Menu Item -->
<div class="ui dropdown type jump item">
<span class="text">
{{.locale.Tr "repo.issues.filter_sort"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{.locale.Tr "repo.issues.filter_sort"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<button class="item" name="sort" value="oldest">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</button>
<button class="item" name="sort" value="newest">{{.locale.Tr "repo.issues.filter_sort.latest"}}</button>

View File

@ -82,7 +82,7 @@
{{end}}
<div class="field">
<button class="ui green button">{{.locale.Tr "admin.users.new_account"}}</button>
<button class="ui primary button">{{.locale.Tr "admin.users.new_account"}}</button>
</div>
</form>
</div>

View File

@ -4,7 +4,7 @@ Template Attributes:
Two buttons (negative, positive):
* ModalButtonTypes: "yes" (default) or "confirm"
* ModalButtonColors: "green" (default) / "blue" / "yellow"
* ModalButtonColors: "primary" (default) / "blue" / "yellow"
* ModalButtonCancelText
* ModalButtonOkText
@ -26,13 +26,13 @@ The ".ok.button" and ".cancel.button" selectors are also used by Fomantic Modal
{{if .ModalButtonCancelText}}{{$textNegitive = .ModalButtonCancelText}}{{end}}
{{if .ModalButtonOkText}}{{$textPositive = .ModalButtonOkText}}{{end}}
{{$stylePositive := "green"}}
{{$stylePositive := "primary"}}
{{if eq .ModalButtonColors "blue"}}
{{$stylePositive = "blue"}}
{{else if eq .ModalButtonColors "yellow"}}
{{$stylePositive = "yellow"}}
{{end}}
<button class="ui basic cancel button">{{svg "octicon-x"}} {{$textNegitive}}</button>
<button class="ui cancel button">{{svg "octicon-x"}} {{$textNegitive}}</button>
<button class="ui {{$stylePositive}} ok button">{{svg "octicon-check"}} {{$textPositive}}</button>
{{end}}
</div>

View File

@ -27,10 +27,10 @@
<button class="ui tiny red button">
{{svg "octicon-warning" 14}} CJK文本测试
</button>
<button class="ui tiny green button">
<button class="ui tiny primary button">
{{svg "octicon-info" 14}} Button
</button>
<button class="ui tiny green button">
<button class="ui tiny primary button">
Button with long text
</button>
</div>

View File

@ -31,8 +31,8 @@
<h2>Recommended colors:</h2>
<button class="ui red button">Red</button>
<button class="ui basic red button">Basic Red</button>
<button class="ui green button">Green</button>
<button class="ui basic green button">Basic Green</button>
<button class="ui primary button">Green</button>
<button class="ui basic primary button">Basic Green</button>
<button class="ui blue button">Blue</button>
<button class="ui basic blue button">Basic Blue</button>
<button class="ui orange button">Orange</button>

View File

@ -16,8 +16,8 @@
<div class="ui dropdown type jump item gt-mr-0">
<span class="text">
{{.locale.Tr "repo.issues.filter_sort"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>

View File

@ -9,8 +9,8 @@
<div class="ui dropdown type jump item gt-mr-0">
<span class="text">
{{.locale.Tr "repo.issues.filter_sort"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>

View File

@ -45,7 +45,7 @@
<div class="inline field">
<label></label>
<button class="ui green button">
<button class="ui primary button">
{{.locale.Tr "org.create_org"}}
</button>
</div>

View File

@ -47,9 +47,9 @@
<div class="ui five wide column">
{{if .CanCreateOrgRepo}}
<div class="center aligned">
<a class="ui green button" href="{{AppSubUrl}}/repo/create?org={{.Org.ID}}">{{.locale.Tr "new_repo"}}</a>
<a class="ui primary button" href="{{AppSubUrl}}/repo/create?org={{.Org.ID}}">{{.locale.Tr "new_repo"}}</a>
{{if not .DisableNewPullMirrors}}
<a class="ui green button" href="{{AppSubUrl}}/repo/migrate?org={{.Org.ID}}&mirror=1">{{.locale.Tr "new_migrate"}}</a>
<a class="ui primary button" href="{{AppSubUrl}}/repo/migrate?org={{.Org.ID}}&mirror=1">{{.locale.Tr "new_migrate"}}</a>
{{end}}
</div>
<div class="divider"></div>

View File

@ -4,7 +4,7 @@
<div class="gt-f1">
{{$.locale.Tr "org.settings.labels_desc" | Str2html}}
</div>
<button class="ui small green new-label button">{{.locale.Tr "repo.issues.new_label"}}</button>
<button class="ui small primary new-label button">{{.locale.Tr "repo.issues.new_label"}}</button>
</div>
<div class="divider"></div>
{{template "repo/issue/labels/label_new" .}}

View File

@ -79,7 +79,7 @@
{{end}}
<div class="field">
<button class="ui green button">{{$.locale.Tr "org.settings.update_settings"}}</button>
<button class="ui primary button">{{$.locale.Tr "org.settings.update_settings"}}</button>
</div>
</form>
@ -93,7 +93,7 @@
</div>
<div class="field">
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
<button class="ui primary button">{{$.locale.Tr "settings.update_avatar"}}</button>
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
</div>
</form>

View File

@ -14,7 +14,7 @@
<div class="extra content">
<form class="ui form" action="" method="post">
{{.CsrfTokenHtml}}
<button class="fluid ui green button">{{.locale.Tr "org.teams.join"}}</button>
<button class="fluid ui primary button">{{.locale.Tr "org.teams.join"}}</button>
</form>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More