Merge branch 'main' into add-issue-planned-time

This commit is contained in:
stuzer05 2023-06-26 16:12:25 +03:00
commit 62094d8cf3
No known key found for this signature in database
GPG Key ID: A6ABAAA9268F9F4F
63 changed files with 689 additions and 307 deletions

View File

@ -88,7 +88,7 @@ func main() {
}
func runEnvironmentToIni(c *cli.Context) error {
setting.InitWorkPathAndCommonConfig(os.Getenv, setting.ArgWorkPathAndCustomConf{
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
WorkPath: c.String("work-path"),
CustomPath: c.String("custom-path"),
CustomConf: c.String("config"),

View File

@ -119,10 +119,13 @@ RUN_USER = ; git
;; Permission for unix socket
;UNIX_SOCKET_PERMISSION = 666
;;
;; Local (DMZ) URL for Gitea workers (such as SSH update) accessing web service.
;; In most cases you do not need to change the default value.
;; Alter it only if your SSH server node is not the same as HTTP node.
;; Do not set this variable if PROTOCOL is set to 'unix'.
;; Local (DMZ) URL for Gitea workers (such as SSH update) accessing web service. In
;; most cases you do not need to change the default value. Alter it only if
;; your SSH server node is not the same as HTTP node. For different protocol, the default
;; values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`.
;; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`.
;; If listen on `0.0.0.0`, the default value is `%(PROTOCOL)s://localhost:%(HTTP_PORT)s/`, Otherwise the default
;; value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`.
;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
;;
;; When making local connections pass the PROXY protocol header.

View File

@ -1,12 +1,14 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-rootless
{{#if build.tags}}
{{#unless (contains "-rc" build.tag)}}
{{#unless (contains "-dev" build.tag)}}
tags:
{{#each build.tags}}
- {{this}}-rootless
{{/each}}
- "latest-rootless"
{{/unless}}
{{/unless}}
{{/if}}
manifests:
-

View File

@ -1,12 +1,14 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}
{{#if build.tags}}
{{#unless (contains "-rc" build.tag)}}
{{#unless (contains "-dev" build.tag)}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
- "latest"
{{/unless}}
{{/unless}}
{{/if}}
manifests:
-

View File

@ -108,6 +108,14 @@ Admin operations:
- `--all`, `-A`: Force a password change for all users
- `--exclude username`, `-e username`: Exclude the given user. Can be set multiple times.
- `--unset`: Revoke forced password change for the given users
- `generate-access-token`:
- Options:
- `--username value`, `-u value`: Username. Required.
- `--token-name value`, `-t value`: Token name. Required.
- `--scopes value`: Comma-separated list of scopes. Scopes follow the format `[read|write]:<block>` or `all` where `<block>` is one of the available visual groups you can see when opening the API page showing the available routes (for example `repo`).
- Examples:
- `gitea admin user generate-access-token --username myname --token-name mytoken`
- `gitea admin user generate-access-token --help`
- `regenerate`
- Options:
- `hooks`: Regenerate Git Hooks for all repositories

View File

@ -314,8 +314,11 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `LOCAL_ROOT_URL`: **%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/**: Local
(DMZ) URL for Gitea workers (such as SSH update) accessing web service. In
most cases you do not need to change the default value. Alter it only if
your SSH server node is not the same as HTTP node. Do not set this variable
if `PROTOCOL` is set to `http+unix`.
your SSH server node is not the same as HTTP node. For different protocol, the default
values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`.
If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`.
If listen on `0.0.0.0`, the default value is `%(PROTOCOL)s://localhost:%(HTTP_PORT)s/`, Otherwise the default
value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`.
- `LOCAL_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)s**: When making local connections pass the PROXY protocol header.
This should be set to false if the local connection will go through the proxy.
- `PER_WRITE_TIMEOUT`: **30s**: Timeout for any write to the connection. (Set to -1 to

2
go.mod
View File

@ -122,7 +122,7 @@ require (
mvdan.cc/xurls/v2 v2.4.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.12
xorm.io/xorm v1.3.3-0.20230219231735-056cecc97e9e
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75
)
require (

4
go.sum
View File

@ -1923,5 +1923,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM=
xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.3-0.20230219231735-056cecc97e9e h1:d5PY6mwuQK5/7T6VKfFswaKMzLmGTHkJ/ZS7+cUIAjk=
xorm.io/xorm v1.3.3-0.20230219231735-056cecc97e9e/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75 h1:ReBAlO50dCIXCWF8Gbi0ZRa62AGAwCJNCPaUNUa7JSg=
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=

15
main.go
View File

@ -47,7 +47,9 @@ func init() {
// ./gitea -h
// ./gitea web help
// ./gitea web -h (due to cli lib limitation, this won't call our cmdHelp, so no extra info)
// ./gitea admin help auth
// ./gitea admin
// ./gitea admin help
// ./gitea admin auth help
// ./gitea -c /tmp/app.ini -h
// ./gitea -c /tmp/app.ini help
// ./gitea help -c /tmp/app.ini
@ -156,11 +158,7 @@ func prepareSubcommands(command *cli.Command, defaultFlags []cli.Flag) {
// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times
func prepareWorkPathAndCustomConf(a any) func(ctx *cli.Context) error {
if a == nil {
return nil
}
action := a.(func(*cli.Context) error)
func prepareWorkPathAndCustomConf(action any) func(ctx *cli.Context) error {
return func(ctx *cli.Context) error {
var args setting.ArgWorkPathAndCustomConf
curCtx := ctx
@ -177,10 +175,11 @@ func prepareWorkPathAndCustomConf(a any) func(ctx *cli.Context) error {
curCtx = curCtx.Parent()
}
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
if ctx.Bool("help") {
if ctx.Bool("help") || action == nil {
// the default behavior of "urfave/cli": "nil action" means "show help"
return cmdHelp.Action.(func(ctx *cli.Context) error)(ctx)
}
return action(ctx)
return action.(func(*cli.Context) error)(ctx)
}
}

View File

@ -36,12 +36,13 @@ type ActionRun struct {
TriggerUser *user_model.User `xorm:"-"`
Ref string
CommitSHA string
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
NeedApproval bool // may need approval if it's a fork pull request
ApprovedBy int64 `xorm:"index"` // who approved
Event webhook_module.HookEventType
EventPayload string `xorm:"LONGTEXT"`
Status Status `xorm:"index"`
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
NeedApproval bool // may need approval if it's a fork pull request
ApprovedBy int64 `xorm:"index"` // who approved
Event webhook_module.HookEventType // the webhook event that causes the workflow to run
EventPayload string `xorm:"LONGTEXT"`
TriggerEvent string // the trigger event defined in the `on` configuration of the triggered workflow
Status Status `xorm:"index"`
Started timeutil.TimeStamp
Stopped timeutil.TimeStamp
Created timeutil.TimeStamp `xorm:"created"`

View File

@ -123,7 +123,10 @@ func newXORMEngine() (*xorm.Engine, error) {
// SyncAllTables sync the schemas of all tables, is required by unit test code
func SyncAllTables() error {
return x.StoreEngine("InnoDB").Sync2(tables...)
_, err := x.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{
WarnIfDatabaseColumnMissed: true,
}, tables...)
return err
}
// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext

View File

@ -229,39 +229,41 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
return nil
}
func (issues IssueList) getProjectIDs() []int64 {
ids := make(container.Set[int64], len(issues))
for _, issue := range issues {
ids.Add(issue.ProjectID())
}
return ids.Values()
}
func (issues IssueList) LoadProjects(ctx context.Context) error {
issueIDs := issues.getIssueIDs()
projectMaps := make(map[int64]*project_model.Project, len(issues))
left := len(issueIDs)
func (issues IssueList) loadProjects(ctx context.Context) error {
projectIDs := issues.getProjectIDs()
if len(projectIDs) == 0 {
return nil
type projectWithIssueID struct {
*project_model.Project `xorm:"extends"`
IssueID int64
}
projectMaps := make(map[int64]*project_model.Project, len(projectIDs))
left := len(projectIDs)
for left > 0 {
limit := db.DefaultMaxInSize
if left < limit {
limit = left
}
projects := make([]*projectWithIssueID, 0, limit)
err := db.GetEngine(ctx).
In("id", projectIDs[:limit]).
Find(&projectMaps)
Table("project").
Select("project.*, project_issue.issue_id").
Join("INNER", "project_issue", "project.id = project_issue.project_id").
In("project_issue.issue_id", issueIDs[:limit]).
Find(&projects)
if err != nil {
return err
}
for _, project := range projects {
projectMaps[project.IssueID] = project.Project
}
left -= limit
projectIDs = projectIDs[limit:]
issueIDs = issueIDs[limit:]
}
for _, issue := range issues {
issue.Project = projectMaps[issue.ProjectID()]
issue.Project = projectMaps[issue.ID]
}
return nil
}
@ -541,7 +543,7 @@ func (issues IssueList) loadAttributes(ctx context.Context) error {
return fmt.Errorf("issue.loadAttributes: loadMilestones: %w", err)
}
if err := issues.loadProjects(ctx); err != nil {
if err := issues.LoadProjects(ctx); err != nil {
return fmt.Errorf("issue.loadAttributes: loadProjects: %w", err)
}

View File

@ -66,8 +66,12 @@ func TestIssueList_LoadAttributes(t *testing.T) {
}
if issue.ID == int64(1) {
assert.Equal(t, int64(400), issue.TotalTrackedTime)
assert.NotNil(t, issue.Project)
} else if issue.ID == int64(2) {
assert.Equal(t, int64(3682), issue.TotalTrackedTime)
assert.Nil(t, issue.Project)
} else {
assert.Nil(t, issue.Project)
}
}
}

View File

@ -27,11 +27,6 @@ func (issue *Issue) LoadProject(ctx context.Context) (err error) {
return err
}
// ProjectID return project id if issue was assigned to one
func (issue *Issue) ProjectID() int64 {
return issue.projectID(db.DefaultContext)
}
func (issue *Issue) projectID(ctx context.Context) int64 {
var ip project_model.ProjectIssue
has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip)

View File

@ -503,11 +503,11 @@ var migrations = []Migration{
// v260 -> v261
NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner),
// v261 -> v262
NewMigration("Add variable table", v1_21.CreateVariableTable),
// v262 -> v263
NewMigration("Add TriggerEvent to action_run table", v1_21.AddTriggerEventToActionRun),
// v263 -> v264
NewMigration("Add TimeEstimate to issue table", v1_21.AddTimeEstimateColumnToIssueTable),
}

View File

@ -7,10 +7,10 @@ import (
"xorm.io/xorm"
)
func AddTimeEstimateColumnToIssueTable(x *xorm.Engine) error {
type Issue struct {
TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"`
func AddTriggerEventToActionRun(x *xorm.Engine) error {
type ActionRun struct {
TriggerEvent string
}
return x.Sync(new(Issue))
return x.Sync(new(ActionRun))
}

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 AddTimeEstimateColumnToIssueTable(x *xorm.Engine) error {
type Issue struct {
TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"`
}
return x.Sync(new(Issue))
}

View File

@ -8,33 +8,33 @@ import (
)
const (
githubEventPullRequest = "pull_request"
githubEventPullRequestTarget = "pull_request_target"
githubEventPullRequestReviewComment = "pull_request_review_comment"
githubEventPullRequestReview = "pull_request_review"
githubEventRegistryPackage = "registry_package"
githubEventCreate = "create"
githubEventDelete = "delete"
githubEventFork = "fork"
githubEventPush = "push"
githubEventIssues = "issues"
githubEventIssueComment = "issue_comment"
githubEventRelease = "release"
githubEventPullRequestComment = "pull_request_comment"
githubEventGollum = "gollum"
GithubEventPullRequest = "pull_request"
GithubEventPullRequestTarget = "pull_request_target"
GithubEventPullRequestReviewComment = "pull_request_review_comment"
GithubEventPullRequestReview = "pull_request_review"
GithubEventRegistryPackage = "registry_package"
GithubEventCreate = "create"
GithubEventDelete = "delete"
GithubEventFork = "fork"
GithubEventPush = "push"
GithubEventIssues = "issues"
GithubEventIssueComment = "issue_comment"
GithubEventRelease = "release"
GithubEventPullRequestComment = "pull_request_comment"
GithubEventGollum = "gollum"
)
// canGithubEventMatch check if the input Github event can match any Gitea event.
func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEventType) bool {
switch eventName {
case githubEventRegistryPackage:
case GithubEventRegistryPackage:
return triggedEvent == webhook_module.HookEventPackage
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#gollum
case githubEventGollum:
case GithubEventGollum:
return triggedEvent == webhook_module.HookEventWiki
case githubEventIssues:
case GithubEventIssues:
switch triggedEvent {
case webhook_module.HookEventIssues,
webhook_module.HookEventIssueAssign,
@ -46,7 +46,7 @@ func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEvent
return false
}
case githubEventPullRequest, githubEventPullRequestTarget:
case GithubEventPullRequest, GithubEventPullRequestTarget:
switch triggedEvent {
case webhook_module.HookEventPullRequest,
webhook_module.HookEventPullRequestSync,
@ -58,7 +58,7 @@ func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEvent
return false
}
case githubEventPullRequestReview:
case GithubEventPullRequestReview:
switch triggedEvent {
case webhook_module.HookEventPullRequestReviewApproved,
webhook_module.HookEventPullRequestReviewComment,

View File

@ -21,85 +21,85 @@ func TestCanGithubEventMatch(t *testing.T) {
// registry_package event
{
"registry_package matches",
githubEventRegistryPackage,
GithubEventRegistryPackage,
webhook_module.HookEventPackage,
true,
},
{
"registry_package cannot match",
githubEventRegistryPackage,
GithubEventRegistryPackage,
webhook_module.HookEventPush,
false,
},
// issues event
{
"issue matches",
githubEventIssues,
GithubEventIssues,
webhook_module.HookEventIssueLabel,
true,
},
{
"issue cannot match",
githubEventIssues,
GithubEventIssues,
webhook_module.HookEventIssueComment,
false,
},
// issue_comment event
{
"issue_comment matches",
githubEventIssueComment,
GithubEventIssueComment,
webhook_module.HookEventIssueComment,
true,
},
{
"issue_comment cannot match",
githubEventIssueComment,
GithubEventIssueComment,
webhook_module.HookEventIssues,
false,
},
// pull_request event
{
"pull_request matches",
githubEventPullRequest,
GithubEventPullRequest,
webhook_module.HookEventPullRequestSync,
true,
},
{
"pull_request cannot match",
githubEventPullRequest,
GithubEventPullRequest,
webhook_module.HookEventPullRequestComment,
false,
},
// pull_request_target event
{
"pull_request_target matches",
githubEventPullRequest,
GithubEventPullRequest,
webhook_module.HookEventPullRequest,
true,
},
{
"pull_request_target cannot match",
githubEventPullRequest,
GithubEventPullRequest,
webhook_module.HookEventPullRequestComment,
false,
},
// pull_request_review event
{
"pull_request_review matches",
githubEventPullRequestReview,
GithubEventPullRequestReview,
webhook_module.HookEventPullRequestReviewComment,
true,
},
{
"pull_request_review cannot match",
githubEventPullRequestReview,
GithubEventPullRequestReview,
webhook_module.HookEventPullRequestComment,
false,
},
// other events
{
"create event",
githubEventCreate,
GithubEventCreate,
webhook_module.HookEventCreate,
true,
},

View File

@ -20,6 +20,14 @@ import (
"gopkg.in/yaml.v3"
)
type DetectedWorkflow struct {
EntryName string
TriggerEvent string
Commit *git.Commit
Ref string
Content []byte
}
func init() {
model.OnDecodeNodeError = func(node yaml.Node, out interface{}, err error) {
// Log the error instead of panic or fatal.
@ -89,13 +97,13 @@ func GetEventsFromContent(content []byte) ([]*jobparser.Event, error) {
return events, nil
}
func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader) (map[string][]byte, error) {
func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader) ([]*DetectedWorkflow, error) {
entries, err := ListWorkflows(commit)
if err != nil {
return nil, err
}
workflows := make(map[string][]byte, len(entries))
workflows := make([]*DetectedWorkflow, 0, len(entries))
for _, entry := range entries {
content, err := GetContentFromEntry(entry)
if err != nil {
@ -109,7 +117,13 @@ func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventTy
for _, evt := range events {
log.Trace("detect workflow %q for event %#v matching %q", entry.Name(), evt, triggedEvent)
if detectMatched(commit, triggedEvent, payload, evt) {
workflows[entry.Name()] = content
dwf := &DetectedWorkflow{
EntryName: entry.Name(),
TriggerEvent: evt.Name,
Commit: commit,
Content: content,
}
workflows = append(workflows, dwf)
}
}
}

View File

@ -23,77 +23,77 @@ func TestDetectMatched(t *testing.T) {
expected bool
}{
{
desc: "HookEventCreate(create) matches githubEventCreate(create)",
desc: "HookEventCreate(create) matches GithubEventCreate(create)",
triggedEvent: webhook_module.HookEventCreate,
payload: nil,
yamlOn: "on: create",
expected: true,
},
{
desc: "HookEventIssues(issues) `opened` action matches githubEventIssues(issues)",
desc: "HookEventIssues(issues) `opened` action matches GithubEventIssues(issues)",
triggedEvent: webhook_module.HookEventIssues,
payload: &api.IssuePayload{Action: api.HookIssueOpened},
yamlOn: "on: issues",
expected: true,
},
{
desc: "HookEventIssues(issues) `milestoned` action matches githubEventIssues(issues)",
desc: "HookEventIssues(issues) `milestoned` action matches GithubEventIssues(issues)",
triggedEvent: webhook_module.HookEventIssues,
payload: &api.IssuePayload{Action: api.HookIssueMilestoned},
yamlOn: "on: issues",
expected: true,
},
{
desc: "HookEventPullRequestSync(pull_request_sync) matches githubEventPullRequest(pull_request)",
desc: "HookEventPullRequestSync(pull_request_sync) matches GithubEventPullRequest(pull_request)",
triggedEvent: webhook_module.HookEventPullRequestSync,
payload: &api.PullRequestPayload{Action: api.HookIssueSynchronized},
yamlOn: "on: pull_request",
expected: true,
},
{
desc: "HookEventPullRequest(pull_request) `label_updated` action doesn't match githubEventPullRequest(pull_request) with no activity type",
desc: "HookEventPullRequest(pull_request) `label_updated` action doesn't match GithubEventPullRequest(pull_request) with no activity type",
triggedEvent: webhook_module.HookEventPullRequest,
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
yamlOn: "on: pull_request",
expected: false,
},
{
desc: "HookEventPullRequest(pull_request) `label_updated` action matches githubEventPullRequest(pull_request) with `label` activity type",
desc: "HookEventPullRequest(pull_request) `label_updated` action matches GithubEventPullRequest(pull_request) with `label` activity type",
triggedEvent: webhook_module.HookEventPullRequest,
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
yamlOn: "on:\n pull_request:\n types: [labeled]",
expected: true,
},
{
desc: "HookEventPullRequestReviewComment(pull_request_review_comment) matches githubEventPullRequestReviewComment(pull_request_review_comment)",
desc: "HookEventPullRequestReviewComment(pull_request_review_comment) matches GithubEventPullRequestReviewComment(pull_request_review_comment)",
triggedEvent: webhook_module.HookEventPullRequestReviewComment,
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
yamlOn: "on:\n pull_request_review_comment:\n types: [created]",
expected: true,
},
{
desc: "HookEventPullRequestReviewRejected(pull_request_review_rejected) doesn't match githubEventPullRequestReview(pull_request_review) with `dismissed` activity type (we don't support `dismissed` at present)",
desc: "HookEventPullRequestReviewRejected(pull_request_review_rejected) doesn't match GithubEventPullRequestReview(pull_request_review) with `dismissed` activity type (we don't support `dismissed` at present)",
triggedEvent: webhook_module.HookEventPullRequestReviewRejected,
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
yamlOn: "on:\n pull_request_review:\n types: [dismissed]",
expected: false,
},
{
desc: "HookEventRelease(release) `published` action matches githubEventRelease(release) with `published` activity type",
desc: "HookEventRelease(release) `published` action matches GithubEventRelease(release) with `published` activity type",
triggedEvent: webhook_module.HookEventRelease,
payload: &api.ReleasePayload{Action: api.HookReleasePublished},
yamlOn: "on:\n release:\n types: [published]",
expected: true,
},
{
desc: "HookEventPackage(package) `created` action doesn't match githubEventRegistryPackage(registry_package) with `updated` activity type",
desc: "HookEventPackage(package) `created` action doesn't match GithubEventRegistryPackage(registry_package) with `updated` activity type",
triggedEvent: webhook_module.HookEventPackage,
payload: &api.PackagePayload{Action: api.HookPackageCreated},
yamlOn: "on:\n registry_package:\n types: [updated]",
expected: false,
},
{
desc: "HookEventWiki(wiki) matches githubEventGollum(gollum)",
desc: "HookEventWiki(wiki) matches GithubEventGollum(gollum)",
triggedEvent: webhook_module.HookEventWiki,
payload: nil,
yamlOn: "on: gollum",

View File

@ -17,6 +17,7 @@ import (
// Notifier defines an interface to notify receiver
type Notifier interface {
Run()
NotifyAdoptRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository)
NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository)
NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository)
NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository)

View File

@ -145,6 +145,10 @@ func (*NullNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *user_mod
func (*NullNotifier) NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
}
// NotifyAdoptRepository places a place holder function
func (*NullNotifier) NotifyAdoptRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
}
// NotifyDeleteRepository places a place holder function
func (*NullNotifier) NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) {
}

View File

@ -29,6 +29,10 @@ func NewNotifier() base.Notifier {
return &indexerNotifier{}
}
func (r *indexerNotifier) NotifyAdoptRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
r.NotifyMigrateRepository(ctx, doer, u, repo)
}
func (r *indexerNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository,
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
) {

View File

@ -274,6 +274,13 @@ func NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo
}
}
// NotifyAdoptRepository notifies the adoption of a repository to notifiers
func NotifyAdoptRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
for _, notifier := range notifiers {
notifier.NotifyAdoptRepository(ctx, doer, u, repo)
}
}
// NotifyMigrateRepository notifies create repository to notifiers
func NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
for _, notifier := range notifiers {

View File

@ -89,6 +89,12 @@ func (s *stringWithDefault) Set(v string) {
// InitWorkPathAndCommonConfig will set AppWorkPath, CustomPath and CustomConf, init default config provider by CustomConf and load common settings,
func InitWorkPathAndCommonConfig(getEnvFn func(name string) string, args ArgWorkPathAndCustomConf) {
InitWorkPathAndCfgProvider(getEnvFn, args)
LoadCommonSettings()
}
// InitWorkPathAndCfgProvider will set AppWorkPath, CustomPath and CustomConf, init default config provider by CustomConf
func InitWorkPathAndCfgProvider(getEnvFn func(name string) string, args ArgWorkPathAndCustomConf) {
tryAbsPath := func(paths ...string) string {
s := paths[len(paths)-1]
for i := len(paths) - 2; i >= 0; i-- {
@ -186,6 +192,4 @@ func InitWorkPathAndCommonConfig(getEnvFn func(name string) string, args ArgWork
AppWorkPath = tmpWorkPath.Value
CustomPath = tmpCustomPath.Value
CustomConf = tmpCustomConf.Value
LoadCommonSettings()
}

View File

@ -696,6 +696,7 @@ requires_activation = Requires activation
primary_email = Make Primary
activate_email = Send Activation
activations_pending = Activations Pending
can_not_add_email_activations_pending = There is a pending activation, try again in a few minutes if you want to add a new email.
delete_email = Remove
email_deletion = Remove Email Address
email_deletion_desc = The email address and related information will be removed from your account. Git commits by this email address will remain unchanged. Continue?

View File

@ -120,11 +120,14 @@ unpin=Открепить
artifacts=Артефакты
concept_system_global=Глобально
concept_user_individual=Индивидуально
concept_code_repository=Репозиторий
concept_user_organization=Организация
show_timestamps=Отображать время
show_log_seconds=Показывать секунды
show_full_screen=Показать во весь экран
[aria]
navbar=Панель навигации
@ -133,6 +136,8 @@ footer.software=О программе
footer.links=Ссылки
[heatmap]
number_of_contributions_in_the_last_12_months=Принимал(а) участие %s раз за последние 12 месяцев
no_contributions=Не принимал(а) участия
less=Меньше
more=Больше
@ -572,6 +577,7 @@ target_branch_not_exist=Целевая ветка не существует.
[user]
change_avatar=Изменить свой аватар…
joined_on=Присоединил(ся/ась) %s
repositories=Репозитории
activity=Активность
followers=Подписчики
@ -767,6 +773,8 @@ ssh_principal_deletion_desc=Удаление принципала сертифи
ssh_key_deletion_success=Ключ SSH удален.
gpg_key_deletion_success=Ключ GPG удалён.
ssh_principal_deletion_success=Принципал удалён.
added_on=Добавлено %s
valid_until_date=Действительно до %s
valid_forever=Действителен навсегда
last_used=Последний раз использовался
no_activity=Еще не применялся
@ -798,7 +806,13 @@ access_token_deletion_cancel_action=Отменить
access_token_deletion_confirm_action=Удалить
access_token_deletion_desc=Удаление токена отзовёт доступ к вашей учетной записи у приложений, использующих его. Это действие не может быть отменено. Продолжить?
delete_token_success=Токен удалён. Приложения, использующие его, больше не имеют доступа к вашему аккаунту.
repo_and_org_access=Доступ к репозиторию и организации
permissions_public_only=Только публичные
permissions_access_all=Все (публичные, приватные и ограниченные)
select_permissions=Выбрать разрешения
scoped_token_desc=Выбранные полномочия токена ограничивают аутентификацию только соответствующими маршрутами <a %s>API</a>. Читайте <a %s>документацию</a> для получения дополнительной информации.
at_least_one_permission=Необходимо выбрать хотя бы одно разрешение для создания токена
permissions_list=Разрешения:
manage_oauth2_applications=Управление приложениями OAuth2
edit_oauth2_application=Изменить приложение OAuth2
@ -957,6 +971,7 @@ mirror_password_blank_placeholder=(Отменено)
mirror_password_help=Смените имя пользователя для удаления пароля.
watchers=Наблюдатели
stargazers=Звездочеты
stars_remove_warning=Данное действие удалит все звёзды из этого репозитория.
forks=Форки
reactions_more=и ещё %d
unit_disabled=Администратор сайта отключил этот раздел репозитория.
@ -1000,6 +1015,7 @@ template.one_item=Необходимо выбрать хотя бы один э
template.invalid=Необходимо выбрать хранилище шаблонов
archive.title=Это репозиторий в архиве. Вы можете его клонировать или просматривать файлы, но не вносить изменения или открывать задачи/запросы на слияние.
archive.title_date=Этот репозиторий архивирован %s. Вы можете смотреть файлы или клонировать его, но не можете вносить изменения, открывать задачи или делать запросы на слияние.
archive.issue.nocomment=Этот репозиторий в архиве. Вы не можете комментировать задачи.
archive.pull.nocomment=Это репозиторий в архиве. Вы не можете комментировать запросы на слияние.
@ -1683,7 +1699,7 @@ pulls.no_merge_access=У вас нет права для слияния данн
pulls.merge_pull_request=Создать коммит на слияние
pulls.rebase_merge_pull_request=Выполнить Rebase, а затем fast-forward слияние
pulls.rebase_merge_commit_pull_request=Выполнить rebase, а затем создать коммит слияния
pulls.squash_merge_pull_request=Создать объединенный (squash) коммит
pulls.squash_merge_pull_request=Создать объединённый коммит
pulls.merge_manually=Слито вручную
pulls.merge_commit_id=ID коммита слияния
pulls.require_signed_wont_sign=Данная ветка ожидает подписанные коммиты, однако слияние не будет подписано
@ -1695,6 +1711,7 @@ pulls.rebase_conflict=Слияние не удалось: Произошел к
pulls.rebase_conflict_summary=Сообщение об ошибке
pulls.unrelated_histories=Слияние не удалось: У источника и цели слияния нет общей истории. Совет: попробуйте другую стратегию
pulls.merge_out_of_date=Ошибка слияния: при создании слияния база данных была обновлена. Подсказка: попробуйте ещё раз.
pulls.head_out_of_date=Ошибка слияния: во время слияния головной коммит был обновлён. Попробуйте ещё раз.
pulls.push_rejected=Слияние не удалось: отправка была отклонена. Проверьте Git-хуки для этого репозитория.
pulls.push_rejected_summary=Полная ошибка отклонения
pulls.push_rejected_no_message=Слияние не удалось: отправка была отклонена, но сервер не указал причину.<br>Проверьте Git-хуки для этого репозитория
@ -1899,6 +1916,10 @@ settings.githooks=Git-хуки
settings.basic_settings=Основные параметры
settings.mirror_settings=Настройки зеркалирования
settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=В настоящее время это можно сделать только в меню «Новая миграция». Для получения дополнительной информации, пожалуйста, ознакомьтесь:
settings.mirror_settings.docs.no_new_mirrors=Ваш репозиторий зеркалирует изменения в другой репозиторий или из него. Пожалуйста, имейте в виду, что в данный момент невозможно создавать новые зеркала.
settings.mirror_settings.docs.can_still_use=Хотя вы не можете изменять существующие зеркала или создавать новые, вы можете по-прежнему использовать существующее зеркало.
settings.mirror_settings.docs.pull_mirror_instructions=Чтобы настроить pull-зеркало, пожалуйста, ознакомьтесь:
settings.mirror_settings.docs.doc_link_title=Как зеркалировать репозитории?
settings.mirror_settings.docs.pulling_remote_title=Получение из удалённого репозитория
settings.mirror_settings.mirrored_repository=Синхронизированное хранилище
settings.mirror_settings.direction=Направление
@ -2012,6 +2033,7 @@ settings.delete_notices_2=- Эта операция навсегда удали
settings.delete_notices_fork_1=- Все форки станут независимыми репозиториями после удаления.
settings.deletion_success=Репозиторий удалён.
settings.update_settings_success=Настройки репозитория обновлены.
settings.update_settings_no_unit=Должно быть разрешено хоть какое-то взаимодействие с репозиторием.
settings.confirm_delete=Удалить репозиторий
settings.add_collaborator=Добавить соавтора
settings.add_collaborator_success=Соавтор добавлен.
@ -2111,6 +2133,7 @@ settings.event_pull_request_sync=Синхронизация запроса на
settings.event_pull_request_sync_desc=Запрос на слияние синхронизирован.
settings.event_pull_request_review_request=Запрошена рецензия для запроса на слияние
settings.event_pull_request_review_request_desc=Создан или удалён запрос на рецензию для запроса на слияние.
settings.event_pull_request_approvals=Утверждения запросов на слияние
settings.event_package=Пакеты
settings.event_package_desc=Пакет создан или удален в репозитории.
settings.branch_filter=Фильтр веток
@ -2185,8 +2208,11 @@ settings.protect_merge_whitelist_committers_desc=Разрешить приним
settings.protect_merge_whitelist_users=Пользователи с правом на слияние:
settings.protect_merge_whitelist_teams=Команды, члены которых обладают правом на слияние:
settings.protect_check_status_contexts=Включить проверку статуса
settings.protect_status_check_patterns=Шаблоны проверки состояния:
settings.protect_check_status_contexts_desc=Требуется пройти проверку состояния перед слиянием. Выберите, какие проверки состояния должны быть пройдены, прежде чем ветви можно будет объединить в ветвь, соответствующую этому правилу. Если этот параметр включен, коммиты сначала должны быть перемещены в другую ветвь, а затем объединены или перемещены непосредственно в ветвь, соответствующую этому правилу, после прохождения проверки состояния. Если контексты не выбраны, то последняя фиксация должна быть успешной независимо от контекста.
settings.protect_check_status_contexts_list=Проверки состояния за последнюю неделю для этого репозитория
settings.protect_invalid_status_check_pattern=Неверный шаблон проверки состояния: «%s».
settings.protect_no_valid_status_check_patterns=Нет допустимых шаблонов проверки состояния.
settings.protect_required_approvals=Необходимые одобрения:
settings.protect_required_approvals_desc=Разрешить принятие запроса на слияние только с достаточным количеством положительных отзывов.
settings.protect_approvals_whitelist_enabled=Ограничить утверждения белым списком пользователей или команд
@ -2198,6 +2224,7 @@ settings.dismiss_stale_approvals_desc=Когда новые коммиты, из
settings.require_signed_commits=Требовать подписанные коммиты
settings.require_signed_commits_desc=Отклонить отправку изменений в эту ветку, если они не подписаны или не проверяемы.
settings.protect_branch_name_pattern=Шаблон имени для защищённых веток
settings.protect_patterns=Шаблоны
settings.protect_protected_file_patterns=Шаблоны защищённых файлов (разделённые точкой с запятой ';'):
settings.protect_protected_file_patterns_desc=Защищенные файлы нельзя изменить напрямую, даже если пользователь имеет право добавлять, редактировать или удалять файлы в этой ветке. Можно указать несколько шаблонов, разделяя их точкой с запятой (';'). О синтаксисе шаблонов читайте в документации <a href='https://godoc.org/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a>. Примеры: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
settings.protect_unprotected_file_patterns=Шаблоны незащищённых файлов (разделённые точкой с запятой ';'):
@ -2412,10 +2439,13 @@ branch.protected_deletion_failed=Ветка «%s» защищена. Её нел
branch.default_deletion_failed=Ветка «%s» является веткой по умолчанию. Её нельзя удалить.
branch.restore=Восстановить ветку «%s»
branch.download=Скачать ветку «%s»
branch.rename=Переименовать ветку «%s»
branch.included_desc=Эта ветка является частью ветки по умолчанию
branch.included=Включено
branch.create_new_branch=Создать ветку из ветви:
branch.confirm_create_branch=Создать ветку
branch.warning_rename_default_branch=Вы переименовываете ветку по умолчанию.
branch.rename_branch_to=Переименовать ветку «%s» в:
branch.confirm_rename_branch=Переименовать ветку
branch.create_branch_operation=Создать ветку
branch.new_branch=Создать новую ветку
@ -2746,6 +2776,7 @@ repos.size=Размер
packages.package_manage_panel=Управление пакетами
packages.total_size=Общий размер: %s
packages.unreferenced_size=Размер по ссылке: %s
packages.owner=Владелец
packages.creator=Автор
packages.name=Наименование
@ -3012,8 +3043,10 @@ config.git_pull_timeout=Лимит времени получения измен
config.git_gc_timeout=Лимит времени сборки мусора
config.log_config=Конфигурация журнала
config.logger_name_fmt=Журнал: %s
config.disabled_logger=Отключен
config.access_log_mode=Режим доступа к журналу
config.access_log_template=Шаблон журнала доступа
config.xorm_log_sql=Лог SQL
config.get_setting_failed=Получить параметр %s не удалось
@ -3030,6 +3063,7 @@ monitor.execute_times=Количество выполнений
monitor.process=Запущенные процессы
monitor.stacktrace=Трассировки стека
monitor.processes_count=%d процессов
monitor.download_diagnosis_report=Скачать диагностический отчёт
monitor.desc=Описание
monitor.start=Время начала
monitor.execute_time=Время выполнения
@ -3050,9 +3084,10 @@ monitor.queue.numberinqueue=Позиция в очереди
monitor.queue.review=Просмотр конфигурации
monitor.queue.review_add=Просмотреть/добавить рабочих
monitor.queue.settings.title=Настройки пула
monitor.queue.settings.desc=Пулы увеличиваются динамически в ответ на блокировку очередей своих рабочих.
monitor.queue.settings.maxnumberworkers=Максимальное количество рабочих
monitor.queue.settings.maxnumberworkers.placeholder=В настоящее время %[1]d
monitor.queue.settings.maxnumberworkers.error=Максимальное количество работников должно быть числом
monitor.queue.settings.maxnumberworkers.error=Максимальное количество рабочих должно быть числом
monitor.queue.settings.submit=Обновить настройки
monitor.queue.settings.changed=Настройки обновлены
monitor.queue.settings.remove_all_items=Удалить все
@ -3166,7 +3201,7 @@ error.unit_not_allowed=У вас нет доступа к этому разде
title=Пакеты
desc=Управление пакетами репозитория.
empty=Пока нет пакетов.
empty.documentation=Дополнительную информацию о реестре пакетов можно найти в <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/usage/packages/overview/">документации</a>.
empty.documentation=Дополнительную информацию о реестре пакетов можно найти в <a target="_blank" rel="noopener noreferrer" href="%s">документации</a>.
empty.repo=Вы загрузили пакет, но он здесь не отображается? Перейдите в <a href="%[1]s">настройки пакета</a> и свяжите его с этим репозиторием.
filter.type=Тип
filter.type.all=Все

View File

@ -9,6 +9,7 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
secret_model "code.gitea.io/gitea/models/secret"
actions_module "code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
@ -54,8 +55,10 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string {
secrets := map[string]string{}
if task.Job.Run.IsForkPullRequest {
if task.Job.Run.IsForkPullRequest && task.Job.Run.TriggerEvent != actions_module.GithubEventPullRequestTarget {
// ignore secrets for fork pull request
// for the tasks triggered by pull_request_target event, they could access the secrets because they will run in the context of the base branch
// see the documentation: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
return secrets
}
@ -116,6 +119,14 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
event := map[string]interface{}{}
_ = json.Unmarshal([]byte(t.Job.Run.EventPayload), &event)
// TriggerEvent is added in https://github.com/go-gitea/gitea/pull/25229
// This fallback is for the old ActionRun that doesn't have the TriggerEvent field
// and should be removed in 1.22
eventName := t.Job.Run.TriggerEvent
if eventName == "" {
eventName = t.Job.Run.Event.Event()
}
baseRef := ""
headRef := ""
if pullPayload, err := t.Job.Run.GetPullRequestEventPayload(); err == nil && pullPayload.PullRequest != nil && pullPayload.PullRequest.Base != nil && pullPayload.PullRequest.Head != nil {
@ -137,7 +148,7 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
"base_ref": baseRef, // string, The base_ref or target branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either pull_request or pull_request_target.
"env": "", // string, Path on the runner to the file that sets environment variables from workflow commands. This file is unique to the current step and is a different file for each step in a job. For more information, see "Workflow commands for GitHub Actions."
"event": event, // object, The full event webhook payload. You can access individual properties of the event using this context. This object is identical to the webhook payload of the event that triggered the workflow run, and is different for each event. The webhooks for each GitHub Actions event is linked in "Events that trigger workflows." For example, for a workflow run triggered by the push event, this object contains the contents of the push webhook payload.
"event_name": t.Job.Run.Event.Event(), // string, The name of the event that triggered the workflow run.
"event_name": eventName, // string, The name of the event that triggered the workflow run.
"event_path": "", // string, The path to the file on the runner that contains the full event webhook payload.
"graphql_url": "", // string, The URL of the GitHub GraphQL API.
"head_ref": headRef, // string, The head_ref or source branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either pull_request or pull_request_target.

View File

@ -383,7 +383,7 @@ func ViewProject(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplProjectsView)
}
func getActionIssues(ctx *context.Context) []*issues_model.Issue {
func getActionIssues(ctx *context.Context) issues_model.IssueList {
commaSeparatedIssueIDs := ctx.FormString("issue_ids")
if len(commaSeparatedIssueIDs) == 0 {
return nil
@ -429,9 +429,14 @@ func UpdateIssueProject(ctx *context.Context) {
return
}
if err := issues.LoadProjects(ctx); err != nil {
ctx.ServerError("LoadProjects", err)
return
}
projectID := ctx.FormInt64("id")
for _, issue := range issues {
oldProjectID := issue.ProjectID()
oldProjectID := issue.Project.ID
if oldProjectID == projectID {
continue
}

View File

@ -1988,7 +1988,7 @@ func checkIssueRights(ctx *context.Context, issue *issues_model.Issue) {
}
}
func getActionIssues(ctx *context.Context) []*issues_model.Issue {
func getActionIssues(ctx *context.Context) issues_model.IssueList {
commaSeparatedIssueIDs := ctx.FormString("issue_ids")
if len(commaSeparatedIssueIDs) == 0 {
return nil
@ -2804,7 +2804,7 @@ func UpdateIssueStatus(ctx *context.Context) {
log.Warn("Unrecognized action: %s", action)
}
if _, err := issues_model.IssueList(issues).LoadRepositories(ctx); err != nil {
if _, err := issues.LoadRepositories(ctx); err != nil {
ctx.ServerError("LoadRepositories", err)
return
}

View File

@ -378,9 +378,14 @@ func UpdateIssueProject(ctx *context.Context) {
return
}
if err := issues.LoadProjects(ctx); err != nil {
ctx.ServerError("LoadProjects", err)
return
}
projectID := ctx.FormInt64("id")
for _, issue := range issues {
oldProjectID := issue.ProjectID()
oldProjectID := issue.Project.ID
if oldProjectID == projectID {
continue
}

View File

@ -273,6 +273,16 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
return nil, nil
}
if rctx.SidebarTocNode != nil {
sb := &strings.Builder{}
err = markdown.SpecializedMarkdown().Renderer().Render(sb, nil, rctx.SidebarTocNode)
if err != nil {
log.Error("Failed to render wiki sidebar TOC: %v", err)
} else {
ctx.Data["sidebarTocContent"] = sb.String()
}
}
if !isSideBar {
buf.Reset()
ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"], err = renderFn(sidebarContent)
@ -303,16 +313,6 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
ctx.Data["footerPresent"] = false
}
if rctx.SidebarTocNode != nil {
sb := &strings.Builder{}
err = markdown.SpecializedMarkdown().Renderer().Render(sb, nil, rctx.SidebarTocNode)
if err != nil {
log.Error("Failed to render wiki sidebar TOC: %v", err)
} else {
ctx.Data["sidebarTocContent"] = sb.String()
}
}
// get commit count - wiki revisions
commitsCount, _ := wikiRepo.FileCommitsCount(wiki_service.DefaultBranch, pageFilename)
ctx.Data["CommitCount"] = commitsCount

View File

@ -142,13 +142,46 @@ func notify(ctx context.Context, input *notifyInput) error {
return fmt.Errorf("gitRepo.GetCommit: %w", err)
}
var detectedWorkflows []*actions_module.DetectedWorkflow
workflows, err := actions_module.DetectWorkflows(commit, input.Event, input.Payload)
if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err)
}
if len(workflows) == 0 {
log.Trace("repo %s with commit %s couldn't find workflows", input.Repo.RepoPath(), commit.ID)
} else {
for _, wf := range workflows {
if wf.TriggerEvent != actions_module.GithubEventPullRequestTarget {
wf.Ref = ref
detectedWorkflows = append(detectedWorkflows, wf)
}
}
}
if input.PullRequest != nil {
// detect pull_request_target workflows
baseRef := git.BranchPrefix + input.PullRequest.BaseBranch
baseCommit, err := gitRepo.GetCommit(baseRef)
if err != nil {
return fmt.Errorf("gitRepo.GetCommit: %w", err)
}
baseWorkflows, err := actions_module.DetectWorkflows(baseCommit, input.Event, input.Payload)
if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err)
}
if len(baseWorkflows) == 0 {
log.Trace("repo %s with commit %s couldn't find pull_request_target workflows", input.Repo.RepoPath(), baseCommit.ID)
} else {
for _, wf := range baseWorkflows {
if wf.TriggerEvent == actions_module.GithubEventPullRequestTarget {
wf.Ref = baseRef
detectedWorkflows = append(detectedWorkflows, wf)
}
}
}
}
if len(detectedWorkflows) == 0 {
return nil
}
@ -172,18 +205,19 @@ func notify(ctx context.Context, input *notifyInput) error {
}
}
for id, content := range workflows {
for _, dwf := range detectedWorkflows {
run := &actions_model.ActionRun{
Title: strings.SplitN(commit.CommitMessage, "\n", 2)[0],
RepoID: input.Repo.ID,
OwnerID: input.Repo.OwnerID,
WorkflowID: id,
WorkflowID: dwf.EntryName,
TriggerUserID: input.Doer.ID,
Ref: ref,
CommitSHA: commit.ID.String(),
Ref: dwf.Ref,
CommitSHA: dwf.Commit.ID.String(),
IsForkPullRequest: isForkPullRequest,
Event: input.Event,
EventPayload: string(p),
TriggerEvent: dwf.TriggerEvent,
Status: actions_model.StatusWaiting,
}
if need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer); err != nil {
@ -193,7 +227,7 @@ func notify(ctx context.Context, input *notifyInput) error {
run.NeedApproval = need
}
jobs, err := jobparser.Parse(content)
jobs, err := jobparser.Parse(dwf.Content)
if err != nil {
log.Error("jobparser.Parse: %v", err)
continue
@ -259,8 +293,10 @@ func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_mo
}
func ifNeedApproval(ctx context.Context, run *actions_model.ActionRun, repo *repo_model.Repository, user *user_model.User) (bool, error) {
// don't need approval if it's not a fork PR
if !run.IsForkPullRequest {
// 1. don't need approval if it's not a fork PR
// 2. don't need approval if the event is `pull_request_target` since the workflow will run in the context of base branch
// see https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks#about-workflow-runs-from-public-forks
if !run.IsForkPullRequest || run.TriggerEvent == actions_module.GithubEventPullRequestTarget {
return false, nil
}

View File

@ -70,9 +70,17 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts repo_mo
if err := repo_module.CreateRepositoryByExample(ctx, doer, u, repo, true, false); err != nil {
return err
}
if err := adoptRepository(ctx, repoPath, doer, repo, opts); err != nil {
// Re-fetch the repository from database before updating it (else it would
// override changes that were done earlier with sql)
if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil {
return fmt.Errorf("getRepositoryByID: %w", err)
}
if err := adoptRepository(ctx, repoPath, doer, repo, opts.DefaultBranch); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err)
}
if err := repo_module.CheckDaemonExportOK(ctx, repo); err != nil {
return fmt.Errorf("checkDaemonExportOK: %w", err)
}
@ -95,12 +103,12 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts repo_mo
return nil, err
}
notification.NotifyCreateRepository(ctx, doer, u, repo)
notification.NotifyAdoptRepository(ctx, doer, u, repo)
return repo, nil
}
func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts repo_module.CreateRepoOptions) (err error) {
func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, defaultBranch string) (err error) {
isExist, err := util.IsExist(repoPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
@ -114,12 +122,6 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r
return fmt.Errorf("createDelegateHooks: %w", err)
}
// Re-fetch the repository from database before updating it (else it would
// override changes that were done earlier with sql)
if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil {
return fmt.Errorf("getRepositoryByID: %w", err)
}
repo.IsEmpty = false
// Don't bother looking this repo in the context it won't be there
@ -129,8 +131,8 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r
}
defer gitRepo.Close()
if len(opts.DefaultBranch) > 0 {
repo.DefaultBranch = opts.DefaultBranch
if len(defaultBranch) > 0 {
repo.DefaultBranch = defaultBranch
if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil {
return fmt.Errorf("setDefaultBranch: %w", err)

View File

@ -11,16 +11,16 @@
</a>
<!-- mobile right menu, it must be here because in mobile view, each item is a flex column, the first item is a full row column -->
<div class="ui secondary menu item navbar-mobile-right gt-gap-2">
<div class="ui secondary menu item navbar-mobile-right">
{{if .IsSigned}}
<a class="item mobile-right-item gt-mr-2 gt-p-3" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{.locale.Tr "notifications"}}" aria-label="{{.locale.Tr "notifications"}}">
<a id="mobile-notifications-icon" class="item gt-w-auto gt-p-3" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{.locale.Tr "notifications"}}" aria-label="{{.locale.Tr "notifications"}}">
<div class="gt-relative">
{{svg "octicon-bell"}}
<span class="notification_count{{if not $notificationUnreadCount}} gt-hidden{{end}}">{{$notificationUnreadCount}}</span>
</div>
</a>
{{end}}
<button class="item mobile-right-item ui icon mini button gt-p-3 gt-m-0" id="navbar-expand-toggle">{{svg "octicon-three-bars"}}</button>
<button class="item gt-w-auto ui icon mini button gt-p-3 gt-m-0" id="navbar-expand-toggle">{{svg "octicon-three-bars"}}</button>
</div>

View File

@ -165,13 +165,6 @@
<div class="item">item</div>
</div>
</div>
<div class="ui button dropdown">
<span class="text">button dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="item">item</div>
</div>
</div>
<div class="ui search selection dropdown">
<span class="text">search ...</span>
<input name="value" class="search">
@ -212,18 +205,39 @@
<div>
<div class="ui dropdown mini button">
<span class="text">small dropdown</span>
{{svg "octicon-triangle-down" 12 "dropdown icon"}}
<div class="menu">
<div class="item">item</div>
</div>
<span class="text">mini dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown tiny button">
<span class="text">tiny dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui button dropdown">
<span class="text">button dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown large button">
<span class="text">large dropdown</span>
{{svg "octicon-triangle-down" 18 "dropdown icon"}}
<div class="menu">
<div class="item">item</div>
</div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
<div>
<div class="ui dropdown mini compact button">
<span class="text">mini compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown tiny compact button">
<span class="text">tiny compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui button compact dropdown">
<span class="text">button compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown large compact button">
<span class="text">large compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
</div>

View File

@ -54,9 +54,9 @@
{{$description := .DescriptionHTML $.Context}}
{{if $description}}<p>{{$description}}</p>{{end}}
{{if .Topics}}
<div class="ui tags">
<div class="gt-df gt-fw gt-gap-2 gt-mb-3">
{{range .Topics}}
{{if ne . ""}}<a href="{{AppSubUrl}}/explore/repos?q={{.}}&topic=1"><div class="ui small label topic">{{.}}</div></a>{{end}}
{{if ne . ""}}<a class="ui label" href="{{AppSubUrl}}/explore/repos?q={{.}}&topic=1">{{.}}</a>{{end}}
{{end}}
</div>
{{end}}

View File

@ -26,7 +26,8 @@
{{.locale.Tr "repo.diff.browse_source"}}
</a>
{{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}}
<div class="ui primary tiny floating dropdown icon button">{{.locale.Tr "repo.commit.operations"}}
<div class="ui dropdown primary tiny button">
{{.locale.Tr "repo.commit.operations"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="ui header">{{.locale.Tr "repo.commit.operations"}}</div>

View File

@ -49,7 +49,7 @@
</div>
</div>
<script id="diff-data-script" type="module">
const diffDataFiles = [{{range $i, $file := .Diff.Files}}{Name:"{{$file.Name}}",NameHash:"{{$file.NameHash}}",Type:{{$file.Type}},IsBin:{{$file.IsBin}},Addition:{{$file.Addition}},Deletion:{{$file.Deletion}}},{{end}}];
const diffDataFiles = [{{range $i, $file := .Diff.Files}}{Name:"{{$file.Name}}",NameHash:"{{$file.NameHash}}",Type:{{$file.Type}},IsBin:{{$file.IsBin}},Addition:{{$file.Addition}},Deletion:{{$file.Deletion}},IsViewed:{{$file.IsViewed}}},{{end}}];
const diffData = {
isIncomplete: {{.Diff.IsIncomplete}},
tooManyFilesMessage: "{{$.locale.Tr "repo.diff.too_many_files"}}",

View File

@ -192,7 +192,7 @@
{{if .HasPullRequest}}
<div class="ui segment grid title">
<div class="twelve wide column issue-title">
{{.locale.Tr "repo.pulls.has_pull_request" (Escape $.RepoLink) (Escape $.RepoRelPath) .PullRequest.Index | Safe}}
{{.locale.Tr "repo.pulls.has_pull_request" (print (Escape $.RepoLink) "/pulls/" .PullRequest.Issue.Index) (Escape $.RepoRelPath) .PullRequest.Index | Safe}}
<h1>
<span id="issue-title">{{RenderIssueTitle $.Context .PullRequest.Issue.Title $.RepoLink $.Repository.ComposeMetas}}</span>
<span class="index">#{{.PullRequest.Issue.Index}}</span>

View File

@ -192,9 +192,9 @@
</div>
</div>
<div class="ui select-project list">
<span class="no-select item {{if .Issue.ProjectID}}gt-hidden{{end}}">{{.locale.Tr "repo.issues.new.no_projects"}}</span>
<span class="no-select item {{if .Issue.Project}}gt-hidden{{end}}">{{.locale.Tr "repo.issues.new.no_projects"}}</span>
<div class="selected">
{{if .Issue.ProjectID}}
{{if .Issue.Project}}
<a class="item muted sidebar-item-link" href="{{.Issue.Project.Link}}">
{{svg .Issue.Project.IconName 18 "gt-mr-3"}}{{.Issue.Project.Title}}
</a>

View File

@ -3,9 +3,9 @@
<div class="ui middle very relaxed page grid">
<div class="column">
{{template "repo/migrate/helper" .}}
<div class="ui three stackable cards">
<div class="ui cards migrate-entries">
{{range .Services}}
<a class="ui card gt-df gt-ac" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}&org={{$.Org}}&mirror={{$.Mirror}}">
<a class="ui card migrate-entry gt-df gt-ac" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}&org={{$.Org}}&mirror={{$.Mirror}}">
{{if eq .Name "github"}}
{{svg "octicon-mark-github" 184 "gt-p-4"}}
{{else if eq .Name "gitlab"}}

View File

@ -4,20 +4,22 @@
{{$title := .title}}
<div class="ui container">
<div class="ui stackable grid">
<div class="ui eight wide column text right gt-df gt-ac gt-je">
<div class="ui eight wide column">
<div class="ui header">
<a class="file-revisions-btn ui basic button" title="{{.locale.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}"><span>{{.revision}}</span> {{svg "octicon-home"}}</a>
{{$title}}
<div class="ui sub header gt-word-break">
{{$timeSince := TimeSince .Author.When $.locale}}
{{.locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
</div>
</div>
</div>
<div class="ui eight wide column text right">
<div class="ui action small input" id="clone-panel">
{{template "repo/clone_buttons" .}}
{{template "repo/clone_script" .}}
</div>
</div>
<div class="ui header eight wide column">
<a class="file-revisions-btn ui basic button" title="{{.locale.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}" ><span>{{.revision}}</span> {{svg "octicon-home"}}</a>
{{$title}}
<div class="ui sub header gt-word-break">
{{$timeSince := TimeSince .Author.When $.locale}}
{{.locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
</div>
</div>
</div>
<h2 class="ui top header">{{.locale.Tr "repo.wiki.wiki_page_revisions"}}</h2>
<div class="gt-mt-4">

View File

@ -2,8 +2,8 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository wiki start">
{{template "repo/header" .}}
<div class="ui container">
<div class="ui center segment">
{{svg "octicon-book" 32}}
<div class="ui center segment gt-py-5">
{{svg "octicon-book" 48}}
<h2>{{.locale.Tr "repo.wiki.welcome"}}</h2>
<p>{{.locale.Tr "repo.wiki.welcome_desc"}}</p>
{{if and .CanWriteWiki (not .Repository.IsMirror)}}

View File

@ -63,39 +63,41 @@
<p>{{.FormatWarning}}</p>
</div>
{{end}}
<div class="ui gt-mt-0 {{if or .sidebarPresent .sidebarTocContent}}grid equal width{{end}}">
<div class="ui {{if or .sidebarPresent .sidebarTocContent}}eleven wide column{{else}}gt-ml-0{{end}} segment markup wiki-content-main">
<div class="wiki-content-parts">
{{if .sidebarTocContent}}
<div class="markup wiki-content-sidebar wiki-content-toc">
{{.sidebarTocContent | Safe}}
</div>
{{end}}
<div class="markup wiki-content-main {{if or .sidebarTocContent .sidebarPresent}}with-sidebar{{end}}">
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
{{.content | Safe}}
</div>
{{if or .sidebarPresent .sidebarTocContent}}
<div class="column gt-pt-0">
{{if .sidebarTocContent}}
<div class="ui segment wiki-content-toc">
{{.sidebarTocContent | Safe}}
</div>
{{if .sidebarPresent}}
<div class="markup wiki-content-sidebar">
{{if and .CanWriteWiki (not .Repository.IsMirror)}}
<a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Sidebar?action=_edit" aria-label="{{.locale.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a>
{{end}}
{{if .sidebarPresent}}
<div class="ui segment wiki-content-sidebar">
{{if and .CanWriteWiki (not .Repository.IsMirror)}}
<a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Sidebar?action=_edit" aria-label="{{.locale.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a>
{{end}}
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .sidebarEscapeStatus "root" $}}
{{.sidebarContent | Safe}}
</div>
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .sidebarEscapeStatus "root" $}}
{{.sidebarContent | Safe}}
</div>
{{end}}
<div class="gt-clear-both"></div>
{{if .footerPresent}}
<div class="markup wiki-content-footer">
{{if and .CanWriteWiki (not .Repository.IsMirror)}}
<a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Footer?action=_edit" aria-label="{{.locale.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a>
{{end}}
{{template "repo/unicode_escape_prompt" dict "footerEscapeStatus" .sidebarEscapeStatus "root" $}}
{{.footerContent | Safe}}
</div>
{{end}}
</div>
{{if .footerPresent}}
<div class="ui segment wiki-content-footer">
{{if and .CanWriteWiki (not .Repository.IsMirror)}}
<a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Footer?action=_edit" aria-label="{{.locale.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a>
{{end}}
{{template "repo/unicode_escape_prompt" dict "footerEscapeStatus" .sidebarEscapeStatus "root" $}}
{{.footerContent | Safe}}
</div>
{{end}}
</div>
</div>

View File

@ -128,6 +128,10 @@
{{.locale.Tr "settings.add_email"}}
</button>
</form>
{{/* if ActivationsPending is false, then CanAddEmails must be true, so if CanAddEmails is false, ActivationsPending must be true */}}
{{if not .CanAddEmails}}
<div class="ui warning message">{{.locale.Tr "settings.can_not_add_email_activations_pending"}}</div>
{{end}}
</div>
<h4 class="ui top attached error header">

View File

@ -1,3 +1,5 @@
{{/* No account links, no way to add account links: Menu will not be shown. */}}
{{if or .AccountLinks .OrderedOAuth2Names}}
<h4 class="ui top attached header">
{{.locale.Tr "settings.manage_account_links"}}
{{if .OrderedOAuth2Names}}
@ -23,20 +25,18 @@
<div class="item">
{{.locale.Tr "settings.manage_account_links_desc"}}
</div>
{{if .AccountLinks}}
{{range $loginSource, $provider := .AccountLinks}}
<div class="item gt-df gt-ac">
<div class="gt-f1">
<span data-tooltip-content="{{$provider}}">
{{$loginSource.Name}}
{{if $loginSource.IsActive}}<span class="text primary">{{$.locale.Tr "repo.settings.active"}}</span>{{end}}
</span>
</div>
<button class="ui red tiny button delete-button" data-modal-id="delete-account-link" data-url="{{AppSubUrl}}/user/settings/security/account_link" data-id="{{$loginSource.ID}}">
{{$.locale.Tr "settings.delete_key"}}
</button>
{{range $loginSource, $provider := .AccountLinks}}
<div class="item gt-df gt-ac">
<div class="gt-f1">
<span data-tooltip-content="{{$provider}}">
{{$loginSource.Name}}
{{if $loginSource.IsActive}}<span class="text primary">{{$.locale.Tr "repo.settings.active"}}</span>{{end}}
</span>
</div>
{{end}}
<button class="ui red tiny button delete-button" data-modal-id="delete-account-link" data-url="{{AppSubUrl}}/user/settings/security/account_link" data-id="{{$loginSource.ID}}">
{{$.locale.Tr "settings.delete_key"}}
</button>
</div>
{{end}}
</div>
</div>
@ -51,3 +51,4 @@
</div>
{{template "base/modal_actions_confirm" .}}
</div>
{{end}}

View File

@ -0,0 +1,144 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"net/url"
"testing"
"time"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
actions_module "code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/git"
repo_module "code.gitea.io/gitea/modules/repository"
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/stretchr/testify/assert"
)
func TestPullRequestTargetEvent(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the base repo
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the forked repo
// create the base repo
baseRepo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_module.CreateRepoOptions{
Name: "repo-pull-request-target",
Description: "test pull-request-target event",
AutoInit: true,
Gitignores: "Go",
License: "MIT",
Readme: "Default",
DefaultBranch: "main",
IsPrivate: false,
})
assert.NoError(t, err)
assert.NotEmpty(t, baseRepo)
// enable actions
err = repo_model.UpdateRepositoryUnits(baseRepo, []repo_model.RepoUnit{{
RepoID: baseRepo.ID,
Type: unit_model.TypeActions,
}}, nil)
assert.NoError(t, err)
// create the forked repo
forkedRepo, err := repo_service.ForkRepository(git.DefaultContext, user2, user3, repo_service.ForkRepoOptions{
BaseRepo: baseRepo,
Name: "forked-repo-pull-request-target",
Description: "test pull-request-target event",
})
assert.NoError(t, err)
assert.NotEmpty(t, forkedRepo)
// add workflow file to the base repo
addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, baseRepo, user2, &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
{
Operation: "create",
TreePath: ".gitea/workflows/pr.yml",
Content: "name: test\non: pull_request_target\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n",
},
},
Message: "add workflow",
OldBranch: "main",
NewBranch: "main",
Author: &files_service.IdentityOptions{
Name: user2.Name,
Email: user2.Email,
},
Committer: &files_service.IdentityOptions{
Name: user2.Name,
Email: user2.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
Committer: time.Now(),
},
})
assert.NoError(t, err)
assert.NotEmpty(t, addWorkflowToBaseResp)
// add a new file to the forked repo
addFileToForkedResp, err := files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, user3, &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
{
Operation: "create",
TreePath: "file_1.txt",
Content: "file1",
},
},
Message: "add file1",
OldBranch: "main",
NewBranch: "fork-branch-1",
Author: &files_service.IdentityOptions{
Name: user3.Name,
Email: user3.Email,
},
Committer: &files_service.IdentityOptions{
Name: user3.Name,
Email: user3.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
Committer: time.Now(),
},
})
assert.NoError(t, err)
assert.NotEmpty(t, addFileToForkedResp)
// create Pull
pullIssue := &issues_model.Issue{
RepoID: baseRepo.ID,
Title: "Test pull-request-target-event",
PosterID: user3.ID,
Poster: user3,
IsPull: true,
}
pullRequest := &issues_model.PullRequest{
HeadRepoID: forkedRepo.ID,
BaseRepoID: baseRepo.ID,
HeadBranch: "fork-branch-1",
BaseBranch: "main",
HeadRepo: forkedRepo,
BaseRepo: baseRepo,
Type: issues_model.PullRequestGitea,
}
err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil)
assert.NoError(t, err)
// load and compare ActionRun
actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{RepoID: baseRepo.ID})
assert.Equal(t, addWorkflowToBaseResp.Commit.SHA, actionRun.CommitSHA)
assert.Equal(t, actions_module.GithubEventPullRequestTarget, actionRun.TriggerEvent)
})
}

View File

@ -35,9 +35,6 @@
font-weight: var(--font-weight-semibold);
width: 220px;
margin-right: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (max-width: 767.98px) {

View File

@ -2192,6 +2192,17 @@ table th[data-sortt-desc] .svg {
- "> .ui.label > .delete.icon": the "x" icon for removing a label item in multiple selection dropdown
*/
.ui.dropdown.mini.button,
.ui.dropdown.tiny.button {
padding-right: 20px;
}
.ui.dropdown.button {
padding-right: 22px;
}
.ui.dropdown.large.button {
padding-right: 24px;
}
/* Gitea uses SVG images instead of Fomantic builtin "<i>" font icons, so we need to reset the icon styles */
.ui.ui.dropdown > .icon.icon {
position: initial; /* plain dropdown and button dropdown use flex layout for icons */

View File

@ -32,10 +32,6 @@
font-size: 12px;
}
.ui.repository.list .item .ui.tags {
margin-bottom: 0.5rem;
}
.ui.repository.list .repo-title .labels {
word-break: normal;
flex-shrink: 0;

View File

@ -75,6 +75,7 @@ Gitea's private styles use `g-` prefix.
.gt-self-start { align-self: flex-start !important; }
.gt-self-end { align-self: flex-end !important; }
.gt-no-underline { text-decoration-line: none !important; }
.gt-w-auto { width: auto !important; }
.gt-overflow-x-auto { overflow-x: auto !important; }
.gt-overflow-x-scroll { overflow-x: scroll !important; }
@ -85,6 +86,7 @@ Gitea's private styles use `g-` prefix.
.gt-float-left { float: left !important; }
.gt-float-right { float: right !important; }
.gt-clear-both { clear: both !important; }
.gt-font-light { font-weight: var(--font-weight-light) !important; }
.gt-font-normal { font-weight: var(--font-weight-normal) !important; }

View File

@ -45,6 +45,7 @@
@import "./repo/issue-list.css";
@import "./repo/list-header.css";
@import "./repo/linebutton.css";
@import "./repo/wiki.css";
@import "./editor/fileeditor.css";
@import "./editor/combomarkdowneditor.css";

View File

@ -514,20 +514,6 @@
padding-left: 2em;
}
.repository.wiki.revisions .ui.container > .ui.stackable.grid {
-ms-flex-direction: row-reverse;
flex-direction: row-reverse;
}
.repository.wiki.revisions .ui.container > .ui.stackable.grid > .header {
margin-top: 0;
}
.repository.wiki.revisions .ui.container > .ui.stackable.grid > .header .sub.header {
padding-left: 52px;
word-break: break-word;
}
.file-revisions-btn {
display: block;
float: left;

View File

@ -34,6 +34,10 @@
justify-content: center;
}
#navbar .dropdown .item {
justify-content: stretch;
}
#navbar a.item:hover,
#navbar button.item:hover {
background: var(--color-nav-hover-bg);
@ -85,19 +89,19 @@
#navbar.navbar-menu-open .item {
display: flex;
width: 100%;
margin: 0;
}
#navbar.navbar-menu-open .navbar-left #navbar-logo {
justify-content: flex-start;
width: 50%;
min-height: 48px;
width: auto;
}
#navbar.navbar-menu-open .navbar-left .navbar-mobile-right {
justify-content: flex-end;
width: 50%;
min-height: 48px;
}
#navbar.navbar-menu-open .mobile-right-item {
width: auto !important;
#navbar #mobile-notifications-icon {
margin-right: 6px !important;
}
}

View File

@ -1887,50 +1887,9 @@
white-space: nowrap;
}
.repository.wiki.start .ui.segment {
padding-top: 70px;
padding-bottom: 100px;
}
.repository.wiki.start .ui.segment .svg {
height: 48px;
}
.repository.wiki.new .ui.attached.tabular.menu.previewtabs {
margin-bottom: 15px;
}
.file-view.markup {
padding: 1em 2em;
}
.wiki-content-main {
padding: 1em 2em !important;
margin-left: 1em !important;
}
.wiki-pages-list .wiki-git-entry {
margin-left: 10px;
display: none;
}
.wiki-pages-list td:hover .wiki-git-entry {
display: inline-block;
}
@media (max-width: 767.98px) {
.repository.wiki .dividing.header .stackable.grid .button {
margin-top: 2px;
margin-bottom: 2px;
}
}
@media (max-width: 767.98px) {
.repository.wiki #clone-panel #repo-clone-url {
width: 160px;
}
}
.repository .activity-header {
display: flex;
justify-content: space-between;
@ -2988,22 +2947,6 @@ tbody.commit-list {
flex-direction: column;
}
.wiki-content-sidebar .ui.message.unicode-escape-prompt p,
.wiki-content-footer .ui.message.unicode-escape-prompt p {
display: none;
}
.wiki-content-toc ul {
margin: 0;
list-style: none;
padding: 5px 0 5px 1em;
}
.wiki-content-toc ul ul {
border-left: 1px var(--color-secondary);
border-left-style: dashed;
}
/* fomantic's last-child selector does not work with hidden last child */
.ui.buttons .unescape-button {
border-top-right-radius: 0.28571429rem;
@ -3157,18 +3100,37 @@ tbody.commit-list {
}
}
.repository.migrate .card {
.migrate-entries {
display: grid !important;
grid-template-columns: repeat(3, 1fr);
gap: 25px;
margin: 0 !important;
}
@media (max-width: 767.98px) {
.migrate-entries {
grid-template-columns: repeat(1, 1fr);
}
}
.migrate-entry {
transition: all 0.1s ease-in-out;
box-shadow: none !important;
border: 1px solid var(--color-secondary);
color: var(--color-text);
color: var(--color-text) !important;
width: auto !important;
margin: 0 !important;
}
.repository.migrate .card:hover {
.migrate-entry:hover {
transform: scale(105%);
box-shadow: 0 0.5rem 1rem var(--color-shadow) !important;
}
.migrate-entry .description {
text-wrap: balance;
}
@media (max-width: 767.98px) {
.repository.file.list #repo-files-table .entry,
.repository.file.list #repo-files-table .commit-list {

63
web_src/css/repo/wiki.css Normal file
View File

@ -0,0 +1,63 @@
.repository.wiki .wiki-pages-list .wiki-git-entry {
margin-left: 10px;
display: none;
}
.repository.wiki .wiki-pages-list td:hover .wiki-git-entry {
display: inline-block;
}
.repository.wiki .markup {
overflow: visible;
}
.repository.wiki .wiki-content-parts .markup {
border: 1px solid var(--color-secondary);
padding: 1em;
margin-top: 1em;
font-size: 1em;
}
.repository.wiki .wiki-content-main.with-sidebar {
float: left;
width: 80%;
max-width: calc(100% - 150px - 1em); /* match the min-width of .wiki-content-sidebar */
}
.repository.wiki .wiki-content-sidebar {
float: right;
width: calc(20% - 1em);
min-width: 150px;
}
.repository.wiki .wiki-content-sidebar .ui.message.unicode-escape-prompt p {
display: none;
}
.repository.wiki .wiki-content-footer {
margin-top: 1em;
}
.repository.wiki .wiki-content-toc ul {
margin: 0;
list-style: none;
padding: 5px 0 5px 1em;
}
.repository.wiki .wiki-content-toc ul ul {
border-left: 1px var(--color-secondary);
border-left-style: dashed;
}
@media (max-width: 767.98px) {
.repository.wiki #clone-panel #repo-clone-url {
width: 160px;
}
.repository.wiki .wiki-content-main.with-sidebar,
.repository.wiki .wiki-content-sidebar {
float: none;
width: 100%;
min-width: unset;
max-width: unset;
}
}

View File

@ -10,7 +10,7 @@
/>
<a
v-if="item.isFile"
class="file gt-ellipsis"
:class="['file gt-ellipsis', {'viewed': item.file.IsViewed}]"
:href="item.isFile ? '#diff-' + item.file.NameHash : ''"
>{{ item.name }}</a>
<SvgIcon
@ -148,4 +148,8 @@ a:hover {
text-decoration: none;
color: var(--color-text);
}
a.file.viewed {
color: var(--color-text-light-3);
}
</style>

View File

@ -395,8 +395,6 @@ function initGlobalShowModal() {
if (colorPickers.length > 0) {
initCompColorPicker(); // FIXME: this might cause duplicate init
}
// all non-"ok" buttons which do not have "type" should not submit the form, should not be triggered by "Enter"
$modal.find('form button:not(.ok):not([type])').attr('type', 'button');
$modal.modal('setting', {
onApprove: () => {
// "form-fetch-action" can handle network errors gracefully,

View File

@ -1,3 +1,4 @@
import {diffTreeStore} from '../modules/stores.js';
import {setFileFolding} from './file-fold.js';
const {csrfToken, pageData} = window.config;
@ -53,9 +54,17 @@ export function initViewedCheckboxListenerFor() {
const hasChangedLabel = form.parentNode.querySelector('.changed-since-last-review');
hasChangedLabel?.remove();
const fileName = checkbox.getAttribute('name');
// check if the file is in our difftreestore and if we find it -> change the IsViewed status
const fileInPageData = diffTreeStore().files.find((x) => x.Name === fileName);
if (fileInPageData) {
fileInPageData.IsViewed = this.checked;
}
// Unfortunately, actual forms cause too many problems, hence another approach is needed
const files = {};
files[checkbox.getAttribute('name')] = this.checked;
files[fileName] = this.checked;
const data = {files};
const headCommitSHA = form.getAttribute('data-headcommit');
if (headCommitSHA) data.headCommitSHA = headCommitSHA;

View File

@ -1,6 +1,7 @@
import $ from 'jquery';
import {initMarkupContent} from '../markup/content.js';
import {validateTextareaNonEmpty, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
import {fomanticMobileScreen} from '../modules/fomantic.js';
const {csrfToken} = window.config;
@ -70,6 +71,17 @@ async function initRepoWikiFormEditor() {
});
}
function collapseWikiTocForMobile(collapse) {
if (collapse) {
document.querySelector('.wiki-content-toc details')?.removeAttribute('open');
}
}
export function initRepoWikiForm() {
if (!document.querySelector('.page-content.repository.wiki')) return;
fomanticMobileScreen.addEventListener('change', (e) => collapseWikiTocForMobile(e.matches));
collapseWikiTocForMobile(fomanticMobileScreen.matches);
initRepoWikiFormEditor();
}

View File

@ -3,6 +3,8 @@ import {initAriaCheckboxPatch} from './aria/checkbox.js';
import {initAriaDropdownPatch} from './aria/dropdown.js';
import {svg} from '../svg.js';
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
export function initGiteaFomantic() {
// Silence fomantic's error logging when tabs are used without a target content element
$.fn.tab.settings.silent = true;