mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-08 23:13:48 +02:00
Merge branch 'main' into feature/workflow-graph
This commit is contained in:
commit
45d3e146ff
2
Makefile
2
Makefile
@ -713,7 +713,7 @@ generate-go: $(TAGS_PREREQ)
|
|||||||
|
|
||||||
.PHONY: security-check
|
.PHONY: security-check
|
||||||
security-check:
|
security-check:
|
||||||
GOEXPERIMENT= go run $(GOVULNCHECK_PACKAGE) -show color ./...
|
GOEXPERIMENT= go run $(GOVULNCHECK_PACKAGE) -show color ./... || true
|
||||||
|
|
||||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
||||||
ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),)
|
ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),)
|
||||||
|
|||||||
@ -168,7 +168,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) {
|
func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) {
|
||||||
if run.Event.IsPullRequest() {
|
if run.Event.IsPullRequest() || run.Event.IsPullRequestReview() {
|
||||||
var payload api.PullRequestPayload
|
var payload api.PullRequestPayload
|
||||||
if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
|
if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -98,6 +98,20 @@ func (h HookEventType) IsPullRequest() bool {
|
|||||||
return h.Event() == "pull_request"
|
return h.Event() == "pull_request"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsPullRequestReview returns true for pull request review events
|
||||||
|
// (approved, rejected, comment). These events use the same PullRequestPayload
|
||||||
|
// as regular pull_request events.
|
||||||
|
func (h HookEventType) IsPullRequestReview() bool {
|
||||||
|
switch h {
|
||||||
|
case HookEventPullRequestReviewApproved,
|
||||||
|
HookEventPullRequestReviewRejected,
|
||||||
|
HookEventPullRequestReviewComment:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HookType is the type of a webhook
|
// HookType is the type of a webhook
|
||||||
type HookType = string
|
type HookType = string
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
"swagger-ui-dist": "5.31.1",
|
"swagger-ui-dist": "5.31.1",
|
||||||
"tailwindcss": "3.4.17",
|
"tailwindcss": "3.4.17",
|
||||||
"throttle-debounce": "5.0.2",
|
"throttle-debounce": "5.0.2",
|
||||||
"tinycolor2": "1.6.0",
|
"colord": "2.9.3",
|
||||||
"tippy.js": "6.3.7",
|
"tippy.js": "6.3.7",
|
||||||
"toastify-js": "1.12.0",
|
"toastify-js": "1.12.0",
|
||||||
"tributejs": "5.1.3",
|
"tributejs": "5.1.3",
|
||||||
@ -82,7 +82,6 @@
|
|||||||
"@types/sortablejs": "1.15.9",
|
"@types/sortablejs": "1.15.9",
|
||||||
"@types/swagger-ui-dist": "3.30.6",
|
"@types/swagger-ui-dist": "3.30.6",
|
||||||
"@types/throttle-debounce": "5.0.2",
|
"@types/throttle-debounce": "5.0.2",
|
||||||
"@types/tinycolor2": "1.4.6",
|
|
||||||
"@types/toastify-js": "1.12.4",
|
"@types/toastify-js": "1.12.4",
|
||||||
"@typescript-eslint/parser": "8.56.0",
|
"@typescript-eslint/parser": "8.56.0",
|
||||||
"@vitejs/plugin-vue": "6.0.4",
|
"@vitejs/plugin-vue": "6.0.4",
|
||||||
|
|||||||
19
pnpm-lock.yaml
generated
19
pnpm-lock.yaml
generated
@ -89,6 +89,9 @@ importers:
|
|||||||
clippie:
|
clippie:
|
||||||
specifier: 4.1.10
|
specifier: 4.1.10
|
||||||
version: 4.1.10
|
version: 4.1.10
|
||||||
|
colord:
|
||||||
|
specifier: 2.9.3
|
||||||
|
version: 2.9.3
|
||||||
compare-versions:
|
compare-versions:
|
||||||
specifier: 6.1.1
|
specifier: 6.1.1
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
@ -164,9 +167,6 @@ importers:
|
|||||||
throttle-debounce:
|
throttle-debounce:
|
||||||
specifier: 5.0.2
|
specifier: 5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
tinycolor2:
|
|
||||||
specifier: 1.6.0
|
|
||||||
version: 1.6.0
|
|
||||||
tippy.js:
|
tippy.js:
|
||||||
specifier: 6.3.7
|
specifier: 6.3.7
|
||||||
version: 6.3.7
|
version: 6.3.7
|
||||||
@ -249,9 +249,6 @@ importers:
|
|||||||
'@types/throttle-debounce':
|
'@types/throttle-debounce':
|
||||||
specifier: 5.0.2
|
specifier: 5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
'@types/tinycolor2':
|
|
||||||
specifier: 1.4.6
|
|
||||||
version: 1.4.6
|
|
||||||
'@types/toastify-js':
|
'@types/toastify-js':
|
||||||
specifier: 1.12.4
|
specifier: 1.12.4
|
||||||
version: 1.12.4
|
version: 1.12.4
|
||||||
@ -1297,9 +1294,6 @@ packages:
|
|||||||
'@types/throttle-debounce@5.0.2':
|
'@types/throttle-debounce@5.0.2':
|
||||||
resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==}
|
resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==}
|
||||||
|
|
||||||
'@types/tinycolor2@1.4.6':
|
|
||||||
resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
|
|
||||||
|
|
||||||
'@types/toastify-js@1.12.4':
|
'@types/toastify-js@1.12.4':
|
||||||
resolution: {integrity: sha512-zfZHU4tKffPCnZRe7pjv/eFKzTVHozKewFCKaCjZ4gFinKgJRz/t0bkZiMCXJxPhv/ZoeDGNOeRD09R0kQZ/nw==}
|
resolution: {integrity: sha512-zfZHU4tKffPCnZRe7pjv/eFKzTVHozKewFCKaCjZ4gFinKgJRz/t0bkZiMCXJxPhv/ZoeDGNOeRD09R0kQZ/nw==}
|
||||||
|
|
||||||
@ -4056,9 +4050,6 @@ packages:
|
|||||||
tinybench@2.9.0:
|
tinybench@2.9.0:
|
||||||
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
||||||
|
|
||||||
tinycolor2@1.6.0:
|
|
||||||
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
|
|
||||||
|
|
||||||
tinyexec@1.0.2:
|
tinyexec@1.0.2:
|
||||||
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
|
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -5241,8 +5232,6 @@ snapshots:
|
|||||||
|
|
||||||
'@types/throttle-debounce@5.0.2': {}
|
'@types/throttle-debounce@5.0.2': {}
|
||||||
|
|
||||||
'@types/tinycolor2@1.4.6': {}
|
|
||||||
|
|
||||||
'@types/toastify-js@1.12.4': {}
|
'@types/toastify-js@1.12.4': {}
|
||||||
|
|
||||||
'@types/trusted-types@2.0.7':
|
'@types/trusted-types@2.0.7':
|
||||||
@ -8215,8 +8204,6 @@ snapshots:
|
|||||||
|
|
||||||
tinybench@2.9.0: {}
|
tinybench@2.9.0: {}
|
||||||
|
|
||||||
tinycolor2@1.6.0: {}
|
|
||||||
|
|
||||||
tinyexec@1.0.2: {}
|
tinyexec@1.0.2: {}
|
||||||
|
|
||||||
tinyglobby@0.2.15:
|
tinyglobby@0.2.15:
|
||||||
|
|||||||
@ -115,6 +115,21 @@ func getCommitStatusEventNameAndCommitID(run *actions_model.ActionRun) (event, c
|
|||||||
return "", "", errors.New("head of pull request is missing in event payload")
|
return "", "", errors.New("head of pull request is missing in event payload")
|
||||||
}
|
}
|
||||||
commitID = payload.PullRequest.Head.Sha
|
commitID = payload.PullRequest.Head.Sha
|
||||||
|
case // pull_request_review events share the same PullRequestPayload as pull_request
|
||||||
|
webhook_module.HookEventPullRequestReviewApproved,
|
||||||
|
webhook_module.HookEventPullRequestReviewRejected,
|
||||||
|
webhook_module.HookEventPullRequestReviewComment:
|
||||||
|
event = run.TriggerEvent
|
||||||
|
payload, err := run.GetPullRequestEventPayload()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("GetPullRequestEventPayload: %w", err)
|
||||||
|
}
|
||||||
|
if payload.PullRequest == nil {
|
||||||
|
return "", "", errors.New("pull request is missing in event payload")
|
||||||
|
} else if payload.PullRequest.Head == nil {
|
||||||
|
return "", "", errors.New("head of pull request is missing in event payload")
|
||||||
|
}
|
||||||
|
commitID = payload.PullRequest.Head.Sha
|
||||||
case webhook_module.HookEventRelease:
|
case webhook_module.HookEventRelease:
|
||||||
event = string(run.Event)
|
event = string(run.Event)
|
||||||
commitID = run.CommitSHA
|
commitID = run.CommitSHA
|
||||||
|
|||||||
@ -691,6 +691,144 @@ func insertFakeStatus(t *testing.T, repo *repo_model.Repository, sha, targetURL,
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPullRequestReviewCommitStatusEvent(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo
|
||||||
|
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // reviewer
|
||||||
|
|
||||||
|
// create a repo
|
||||||
|
repo, err := repo_service.CreateRepository(t.Context(), user2, user2, repo_service.CreateRepoOptions{
|
||||||
|
Name: "repo-pull-request-review",
|
||||||
|
Description: "test pull-request-review commit status",
|
||||||
|
AutoInit: true,
|
||||||
|
Gitignores: "Go",
|
||||||
|
License: "MIT",
|
||||||
|
Readme: "Default",
|
||||||
|
DefaultBranch: "main",
|
||||||
|
IsPrivate: false,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, repo)
|
||||||
|
|
||||||
|
// add user4 as collaborator so they can review
|
||||||
|
ctx := NewAPITestContext(t, repo.OwnerName, repo.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
t.Run("AddUser4AsCollaboratorWithWriteAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeWrite))
|
||||||
|
|
||||||
|
// add workflow file that triggers on pull_request_review
|
||||||
|
addWorkflow, err := files_service.ChangeRepoFiles(t.Context(), repo, user2, &files_service.ChangeRepoFilesOptions{
|
||||||
|
Files: []*files_service.ChangeRepoFile{
|
||||||
|
{
|
||||||
|
Operation: "create",
|
||||||
|
TreePath: ".gitea/workflows/pr-review.yml",
|
||||||
|
ContentReader: strings.NewReader(`name: test
|
||||||
|
on:
|
||||||
|
pull_request_review:
|
||||||
|
types: [submitted]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo helloworld
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "add workflow",
|
||||||
|
OldBranch: "main",
|
||||||
|
NewBranch: "main",
|
||||||
|
Author: &files_service.IdentityOptions{
|
||||||
|
GitUserName: user2.Name,
|
||||||
|
GitUserEmail: user2.Email,
|
||||||
|
},
|
||||||
|
Committer: &files_service.IdentityOptions{
|
||||||
|
GitUserName: user2.Name,
|
||||||
|
GitUserEmail: user2.Email,
|
||||||
|
},
|
||||||
|
Dates: &files_service.CommitDateOptions{
|
||||||
|
Author: time.Now(),
|
||||||
|
Committer: time.Now(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, addWorkflow)
|
||||||
|
|
||||||
|
// create a branch and a PR
|
||||||
|
testBranch := "test-review-branch"
|
||||||
|
err = repo_service.CreateNewBranch(t.Context(), user2, repo, "main", testBranch)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// add a file on the test branch so the PR has changes
|
||||||
|
addFileResp, err := files_service.ChangeRepoFiles(t.Context(), repo, user2, &files_service.ChangeRepoFilesOptions{
|
||||||
|
Files: []*files_service.ChangeRepoFile{
|
||||||
|
{
|
||||||
|
Operation: "create",
|
||||||
|
TreePath: "test.txt",
|
||||||
|
ContentReader: strings.NewReader("test content"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "add test file",
|
||||||
|
OldBranch: testBranch,
|
||||||
|
NewBranch: testBranch,
|
||||||
|
Author: &files_service.IdentityOptions{
|
||||||
|
GitUserName: user2.Name,
|
||||||
|
GitUserEmail: user2.Email,
|
||||||
|
},
|
||||||
|
Committer: &files_service.IdentityOptions{
|
||||||
|
GitUserName: user2.Name,
|
||||||
|
GitUserEmail: user2.Email,
|
||||||
|
},
|
||||||
|
Dates: &files_service.CommitDateOptions{
|
||||||
|
Author: time.Now(),
|
||||||
|
Committer: time.Now(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, addFileResp)
|
||||||
|
sha := addFileResp.Commit.SHA
|
||||||
|
|
||||||
|
pullIssue := &issues_model.Issue{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Title: "A test PR for review",
|
||||||
|
PosterID: user2.ID,
|
||||||
|
Poster: user2,
|
||||||
|
IsPull: true,
|
||||||
|
}
|
||||||
|
pullRequest := &issues_model.PullRequest{
|
||||||
|
HeadRepoID: repo.ID,
|
||||||
|
BaseRepoID: repo.ID,
|
||||||
|
HeadBranch: testBranch,
|
||||||
|
BaseBranch: "main",
|
||||||
|
HeadRepo: repo,
|
||||||
|
BaseRepo: repo,
|
||||||
|
Type: issues_model.PullRequestGitea,
|
||||||
|
}
|
||||||
|
prOpts := &pull_service.NewPullRequestOptions{Repo: repo, Issue: pullIssue, PullRequest: pullRequest}
|
||||||
|
err = pull_service.NewPullRequest(t.Context(), prOpts)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// submit an approval review as user4
|
||||||
|
gitRepo, err := gitrepo.OpenRepository(t.Context(), repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
_, _, err = pull_service.SubmitReview(t.Context(), user4, gitRepo, pullIssue, issues_model.ReviewTypeApprove, "lgtm", sha, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// verify that a commit status was created for the review event
|
||||||
|
assert.Eventually(t, func() bool {
|
||||||
|
latestCommitStatuses, err := git_model.GetLatestCommitStatus(t.Context(), repo.ID, sha, db.ListOptionsAll)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if len(latestCommitStatuses) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if latestCommitStatuses[0].State == commitstatus.CommitStatusPending {
|
||||||
|
insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, 1*time.Second, 100*time.Millisecond)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestWorkflowDispatchPublicApi(t *testing.T) {
|
func TestWorkflowDispatchPublicApi(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import tinycolor from 'tinycolor2';
|
import {colord} from 'colord';
|
||||||
import {basename, extname, isObject, isDarkTheme} from '../utils.ts';
|
import {basename, extname, isObject, isDarkTheme} from '../utils.ts';
|
||||||
import {onInputDebounce} from '../utils/dom.ts';
|
import {onInputDebounce} from '../utils/dom.ts';
|
||||||
import type MonacoNamespace from 'monaco-editor';
|
import type MonacoNamespace from 'monaco-editor';
|
||||||
@ -94,7 +94,7 @@ function updateTheme(monaco: Monaco): void {
|
|||||||
// https://github.com/microsoft/monaco-editor/issues/2427
|
// https://github.com/microsoft/monaco-editor/issues/2427
|
||||||
// also, monaco can only parse 6-digit hex colors, so we convert the colors to that format
|
// also, monaco can only parse 6-digit hex colors, so we convert the colors to that format
|
||||||
const styles = window.getComputedStyle(document.documentElement);
|
const styles = window.getComputedStyle(document.documentElement);
|
||||||
const getColor = (name: string) => tinycolor(styles.getPropertyValue(name).trim()).toString('hex6');
|
const getColor = (name: string) => colord(styles.getPropertyValue(name).trim()).alpha(1).toHex();
|
||||||
|
|
||||||
monaco.editor.defineTheme('gitea', {
|
monaco.editor.defineTheme('gitea', {
|
||||||
base: isDarkTheme() ? 'vs-dark' : 'vs',
|
base: isDarkTheme() ? 'vs-dark' : 'vs',
|
||||||
|
|||||||
@ -1,22 +1,21 @@
|
|||||||
import tinycolor from 'tinycolor2';
|
import {colord} from 'colord';
|
||||||
import type {ColorInput} from 'tinycolor2';
|
import type {AnyColor} from 'colord';
|
||||||
|
|
||||||
/** Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance */
|
/** Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance */
|
||||||
// Keep this in sync with modules/util/color.go
|
// Keep this in sync with modules/util/color.go
|
||||||
function getRelativeLuminance(color: ColorInput): number {
|
function getRelativeLuminance(color: AnyColor): number {
|
||||||
const {r, g, b} = tinycolor(color).toRgb();
|
const {r, g, b} = colord(color).toRgb();
|
||||||
return (0.2126729 * r + 0.7151522 * g + 0.072175 * b) / 255;
|
return (0.2126729 * r + 0.7151522 * g + 0.072175 * b) / 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useLightText(backgroundColor: ColorInput): boolean {
|
function useLightText(backgroundColor: AnyColor): boolean {
|
||||||
return getRelativeLuminance(backgroundColor) < 0.453;
|
return getRelativeLuminance(backgroundColor) < 0.453;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Given a background color, returns a black or white foreground color that the highest
|
/** Given a background color, returns a black or white foreground color with the highest contrast ratio. */
|
||||||
* contrast ratio. */
|
|
||||||
// In the future, the APCA contrast function, or CSS `contrast-color` will be better.
|
// In the future, the APCA contrast function, or CSS `contrast-color` will be better.
|
||||||
// https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42
|
// https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42
|
||||||
export function contrastColor(backgroundColor: ColorInput): string {
|
export function contrastColor(backgroundColor: AnyColor): string {
|
||||||
return useLightText(backgroundColor) ? '#fff' : '#000';
|
return useLightText(backgroundColor) ? '#fff' : '#000';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user