1
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2024-10-02 21:33:16 +00:00

Compare commits

...

20 commits

Author SHA1 Message Date
Renovate Bot
f79d2fba07 Update ghcr.io/devcontainers/features/git-lfs Docker tag to v1.2.3 2024-10-01 10:02:11 +00:00
forgejo-renovate-action
d2eac83f6a Merge pull request 'Update dependency eslint-plugin-sonarjs to v2.0.3 (forgejo)' (#5436) from renovate/forgejo-linters into forgejo 2024-10-01 08:53:47 +00:00
Earl Warren
df0e50a08f Merge pull request 'Update dependency @github/text-expander-element to v2.7.2 (forgejo)' (#5396) from renovate/forgejo-github-text-expander-element-2.x into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5396
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-10-01 08:38:55 +00:00
Earl Warren
d25a3709d9 Merge pull request 'chore: remove spurious comment in tests' (#5434) from earl-warren/forgejo:wip-container-cleanup into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5434
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-10-01 08:37:36 +00:00
Renovate Bot
e28a1e1d38 Update dependency eslint-plugin-sonarjs to v2.0.3 2024-10-01 08:05:28 +00:00
Earl Warren
aec55ac1b6 Merge pull request '[gitea] week 2024-40 cherry pick (gitea/main -> forgejo)' (#5416) from earl-warren/wcp/2024-40 into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5416
Reviewed-by: Shiny Nematoda <snematoda@noreply.codeberg.org>
2024-10-01 07:52:05 +00:00
Earl Warren
9a7fc2e55e Merge pull request 'Update actions/cache action to v4 (forgejo)' (#5426) from renovate/forgejo-actions-cache-4.x into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5426
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-10-01 07:50:24 +00:00
Earl Warren
2099c2af7c
chore: remove spurious comment in tests 2024-09-30 18:47:30 +02:00
Renovate Bot
502a6a4461 Update actions/cache action to v4 2024-09-30 12:06:49 +00:00
Earl Warren
c9ea78eb1c
chore(release-notes): weekly cherry-pick week 2024-40 2024-09-29 11:35:18 +02:00
Bruno Sofiato
8178d6eaba
Change the code search to sort results by relevance (#32134)
Resolves #32129

Signed-off-by: Bruno Sofiato <bruno.sofiato@gmail.com>
(cherry picked from commit 99d0510cb69c3c53cee05ef0e83ed02389925a90)
2024-09-29 11:00:25 +02:00
yp05327
36af3348bc
Fix wrong status of Set up Job when first step is skipped (#32120)
Fix #32089

(cherry picked from commit 6fa962f409c84477a7a4cf35b4a38a4a93fc3224)
2024-09-29 10:38:49 +02:00
Lunny Xiao
b496317b5a
Fix bug when deleting a migrated branch (#32075)
After migrating a repository with pull request, the branch is missed and
after the pull request merged, the branch cannot be deleted.

(cherry picked from commit 5a8568459d22e57cac506465463660526ca6a08f)

Conflicts:
	services/repository/branch.go
  conflict because of [GITEA] Fix typo in formatting error e71b5a038e
2024-09-29 10:37:39 +02:00
Lunny Xiao
5ccf79d05c
Include collaboration repositories on dashboard source/forks/mirrors list (#31946)
Fix #13489

In the original implementation, only `All` will display your owned and
collaborated repositories. For other filters like `Source`, `Mirrors`
and etc. will only display your owned repositories.

This PR removed the limitations. Now except `collbrations`, other
filters will always display your owned and collaborated repositories.

(cherry picked from commit 4947bec8360c152daca23e120eae1732d3848492)
2024-09-29 10:28:08 +02:00
Kemal Zebari
30b8b45e5e
Truncate commit message during Discord webhook push events (#31970)
Resolves #31668.

(cherry picked from commit aadbe0488f454b9f7f5a56765f4530f9d1e2c6ec)
2024-09-29 10:25:52 +02:00
Lunny Xiao
65b3136261
Fix panic when cloning with wrong ssh format. (#32076)
(cherry picked from commit 3f2d8f873035b614b4cdb447d8e16f5af82cefe8)
2024-09-29 10:22:01 +02:00
cloudchamb3r
ff65d34f03
Fix Bug in Issue/pulls list (#32081)
fix #32080

## After
### for opened issues
<img width="1199" alt="Screenshot 2024-09-19 at 6 29 31 PM"
src="https://github.com/user-attachments/assets/86cf48ad-5e4b-4dcb-8abe-4d7fd74e0aec">

### for closed issues
<img width="1208" alt="Screenshot 2024-09-19 at 6 29 37 PM"
src="https://github.com/user-attachments/assets/a16bc545-bfcf-49a4-be52-3e7334910482">

### for all issues
<img width="1340" alt="Screenshot 2024-09-20 at 12 07 12 PM"
src="https://github.com/user-attachments/assets/b2309c8f-e59d-44e9-ae3b-bf54e1196169">

(cherry picked from commit e1f0598c8f5af5ac95f5e13b74fbab99506762db)
2024-09-29 10:08:30 +02:00
Earl Warren
a226064711
Fix artifact v4 upload above 8MB (#31664) (fix lint errors) 2024-09-29 09:58:47 +02:00
ChristopherHX
8f0a05a7e4
Fix artifact v4 upload above 8MB (#31664)
Multiple chunks are uploaded with type "block" without using
"appendBlock" and eventually out of order for bigger uploads.
8MB seems to be the chunk size

This change parses the blockList uploaded after all blocks to get the
final artifact size and order them correctly before calculating the
sha256 checksum over all blocks

Fixes #31354

(cherry picked from commit b594cec2bda6f861effedb2e8e0a7ebba191c0e9)

Conflicts:
	routers/api/actions/artifactsv4.go
  conflict because of Refactor AppURL usage (#30885) 67c1a07285008cc00036a87cef966c3bd519a50c
    that was not cherry-picked in Forgejo
    the resolution consist of removing the extra ctx argument
2024-09-29 09:24:15 +02:00
Renovate Bot
ed656ca0f3 Update dependency @github/text-expander-element to v2.7.2 2024-09-26 00:05:12 +00:00
21 changed files with 629 additions and 266 deletions

View file

@ -6,7 +6,7 @@
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {
"version": "20" "version": "20"
}, },
"ghcr.io/devcontainers/features/git-lfs:1.2.1": {}, "ghcr.io/devcontainers/features/git-lfs:1.2.3": {},
"ghcr.io/devcontainers-contrib/features/poetry:2": {}, "ghcr.io/devcontainers-contrib/features/poetry:2": {},
"ghcr.io/devcontainers/features/python:1": { "ghcr.io/devcontainers/features/python:1": {
"version": "3.12" "version": "3.12"

View file

@ -87,7 +87,7 @@ jobs:
- name: cache node_modules - name: cache node_modules
id: node id: node
uses: https://code.forgejo.org/actions/cache@v3 uses: https://code.forgejo.org/actions/cache@v4
with: with:
path: | path: |
node_modules node_modules

View file

@ -147,6 +147,12 @@ func runServ(c *cli.Context) error {
return nil return nil
} }
defer func() {
if err := recover(); err != nil {
_ = fail(ctx, "Internal Server Error", "Panic: %v\n%s", err, log.Stack(2))
}
}()
keys := strings.Split(c.Args().First(), "-") keys := strings.Split(c.Args().First(), "-")
if len(keys) != 2 || keys[0] != "key" { if len(keys) != 2 || keys[0] != "key" {
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args().First()) return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args().First())
@ -193,10 +199,7 @@ func runServ(c *cli.Context) error {
} }
verb := words[0] verb := words[0]
repoPath := words[1] repoPath := strings.TrimPrefix(words[1], "/")
if repoPath[0] == '/' {
repoPath = repoPath[1:]
}
var lfsVerb string var lfsVerb string
if verb == lfsAuthenticateVerb { if verb == lfsAuthenticateVerb {

View file

@ -18,8 +18,32 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
return fullStepsOfEmptySteps(task) return fullStepsOfEmptySteps(task)
} }
firstStep := task.Steps[0] // firstStep is the first step that has run or running, not include preStep.
// For example,
// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): firstStep is step1.
// 2. preStep(Success) -> step1(Skipped) -> step2(Success) -> postStep(Success): firstStep is step2.
// 3. preStep(Success) -> step1(Running) -> step2(Waiting) -> postStep(Waiting): firstStep is step1.
// 4. preStep(Success) -> step1(Skipped) -> step2(Skipped) -> postStep(Skipped): firstStep is nil.
// 5. preStep(Success) -> step1(Cancelled) -> step2(Cancelled) -> postStep(Cancelled): firstStep is nil.
var firstStep *actions_model.ActionTaskStep
// lastHasRunStep is the last step that has run.
// For example,
// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
// 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
// 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
// So its Stopped is the Started of postStep when there are no more steps to run.
var lastHasRunStep *actions_model.ActionTaskStep
var logIndex int64 var logIndex int64
for _, step := range task.Steps {
if firstStep == nil && (step.Status.HasRun() || step.Status.IsRunning()) {
firstStep = step
}
if step.Status.HasRun() {
lastHasRunStep = step
}
logIndex += step.LogLength
}
preStep := &actions_model.ActionTaskStep{ preStep := &actions_model.ActionTaskStep{
Name: preStepName, Name: preStepName,
@ -28,32 +52,17 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
Status: actions_model.StatusRunning, Status: actions_model.StatusRunning,
} }
if firstStep.Status.HasRun() || firstStep.Status.IsRunning() { // No step has run or is running, so preStep is equal to the task
if firstStep == nil {
preStep.Stopped = task.Stopped
preStep.Status = task.Status
} else {
preStep.LogLength = firstStep.LogIndex preStep.LogLength = firstStep.LogIndex
preStep.Stopped = firstStep.Started preStep.Stopped = firstStep.Started
preStep.Status = actions_model.StatusSuccess preStep.Status = actions_model.StatusSuccess
} else if task.Status.IsDone() {
preStep.Stopped = task.Stopped
preStep.Status = actions_model.StatusFailure
if task.Status.IsSkipped() {
preStep.Status = actions_model.StatusSkipped
}
} }
logIndex += preStep.LogLength logIndex += preStep.LogLength
// lastHasRunStep is the last step that has run.
// For example,
// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
// 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
// 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
// So its Stopped is the Started of postStep when there are no more steps to run.
var lastHasRunStep *actions_model.ActionTaskStep
for _, step := range task.Steps {
if step.Status.HasRun() {
lastHasRunStep = step
}
logIndex += step.LogLength
}
if lastHasRunStep == nil { if lastHasRunStep == nil {
lastHasRunStep = preStep lastHasRunStep = preStep
} }

View file

@ -137,6 +137,25 @@ func TestFullSteps(t *testing.T) {
{Name: postStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0}, {Name: postStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
}, },
}, },
{
name: "first step is skipped",
task: &actions_model.ActionTask{
Steps: []*actions_model.ActionTaskStep{
{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
},
Status: actions_model.StatusSuccess,
Started: 10000,
Stopped: 10100,
LogLength: 100,
},
want: []*actions_model.ActionTaskStep{
{Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
{Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 10100},
},
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -288,6 +288,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
searchRequest.AddFacet("languages", bleve.NewFacetRequest("Language", 10)) searchRequest.AddFacet("languages", bleve.NewFacetRequest("Language", 10))
} }
searchRequest.SortBy([]string{"-_score", "UpdatedAt"})
result, err := b.inner.Indexer.SearchInContext(ctx, searchRequest) result, err := b.inner.Indexer.SearchInContext(ctx, searchRequest)
if err != nil { if err != nil {
return 0, nil, nil, err return 0, nil, nil, err

View file

@ -318,7 +318,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
NumOfFragments(0). // return all highting content on fragments NumOfFragments(0). // return all highting content on fragments
HighlighterType("fvh"), HighlighterType("fvh"),
). ).
Sort("repo_id", true). Sort("_score", false).
Sort("updated_at", true).
From(start).Size(pageSize). From(start).Size(pageSize).
Do(ctx) Do(ctx)
if err != nil { if err != nil {
@ -349,7 +350,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
NumOfFragments(0). // return all highting content on fragments NumOfFragments(0). // return all highting content on fragments
HighlighterType("fvh"), HighlighterType("fvh"),
). ).
Sort("repo_id", true). Sort("_score", false).
Sort("updated_at", true).
From(start).Size(pageSize). From(start).Size(pageSize).
Do(ctx) Do(ctx)
if err != nil { if err != nil {

416
package-lock.json generated
View file

@ -10,7 +10,7 @@
"@citation-js/plugin-software-formats": "0.6.1", "@citation-js/plugin-software-formats": "0.6.1",
"@github/markdown-toolbar-element": "2.2.3", "@github/markdown-toolbar-element": "2.2.3",
"@github/relative-time-element": "4.4.3", "@github/relative-time-element": "4.4.3",
"@github/text-expander-element": "2.7.1", "@github/text-expander-element": "2.7.2",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.9.0", "@primer/octicons": "19.9.0",
"ansi_up": "6.0.2", "ansi_up": "6.0.2",
@ -78,7 +78,7 @@
"eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-no-use-extend-native": "0.5.0",
"eslint-plugin-playwright": "1.6.2", "eslint-plugin-playwright": "1.6.2",
"eslint-plugin-regexp": "2.6.0", "eslint-plugin-regexp": "2.6.0",
"eslint-plugin-sonarjs": "2.0.2", "eslint-plugin-sonarjs": "2.0.3",
"eslint-plugin-unicorn": "55.0.0", "eslint-plugin-unicorn": "55.0.0",
"eslint-plugin-vitest-globals": "1.5.0", "eslint-plugin-vitest-globals": "1.5.0",
"eslint-plugin-vue": "9.28.0", "eslint-plugin-vue": "9.28.0",
@ -195,22 +195,22 @@
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.24.3", "version": "7.25.2",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz",
"integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.2", "@babel/code-frame": "^7.24.7",
"@babel/generator": "^7.24.1", "@babel/generator": "^7.25.0",
"@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-compilation-targets": "^7.25.2",
"@babel/helper-module-transforms": "^7.23.3", "@babel/helper-module-transforms": "^7.25.2",
"@babel/helpers": "^7.24.1", "@babel/helpers": "^7.25.0",
"@babel/parser": "^7.24.1", "@babel/parser": "^7.25.0",
"@babel/template": "^7.24.0", "@babel/template": "^7.25.0",
"@babel/traverse": "^7.24.1", "@babel/traverse": "^7.25.2",
"@babel/types": "^7.24.0", "@babel/types": "^7.25.2",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
@ -236,9 +236,9 @@
} }
}, },
"node_modules/@babel/eslint-parser": { "node_modules/@babel/eslint-parser": {
"version": "7.24.1", "version": "7.25.1",
"resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz", "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.1.tgz",
"integrity": "sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==", "integrity": "sha512-Y956ghgTT4j7rKesabkh5WeqgSFZVFwaPR0IWFm7KFHFmmJ4afbG49SmfW4S+GyRPx0Dy5jxEWA5t0rpxfElWg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -251,7 +251,7 @@
}, },
"peerDependencies": { "peerDependencies": {
"@babel/core": "^7.11.0", "@babel/core": "^7.11.0",
"eslint": "^7.5.0 || ^8.0.0" "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0"
} }
}, },
"node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": {
@ -713,6 +713,39 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
"version": "7.25.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz",
"integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.24.8",
"@babel/traverse": "^7.25.3"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": {
"version": "7.25.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz",
"integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.24.8"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
"version": "7.25.0", "version": "7.25.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz",
@ -765,15 +798,15 @@
} }
}, },
"node_modules/@babel/plugin-proposal-decorators": { "node_modules/@babel/plugin-proposal-decorators": {
"version": "7.24.1", "version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.1.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz",
"integrity": "sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==", "integrity": "sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-create-class-features-plugin": "^7.24.1", "@babel/helper-create-class-features-plugin": "^7.24.7",
"@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-plugin-utils": "^7.24.7",
"@babel/plugin-syntax-decorators": "^7.24.1" "@babel/plugin-syntax-decorators": "^7.24.7"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1313,6 +1346,23 @@
"@babel/core": "^7.0.0-0" "@babel/core": "^7.0.0-0"
} }
}, },
"node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": {
"version": "7.25.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz",
"integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.0",
"@babel/helper-plugin-utils": "^7.24.8"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/plugin-transform-dynamic-import": { "node_modules/@babel/plugin-transform-dynamic-import": {
"version": "7.24.7", "version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz",
@ -2010,27 +2060,29 @@
} }
}, },
"node_modules/@babel/preset-env": { "node_modules/@babel/preset-env": {
"version": "7.24.3", "version": "7.25.4",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.3.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz",
"integrity": "sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==", "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.24.1", "@babel/compat-data": "^7.25.4",
"@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-compilation-targets": "^7.25.2",
"@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-plugin-utils": "^7.24.8",
"@babel/helper-validator-option": "^7.23.5", "@babel/helper-validator-option": "^7.24.8",
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3",
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0",
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0",
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7",
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0",
"@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
"@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-async-generators": "^7.8.4",
"@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-properties": "^7.12.13",
"@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-class-static-block": "^7.14.5",
"@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-export-namespace-from": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
"@babel/plugin-syntax-import-assertions": "^7.24.1", "@babel/plugin-syntax-import-assertions": "^7.24.7",
"@babel/plugin-syntax-import-attributes": "^7.24.1", "@babel/plugin-syntax-import-attributes": "^7.24.7",
"@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-json-strings": "^7.8.3",
"@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
@ -2042,59 +2094,60 @@
"@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
"@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5",
"@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
"@babel/plugin-transform-arrow-functions": "^7.24.1", "@babel/plugin-transform-arrow-functions": "^7.24.7",
"@babel/plugin-transform-async-generator-functions": "^7.24.3", "@babel/plugin-transform-async-generator-functions": "^7.25.4",
"@babel/plugin-transform-async-to-generator": "^7.24.1", "@babel/plugin-transform-async-to-generator": "^7.24.7",
"@babel/plugin-transform-block-scoped-functions": "^7.24.1", "@babel/plugin-transform-block-scoped-functions": "^7.24.7",
"@babel/plugin-transform-block-scoping": "^7.24.1", "@babel/plugin-transform-block-scoping": "^7.25.0",
"@babel/plugin-transform-class-properties": "^7.24.1", "@babel/plugin-transform-class-properties": "^7.25.4",
"@babel/plugin-transform-class-static-block": "^7.24.1", "@babel/plugin-transform-class-static-block": "^7.24.7",
"@babel/plugin-transform-classes": "^7.24.1", "@babel/plugin-transform-classes": "^7.25.4",
"@babel/plugin-transform-computed-properties": "^7.24.1", "@babel/plugin-transform-computed-properties": "^7.24.7",
"@babel/plugin-transform-destructuring": "^7.24.1", "@babel/plugin-transform-destructuring": "^7.24.8",
"@babel/plugin-transform-dotall-regex": "^7.24.1", "@babel/plugin-transform-dotall-regex": "^7.24.7",
"@babel/plugin-transform-duplicate-keys": "^7.24.1", "@babel/plugin-transform-duplicate-keys": "^7.24.7",
"@babel/plugin-transform-dynamic-import": "^7.24.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0",
"@babel/plugin-transform-exponentiation-operator": "^7.24.1", "@babel/plugin-transform-dynamic-import": "^7.24.7",
"@babel/plugin-transform-export-namespace-from": "^7.24.1", "@babel/plugin-transform-exponentiation-operator": "^7.24.7",
"@babel/plugin-transform-for-of": "^7.24.1", "@babel/plugin-transform-export-namespace-from": "^7.24.7",
"@babel/plugin-transform-function-name": "^7.24.1", "@babel/plugin-transform-for-of": "^7.24.7",
"@babel/plugin-transform-json-strings": "^7.24.1", "@babel/plugin-transform-function-name": "^7.25.1",
"@babel/plugin-transform-literals": "^7.24.1", "@babel/plugin-transform-json-strings": "^7.24.7",
"@babel/plugin-transform-logical-assignment-operators": "^7.24.1", "@babel/plugin-transform-literals": "^7.25.2",
"@babel/plugin-transform-member-expression-literals": "^7.24.1", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7",
"@babel/plugin-transform-modules-amd": "^7.24.1", "@babel/plugin-transform-member-expression-literals": "^7.24.7",
"@babel/plugin-transform-modules-commonjs": "^7.24.1", "@babel/plugin-transform-modules-amd": "^7.24.7",
"@babel/plugin-transform-modules-systemjs": "^7.24.1", "@babel/plugin-transform-modules-commonjs": "^7.24.8",
"@babel/plugin-transform-modules-umd": "^7.24.1", "@babel/plugin-transform-modules-systemjs": "^7.25.0",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-modules-umd": "^7.24.7",
"@babel/plugin-transform-new-target": "^7.24.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1", "@babel/plugin-transform-new-target": "^7.24.7",
"@babel/plugin-transform-numeric-separator": "^7.24.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7",
"@babel/plugin-transform-object-rest-spread": "^7.24.1", "@babel/plugin-transform-numeric-separator": "^7.24.7",
"@babel/plugin-transform-object-super": "^7.24.1", "@babel/plugin-transform-object-rest-spread": "^7.24.7",
"@babel/plugin-transform-optional-catch-binding": "^7.24.1", "@babel/plugin-transform-object-super": "^7.24.7",
"@babel/plugin-transform-optional-chaining": "^7.24.1", "@babel/plugin-transform-optional-catch-binding": "^7.24.7",
"@babel/plugin-transform-parameters": "^7.24.1", "@babel/plugin-transform-optional-chaining": "^7.24.8",
"@babel/plugin-transform-private-methods": "^7.24.1", "@babel/plugin-transform-parameters": "^7.24.7",
"@babel/plugin-transform-private-property-in-object": "^7.24.1", "@babel/plugin-transform-private-methods": "^7.25.4",
"@babel/plugin-transform-property-literals": "^7.24.1", "@babel/plugin-transform-private-property-in-object": "^7.24.7",
"@babel/plugin-transform-regenerator": "^7.24.1", "@babel/plugin-transform-property-literals": "^7.24.7",
"@babel/plugin-transform-reserved-words": "^7.24.1", "@babel/plugin-transform-regenerator": "^7.24.7",
"@babel/plugin-transform-shorthand-properties": "^7.24.1", "@babel/plugin-transform-reserved-words": "^7.24.7",
"@babel/plugin-transform-spread": "^7.24.1", "@babel/plugin-transform-shorthand-properties": "^7.24.7",
"@babel/plugin-transform-sticky-regex": "^7.24.1", "@babel/plugin-transform-spread": "^7.24.7",
"@babel/plugin-transform-template-literals": "^7.24.1", "@babel/plugin-transform-sticky-regex": "^7.24.7",
"@babel/plugin-transform-typeof-symbol": "^7.24.1", "@babel/plugin-transform-template-literals": "^7.24.7",
"@babel/plugin-transform-unicode-escapes": "^7.24.1", "@babel/plugin-transform-typeof-symbol": "^7.24.8",
"@babel/plugin-transform-unicode-property-regex": "^7.24.1", "@babel/plugin-transform-unicode-escapes": "^7.24.7",
"@babel/plugin-transform-unicode-regex": "^7.24.1", "@babel/plugin-transform-unicode-property-regex": "^7.24.7",
"@babel/plugin-transform-unicode-sets-regex": "^7.24.1", "@babel/plugin-transform-unicode-regex": "^7.24.7",
"@babel/plugin-transform-unicode-sets-regex": "^7.25.4",
"@babel/preset-modules": "0.1.6-no-external-plugins", "@babel/preset-modules": "0.1.6-no-external-plugins",
"babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs2": "^0.4.10",
"babel-plugin-polyfill-corejs3": "^0.10.4", "babel-plugin-polyfill-corejs3": "^0.10.6",
"babel-plugin-polyfill-regenerator": "^0.6.1", "babel-plugin-polyfill-regenerator": "^0.6.1",
"core-js-compat": "^3.31.0", "core-js-compat": "^3.37.1",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
"engines": { "engines": {
@ -2115,15 +2168,15 @@
} }
}, },
"node_modules/@babel/preset-flow": { "node_modules/@babel/preset-flow": {
"version": "7.24.1", "version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.1.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz",
"integrity": "sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA==", "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-plugin-utils": "^7.24.7",
"@babel/helper-validator-option": "^7.23.5", "@babel/helper-validator-option": "^7.24.7",
"@babel/plugin-transform-flow-strip-types": "^7.24.1" "@babel/plugin-transform-flow-strip-types": "^7.24.7"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -2148,18 +2201,18 @@
} }
}, },
"node_modules/@babel/preset-react": { "node_modules/@babel/preset-react": {
"version": "7.24.1", "version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz",
"integrity": "sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==", "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-plugin-utils": "^7.24.7",
"@babel/helper-validator-option": "^7.23.5", "@babel/helper-validator-option": "^7.24.7",
"@babel/plugin-transform-react-display-name": "^7.24.1", "@babel/plugin-transform-react-display-name": "^7.24.7",
"@babel/plugin-transform-react-jsx": "^7.23.4", "@babel/plugin-transform-react-jsx": "^7.24.7",
"@babel/plugin-transform-react-jsx-development": "^7.22.5", "@babel/plugin-transform-react-jsx-development": "^7.24.7",
"@babel/plugin-transform-react-pure-annotations": "^7.24.1" "@babel/plugin-transform-react-pure-annotations": "^7.24.7"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -2976,9 +3029,9 @@
} }
}, },
"node_modules/@eslint-community/regexpp": { "node_modules/@eslint-community/regexpp": {
"version": "4.10.0", "version": "4.11.1",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz",
"integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -3124,13 +3177,13 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@github/text-expander-element": { "node_modules/@github/text-expander-element": {
"version": "2.7.1", "version": "2.7.2",
"resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.7.1.tgz", "resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.7.2.tgz",
"integrity": "sha512-CWxfYxJRkeWVCUhJveproLs6pHsPrWtK8TsjL8ByYVcSCs8CJmNzF8b7ZawrUgfai0F2jb4aIdw2FoBTykj9XA==", "integrity": "sha512-eTIOUQKoBxe+e0yHKHQHoo4x61Erb7m0lhi2vMRHZS7TwI6OCGSj/3YydAr3obbQbZjevF9wPihLf1wADu3A9g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@github/combobox-nav": "^2.0.2", "@github/combobox-nav": "^2.0.2",
"dom-input-range": "^1.1.6" "dom-input-range": "^1.2.0"
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
@ -8560,9 +8613,9 @@
} }
}, },
"node_modules/eslint-plugin-react-hooks": { "node_modules/eslint-plugin-react-hooks": {
"version": "4.6.0", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz",
"integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -8660,33 +8713,33 @@
} }
}, },
"node_modules/eslint-plugin-sonarjs": { "node_modules/eslint-plugin-sonarjs": {
"version": "2.0.2", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-2.0.2.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-2.0.3.tgz",
"integrity": "sha512-0JUYTlUDk/up3mS0rFP9vHCRvhIYNTy06m99IPFeyMDUWL8u0ebz+nFPYn6OWDBTIEfbvQ/Xe0PdjWO8w0WD0Q==", "integrity": "sha512-Xsy+x5xNxc/h+M/B2s8XMPoKw0o4gUL0cqT8gl6SiEtA6qKX6/SlOjj4Avp7bT7UIguHbjKv/RACy3AxIGOvwA==",
"dev": true, "dev": true,
"license": "LGPL-3.0-only", "license": "LGPL-3.0-only",
"dependencies": { "dependencies": {
"@babel/core": "7.24.3", "@babel/core": "7.25.2",
"@babel/eslint-parser": "7.24.1", "@babel/eslint-parser": "7.25.1",
"@babel/plugin-proposal-decorators": "7.24.1", "@babel/plugin-proposal-decorators": "7.24.7",
"@babel/preset-env": "7.24.3", "@babel/preset-env": "7.25.4",
"@babel/preset-flow": "7.24.1", "@babel/preset-flow": "7.24.7",
"@babel/preset-react": "7.24.1", "@babel/preset-react": "7.24.7",
"@eslint-community/regexpp": "4.10.0", "@eslint-community/regexpp": "4.11.1",
"@typescript-eslint/eslint-plugin": "7.16.1", "@typescript-eslint/eslint-plugin": "7.16.1",
"@typescript-eslint/utils": "^7.16.1", "@typescript-eslint/utils": "^7.16.1",
"builtin-modules": "3.3.0", "builtin-modules": "3.3.0",
"bytes": "3.1.2", "bytes": "3.1.2",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.30.0",
"eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-jsx-a11y": "^6.10.0",
"eslint-plugin-react": "^7.35.0", "eslint-plugin-react": "^7.36.1",
"eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-react-hooks": "4.6.2",
"eslint-scope": "8.0.1", "eslint-scope": "8.0.2",
"functional-red-black-tree": "1.0.1", "functional-red-black-tree": "1.0.1",
"jsx-ast-utils": "^3.3.5", "jsx-ast-utils": "^3.3.5",
"minimatch": "^9.0.3", "minimatch": "^10.0.1",
"scslre": "0.3.0", "scslre": "0.3.0",
"semver": "7.6.0", "semver": "7.6.3",
"typescript": "*", "typescript": "*",
"vue-eslint-parser": "9.4.3" "vue-eslint-parser": "9.4.3"
}, },
@ -8899,6 +8952,22 @@
} }
} }
}, },
"node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/type-utils/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/types": { "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/types": {
"version": "7.18.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
@ -8963,6 +9032,23 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
} }
}, },
"node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"license": "ISC",
"peer": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/utils": { "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/utils": {
"version": "7.16.1", "version": "7.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.1.tgz",
@ -9029,6 +9115,22 @@
} }
} }
}, },
"node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/utils/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/visitor-keys": { "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/visitor-keys": {
"version": "7.16.1", "version": "7.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz",
@ -9062,9 +9164,9 @@
} }
}, },
"node_modules/eslint-plugin-sonarjs/node_modules/eslint-scope": { "node_modules/eslint-plugin-sonarjs/node_modules/eslint-scope": {
"version": "8.0.1", "version": "8.0.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz",
"integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
@ -9091,58 +9193,6 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint-plugin-sonarjs/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/eslint-plugin-sonarjs/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/eslint-plugin-sonarjs/node_modules/semver": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true,
"license": "ISC",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/eslint-plugin-sonarjs/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true,
"license": "ISC"
},
"node_modules/eslint-plugin-unicorn": { "node_modules/eslint-plugin-unicorn": {
"version": "55.0.0", "version": "55.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz",

View file

@ -9,7 +9,7 @@
"@citation-js/plugin-software-formats": "0.6.1", "@citation-js/plugin-software-formats": "0.6.1",
"@github/markdown-toolbar-element": "2.2.3", "@github/markdown-toolbar-element": "2.2.3",
"@github/relative-time-element": "4.4.3", "@github/relative-time-element": "4.4.3",
"@github/text-expander-element": "2.7.1", "@github/text-expander-element": "2.7.2",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.9.0", "@primer/octicons": "19.9.0",
"ansi_up": "6.0.2", "ansi_up": "6.0.2",
@ -77,7 +77,7 @@
"eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-no-use-extend-native": "0.5.0",
"eslint-plugin-playwright": "1.6.2", "eslint-plugin-playwright": "1.6.2",
"eslint-plugin-regexp": "2.6.0", "eslint-plugin-regexp": "2.6.0",
"eslint-plugin-sonarjs": "2.0.2", "eslint-plugin-sonarjs": "2.0.3",
"eslint-plugin-unicorn": "55.0.0", "eslint-plugin-unicorn": "55.0.0",
"eslint-plugin-vitest-globals": "1.5.0", "eslint-plugin-vitest-globals": "1.5.0",
"eslint-plugin-vue": "9.28.0", "eslint-plugin-vue": "9.28.0",

3
release-notes/5416.md Normal file
View file

@ -0,0 +1,3 @@
feat: [commit](https://codeberg.org/forgejo/forgejo/commit/8178d6eaba64d05799fd3b62fa889bd13bee07c7) Code search results when using the bleve indexer are sorted by relevance.
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/b496317b5a2aea970bc94ccf6fcde35cd417ec20) After migrating a repository that contains merged pull requests, the branch is missing and cannot be deleted.
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/a226064711899da07d6b1455a68ef758f2f3e7e0) Forgejo Actions artifact v4 upload above 8MB.

View file

@ -123,6 +123,54 @@ func listChunksByRunID(st storage.ObjectStorage, runID int64) (map[int64][]*chun
return chunksMap, nil return chunksMap, nil
} }
func listChunksByRunIDV4(st storage.ObjectStorage, runID, artifactID int64, blist *BlockList) ([]*chunkFileItem, error) {
storageDir := fmt.Sprintf("tmpv4%d", runID)
var chunks []*chunkFileItem
chunkMap := map[string]*chunkFileItem{}
dummy := &chunkFileItem{}
for _, name := range blist.Latest {
chunkMap[name] = dummy
}
if err := st.IterateObjects(storageDir, func(fpath string, obj storage.Object) error {
baseName := filepath.Base(fpath)
if !strings.HasPrefix(baseName, "block-") {
return nil
}
// when read chunks from storage, it only contains storage dir and basename,
// no matter the subdirectory setting in storage config
item := chunkFileItem{Path: storageDir + "/" + baseName, ArtifactID: artifactID}
var size int64
var b64chunkName string
if _, err := fmt.Sscanf(baseName, "block-%d-%d-%s", &item.RunID, &size, &b64chunkName); err != nil {
return fmt.Errorf("parse content range error: %v", err)
}
rchunkName, err := base64.URLEncoding.DecodeString(b64chunkName)
if err != nil {
return fmt.Errorf("failed to parse chunkName: %v", err)
}
chunkName := string(rchunkName)
item.End = item.Start + size - 1
if _, ok := chunkMap[chunkName]; ok {
chunkMap[chunkName] = &item
}
return nil
}); err != nil {
return nil, err
}
for i, name := range blist.Latest {
chunk, ok := chunkMap[name]
if !ok || chunk.Path == "" {
return nil, fmt.Errorf("missing Chunk (%d/%d): %s", i, len(blist.Latest), name)
}
chunks = append(chunks, chunk)
if i > 0 {
chunk.Start = chunkMap[blist.Latest[i-1]].End + 1
chunk.End += chunk.Start
}
}
return chunks, nil
}
func mergeChunksForRun(ctx *ArtifactContext, st storage.ObjectStorage, runID int64, artifactName string) error { func mergeChunksForRun(ctx *ArtifactContext, st storage.ObjectStorage, runID int64, artifactName string) error {
// read all db artifacts by name // read all db artifacts by name
artifacts, err := db.Find[actions.ActionArtifact](ctx, actions.FindArtifactsOptions{ artifacts, err := db.Find[actions.ActionArtifact](ctx, actions.FindArtifactsOptions{
@ -230,7 +278,7 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
rawChecksum := hash.Sum(nil) rawChecksum := hash.Sum(nil)
actualChecksum := hex.EncodeToString(rawChecksum) actualChecksum := hex.EncodeToString(rawChecksum)
if !strings.HasSuffix(checksum, actualChecksum) { if !strings.HasSuffix(checksum, actualChecksum) {
return fmt.Errorf("update artifact error checksum is invalid") return fmt.Errorf("update artifact error checksum is invalid %v vs %v", checksum, actualChecksum)
} }
} }

View file

@ -24,8 +24,15 @@ package actions
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=block // PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=block
// 1.3. Continue Upload Zip Content to Blobstorage (unauthenticated request), repeat until everything is uploaded // 1.3. Continue Upload Zip Content to Blobstorage (unauthenticated request), repeat until everything is uploaded
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=appendBlock // PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=appendBlock
// 1.4. Unknown xml payload to Blobstorage (unauthenticated request), ignored for now // 1.4. BlockList xml payload to Blobstorage (unauthenticated request)
// Files of about 800MB are parallel in parallel and / or out of order, this file is needed to enshure the correct order
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=blockList // PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=blockList
// Request
// <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
// <BlockList>
// <Latest>blockId1</Latest>
// <Latest>blockId2</Latest>
// </BlockList>
// 1.5. FinalizeArtifact // 1.5. FinalizeArtifact
// Post: /twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact // Post: /twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact
// Request // Request
@ -82,6 +89,7 @@ import (
"crypto/hmac" "crypto/hmac"
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"encoding/xml"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -153,31 +161,34 @@ func ArtifactsV4Routes(prefix string) *web.Route {
return m return m
} }
func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, taskID int64) []byte { func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, taskID, artifactID int64) []byte {
mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret()) mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret())
mac.Write([]byte(endp)) mac.Write([]byte(endp))
mac.Write([]byte(expires)) mac.Write([]byte(expires))
mac.Write([]byte(artifactName)) mac.Write([]byte(artifactName))
mac.Write([]byte(fmt.Sprint(taskID))) mac.Write([]byte(fmt.Sprint(taskID)))
mac.Write([]byte(fmt.Sprint(artifactID)))
return mac.Sum(nil) return mac.Sum(nil)
} }
func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID int64) string { func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID, artifactID int64) string {
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST") expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
uploadURL := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") + uploadURL := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") +
"/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID) "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID, artifactID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID) + "&artifactID=" + fmt.Sprint(artifactID)
return uploadURL return uploadURL
} }
func (r artifactV4Routes) verifySignature(ctx *ArtifactContext, endp string) (*actions.ActionTask, string, bool) { func (r artifactV4Routes) verifySignature(ctx *ArtifactContext, endp string) (*actions.ActionTask, string, bool) {
rawTaskID := ctx.Req.URL.Query().Get("taskID") rawTaskID := ctx.Req.URL.Query().Get("taskID")
rawArtifactID := ctx.Req.URL.Query().Get("artifactID")
sig := ctx.Req.URL.Query().Get("sig") sig := ctx.Req.URL.Query().Get("sig")
expires := ctx.Req.URL.Query().Get("expires") expires := ctx.Req.URL.Query().Get("expires")
artifactName := ctx.Req.URL.Query().Get("artifactName") artifactName := ctx.Req.URL.Query().Get("artifactName")
dsig, _ := base64.URLEncoding.DecodeString(sig) dsig, _ := base64.URLEncoding.DecodeString(sig)
taskID, _ := strconv.ParseInt(rawTaskID, 10, 64) taskID, _ := strconv.ParseInt(rawTaskID, 10, 64)
artifactID, _ := strconv.ParseInt(rawArtifactID, 10, 64)
expecedsig := r.buildSignature(endp, expires, artifactName, taskID) expecedsig := r.buildSignature(endp, expires, artifactName, taskID, artifactID)
if !hmac.Equal(dsig, expecedsig) { if !hmac.Equal(dsig, expecedsig) {
log.Error("Error unauthorized") log.Error("Error unauthorized")
ctx.Error(http.StatusUnauthorized, "Error unauthorized") ctx.Error(http.StatusUnauthorized, "Error unauthorized")
@ -272,6 +283,8 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
return return
} }
artifact.ContentEncoding = ArtifactV4ContentEncoding artifact.ContentEncoding = ArtifactV4ContentEncoding
artifact.FileSize = 0
artifact.FileCompressedSize = 0
if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil { if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
log.Error("Error UpdateArtifactByID: %v", err) log.Error("Error UpdateArtifactByID: %v", err)
ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID") ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
@ -280,7 +293,7 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
respData := CreateArtifactResponse{ respData := CreateArtifactResponse{
Ok: true, Ok: true,
SignedUploadUrl: r.buildArtifactURL("UploadArtifact", artifactName, ctx.ActionTask.ID), SignedUploadUrl: r.buildArtifactURL("UploadArtifact", artifactName, ctx.ActionTask.ID, artifact.ID),
} }
r.sendProtbufBody(ctx, &respData) r.sendProtbufBody(ctx, &respData)
} }
@ -306,38 +319,77 @@ func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
comp := ctx.Req.URL.Query().Get("comp") comp := ctx.Req.URL.Query().Get("comp")
switch comp { switch comp {
case "block", "appendBlock": case "block", "appendBlock":
// get artifact by name blockid := ctx.Req.URL.Query().Get("blockid")
artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName) if blockid == "" {
if err != nil { // get artifact by name
log.Error("Error artifact not found: %v", err) artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName)
ctx.Error(http.StatusNotFound, "Error artifact not found") if err != nil {
return log.Error("Error artifact not found: %v", err)
} ctx.Error(http.StatusNotFound, "Error artifact not found")
return
}
if comp == "block" { _, err = appendUploadChunk(r.fs, ctx, artifact, artifact.FileSize, ctx.Req.ContentLength, artifact.RunID)
artifact.FileSize = 0 if err != nil {
artifact.FileCompressedSize = 0 log.Error("Error runner api getting task: task is not running")
ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
return
}
artifact.FileCompressedSize += ctx.Req.ContentLength
artifact.FileSize += ctx.Req.ContentLength
if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
log.Error("Error UpdateArtifactByID: %v", err)
ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
return
}
} else {
_, err := r.fs.Save(fmt.Sprintf("tmpv4%d/block-%d-%d-%s", task.Job.RunID, task.Job.RunID, ctx.Req.ContentLength, base64.URLEncoding.EncodeToString([]byte(blockid))), ctx.Req.Body, -1)
if err != nil {
log.Error("Error runner api getting task: task is not running")
ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
return
}
} }
ctx.JSON(http.StatusCreated, "appended")
_, err = appendUploadChunk(r.fs, ctx, artifact, artifact.FileSize, ctx.Req.ContentLength, artifact.RunID) case "blocklist":
rawArtifactID := ctx.Req.URL.Query().Get("artifactID")
artifactID, _ := strconv.ParseInt(rawArtifactID, 10, 64)
_, err := r.fs.Save(fmt.Sprintf("tmpv4%d/%d-%d-blocklist", task.Job.RunID, task.Job.RunID, artifactID), ctx.Req.Body, -1)
if err != nil { if err != nil {
log.Error("Error runner api getting task: task is not running") log.Error("Error runner api getting task: task is not running")
ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running") ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
return return
} }
artifact.FileCompressedSize += ctx.Req.ContentLength
artifact.FileSize += ctx.Req.ContentLength
if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
log.Error("Error UpdateArtifactByID: %v", err)
ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
return
}
ctx.JSON(http.StatusCreated, "appended")
case "blocklist":
ctx.JSON(http.StatusCreated, "created") ctx.JSON(http.StatusCreated, "created")
} }
} }
type BlockList struct {
Latest []string `xml:"Latest"`
}
type Latest struct {
Value string `xml:",chardata"`
}
func (r *artifactV4Routes) readBlockList(runID, artifactID int64) (*BlockList, error) {
blockListName := fmt.Sprintf("tmpv4%d/%d-%d-blocklist", runID, runID, artifactID)
s, err := r.fs.Open(blockListName)
if err != nil {
return nil, err
}
xdec := xml.NewDecoder(s)
blockList := &BlockList{}
err = xdec.Decode(blockList)
delerr := r.fs.Delete(blockListName)
if delerr != nil {
log.Warn("Failed to delete blockList %s: %v", blockListName, delerr)
}
return blockList, err
}
func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) { func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
var req FinalizeArtifactRequest var req FinalizeArtifactRequest
@ -356,18 +408,34 @@ func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
ctx.Error(http.StatusNotFound, "Error artifact not found") ctx.Error(http.StatusNotFound, "Error artifact not found")
return return
} }
chunkMap, err := listChunksByRunID(r.fs, runID)
var chunks []*chunkFileItem
blockList, err := r.readBlockList(runID, artifact.ID)
if err != nil { if err != nil {
log.Error("Error merge chunks: %v", err) log.Warn("Failed to read BlockList, fallback to old behavior: %v", err)
ctx.Error(http.StatusInternalServerError, "Error merge chunks") chunkMap, err := listChunksByRunID(r.fs, runID)
return if err != nil {
} log.Error("Error merge chunks: %v", err)
chunks, ok := chunkMap[artifact.ID] ctx.Error(http.StatusInternalServerError, "Error merge chunks")
if !ok { return
log.Error("Error merge chunks") }
ctx.Error(http.StatusInternalServerError, "Error merge chunks") chunks, ok = chunkMap[artifact.ID]
return if !ok {
log.Error("Error merge chunks")
ctx.Error(http.StatusInternalServerError, "Error merge chunks")
return
}
} else {
chunks, err = listChunksByRunIDV4(r.fs, runID, artifact.ID, blockList)
if err != nil {
log.Error("Error merge chunks: %v", err)
ctx.Error(http.StatusInternalServerError, "Error merge chunks")
return
}
artifact.FileSize = chunks[len(chunks)-1].End + 1
artifact.FileCompressedSize = chunks[len(chunks)-1].End + 1
} }
checksum := "" checksum := ""
if req.Hash != nil { if req.Hash != nil {
checksum = req.Hash.Value checksum = req.Hash.Value
@ -468,7 +536,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
} }
} }
if respData.SignedUrl == "" { if respData.SignedUrl == "" {
respData.SignedUrl = r.buildArtifactURL("DownloadArtifact", artifactName, ctx.ActionTask.ID) respData.SignedUrl = r.buildArtifactURL("DownloadArtifact", artifactName, ctx.ActionTask.ID, artifact.ID)
} }
r.sendProtbufBody(ctx, &respData) r.sendProtbufBody(ctx, &respData)
} }

View file

@ -476,6 +476,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
ctx.Data["PosterID"] = posterID ctx.Data["PosterID"] = posterID
ctx.Data["IsFuzzy"] = isFuzzy ctx.Data["IsFuzzy"] = isFuzzy
ctx.Data["Keyword"] = keyword ctx.Data["Keyword"] = keyword
ctx.Data["IsShowClosed"] = isShowClosed
switch { switch {
case isShowClosed.Value(): case isShowClosed.Value():
ctx.Data["State"] = "closed" ctx.Data["State"] = "closed"

View file

@ -38,7 +38,6 @@ func TestCleanupSHA256(t *testing.T) {
Type: packages.TypeContainer, Type: packages.TypeContainer,
} }
_, err := db.GetEngine(ctx).Insert(&p) _, err := db.GetEngine(ctx).Insert(&p)
// package_version").Where("version = ?", multiTag).Update(&packages_model.PackageVersion{MetadataJSON: `corrupted "manifests":[{ bad`})
require.NoError(t, err) require.NoError(t, err)
var metadata string var metadata string

View file

@ -430,13 +430,12 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
} }
rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName) rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName)
if err != nil { if err != nil && !git_model.IsErrBranchNotExist(err) {
return fmt.Errorf("GetBranch: %v", err) return fmt.Errorf("GetBranch: %v", err)
} }
if rawBranch.IsDeleted { // database branch record not exist or it's a deleted branch
return nil notExist := git_model.IsErrBranchNotExist(err) || rawBranch.IsDeleted
}
commit, err := gitRepo.GetBranchCommit(branchName) commit, err := gitRepo.GetBranchCommit(branchName)
if err != nil { if err != nil {
@ -444,8 +443,10 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
} }
if err := db.WithTx(ctx, func(ctx context.Context) error { if err := db.WithTx(ctx, func(ctx context.Context) error {
if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil { if !notExist {
return err if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil {
return err
}
} }
return gitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{ return gitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{

View file

@ -12,6 +12,7 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
"unicode/utf8"
webhook_model "code.gitea.io/gitea/models/webhook" webhook_model "code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -179,8 +180,14 @@ func (d discordConvertor) Push(p *api.PushPayload) (DiscordPayload, error) {
var text string var text string
// for each commit, generate attachment text // for each commit, generate attachment text
for i, commit := range p.Commits { for i, commit := range p.Commits {
text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL, // limit the commit message display to just the summary, otherwise it would be hard to read
strings.TrimRight(commit.Message, "\r\n"), commit.Author.Name) message := strings.TrimRight(strings.SplitN(commit.Message, "\n", 1)[0], "\r")
// a limit of 50 is set because GitHub does the same
if utf8.RuneCountInString(message) > 50 {
message = fmt.Sprintf("%.47s...", message)
}
text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL, message, commit.Author.Name)
// add linebreak to each commit but the last // add linebreak to each commit but the last
if i < len(p.Commits)-1 { if i < len(p.Commits)-1 {
text += "\n" text += "\n"

View file

@ -80,6 +80,20 @@ func TestDiscordPayload(t *testing.T) {
assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL) assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL)
}) })
t.Run("PushWithLongCommitMessage", func(t *testing.T) {
p := pushTestMultilineCommitMessagePayload()
pl, err := dc.Push(p)
require.NoError(t, err)
assert.Len(t, pl.Embeds, 1)
assert.Equal(t, "[test/repo:test] 2 new commits", pl.Embeds[0].Title)
assert.Equal(t, "[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) This is a commit summary ⚠️⚠️⚠️⚠️ containing 你好... - user1\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) This is a commit summary ⚠️⚠️⚠️⚠️ containing 你好... - user1", pl.Embeds[0].Description)
assert.Equal(t, p.Sender.UserName, pl.Embeds[0].Author.Name)
assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.Embeds[0].Author.URL)
assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL)
})
t.Run("Issue", func(t *testing.T) { t.Run("Issue", func(t *testing.T) {
p := issueTestPayload() p := issueTestPayload()

View file

@ -64,9 +64,17 @@ func forkTestPayload() *api.ForkPayload {
} }
func pushTestPayload() *api.PushPayload { func pushTestPayload() *api.PushPayload {
return pushTestPayloadWithCommitMessage("commit message")
}
func pushTestMultilineCommitMessagePayload() *api.PushPayload {
return pushTestPayloadWithCommitMessage("This is a commit summary ⚠️⚠️⚠️⚠️ containing 你好 ⚠️⚠️️\n\nThis is the message body.")
}
func pushTestPayloadWithCommitMessage(message string) *api.PushPayload {
commit := &api.PayloadCommit{ commit := &api.PayloadCommit{
ID: "2020558fe2e34debb818a514715839cabd25e778", ID: "2020558fe2e34debb818a514715839cabd25e778",
Message: "commit message", Message: message,
URL: "http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778", URL: "http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778",
Author: &api.PayloadUser{ Author: &api.PayloadUser{
Name: "user1", Name: "user1",

View file

@ -1,9 +1,9 @@
<div class="ui secondary filter menu"> <div class="ui secondary filter menu">
{{if not .Repository.IsArchived}} {{if not .Repository.IsArchived}}
<!-- Action Button --> <!-- Action Button -->
{{if .IsShowClosed}} {{if and .IsShowClosed.Has .IsShowClosed.Value}}
<button class="ui primary basic button issue-action" data-action="open" data-url="{{$.RepoLink}}/issues/status">{{ctx.Locale.Tr "repo.issues.action_open"}}</button> <button class="ui primary basic button issue-action" data-action="open" data-url="{{$.RepoLink}}/issues/status">{{ctx.Locale.Tr "repo.issues.action_open"}}</button>
{{else}} {{else if and .IsShowClosed.Has (not .IsShowClosed.Value)}}
<button class="ui red basic button issue-action" data-action="close" data-url="{{$.RepoLink}}/issues/status">{{ctx.Locale.Tr "repo.issues.action_close"}}</button> <button class="ui red basic button issue-action" data-action="close" data-url="{{$.RepoLink}}/issues/status">{{ctx.Locale.Tr "repo.issues.action_close"}}</button>
{{end}} {{end}}
{{if $.IsRepoAdmin}} {{if $.IsRepoAdmin}}

View file

@ -7,12 +7,14 @@ import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"encoding/xml"
"io" "io"
"net/http" "net/http"
"strings" "strings"
"testing" "testing"
"time" "time"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/routers/api/actions" "code.gitea.io/gitea/routers/api/actions"
actions_service "code.gitea.io/gitea/services/actions" actions_service "code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
@ -175,6 +177,134 @@ func TestActionsArtifactV4UploadSingleFileWithRetentionDays(t *testing.T) {
assert.True(t, finalizeResp.Ok) assert.True(t, finalizeResp.Ok)
} }
func TestActionsArtifactV4UploadSingleFileWithPotentialHarmfulBlockID(t *testing.T) {
defer tests.PrepareTestEnv(t)()
token, err := actions_service.CreateAuthorizationToken(48, 792, 193)
require.NoError(t, err)
// acquire artifact upload url
req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJSON(&actions.CreateArtifactRequest{
Version: 4,
Name: "artifactWithPotentialHarmfulBlockID",
WorkflowRunBackendId: "792",
WorkflowJobRunBackendId: "193",
})).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var uploadResp actions.CreateArtifactResponse
protojson.Unmarshal(resp.Body.Bytes(), &uploadResp)
assert.True(t, uploadResp.Ok)
assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact")
// get upload urls
idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/")
url := uploadResp.SignedUploadUrl[idx:] + "&comp=block&blockid=%2f..%2fmyfile"
blockListURL := uploadResp.SignedUploadUrl[idx:] + "&comp=blocklist"
// upload artifact chunk
body := strings.Repeat("A", 1024)
req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body))
MakeRequest(t, req, http.StatusCreated)
// verify that the exploit didn't work
_, err = storage.Actions.Stat("myfile")
require.Error(t, err)
// upload artifact blockList
blockList := &actions.BlockList{
Latest: []string{
"/../myfile",
},
}
rawBlockList, err := xml.Marshal(blockList)
require.NoError(t, err)
req = NewRequestWithBody(t, "PUT", blockListURL, bytes.NewReader(rawBlockList))
MakeRequest(t, req, http.StatusCreated)
t.Logf("Create artifact confirm")
sha := sha256.Sum256([]byte(body))
// confirm artifact upload
req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJSON(&actions.FinalizeArtifactRequest{
Name: "artifactWithPotentialHarmfulBlockID",
Size: 1024,
Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])),
WorkflowRunBackendId: "792",
WorkflowJobRunBackendId: "193",
})).
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
var finalizeResp actions.FinalizeArtifactResponse
protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp)
assert.True(t, finalizeResp.Ok)
}
func TestActionsArtifactV4UploadSingleFileWithChunksOutOfOrder(t *testing.T) {
defer tests.PrepareTestEnv(t)()
token, err := actions_service.CreateAuthorizationToken(48, 792, 193)
require.NoError(t, err)
// acquire artifact upload url
req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJSON(&actions.CreateArtifactRequest{
Version: 4,
Name: "artifactWithChunksOutOfOrder",
WorkflowRunBackendId: "792",
WorkflowJobRunBackendId: "193",
})).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var uploadResp actions.CreateArtifactResponse
protojson.Unmarshal(resp.Body.Bytes(), &uploadResp)
assert.True(t, uploadResp.Ok)
assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact")
// get upload urls
idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/")
block1URL := uploadResp.SignedUploadUrl[idx:] + "&comp=block&blockid=block1"
block2URL := uploadResp.SignedUploadUrl[idx:] + "&comp=block&blockid=block2"
blockListURL := uploadResp.SignedUploadUrl[idx:] + "&comp=blocklist"
// upload artifact chunks
bodyb := strings.Repeat("B", 1024)
req = NewRequestWithBody(t, "PUT", block2URL, strings.NewReader(bodyb))
MakeRequest(t, req, http.StatusCreated)
bodya := strings.Repeat("A", 1024)
req = NewRequestWithBody(t, "PUT", block1URL, strings.NewReader(bodya))
MakeRequest(t, req, http.StatusCreated)
// upload artifact blockList
blockList := &actions.BlockList{
Latest: []string{
"block1",
"block2",
},
}
rawBlockList, err := xml.Marshal(blockList)
require.NoError(t, err)
req = NewRequestWithBody(t, "PUT", blockListURL, bytes.NewReader(rawBlockList))
MakeRequest(t, req, http.StatusCreated)
t.Logf("Create artifact confirm")
sha := sha256.Sum256([]byte(bodya + bodyb))
// confirm artifact upload
req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJSON(&actions.FinalizeArtifactRequest{
Name: "artifactWithChunksOutOfOrder",
Size: 2048,
Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])),
WorkflowRunBackendId: "792",
WorkflowJobRunBackendId: "193",
})).
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
var finalizeResp actions.FinalizeArtifactResponse
protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp)
assert.True(t, finalizeResp.Ok)
}
func TestActionsArtifactV4DownloadSingle(t *testing.T) { func TestActionsArtifactV4DownloadSingle(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()

View file

@ -78,7 +78,6 @@ const sfc = {
searchURL() { searchURL() {
return `${this.subUrl}/repo/search?sort=updated&order=desc&uid=${this.uid}&team_id=${this.teamId}&q=${this.searchQuery return `${this.subUrl}/repo/search?sort=updated&order=desc&uid=${this.uid}&team_id=${this.teamId}&q=${this.searchQuery
}&page=${this.page}&limit=${this.searchLimit}&mode=${this.repoTypes[this.reposFilter].searchMode }&page=${this.page}&limit=${this.searchLimit}&mode=${this.repoTypes[this.reposFilter].searchMode
}${this.reposFilter !== 'all' ? '&exclusive=1' : ''
}${this.archivedFilter === 'archived' ? '&archived=true' : ''}${this.archivedFilter === 'unarchived' ? '&archived=false' : '' }${this.archivedFilter === 'archived' ? '&archived=true' : ''}${this.archivedFilter === 'unarchived' ? '&archived=false' : ''
}${this.privateFilter === 'private' ? '&is_private=true' : ''}${this.privateFilter === 'public' ? '&is_private=false' : '' }${this.privateFilter === 'private' ? '&is_private=true' : ''}${this.privateFilter === 'public' ? '&is_private=false' : ''
}`; }`;