diff --git a/.forgejo/workflows-composite/install-minimum-git-version/action.yaml b/.forgejo/workflows-composite/install-minimum-git-version/action.yaml deleted file mode 100644 index d4e6e3f2a7..0000000000 --- a/.forgejo/workflows-composite/install-minimum-git-version/action.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Install the minimal version of Git supported by Forgejo -# -runs: - using: "composite" - steps: - - name: install git and git-lfs - run: | - set -x - - export DEBIAN_FRONTEND=noninteractive - - apt-get update -qq - apt-get -q install -y -qq curl ca-certificates - - curl -sS -o /tmp/git-man.deb http://archive.ubuntu.com/ubuntu/pool/main/g/git/git-man_2.34.1-1ubuntu1_all.deb - curl -sS -o /tmp/git.deb https://archive.ubuntu.com/ubuntu/pool/main/g/git/git_2.34.1-1ubuntu1_amd64.deb - curl -sS -o /tmp/git-lfs.deb https://archive.ubuntu.com/ubuntu/pool/universe/g/git-lfs/git-lfs_3.0.2-1_amd64.deb - - apt-get -q install --allow-downgrades -y -qq /tmp/git-man.deb - apt-get -q install --allow-downgrades -y -qq /tmp/git.deb - apt-get -q install --allow-downgrades -y -qq /tmp/git-lfs.deb diff --git a/.forgejo/workflows/renovate.yml b/.forgejo/workflows/renovate.yml index 729cba3723..5aa6c8cd98 100644 --- a/.forgejo/workflows/renovate.yml +++ b/.forgejo/workflows/renovate.yml @@ -28,7 +28,7 @@ jobs: runs-on: docker container: - image: data.forgejo.org/renovate/renovate:41.17.2 + image: data.forgejo.org/renovate/renovate:41.1.4 steps: - name: Load renovate repo cache diff --git a/.forgejo/workflows/testing-integration.yml b/.forgejo/workflows/testing-integration.yml index 102a2d9774..9e5cfb92ed 100644 --- a/.forgejo/workflows/testing-integration.yml +++ b/.forgejo/workflows/testing-integration.yml @@ -33,8 +33,11 @@ jobs: steps: - uses: https://data.forgejo.org/actions/checkout@v4 - uses: ./.forgejo/workflows-composite/setup-env - - name: install git 2.34.1 and git-lfs 3.0.2 - uses: ./.forgejo/workflows-composite/install-minimum-git-version + - name: install git 2.30 + uses: ./.forgejo/workflows-composite/apt-install-from + with: + packages: git/bullseye git-lfs/bullseye + release: bullseye - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-backend test-check' @@ -52,8 +55,11 @@ jobs: steps: - uses: https://data.forgejo.org/actions/checkout@v4 - uses: ./.forgejo/workflows-composite/setup-env - - name: install git 2.34.1 and git-lfs 3.0.2 - uses: ./.forgejo/workflows-composite/install-minimum-git-version + - name: install git 2.30 + uses: ./.forgejo/workflows-composite/apt-install-from + with: + packages: git/bullseye git-lfs/bullseye + release: bullseye - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-sqlite-migration test-sqlite' diff --git a/Makefile b/Makefile index db4ec2fbd5..e770f2a989 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasour GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.34.0 # renovate: datasource=go GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.2 # renovate: datasource=go -RENOVATE_NPM_PACKAGE ?= renovate@41.17.2 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate +RENOVATE_NPM_PACKAGE ?= renovate@41.1.4 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate # https://github.com/disposable-email-domains/disposable-email-domains/commits/main/ DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ... diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index 7159d55e99..eb89273e7f 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -82,11 +82,6 @@ wiki, issues, labels, releases, release_assets, milestones, pull_requests, comme } func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error { - setupConsoleLogger(log.INFO, log.CanColorStderr, os.Stderr) - - // setting.DisableLoggerInit() - setting.LoadSettings() // cannot access skip_tls_verify settings otherwise - stdCtx, cancel := installSignals(stdCtx) defer cancel() diff --git a/cmd/hook.go b/cmd/hook.go index 7378dc21ad..909cdfdf84 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -231,6 +231,8 @@ Forgejo or set your environment appropriately.`, "") } } + supportProcReceive := git.CheckGitVersionAtLeast("2.29") == nil + for scanner.Scan() { // TODO: support news feeds for wiki if isWiki { @@ -248,25 +250,31 @@ Forgejo or set your environment appropriately.`, "") total++ lastline++ - // All references should be checked because permission check was delayed. - oldCommitIDs[count] = oldCommitID - newCommitIDs[count] = newCommitID - refFullNames[count] = refFullName - count++ - fmt.Fprint(out, "*") + // If the ref is a branch or tag, check if it's protected + // if supportProcReceive all ref should be checked because + // permission check was delayed + if supportProcReceive || refFullName.IsBranch() || refFullName.IsTag() { + oldCommitIDs[count] = oldCommitID + newCommitIDs[count] = newCommitID + refFullNames[count] = refFullName + count++ + fmt.Fprint(out, "*") - if count >= hookBatchSize { - fmt.Fprintf(out, " Checking %d references\n", count) + if count >= hookBatchSize { + fmt.Fprintf(out, " Checking %d references\n", count) - hookOptions.OldCommitIDs = oldCommitIDs - hookOptions.NewCommitIDs = newCommitIDs - hookOptions.RefFullNames = refFullNames - extra := private.HookPreReceive(ctx, username, reponame, hookOptions) - if extra.HasError() { - return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error) + hookOptions.OldCommitIDs = oldCommitIDs + hookOptions.NewCommitIDs = newCommitIDs + hookOptions.RefFullNames = refFullNames + extra := private.HookPreReceive(ctx, username, reponame, hookOptions) + if extra.HasError() { + return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error) + } + count = 0 + lastline = 0 } - count = 0 - lastline = 0 + } else { + fmt.Fprint(out, ".") } if lastline >= hookBatchSize { fmt.Fprint(out, "\n") @@ -505,6 +513,10 @@ Forgejo or set your environment appropriately.`, "") return nil } + if git.CheckGitVersionAtLeast("2.29") != nil { + return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.") + } + reader := bufio.NewReader(os.Stdin) repoUser := os.Getenv(repo_module.EnvRepoUsername) repoName := os.Getenv(repo_module.EnvRepoName) diff --git a/cmd/serv.go b/cmd/serv.go index b0571a276c..1fac2d13f5 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -193,10 +193,12 @@ func runServ(ctx context.Context, c *cli.Command) error { } if len(words) < 2 { - // for AGit Flow - if cmd == "ssh_info" { - fmt.Print(`{"type":"agit","version":1}`) - return nil + if git.CheckGitVersionAtLeast("2.29") == nil { + // for AGit Flow + if cmd == "ssh_info" { + fmt.Print(`{"type":"agit","version":1}`) + return nil + } } return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd) } diff --git a/go.mod b/go.mod index 33ad5dbc67..510ec9c3ae 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,7 @@ require ( github.com/minio/minio-go/v7 v7.0.94 github.com/msteinert/pam/v2 v2.1.0 github.com/nektos/act v0.2.52 - github.com/niklasfasching/go-org v1.9.0 + github.com/niklasfasching/go-org v1.8.0 github.com/olivere/elastic/v7 v7.0.32 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 diff --git a/go.sum b/go.sum index 45497a1b49..53558fddd7 100644 --- a/go.sum +++ b/go.sum @@ -426,8 +426,8 @@ github.com/msteinert/pam/v2 v2.1.0 h1:er5F9TKV5nGFuTt12ubtqPHEUdeBwReP7vd3wovidG github.com/msteinert/pam/v2 v2.1.0/go.mod h1:KT28NNIcDFf3PcBmNI2mIGO4zZJ+9RSs/At2PB3IDVc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/niklasfasching/go-org v1.9.0 h1:4/Sr68Qx06hjC9MVDB/4etGP67JionLHGscLMOClpnk= -github.com/niklasfasching/go-org v1.9.0/go.mod h1:ZAGFFkWvUQcpazmi/8nHqwvARpr1xpb+Es67oUGX/48= +github.com/niklasfasching/go-org v1.8.0 h1:WyGLaajLLp8JbQzkmapZ1y0MOzKuKV47HkZRloi+HGY= +github.com/niklasfasching/go-org v1.8.0/go.mod h1:e2A9zJs7cdONrEGs3gvxCcaAEpwwPNPG7csDpXckMNg= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= diff --git a/models/fixtures/comment.yml b/models/fixtures/comment.yml index 6908d85dda..34407d6f81 100644 --- a/models/fixtures/comment.yml +++ b/models/fixtures/comment.yml @@ -186,46 +186,10 @@ type: 8 # milestone poster_id: 1 issue_id: 1 # in repo_id 1 - milestone_id: 10 # not existing milestone + milestone_id: 10 # not exsting milestone old_milestone_id: 0 created_unix: 946685080 -- - id: 2004 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 1 - old_milestone_id: 10 # not existing (ghost) milestone - created_unix: 946685085 - -- - id: 2005 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 10 # not existing (ghost) milestone - old_milestone_id: 1 - created_unix: 946685090 - -- - id: 2006 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 11 # not existing (ghost) milestone - old_milestone_id: 10 # not existing (ghost) milestone - created_unix: 946685095 - -- - id: 2007 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 0 - old_milestone_id: 11 # not existing (ghost) milestone - created_unix: 946685100 - - id: 2010 type: 30 # project diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 2f104eed65..c383fa43ac 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -32,7 +32,7 @@ created_unix: 1731254961 updated_unix: 1731254961 topics: '[]' - + - id: 2 owner_id: 2 diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go index 9b502d1c91..7285e347b4 100644 --- a/models/issues/comment_list.go +++ b/models/issues/comment_list.go @@ -101,7 +101,7 @@ func (comments CommentList) loadMilestones(ctx context.Context) error { return nil } - milestones := make(map[int64]*Milestone, len(milestoneIDs)) + milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs)) left := len(milestoneIDs) for left > 0 { limit := db.DefaultMaxInSize @@ -110,7 +110,7 @@ func (comments CommentList) loadMilestones(ctx context.Context) error { } err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). - Find(&milestones) + Find(&milestoneMaps) if err != nil { return err } @@ -118,8 +118,8 @@ func (comments CommentList) loadMilestones(ctx context.Context) error { milestoneIDs = milestoneIDs[limit:] } - for _, comment := range comments { - comment.Milestone = milestones[comment.MilestoneID] + for _, issue := range comments { + issue.Milestone = milestoneMaps[issue.MilestoneID] } return nil } @@ -140,7 +140,7 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error { return nil } - milestones := make(map[int64]*Milestone, len(milestoneIDs)) + milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs)) left := len(milestoneIDs) for left > 0 { limit := db.DefaultMaxInSize @@ -149,7 +149,7 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error { } err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). - Find(&milestones) + Find(&milestoneMaps) if err != nil { return err } @@ -157,8 +157,8 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error { milestoneIDs = milestoneIDs[limit:] } - for _, comment := range comments { - comment.OldMilestone = milestones[comment.OldMilestoneID] + for _, issue := range comments { + issue.OldMilestone = milestoneMaps[issue.MilestoneID] } return nil } diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 529f0c15d4..91a69c26a7 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -48,9 +48,7 @@ type IssuesOptions struct { //nolint UpdatedBeforeUnix int64 // prioritize issues from this repo PriorityRepoID int64 - // if this issue index (not ID) exists and matches the filters, *and* priorityrepo sort is used, show it first - PriorityIssueIndex int64 - IsArchived optional.Option[bool] + IsArchived optional.Option[bool] // If combined with AllPublic, then private as well as public issues // that matches the criteria will be returned, if AllPublic is false @@ -62,7 +60,7 @@ type IssuesOptions struct { //nolint // applySorts sort an issues-related session based on the provided // sortType string -func applySorts(sess *xorm.Session, sortType string, priorityRepoID, priorityIssueIndex int64) { +func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) { switch sortType { case "oldest": sess.Asc("issue.created_unix").Asc("issue.id") @@ -99,11 +97,8 @@ func applySorts(sess *xorm.Session, sortType string, priorityRepoID, priorityIss case "priorityrepo": sess.OrderBy("CASE "+ "WHEN issue.repo_id = ? THEN 1 "+ - "ELSE 2 END ASC", priorityRepoID) - if priorityIssueIndex != 0 { - sess.OrderBy("issue.index = ? DESC", priorityIssueIndex) - } - sess.Desc("issue.created_unix"). + "ELSE 2 END ASC", priorityRepoID). + Desc("issue.created_unix"). Desc("issue.id") case "project-column-sorting": sess.Asc("project_issue.sorting").Desc("issue.created_unix").Desc("issue.id") @@ -475,7 +470,7 @@ func Issues(ctx context.Context, opts *IssuesOptions) (IssueList, error) { Join("INNER", "repository", "`issue`.repo_id = `repository`.id") applyLimit(sess, opts) applyConditions(sess, opts) - applySorts(sess, opts.SortType, opts.PriorityRepoID, opts.PriorityIssueIndex) + applySorts(sess, opts.SortType, opts.PriorityRepoID) issues := IssueList{} if err := sess.Find(&issues); err != nil { @@ -499,7 +494,7 @@ func IssueIDs(ctx context.Context, opts *IssuesOptions, otherConds ...builder.Co } applyLimit(sess, opts) - applySorts(sess, opts.SortType, opts.PriorityRepoID, opts.PriorityIssueIndex) + applySorts(sess, opts.SortType, opts.PriorityRepoID) var res []int64 total, err := sess.Select("`issue`.id").Table(&Issue{}).FindAndCount(&res) diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go index ddb813cf44..8fc0491026 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -149,7 +149,7 @@ func PullRequests(ctx context.Context, baseRepoID int64, opts *PullRequestsOptio } findSession := listPullRequestStatement(ctx, baseRepoID, opts) - applySorts(findSession, opts.SortType, 0, 0) + applySorts(findSession, opts.SortType, 0) findSession = db.SetSessionPagination(findSession, opts) prs := make([]*PullRequest, 0, opts.PageSize) found := findSession.Find(&prs) diff --git a/models/moderation/abuse_report.go b/models/moderation/abuse_report.go index 3a6244ef4c..dadd61a95e 100644 --- a/models/moderation/abuse_report.go +++ b/models/moderation/abuse_report.go @@ -100,7 +100,7 @@ type AbuseReport struct { // The abuse category selected by the reporter. Category AbuseCategoryType `xorm:"INDEX NOT NULL"` // Remarks provided by the reporter. - Remarks string `xorm:"VARCHAR(500)"` + Remarks string // The ID of the corresponding shadow-copied content when exists; otherwise null. ShadowCopyID sql.NullInt64 `xorm:"DEFAULT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` diff --git a/models/moderation/shadow_copy.go b/models/moderation/shadow_copy.go index d363610a48..cdd8f69c52 100644 --- a/models/moderation/shadow_copy.go +++ b/models/moderation/shadow_copy.go @@ -17,7 +17,7 @@ import ( type AbuseReportShadowCopy struct { ID int64 `xorm:"pk autoincr"` - RawValue string `xorm:"LONGTEXT NOT NULL"` // A JSON with relevant fields from user, repository, issue or comment table. + RawValue string `xorm:"NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` } diff --git a/modules/git/blame.go b/modules/git/blame.go index 868edab2b8..4ff347e31b 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -132,7 +132,7 @@ func (r *BlameReader) Close() error { // CreateBlameReader creates reader for given repository, commit and file func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) { var ignoreRevsFile *string - if !bypassBlameIgnore { + if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore { ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit) } diff --git a/modules/git/blob.go b/modules/git/blob.go index 14ca2b1445..30615afe32 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -8,7 +8,6 @@ import ( "bufio" "bytes" "encoding/base64" - "fmt" "io" "forgejo.org/modules/log" @@ -173,43 +172,33 @@ func (b *Blob) GetBlobContent(limit int64) (string, error) { return string(buf), err } -type BlobTooLargeError struct { - Size, Limit int64 -} - -func (b BlobTooLargeError) Error() string { - return fmt.Sprintf("blob: content larger than limit (%d > %d)", b.Size, b.Limit) -} - -// GetContentBase64 Reads the content of the blob and returns it as base64 encoded string. -// Returns [BlobTooLargeError] if the (unencoded) content is larger than the limit. -func (b *Blob) GetContentBase64(limit int64) (string, error) { - if b.Size() > limit { - return "", BlobTooLargeError{ - Size: b.Size(), - Limit: limit, - } - } - - rc, size, err := b.NewTruncatedReader(limit) +// GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string +func (b *Blob) GetBlobContentBase64() (string, error) { + dataRc, err := b.DataAsync() if err != nil { return "", err } - defer rc.Close() + defer dataRc.Close() - encoding := base64.StdEncoding - buf := bytes.NewBuffer(make([]byte, 0, encoding.EncodedLen(int(size)))) + pr, pw := io.Pipe() + encoder := base64.NewEncoder(base64.StdEncoding, pw) - encoder := base64.NewEncoder(encoding, buf) + go func() { + _, err := io.Copy(encoder, dataRc) + _ = encoder.Close() - if _, err := io.Copy(encoder, rc); err != nil { + if err != nil { + _ = pw.CloseWithError(err) + } else { + _ = pw.Close() + } + }() + + out, err := io.ReadAll(pr) + if err != nil { return "", err } - if err := encoder.Close(); err != nil { - return "", err - } - - return buf.String(), nil + return string(out), nil } // GuessContentType guesses the content type of the blob. diff --git a/modules/git/blob_test.go b/modules/git/blob_test.go index a4b8033941..54115013d3 100644 --- a/modules/git/blob_test.go +++ b/modules/git/blob_test.go @@ -63,24 +63,6 @@ func TestBlob(t *testing.T) { require.Equal(t, "file2\n", r) }) - t.Run("GetContentBase64", func(t *testing.T) { - r, err := testBlob.GetContentBase64(100) - require.NoError(t, err) - require.Equal(t, "ZmlsZTIK", r) - - r, err = testBlob.GetContentBase64(-1) - require.ErrorAs(t, err, &BlobTooLargeError{}) - require.Empty(t, r) - - r, err = testBlob.GetContentBase64(4) - require.ErrorAs(t, err, &BlobTooLargeError{}) - require.Empty(t, r) - - r, err = testBlob.GetContentBase64(6) - require.NoError(t, err) - require.Equal(t, "ZmlsZTIK", r) - }) - t.Run("NewTruncatedReader", func(t *testing.T) { // read fewer than available rc, size, err := testBlob.NewTruncatedReader(100) diff --git a/modules/git/commit.go b/modules/git/commit.go index 1228b4523b..96831e3ae4 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -412,7 +412,11 @@ func (c *Commit) GetSubModule(entryname string) (string, error) { // GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only') func (c *Commit) GetBranchName() (string, error) { - cmd := NewCommand(c.repo.Ctx, "name-rev", "--exclude", "refs/tags/*", "--name-only", "--no-undefined").AddDynamicArguments(c.ID.String()) + cmd := NewCommand(c.repo.Ctx, "name-rev") + if CheckGitVersionAtLeast("2.13.0") == nil { + cmd.AddArguments("--exclude", "refs/tags/*") + } + cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String()) data, _, err := cmd.RunStdString(&RunOpts{Dir: c.repo.Path}) if err != nil { // handle special case where git can not describe commit diff --git a/modules/git/git.go b/modules/git/git.go index 851b090b53..1dfd0b5134 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -23,7 +23,7 @@ import ( ) // RequiredVersion is the minimum Git version required -const RequiredVersion = "2.34.1" +const RequiredVersion = "2.0.0" var ( // GitExecutable is the command name of git @@ -33,6 +33,7 @@ var ( // DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx DefaultContext context.Context + SupportProcReceive bool // >= 2.29 SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’ InvertedGitFlushEnv bool // 2.43.1 SupportCheckAttrOnBare bool // >= 2.40 @@ -112,7 +113,7 @@ func VersionInfo() string { format := "%s" args := []any{GitVersion.Original()} // Since git wire protocol has been released from git v2.18 - if setting.Git.EnableAutoGitWireProtocol { + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { format += ", Wire Protocol %s Enabled" args = append(args, "Version 2") // for focus color } @@ -171,13 +172,16 @@ func InitFull(ctx context.Context) (err error) { _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg")) } - if setting.Git.EnableAutoGitWireProtocol { + // Since git wire protocol has been released from git v2.18 + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2") } // Explicitly disable credential helper, otherwise Git credentials might leak - globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") - + if CheckGitVersionAtLeast("2.9") == nil { + globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") + } + SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil SupportCheckAttrOnBare = CheckGitVersionAtLeast("2.40") == nil if SupportHashSha256 { @@ -191,6 +195,9 @@ func InitFull(ctx context.Context) (err error) { SupportGrepMaxCount = CheckGitVersionAtLeast("2.38") == nil if setting.LFS.StartServer { + if CheckGitVersionAtLeast("2.1.2") != nil { + return errors.New("LFS server support requires Git >= 2.1.2") + } globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") } @@ -227,28 +234,38 @@ func syncGitConfig() (err error) { } } - // Set git some configurations - these must be set to these values for forgejo to work correctly + // Set git some configurations - these must be set to these values for gitea to work correctly if err := configSet("core.quotePath", "false"); err != nil { return err } - if err := configSet("receive.advertisePushOptions", "true"); err != nil { - return err + if CheckGitVersionAtLeast("2.10") == nil { + if err := configSet("receive.advertisePushOptions", "true"); err != nil { + return err + } } - if err := configSet("core.commitGraph", "true"); err != nil { - return err - } - if err := configSet("gc.writeCommitGraph", "true"); err != nil { - return err - } - if err := configSet("fetch.writeCommitGraph", "true"); err != nil { - return err + if CheckGitVersionAtLeast("2.18") == nil { + if err := configSet("core.commitGraph", "true"); err != nil { + return err + } + if err := configSet("gc.writeCommitGraph", "true"); err != nil { + return err + } + if err := configSet("fetch.writeCommitGraph", "true"); err != nil { + return err + } } - // set support for AGit flow - if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { - return err + if SupportProcReceive { + // set support for AGit flow + if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { + return err + } + } else { + if err := configUnsetAll("receive.procReceiveRefs", "refs/for"); err != nil { + return err + } } // Due to CVE-2022-24765, git now denies access to git directories which are not owned by current user @@ -267,6 +284,11 @@ func syncGitConfig() (err error) { switch setting.Repository.Signing.Format { case "ssh": + // First do a git version check. + if CheckGitVersionAtLeast("2.34.0") != nil { + return errors.New("ssh signing requires Git >= 2.34.0") + } + // Get the ssh-keygen binary that Git will use. // This can be overridden in app.ini in [git.config] section, so we must // query this information. @@ -303,7 +325,8 @@ func syncGitConfig() (err error) { } } - if !setting.Git.DisablePartialClone { + // By default partial clones are disabled, enable them from git v2.22 + if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil { if err = configSet("uploadpack.allowfilter", "true"); err != nil { return err } diff --git a/modules/git/git_test.go b/modules/git/git_test.go index 38d4db169c..01200dba68 100644 --- a/modules/git/git_test.go +++ b/modules/git/git_test.go @@ -14,6 +14,7 @@ import ( "forgejo.org/modules/test" "forgejo.org/modules/util" + "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -104,6 +105,10 @@ func TestSyncConfigGPGFormat(t *testing.T) { }) t.Run("SSH format", func(t *testing.T) { + if CheckGitVersionAtLeast("2.34.0") != nil { + t.SkipNow() + } + r, err := os.OpenRoot(t.TempDir()) require.NoError(t, err) f, err := r.OpenFile("ssh-keygen", os.O_CREATE|os.O_TRUNC, 0o700) @@ -116,6 +121,13 @@ func TestSyncConfigGPGFormat(t *testing.T) { assert.True(t, gitConfigContains("[gpg]")) assert.True(t, gitConfigContains("format = ssh")) + t.Run("Old version", func(t *testing.T) { + oldVersion, err := version.NewVersion("2.33.0") + require.NoError(t, err) + defer test.MockVariableValue(&GitVersion, oldVersion)() + require.ErrorContains(t, syncGitConfig(), "ssh signing requires Git >= 2.34.0") + }) + t.Run("No ssh-keygen binary", func(t *testing.T) { require.NoError(t, r.Remove("ssh-keygen")) require.ErrorContains(t, syncGitConfig(), "git signing requires a ssh-keygen binary") diff --git a/modules/git/pipeline/revlist.go b/modules/git/pipeline/revlist.go index 1ee8921854..f39b7113bb 100644 --- a/modules/git/pipeline/revlist.go +++ b/modules/git/pipeline/revlist.go @@ -16,6 +16,26 @@ import ( "forgejo.org/modules/log" ) +// RevListAllObjects runs rev-list --objects --all and writes to a pipewriter +func RevListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.WaitGroup, basePath string, errChan chan<- error) { + defer wg.Done() + defer revListWriter.Close() + + stderr := new(bytes.Buffer) + var errbuf strings.Builder + cmd := git.NewCommand(ctx, "rev-list", "--objects", "--all") + if err := cmd.Run(&git.RunOpts{ + Dir: basePath, + Stdout: revListWriter, + Stderr: stderr, + }); err != nil { + log.Error("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String()) + err = fmt.Errorf("git rev-list --objects --all [%s]: %w - %s", basePath, err, errbuf.String()) + _ = revListWriter.CloseWithError(err) + errChan <- err + } +} + // RevListObjects run rev-list --objects from headSHA to baseSHA func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath, headSHA, baseSHA string, errChan chan<- error) { defer wg.Done() diff --git a/modules/git/remote.go b/modules/git/remote.go index 83a02fe2be..fb66d76ff0 100644 --- a/modules/git/remote.go +++ b/modules/git/remote.go @@ -12,7 +12,14 @@ import ( // GetRemoteAddress returns remote url of git repository in the repoPath with special remote name func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) { - result, _, err := NewCommand(ctx, "remote", "get-url").AddDynamicArguments(remoteName).RunStdString(&RunOpts{Dir: repoPath}) + var cmd *Command + if CheckGitVersionAtLeast("2.7") == nil { + cmd = NewCommand(ctx, "remote", "get-url").AddDynamicArguments(remoteName) + } else { + cmd = NewCommand(ctx, "config", "--get").AddDynamicArguments("remote." + remoteName + ".url") + } + + result, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath}) if err != nil { return "", err } diff --git a/modules/git/repo_attribute_test.go b/modules/git/repo_attribute_test.go index 3d2c845fa0..c69382e245 100644 --- a/modules/git/repo_attribute_test.go +++ b/modules/git/repo_attribute_test.go @@ -5,6 +5,7 @@ package git import ( "context" + "fmt" "io" "io/fs" "os" @@ -196,7 +197,7 @@ func TestGitAttributeCheckerError(t *testing.T) { path := t.TempDir() // we can't use unittest.CopyDir because of an import cycle (git.Init in unittest) - require.NoError(t, os.CopyFS(path, os.DirFS(filepath.Join(testReposDir, "language_stats_repo")))) + require.NoError(t, CopyFS(path, os.DirFS(filepath.Join(testReposDir, "language_stats_repo")))) gitRepo, err := openRepositoryWithDefaultContext(path) require.NoError(t, err) @@ -323,3 +324,32 @@ func TestGitAttributeCheckerError(t *testing.T) { require.ErrorIs(t, err, fs.ErrClosed) }) } + +// CopyFS is adapted from https://github.com/golang/go/issues/62484 +// which should be available with go1.23 +func CopyFS(dir string, fsys fs.FS) error { + return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, _ error) error { + targ := filepath.Join(dir, filepath.FromSlash(path)) + if d.IsDir() { + return os.MkdirAll(targ, 0o777) + } + r, err := fsys.Open(path) + if err != nil { + return err + } + defer r.Close() + info, err := r.Stat() + if err != nil { + return err + } + w, err := os.OpenFile(targ, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o666|info.Mode()&0o777) + if err != nil { + return err + } + if _, err := io.Copy(w, r); err != nil { + w.Close() + return fmt.Errorf("copying %s: %v", path, err) + } + return w.Close() + }) +} diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 41ca0e39b1..4c8516f828 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -443,18 +443,42 @@ func (repo *Repository) getCommitsBeforeLimit(id ObjectID, num int) ([]*Commit, } func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) { - command := NewCommand(repo.Ctx, "for-each-ref", "--format=%(refname:strip=2)").AddOptionValues("--contains", commit.ID.String(), BranchPrefix) + if CheckGitVersionAtLeast("2.7.0") == nil { + command := NewCommand(repo.Ctx, "for-each-ref", "--format=%(refname:strip=2)").AddOptionValues("--contains", commit.ID.String(), BranchPrefix) - if limit != -1 { - command = command.AddOptionFormat("--count=%d", limit) + if limit != -1 { + command = command.AddOptionFormat("--count=%d", limit) + } + + stdout, _, err := command.RunStdString(&RunOpts{Dir: repo.Path}) + if err != nil { + return nil, err + } + + branches := strings.Fields(stdout) + return branches, nil } - stdout, _, err := command.RunStdString(&RunOpts{Dir: repo.Path}) + stdout, _, err := NewCommand(repo.Ctx, "branch").AddOptionValues("--contains", commit.ID.String()).RunStdString(&RunOpts{Dir: repo.Path}) if err != nil { return nil, err } - branches := strings.Fields(stdout) + refs := strings.Split(stdout, "\n") + + var max int + if len(refs) > limit { + max = limit + } else { + max = len(refs) - 1 + } + + branches := make([]string, max) + for i, ref := range refs[:max] { + parts := strings.Fields(ref) + + branches[i] = parts[len(parts)-1] + } return branches, nil } diff --git a/modules/git/repo_commitgraph.go b/modules/git/repo_commitgraph.go index c3647bd894..492438be37 100644 --- a/modules/git/repo_commitgraph.go +++ b/modules/git/repo_commitgraph.go @@ -11,8 +11,10 @@ import ( // WriteCommitGraph write commit graph to speed up repo access // this requires git v2.18 to be installed func WriteCommitGraph(ctx context.Context, repoPath string) error { - if _, _, err := NewCommand(ctx, "commit-graph", "write").RunStdString(&RunOpts{Dir: repoPath}); err != nil { - return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err) + if CheckGitVersionAtLeast("2.18") == nil { + if _, _, err := NewCommand(ctx, "commit-graph", "write").RunStdString(&RunOpts{Dir: repoPath}); err != nil { + return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err) + } } return nil } diff --git a/modules/git/tree_entry.go b/modules/git/tree_entry.go index ec5c632ca0..d51b7992fe 100644 --- a/modules/git/tree_entry.go +++ b/modules/git/tree_entry.go @@ -116,37 +116,32 @@ func (te *TreeEntry) Type() string { } } -// LinkTarget returns the target of the symlink as string. -func (te *TreeEntry) LinkTarget() (string, error) { - if !te.IsLink() { - return "", ErrBadLink{te.Name(), "not a symlink"} - } - - const symlinkLimit = 4096 // according to git config core.longpaths https://stackoverflow.com/a/22575737 - blob := te.Blob() - if blob.Size() > symlinkLimit { - return "", ErrBadLink{te.Name(), "symlink too large"} - } - - rc, size, err := blob.NewTruncatedReader(symlinkLimit) - if err != nil { - return "", err - } - defer rc.Close() - - buf := make([]byte, int(size)) - _, err = io.ReadFull(rc, buf) - return string(buf), err -} - // FollowLink returns the entry pointed to by a symlink func (te *TreeEntry) FollowLink() (*TreeEntry, string, error) { + if !te.IsLink() { + return nil, "", ErrBadLink{te.Name(), "not a symlink"} + } + // read the link - lnk, err := te.LinkTarget() + r, err := te.Blob().DataAsync() if err != nil { return nil, "", err } + closed := false + defer func() { + if !closed { + _ = r.Close() + } + }() + buf := make([]byte, te.Size()) + _, err = io.ReadFull(r, buf) + if err != nil { + return nil, "", err + } + _ = r.Close() + closed = true + lnk := string(buf) t := te.ptree // traverse up directories diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go index 8549ba8dfc..573d63a446 100644 --- a/modules/indexer/issues/bleve/bleve.go +++ b/modules/indexer/issues/bleve/bleve.go @@ -170,7 +170,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if issueID, err := token.ParseIssueReference(); err == nil { idQuery := inner_bleve.NumericEqualityQuery(issueID, "index") - idQuery.SetBoost(20.0) + idQuery.SetBoost(5.0) innerQ.AddQuery(idQuery) } @@ -197,15 +197,6 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( queries = append(queries, bleve.NewDisjunctionQuery(repoQueries...)) } - if options.PriorityRepoID.Has() { - eq := inner_bleve.NumericEqualityQuery(options.PriorityRepoID.Value(), "repo_id") - eq.SetBoost(10.0) - meh := bleve.NewMatchAllQuery() - meh.SetBoost(0) - should := bleve.NewDisjunctionQuery(eq, meh) - queries = append(queries, should) - } - if options.IsPull.Has() { queries = append(queries, inner_bleve.BoolFieldQuery(options.IsPull.Value(), "is_pull")) } diff --git a/modules/indexer/issues/db/db.go b/modules/indexer/issues/db/db.go index 5f42bce9a1..397daa3265 100644 --- a/modules/indexer/issues/db/db.go +++ b/modules/indexer/issues/db/db.go @@ -53,7 +53,6 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( cond := builder.NewCond() - var priorityIssueIndex int64 if options.Keyword != "" { repoCond := builder.In("repo_id", options.RepoIDs) if len(options.RepoIDs) == 1 { @@ -83,7 +82,6 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( builder.Eq{"`index`": issueID}, cond, ) - priorityIssueIndex = issueID } } @@ -91,7 +89,6 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if err != nil { return nil, err } - opt.PriorityIssueIndex = priorityIssueIndex // If pagesize == 0, return total count only. It's a special case for search count. if options.Paginator != nil && options.Paginator.PageSize == 0 { diff --git a/modules/indexer/issues/db/options.go b/modules/indexer/issues/db/options.go index 55a471fc8e..4411cc1c37 100644 --- a/modules/indexer/issues/db/options.go +++ b/modules/indexer/issues/db/options.go @@ -78,11 +78,6 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m User: nil, } - if options.PriorityRepoID.Has() { - opts.SortType = "priorityrepo" - opts.PriorityRepoID = options.PriorityRepoID.Value() - } - if len(options.MilestoneIDs) == 1 && options.MilestoneIDs[0] == 0 { opts.MilestoneIDs = []int64{db.NoConditionID} } else { diff --git a/modules/indexer/issues/elasticsearch/elasticsearch.go b/modules/indexer/issues/elasticsearch/elasticsearch.go index d632a22b2a..9d2786e101 100644 --- a/modules/indexer/issues/elasticsearch/elasticsearch.go +++ b/modules/indexer/issues/elasticsearch/elasticsearch.go @@ -165,7 +165,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( } var eitherQ elastic.Query = innerQ if issueID, err := token.ParseIssueReference(); err == nil { - indexQ := elastic.NewTermQuery("index", issueID).Boost(20) + indexQ := elastic.NewTermQuery("index", issueID).Boost(15.0) eitherQ = elastic.NewDisMaxQuery().Query(indexQ).Query(innerQ).TieBreaker(0.5) } switch token.Kind { @@ -188,10 +188,6 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( } query.Must(q) } - if options.PriorityRepoID.Has() { - q := elastic.NewTermQuery("repo_id", options.PriorityRepoID.Value()).Boost(10) - query.Should(q) - } if options.IsPull.Has() { query.Must(elastic.NewTermQuery("is_pull", options.IsPull.Value())) diff --git a/modules/indexer/issues/internal/model.go b/modules/indexer/issues/internal/model.go index cdd113212d..6c55405179 100644 --- a/modules/indexer/issues/internal/model.go +++ b/modules/indexer/issues/internal/model.go @@ -75,9 +75,8 @@ type SearchResult struct { type SearchOptions struct { Keyword string // keyword to search - RepoIDs []int64 // repository IDs which the issues belong to - AllPublic bool // if include all public repositories - PriorityRepoID optional.Option[int64] // issues from this repository will be prioritized when SortByScore + RepoIDs []int64 // repository IDs which the issues belong to + AllPublic bool // if include all public repositories IsPull optional.Option[bool] // if the issues is a pull request IsClosed optional.Option[bool] // if the issues is closed diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go index b63957ff84..ef75955a14 100644 --- a/modules/indexer/issues/internal/tests/tests.go +++ b/modules/indexer/issues/internal/tests/tests.go @@ -742,25 +742,6 @@ var cases = []*testIndexerCase{ } }, }, - { - Name: "PriorityRepoID", - SearchOptions: &internal.SearchOptions{ - IsPull: optional.Some(false), - IsClosed: optional.Some(false), - PriorityRepoID: optional.Some(int64(3)), - Paginator: &db.ListOptionsAll, - SortBy: internal.SortByScore, - }, - Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { - for i, v := range result.Hits { - if i < 7 { - assert.Equal(t, int64(3), data[v.ID].RepoID) - } else { - assert.NotEqual(t, int64(3), data[v.ID].RepoID) - } - } - }, - }, } type testIndexerCase struct { diff --git a/modules/lfs/pointer_scanner.go b/modules/lfs/pointer_scanner.go index 80da8e5222..632ecd19ae 100644 --- a/modules/lfs/pointer_scanner.go +++ b/modules/lfs/pointer_scanner.go @@ -39,7 +39,16 @@ func SearchPointerBlobs(ctx context.Context, repo *git.Repository, pointerChan c go pipeline.BlobsLessThan1024FromCatFileBatchCheck(catFileCheckReader, shasToBatchWriter, &wg) // 1. Run batch-check on all objects in the repository - go pipeline.CatFileBatchCheckAllObjects(ctx, catFileCheckWriter, &wg, basePath, errChan) + if git.CheckGitVersionAtLeast("2.6.0") != nil { + revListReader, revListWriter := io.Pipe() + shasToCheckReader, shasToCheckWriter := io.Pipe() + wg.Add(2) + go pipeline.CatFileBatchCheck(ctx, shasToCheckReader, catFileCheckWriter, &wg, basePath) + go pipeline.BlobsFromRevListObjects(revListReader, shasToCheckWriter, &wg) + go pipeline.RevListAllObjects(ctx, revListWriter, &wg, basePath, errChan) + } else { + go pipeline.CatFileBatchCheckAllObjects(ctx, catFileCheckWriter, &wg, basePath, errChan) + } wg.Wait() close(pointerChan) diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json index a551db87dc..b1c98e4551 100644 --- a/options/locale_next/locale_en-US.json +++ b/options/locale_next/locale_en-US.json @@ -102,6 +102,5 @@ "admin.dashboard.cleanup_offline_runners": "Cleanup offline runners", "settings.visibility.description": "Profile visibility affects others' ability to access your non-private repositories. Learn more", "avatar.constraints_hint": "Custom avatar may not exceed %[1]s in size or be larger than %[2]dx%[3]d pixels", - "og.repo.summary_card.alt_description": "Summary card of repository %[1]s, described as: %[2]s", "meta.last_line": "Thank you for translating Forgejo! This line isn't seen by the users but it serves other purposes in the translation management. You can place a fun fact in the translation instead of translating it." } diff --git a/package-lock.json b/package-lock.json index 06a9497efc..604ff38c18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "esbuild-loader": "4.3.0", "escape-goat": "4.0.0", "fast-glob": "3.3.3", - "htmx.org": "2.0.6", + "htmx.org": "1.9.12", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.22", @@ -65,21 +65,21 @@ "@eslint-community/eslint-plugin-eslint-comments": "4.5.0", "@playwright/test": "1.52.0", "@stoplight/spectral-cli": "6.15.0", - "@stylistic/eslint-plugin": "5.0.0", - "@stylistic/stylelint-plugin": "3.1.3", - "@vitejs/plugin-vue": "6.0.0", + "@stylistic/eslint-plugin": "4.4.1", + "@stylistic/stylelint-plugin": "3.1.2", + "@vitejs/plugin-vue": "5.2.4", "@vitest/coverage-v8": "3.2.3", "@vitest/eslint-plugin": "1.2.2", "@vue/test-utils": "2.4.6", - "eslint": "9.30.0", - "eslint-import-resolver-typescript": "4.4.4", + "eslint": "9.28.0", + "eslint-import-resolver-typescript": "4.4.3", "eslint-plugin-array-func": "5.0.2", - "eslint-plugin-import-x": "4.16.1", + "eslint-plugin-import-x": "4.15.1", "eslint-plugin-no-jquery": "3.1.1", "eslint-plugin-no-use-extend-native": "0.7.2", "eslint-plugin-playwright": "2.2.0", "eslint-plugin-regexp": "2.9.0", - "eslint-plugin-sonarjs": "3.0.4", + "eslint-plugin-sonarjs": "3.0.2", "eslint-plugin-toml": "0.12.0", "eslint-plugin-unicorn": "59.0.1", "eslint-plugin-vitest-globals": "1.5.0", @@ -87,18 +87,18 @@ "eslint-plugin-vue-scoped-css": "2.10.0", "eslint-plugin-wc": "3.0.1", "globals": "16.1.0", - "happy-dom": "18.0.1", + "happy-dom": "18.0.0", "license-checker-rseidelsohn": "4.4.2", "markdownlint-cli": "0.45.0", "postcss-html": "1.8.0", "sharp": "0.34.2", - "stylelint": "16.21.0", + "stylelint": "16.20.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.11", "stylelint-value-no-unknown-custom-properties": "6.0.1", - "svgo": "4.0.0", + "svgo": "3.2.0", "typescript": "5.8.3", - "typescript-eslint": "8.35.0", + "typescript-eslint": "8.34.0", "vite-string-plugin": "1.3.4", "vitest": "3.2.3" }, @@ -216,12 +216,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.7.tgz", - "integrity": "sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.7" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -240,9 +240,9 @@ } }, "node_modules/@babel/types": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.7.tgz", - "integrity": "sha512-8OLQgDScAOHXnAz2cV+RfzzNMipuLVBz2biuAJFMV9bfkNf393je3VM8CLkjQodW5+iWsSJdSgSWT6rsZoXHPw==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -1021,9 +1021,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz", + "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1049,9 +1049,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", - "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz", + "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1146,9 +1146,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.30.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.0.tgz", - "integrity": "sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", "dev": true, "license": "MIT", "engines": { @@ -1169,13 +1169,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", - "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz", + "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.1", + "@eslint/core": "^0.15.0", "levn": "^0.4.1" }, "engines": { @@ -1183,9 +1183,9 @@ } }, "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", - "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz", + "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1884,13 +1884,17 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.9.tgz", - "integrity": "sha512-xpz6C/vXOegF9VEtlMBlkNNIjHrLhKaFBsO4lmQGr00x5BHp7p+oliR6i7LwIcM5cZU2VjLSwm2R+/zj5IjPWg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1902,10 +1906,19 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/source-map": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.7.tgz", - "integrity": "sha512-maArE+jvYbj06DXh2iFlXSSDjTWXODlPTQHdDRQdGoYw7KvT4SfYCnPHfCyww8Z3JqFsW0BBjPLj8A2fwAvv7Q==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1913,15 +1926,15 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.1.tgz", - "integrity": "sha512-mBLKRHc7Ffw/hObYb9+cunuGNjshQk+vZdwZBJoqiysK/mW3Jq0UXosq8aIhMnLevANhR9yoYfdUEOHg6M9y0g==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.26", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.26.tgz", - "integrity": "sha512-Z9rjt4BUVEbLFpw0qjCklVxxf421wrmcbP4w+LmBUxYCyJTYYSclgJD0YsCgGqQCtCIPiz7kjbYYJiAKhjJ3kA==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2208,13 +2221,6 @@ "object-assign": "^4.1.1" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.19", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", - "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/plugin-commonjs": { "version": "22.0.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz", @@ -2263,9 +2269,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz", - "integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", + "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==", "cpu": [ "arm" ], @@ -2277,9 +2283,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz", - "integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz", + "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==", "cpu": [ "arm64" ], @@ -2291,9 +2297,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz", - "integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz", + "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==", "cpu": [ "arm64" ], @@ -2305,9 +2311,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz", - "integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz", + "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==", "cpu": [ "x64" ], @@ -2319,9 +2325,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz", - "integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz", + "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==", "cpu": [ "arm64" ], @@ -2333,9 +2339,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz", - "integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz", + "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==", "cpu": [ "x64" ], @@ -2347,9 +2353,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz", - "integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz", + "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==", "cpu": [ "arm" ], @@ -2361,9 +2367,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz", - "integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz", + "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==", "cpu": [ "arm" ], @@ -2375,9 +2381,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz", - "integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz", + "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==", "cpu": [ "arm64" ], @@ -2389,9 +2395,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz", - "integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz", + "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==", "cpu": [ "arm64" ], @@ -2403,9 +2409,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz", - "integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz", + "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==", "cpu": [ "loong64" ], @@ -2417,9 +2423,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz", - "integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz", + "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==", "cpu": [ "ppc64" ], @@ -2431,9 +2437,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz", - "integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz", + "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==", "cpu": [ "riscv64" ], @@ -2445,9 +2451,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz", - "integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz", + "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==", "cpu": [ "riscv64" ], @@ -2459,9 +2465,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz", - "integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz", + "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==", "cpu": [ "s390x" ], @@ -2473,9 +2479,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz", - "integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz", + "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==", "cpu": [ "x64" ], @@ -2487,9 +2493,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz", - "integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz", + "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==", "cpu": [ "x64" ], @@ -2501,9 +2507,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz", - "integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz", + "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==", "cpu": [ "arm64" ], @@ -2515,9 +2521,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz", - "integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz", + "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==", "cpu": [ "ia32" ], @@ -2529,9 +2535,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz", - "integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz", + "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==", "cpu": [ "x64" ], @@ -3050,16 +3056,15 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.0.0.tgz", - "integrity": "sha512-nVV2FSzeTJ3oFKw+3t9gQYQcrgbopgCASSY27QOtkhEGgSfdQQjDmzZd41NeT1myQ8Wc6l+pZllST9qIu4NKzg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.4.1.tgz", + "integrity": "sha512-CEigAk7eOLyHvdgmpZsKFwtiqS2wFwI1fn4j09IU9GmD4euFM4jEBAViWeCqaNLlbX2k2+A/Fq9cje4HQBXuJQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/types": "^8.34.1", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", + "@typescript-eslint/utils": "^8.32.1", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "estraverse": "^5.3.0", "picomatch": "^4.0.2" }, @@ -3084,9 +3089,9 @@ } }, "node_modules/@stylistic/stylelint-plugin": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.3.tgz", - "integrity": "sha512-85fsmzgsIVmyG3/GFrjuYj6Cz8rAM7IZiPiXCMiSMfoDOC1lOrzrXPDk24WqviAghnPqGpx8b0caK2PuewWGFg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.2.tgz", + "integrity": "sha512-tylFJGMQo62alGazK74MNxFjMagYOHmBZiePZFOJK2n13JZta0uVkB3Bh5qodUmOLtRH+uxH297EibK14UKm8g==", "dev": true, "license": "MIT", "dependencies": { @@ -3094,10 +3099,10 @@ "@csstools/css-tokenizer": "^3.0.1", "@csstools/media-query-list-parser": "^3.0.1", "is-plain-object": "^5.0.0", - "postcss": "^8.4.41", "postcss-selector-parser": "^6.1.2", "postcss-value-parser": "^4.2.0", - "style-search": "^0.1.0" + "style-search": "^0.1.0", + "stylelint": "^16.8.2" }, "engines": { "node": "^18.12 || >=20.9" @@ -3112,6 +3117,16 @@ "integrity": "sha512-wpCQMhf5p5GhNg2MmGKXzUNwxe7zRiCsmqYsamez2beP7mKPCSiu+BjZcdN95yYSzO857kr0VfQewmGpS77nqA==", "license": "MIT" }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", @@ -3494,9 +3509,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz", + "integrity": "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -3546,17 +3561,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.0.tgz", - "integrity": "sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz", + "integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.35.0", - "@typescript-eslint/type-utils": "8.35.0", - "@typescript-eslint/utils": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0", + "@typescript-eslint/scope-manager": "8.34.0", + "@typescript-eslint/type-utils": "8.34.0", + "@typescript-eslint/utils": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -3570,7 +3585,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.35.0", + "@typescript-eslint/parser": "^8.34.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } @@ -3586,16 +3601,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.0.tgz", - "integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz", + "integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.35.0", - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/typescript-estree": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0", + "@typescript-eslint/scope-manager": "8.34.0", + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/typescript-estree": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0", "debug": "^4.3.4" }, "engines": { @@ -3611,14 +3626,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.0.tgz", - "integrity": "sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz", + "integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.35.0", - "@typescript-eslint/types": "^8.35.0", + "@typescript-eslint/tsconfig-utils": "^8.34.0", + "@typescript-eslint/types": "^8.34.0", "debug": "^4.3.4" }, "engines": { @@ -3633,14 +3648,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz", - "integrity": "sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz", + "integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0" + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3651,9 +3666,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz", - "integrity": "sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz", + "integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==", "dev": true, "license": "MIT", "engines": { @@ -3668,14 +3683,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.0.tgz", - "integrity": "sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz", + "integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.35.0", - "@typescript-eslint/utils": "8.35.0", + "@typescript-eslint/typescript-estree": "8.34.0", + "@typescript-eslint/utils": "8.34.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -3692,9 +3707,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz", - "integrity": "sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz", + "integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==", "dev": true, "license": "MIT", "engines": { @@ -3706,16 +3721,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.0.tgz", - "integrity": "sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz", + "integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.35.0", - "@typescript-eslint/tsconfig-utils": "8.35.0", - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0", + "@typescript-eslint/project-service": "8.34.0", + "@typescript-eslint/tsconfig-utils": "8.34.0", + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -3768,16 +3783,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.0.tgz", - "integrity": "sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz", + "integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.35.0", - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/typescript-estree": "8.35.0" + "@typescript-eslint/scope-manager": "8.34.0", + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/typescript-estree": "8.34.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3792,14 +3807,14 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.0.tgz", - "integrity": "sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz", + "integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.35.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.34.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3810,9 +3825,9 @@ } }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.9.2.tgz", - "integrity": "sha512-tS+lqTU3N0kkthU+rYp0spAYq15DU8ld9kXkaKg9sbQqJNF+WPMuNHZQGCgdxrUOEO0j22RKMwRVhF1HTl+X8A==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.9.1.tgz", + "integrity": "sha512-dd7yIp1hfJFX9ZlVLQRrh/Re9WMUHHmF9hrKD1yIvxcyNr2BhQ3xc1upAVhy8NijadnCswAxWQu8MkkSMC1qXQ==", "cpu": [ "arm" ], @@ -3824,9 +3839,9 @@ ] }, "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.9.2.tgz", - "integrity": "sha512-MffGiZULa/KmkNjHeuuflLVqfhqLv1vZLm8lWIyeADvlElJ/GLSOkoUX+5jf4/EGtfwrNFcEaB8BRas03KT0/Q==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.9.1.tgz", + "integrity": "sha512-EzUPcMFtDVlo5yrbzMqUsGq3HnLXw+3ZOhSd7CUaDmbTtnrzM+RO2ntw2dm2wjbbc5djWj3yX0wzbbg8pLhx8g==", "cpu": [ "arm64" ], @@ -3838,9 +3853,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.9.2.tgz", - "integrity": "sha512-dzJYK5rohS1sYl1DHdJ3mwfwClJj5BClQnQSyAgEfggbUwA9RlROQSSbKBLqrGfsiC/VyrDPtbO8hh56fnkbsQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.9.1.tgz", + "integrity": "sha512-nB+dna3q4kOleKFcSZJ/wDXIsAd1kpMO9XrVAt8tG3RDWJ6vi+Ic6bpz4cmg5tWNeCfHEY4KuqJCB+pKejPEmQ==", "cpu": [ "arm64" ], @@ -3852,9 +3867,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.9.2.tgz", - "integrity": "sha512-gaIMWK+CWtXcg9gUyznkdV54LzQ90S3X3dn8zlh+QR5Xy7Y+Efqw4Rs4im61K1juy4YNb67vmJsCDAGOnIeffQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.9.1.tgz", + "integrity": "sha512-aKWHCrOGaCGwZcekf3TnczQoBxk5w//W3RZ4EQyhux6rKDwBPgDU9Y2yGigCV1Z+8DWqZgVGQi+hdpnlSy3a1w==", "cpu": [ "x64" ], @@ -3866,9 +3881,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.9.2.tgz", - "integrity": "sha512-S7QpkMbVoVJb0xwHFwujnwCAEDe/596xqY603rpi/ioTn9VDgBHnCCxh+UFrr5yxuMH+dliHfjwCZJXOPJGPnw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.9.1.tgz", + "integrity": "sha512-4dIEMXrXt0UqDVgrsUd1I+NoIzVQWXy/CNhgpfS75rOOMK/4Abn0Mx2M2gWH4Mk9+ds/ASAiCmqoUFynmMY5hA==", "cpu": [ "x64" ], @@ -3880,9 +3895,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.9.2.tgz", - "integrity": "sha512-+XPUMCuCCI80I46nCDFbGum0ZODP5NWGiwS3Pj8fOgsG5/ctz+/zzuBlq/WmGa+EjWZdue6CF0aWWNv84sE1uw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.9.1.tgz", + "integrity": "sha512-vtvS13IXPs1eE8DuS/soiosqMBeyh50YLRZ+p7EaIKAPPeevRnA9G/wu/KbVt01ZD5qiGjxS+CGIdVC7I6gTOw==", "cpu": [ "arm" ], @@ -3894,9 +3909,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.9.2.tgz", - "integrity": "sha512-sqvUyAd1JUpwbz33Ce2tuTLJKM+ucSsYpPGl2vuFwZnEIg0CmdxiZ01MHQ3j6ExuRqEDUCy8yvkDKvjYFPb8Zg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.9.1.tgz", + "integrity": "sha512-BfdnN6aZ7NcX8djW8SR6GOJc+K+sFhWRF4vJueVE0vbUu5N1bLnBpxJg1TGlhSyo+ImC4SR0jcNiKN0jdoxt+A==", "cpu": [ "arm" ], @@ -3908,9 +3923,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.9.2.tgz", - "integrity": "sha512-UYA0MA8ajkEDCFRQdng/FVx3F6szBvk3EPnkTTQuuO9lV1kPGuTB+V9TmbDxy5ikaEgyWKxa4CI3ySjklZ9lFA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.9.1.tgz", + "integrity": "sha512-Jhge7lFtH0QqfRz2PyJjJXWENqywPteITd+nOS0L6AhbZli+UmEyGBd2Sstt1c+l9C+j/YvKTl9wJo9PPmsFNg==", "cpu": [ "arm64" ], @@ -3922,9 +3937,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.9.2.tgz", - "integrity": "sha512-P/CO3ODU9YJIHFqAkHbquKtFst0COxdphc8TKGL5yCX75GOiVpGqd1d15ahpqu8xXVsqP4MGFP2C3LRZnnL5MA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.9.1.tgz", + "integrity": "sha512-ofdK/ow+ZSbSU0pRoB7uBaiRHeaAOYQFU5Spp87LdcPL/P1RhbCTMSIYVb61XWzsVEmYKjHFtoIE0wxP6AFvrA==", "cpu": [ "arm64" ], @@ -3936,9 +3951,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.9.2.tgz", - "integrity": "sha512-uKStFlOELBxBum2s1hODPtgJhY4NxYJE9pAeyBgNEzHgTqTiVBPjfTlPFJkfxyTjQEuxZbbJlJnMCrRgD7ubzw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.9.1.tgz", + "integrity": "sha512-eC8SXVn8de67HacqU7PoGdHA+9tGbqfEdD05AEFRAB81ejeQtNi5Fx7lPcxpLH79DW0BnMAHau3hi4RVkHfSCw==", "cpu": [ "ppc64" ], @@ -3950,9 +3965,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.9.2.tgz", - "integrity": "sha512-LkbNnZlhINfY9gK30AHs26IIVEZ9PEl9qOScYdmY2o81imJYI4IMnJiW0vJVtXaDHvBvxeAgEy5CflwJFIl3tQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.9.1.tgz", + "integrity": "sha512-fIkwvAAQ41kfoGWfzeJ33iLGShl0JEDZHrMnwTHMErUcPkaaZRJYjQjsFhMl315NEQ4mmTlC+2nfK/J2IszDOw==", "cpu": [ "riscv64" ], @@ -3964,9 +3979,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.9.2.tgz", - "integrity": "sha512-vI+e6FzLyZHSLFNomPi+nT+qUWN4YSj8pFtQZSFTtmgFoxqB6NyjxSjAxEC1m93qn6hUXhIsh8WMp+fGgxCoRg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.9.1.tgz", + "integrity": "sha512-RAAszxImSOFLk44aLwnSqpcOdce8sBcxASledSzuFAd8Q5ZhhVck472SisspnzHdc7THCvGXiUeZ2hOC7NUoBQ==", "cpu": [ "riscv64" ], @@ -3978,9 +3993,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.9.2.tgz", - "integrity": "sha512-sSO4AlAYhSM2RAzBsRpahcJB1msc6uYLAtP6pesPbZtptF8OU/CbCPhSRW6cnYOGuVmEmWVW5xVboAqCnWTeHQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.9.1.tgz", + "integrity": "sha512-QoP9vkY+THuQdZi05bA6s6XwFd6HIz3qlx82v9bTOgxeqin/3C12Ye7f7EOD00RQ36OtOPWnhEMMm84sv7d1XQ==", "cpu": [ "s390x" ], @@ -3992,9 +4007,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.9.2.tgz", - "integrity": "sha512-jkSkwch0uPFva20Mdu8orbQjv2A3G88NExTN2oPTI1AJ+7mZfYW3cDCTyoH6OnctBKbBVeJCEqh0U02lTkqD5w==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.9.1.tgz", + "integrity": "sha512-/p77cGN/h9zbsfCseAP5gY7tK+7+DdM8fkPfr9d1ye1fsF6bmtGbtZN6e/8j4jCZ9NEIBBkT0GhdgixSelTK9g==", "cpu": [ "x64" ], @@ -4006,9 +4021,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.9.2.tgz", - "integrity": "sha512-Uk64NoiTpQbkpl+bXsbeyOPRpUoMdcUqa+hDC1KhMW7aN1lfW8PBlBH4mJ3n3Y47dYE8qi0XTxy1mBACruYBaw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.9.1.tgz", + "integrity": "sha512-wInTqT3Bu9u50mDStEig1v8uxEL2Ht+K8pir/YhyyrM5ordJtxoqzsL1vR/CQzOJuDunUTrDkMM0apjW/d7/PA==", "cpu": [ "x64" ], @@ -4020,9 +4035,9 @@ ] }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.9.2.tgz", - "integrity": "sha512-EpBGwkcjDicjR/ybC0g8wO5adPNdVuMrNalVgYcWi+gYtC1XYNuxe3rufcO7dA76OHGeVabcO6cSkPJKVcbCXQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.9.1.tgz", + "integrity": "sha512-eNwqO5kUa+1k7yFIircwwiniKWA0UFHo2Cfm8LYgkh9km7uMad+0x7X7oXbQonJXlqfitBTSjhA0un+DsHIrhw==", "cpu": [ "wasm32" ], @@ -4037,9 +4052,9 @@ } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.9.2.tgz", - "integrity": "sha512-EdFbGn7o1SxGmN6aZw9wAkehZJetFPao0VGZ9OMBwKx6TkvDuj6cNeLimF/Psi6ts9lMOe+Dt6z19fZQ9Ye2fw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.9.1.tgz", + "integrity": "sha512-Eaz1xMUnoa2mFqh20mPqSdbYl6crnk8HnIXDu6nsla9zpgZJZO8w3c1gvNN/4Eb0RXRq3K9OG6mu8vw14gIqiA==", "cpu": [ "arm64" ], @@ -4051,9 +4066,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.9.2.tgz", - "integrity": "sha512-JY9hi1p7AG+5c/dMU8o2kWemM8I6VZxfGwn1GCtf3c5i+IKcMo2NQ8OjZ4Z3/itvY/Si3K10jOBQn7qsD/whUA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.9.1.tgz", + "integrity": "sha512-H/+d+5BGlnEQif0gnwWmYbYv7HJj563PUKJfn8PlmzF8UmF+8KxdvXdwCsoOqh4HHnENnoLrav9NYBrv76x1wQ==", "cpu": [ "ia32" ], @@ -4065,9 +4080,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.9.2.tgz", - "integrity": "sha512-ryoo+EB19lMxAd80ln9BVf8pdOAxLb97amrQ3SFN9OCRn/5M5wvwDgAe4i8ZjhpbiHoDeP8yavcTEnpKBo7lZg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.9.1.tgz", + "integrity": "sha512-rS86wI4R6cknYM3is3grCb/laE8XBEbpWAMSIPjYfmYp75KL5dT87jXF2orDa4tQYg5aajP5G8Fgh34dRyR+Rw==", "cpu": [ "x64" ], @@ -4079,19 +4094,16 @@ ] }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.0.tgz", - "integrity": "sha512-iAliE72WsdhjzTOp2DtvKThq1VBC4REhwRcaA+zPAAph6I+OQhUXv+Xu2KS7ElxYtb7Zc/3R30Hwv1DxEo7NXQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", "dev": true, "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "1.0.0-beta.19" - }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, @@ -5143,9 +5155,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", "funding": [ { "type": "opencollective", @@ -5162,8 +5174,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", + "caniuse-lite": "^1.0.30001718", + "electron-to-chromium": "^1.5.160", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -5334,9 +5346,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001726", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", - "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "version": "1.0.30001724", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz", + "integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==", "funding": [ { "type": "opencollective", @@ -5882,9 +5894,9 @@ } }, "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5913,9 +5925,9 @@ } }, "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -6904,9 +6916,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.177", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.177.tgz", - "integrity": "sha512-7EH2G59nLsEMj97fpDuvVcYi6lwTcM1xuWw3PssD8xzboAW7zj7iB3COEEEATUfjLHrs5uKBLQT03V/8URx06g==", + "version": "1.5.171", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.171.tgz", + "integrity": "sha512-scWpzXEJEMrGJa4Y6m/tVotb0WuvNmasv3wWVzUAeCgKU0ToFOhUW6Z+xWnRQANMYGxN4ngJXIThgBJOqzVPCQ==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -6925,9 +6937,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", - "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -7250,19 +7262,19 @@ } }, "node_modules/eslint": { - "version": "9.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.0.tgz", - "integrity": "sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.0", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.30.0", + "@eslint/js": "9.28.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -7274,9 +7286,9 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -7327,14 +7339,14 @@ } }, "node_modules/eslint-import-context": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", - "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.8.tgz", + "integrity": "sha512-bq+F7nyc65sKpZGT09dY0S0QrOnQtuDVIfyTGQ8uuvtMIF7oHp6CEP3mouN0rrnYF3Jqo6Ke0BfU/5wASZue1w==", "dev": true, "license": "MIT", "dependencies": { "get-tsconfig": "^4.10.1", - "stable-hash-x": "^0.2.0" + "stable-hash-x": "^0.1.1" }, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -7352,9 +7364,9 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", - "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.3.tgz", + "integrity": "sha512-elVDn1eWKFrWlzxlWl9xMt8LltjKl161Ix50JFC50tHXI5/TRP32SNEqlJ/bo/HV+g7Rou/tlPQU2AcRtIhrOg==", "dev": true, "license": "ISC", "dependencies": { @@ -7362,7 +7374,7 @@ "eslint-import-context": "^0.1.8", "get-tsconfig": "^4.10.1", "is-bun-module": "^2.0.0", - "stable-hash-x": "^0.2.0", + "stable-hash-x": "^0.1.1", "tinyglobby": "^0.2.14", "unrs-resolver": "^1.7.11" }, @@ -7400,21 +7412,21 @@ } }, "node_modules/eslint-plugin-import-x": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.1.tgz", - "integrity": "sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.15.1.tgz", + "integrity": "sha512-JfVpNg1qMkPD66iaSgmMoSYeUCGS8UFSm3GwHV0IbuV3Knar/SyK5qqCct9+AxoMIzaM+KSO7KK5pOeOkC/3GQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.35.0", + "@typescript-eslint/types": "^8.33.1", "comment-parser": "^1.4.1", "debug": "^4.4.1", - "eslint-import-context": "^0.1.9", + "eslint-import-context": "^0.1.7", "is-glob": "^4.0.3", "minimatch": "^9.0.3 || ^10.0.1", "semver": "^7.7.2", - "stable-hash-x": "^0.2.0", - "unrs-resolver": "^1.9.2" + "stable-hash-x": "^0.1.1", + "unrs-resolver": "^1.7.10" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7523,9 +7535,9 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-3.0.4.tgz", - "integrity": "sha512-ftQcP811kRJNXapqpQXHErEoVOdTPfYPPYd7n3AExIPwv4qWKKHf4slFvXmodiOnfgy1Tl3waPZZLD7lcvJOtw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-3.0.2.tgz", + "integrity": "sha512-LxjbfwI7ypENeTmGyKmDyNux3COSkMi7H/6Cal5StSLQ6edf0naP45SZR43OclaNR7WfhVTZdhOn63q3/Y6puQ==", "dev": true, "license": "LGPL-3.0-only", "dependencies": { @@ -7534,11 +7546,10 @@ "bytes": "3.1.2", "functional-red-black-tree": "1.0.1", "jsx-ast-utils": "3.3.5", - "lodash.merge": "4.6.2", "minimatch": "9.0.5", "scslre": "0.3.0", - "semver": "7.7.2", - "typescript": ">=5" + "semver": "7.7.1", + "typescript": "^5" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0" @@ -7577,6 +7588,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/eslint-plugin-sonarjs/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-plugin-toml": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/eslint-plugin-toml/-/eslint-plugin-toml-0.12.0.tgz", @@ -8539,9 +8563,9 @@ } }, "node_modules/happy-dom": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-18.0.1.tgz", - "integrity": "sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-18.0.0.tgz", + "integrity": "sha512-o3p2Axi1EdIfMaOUulDzO/5yXzLLV0g/54eLPVrkt3u20r3yOuOenHpyp2clAJ0eHMc+HyE139ulQxl+8pEJIw==", "dev": true, "license": "MIT", "dependencies": { @@ -8652,9 +8676,9 @@ } }, "node_modules/hookified": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.10.0.tgz", - "integrity": "sha512-dJw0492Iddsj56U1JsSTm9E/0B/29a1AuoSLRAte8vQg/kaTGF3IgjEWT8c8yG4cC10+HisE1x5QAwR0Xwc+DA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.9.1.tgz", + "integrity": "sha512-u3pxtGhKjcSXnGm1CX6aXS9xew535j3lkOCegbA6jdyh0BaAjTbXI4aslKstCr6zUNtoCxFGFKwjbSHdGrMB8g==", "dev": true, "license": "MIT" }, @@ -8722,9 +8746,9 @@ } }, "node_modules/htmx.org": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.6.tgz", - "integrity": "sha512-7ythjYneGSk3yCHgtCnQeaoF+D+o7U2LF37WU3O0JYv3gTZSicdEFiI/Ai/NJyC5ZpYJWMpUb11OC5Lr6AfAqA==", + "version": "1.9.12", + "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.12.tgz", + "integrity": "sha512-VZAohXyF7xPGS52IM8d1T1283y+X4D+Owf3qY1NZ9RuBypyu9l8cGsxUMAG5fEAb/DhT7rDoJ9Hpu5/HxFD3cw==", "license": "0BSD" }, "node_modules/iconv-lite": { @@ -9969,9 +9993,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz", - "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.36.0.tgz", + "integrity": "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==", "dev": true, "license": "MIT" }, @@ -11320,9 +11344,9 @@ } }, "node_modules/napi-postinstall": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.5.tgz", - "integrity": "sha512-kmsgUvCRIJohHjbZ3V8avP0I1Pekw329MVAMDzVxsrkjgdnqiwvMX5XwR+hWV66vsAtZ+iM+fVnq8RTQawUmCQ==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz", + "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==", "dev": true, "license": "MIT", "bin": { @@ -11803,9 +11827,9 @@ "license": "MIT" }, "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "license": "MIT", "engines": { @@ -11919,13 +11943,13 @@ } }, "node_modules/pkg-types": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.1.tgz", - "integrity": "sha512-eY0QFb6eSwc9+0d/5D2lFFUq+A3n3QNGSy/X2Nvp+6MfzGw2u6EbA7S80actgjY1lkvvI0pqB+a4hioMh443Ew==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", + "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==", "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", + "confbox": "^0.2.1", + "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, @@ -13566,9 +13590,9 @@ } }, "node_modules/stable-hash-x": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", - "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.1.1.tgz", + "integrity": "sha512-l0x1D6vhnsNUGPFVDx45eif0y6eedVC8nm5uACTrVFJFtl2mLRW17aWtVyxFCpn5t94VUPkjU8vSLwIuwwqtJQ==", "dev": true, "license": "MIT", "engines": { @@ -13777,9 +13801,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.21.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.21.0.tgz", - "integrity": "sha512-ki3PpJGG7xhm3WtINoWGnlvqAmbqSexoRMbEMJzlwewSIOqPRKPlq452c22xAdEJISVi80r+I7KL9GPUiwFgbg==", + "version": "16.20.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.20.0.tgz", + "integrity": "sha512-B5Myu9WRxrgKuLs3YyUXLP2H0mrbejwNxPmyADlACWwFsrL8Bmor/nTSh4OMae5sHjOz6gkSeccQH34gM4/nAw==", "dev": true, "funding": [ { @@ -13793,9 +13817,9 @@ ], "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2", "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", @@ -13806,21 +13830,21 @@ "debug": "^4.4.1", "fast-glob": "^3.3.3", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^10.1.1", + "file-entry-cache": "^10.1.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", - "ignore": "^7.0.5", + "ignore": "^7.0.4", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.37.0", + "known-css-properties": "^0.36.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.1.1", - "postcss": "^8.5.5", + "postcss": "^8.5.3", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", "postcss-selector-parser": "^7.1.0", @@ -14178,25 +14202,25 @@ "dev": true }, "node_modules/svgo": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", - "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", + "integrity": "sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==", "dev": true, "license": "MIT", "dependencies": { - "commander": "^11.1.0", + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", "css-select": "^5.1.0", - "css-tree": "^3.0.1", + "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", - "picocolors": "^1.1.1", - "sax": "^1.4.1" + "picocolors": "^1.0.0" }, "bin": { - "svgo": "bin/svgo.js" + "svgo": "bin/svgo" }, "engines": { - "node": ">=16" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -14204,21 +14228,35 @@ } }, "node_modules/svgo/node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">= 10" } }, - "node_modules/svgo/node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "node_modules/svgo/node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/svgo/node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/swagger-ui-dist": { "version": "5.17.14", @@ -14834,15 +14872,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.0.tgz", - "integrity": "sha512-uEnz70b7kBz6eg/j0Czy6K5NivaYopgxRjsnAJ2Fx5oTLo3wefTHIbL7AkQr1+7tJCRVpTs/wiM8JR/11Loq9A==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz", + "integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.35.0", - "@typescript-eslint/parser": "8.35.0", - "@typescript-eslint/utils": "8.35.0" + "@typescript-eslint/eslint-plugin": "8.34.0", + "@typescript-eslint/parser": "8.34.0", + "@typescript-eslint/utils": "8.34.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -14917,38 +14955,38 @@ } }, "node_modules/unrs-resolver": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.9.2.tgz", - "integrity": "sha512-VUyWiTNQD7itdiMuJy+EuLEErLj3uwX/EpHQF8EOf33Dq3Ju6VW1GXm+swk6+1h7a49uv9fKZ+dft9jU7esdLA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.9.1.tgz", + "integrity": "sha512-4AZVxP05JGN6DwqIkSP4VKLOcwQa5l37SWHF/ahcuqBMbfxbpN1L1QKafEhWCziHhzKex9H/AR09H0OuVyU+9g==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "napi-postinstall": "^0.2.4" + "napi-postinstall": "^0.2.2" }, "funding": { "url": "https://opencollective.com/unrs-resolver" }, "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.9.2", - "@unrs/resolver-binding-android-arm64": "1.9.2", - "@unrs/resolver-binding-darwin-arm64": "1.9.2", - "@unrs/resolver-binding-darwin-x64": "1.9.2", - "@unrs/resolver-binding-freebsd-x64": "1.9.2", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.9.2", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.9.2", - "@unrs/resolver-binding-linux-arm64-gnu": "1.9.2", - "@unrs/resolver-binding-linux-arm64-musl": "1.9.2", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.9.2", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.9.2", - "@unrs/resolver-binding-linux-riscv64-musl": "1.9.2", - "@unrs/resolver-binding-linux-s390x-gnu": "1.9.2", - "@unrs/resolver-binding-linux-x64-gnu": "1.9.2", - "@unrs/resolver-binding-linux-x64-musl": "1.9.2", - "@unrs/resolver-binding-wasm32-wasi": "1.9.2", - "@unrs/resolver-binding-win32-arm64-msvc": "1.9.2", - "@unrs/resolver-binding-win32-ia32-msvc": "1.9.2", - "@unrs/resolver-binding-win32-x64-msvc": "1.9.2" + "@unrs/resolver-binding-android-arm-eabi": "1.9.1", + "@unrs/resolver-binding-android-arm64": "1.9.1", + "@unrs/resolver-binding-darwin-arm64": "1.9.1", + "@unrs/resolver-binding-darwin-x64": "1.9.1", + "@unrs/resolver-binding-freebsd-x64": "1.9.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.9.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.9.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.9.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.9.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.9.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.9.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.9.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.9.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.9.1", + "@unrs/resolver-binding-linux-x64-musl": "1.9.1", + "@unrs/resolver-binding-wasm32-wasi": "1.9.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.9.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.9.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.9.1" } }, "node_modules/update-browserslist-db": { @@ -15055,24 +15093,24 @@ "license": "MIT" }, "node_modules/vite": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.0.tgz", - "integrity": "sha512-ixXJB1YRgDIw2OszKQS9WxGHKwLdCsbQNkpJN171udl6szi/rIySHL6/Os3s2+oE4P/FLD4dxg4mD7Wust+u5g==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", - "fdir": "^6.4.6", + "fdir": "^6.4.4", "picomatch": "^4.0.2", - "postcss": "^8.5.6", - "rollup": "^4.40.0", - "tinyglobby": "^0.2.14" + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -15081,14 +15119,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", - "less": "^4.0.0", + "less": "*", "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -15209,39 +15247,10 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/vite/node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/vite/node_modules/rollup": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz", - "integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz", + "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==", "dev": true, "license": "MIT", "dependencies": { @@ -15255,26 +15264,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.44.1", - "@rollup/rollup-android-arm64": "4.44.1", - "@rollup/rollup-darwin-arm64": "4.44.1", - "@rollup/rollup-darwin-x64": "4.44.1", - "@rollup/rollup-freebsd-arm64": "4.44.1", - "@rollup/rollup-freebsd-x64": "4.44.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.44.1", - "@rollup/rollup-linux-arm-musleabihf": "4.44.1", - "@rollup/rollup-linux-arm64-gnu": "4.44.1", - "@rollup/rollup-linux-arm64-musl": "4.44.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.44.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.44.1", - "@rollup/rollup-linux-riscv64-gnu": "4.44.1", - "@rollup/rollup-linux-riscv64-musl": "4.44.1", - "@rollup/rollup-linux-s390x-gnu": "4.44.1", - "@rollup/rollup-linux-x64-gnu": "4.44.1", - "@rollup/rollup-linux-x64-musl": "4.44.1", - "@rollup/rollup-win32-arm64-msvc": "4.44.1", - "@rollup/rollup-win32-ia32-msvc": "4.44.1", - "@rollup/rollup-win32-x64-msvc": "4.44.1", + "@rollup/rollup-android-arm-eabi": "4.44.0", + "@rollup/rollup-android-arm64": "4.44.0", + "@rollup/rollup-darwin-arm64": "4.44.0", + "@rollup/rollup-darwin-x64": "4.44.0", + "@rollup/rollup-freebsd-arm64": "4.44.0", + "@rollup/rollup-freebsd-x64": "4.44.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.0", + "@rollup/rollup-linux-arm-musleabihf": "4.44.0", + "@rollup/rollup-linux-arm64-gnu": "4.44.0", + "@rollup/rollup-linux-arm64-musl": "4.44.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-musl": "4.44.0", + "@rollup/rollup-linux-s390x-gnu": "4.44.0", + "@rollup/rollup-linux-x64-gnu": "4.44.0", + "@rollup/rollup-linux-x64-musl": "4.44.0", + "@rollup/rollup-win32-arm64-msvc": "4.44.0", + "@rollup/rollup-win32-ia32-msvc": "4.44.0", + "@rollup/rollup-win32-x64-msvc": "4.44.0", "fsevents": "~2.3.2" } }, @@ -15469,9 +15478,9 @@ "license": "MIT" }, "node_modules/vue-eslint-parser": { - "version": "10.1.4", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.1.4.tgz", - "integrity": "sha512-EIZvCukIEMHEb3mxOKemtvWR1fcUAdWWAgkfyjmRHzvyhrZvBvH9oz69+thDIWhGiIQjZnPkCn8yHqvjM+a9eg==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.1.3.tgz", + "integrity": "sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==", "dev": true, "license": "MIT", "peer": true, diff --git a/package.json b/package.json index 88f904c44b..3d71e94cd3 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "esbuild-loader": "4.3.0", "escape-goat": "4.0.0", "fast-glob": "3.3.3", - "htmx.org": "2.0.6", + "htmx.org": "1.9.12", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.22", @@ -64,21 +64,21 @@ "@eslint-community/eslint-plugin-eslint-comments": "4.5.0", "@playwright/test": "1.52.0", "@stoplight/spectral-cli": "6.15.0", - "@stylistic/eslint-plugin": "5.0.0", - "@stylistic/stylelint-plugin": "3.1.3", - "@vitejs/plugin-vue": "6.0.0", + "@stylistic/eslint-plugin": "4.4.1", + "@stylistic/stylelint-plugin": "3.1.2", + "@vitejs/plugin-vue": "5.2.4", "@vitest/coverage-v8": "3.2.3", "@vitest/eslint-plugin": "1.2.2", "@vue/test-utils": "2.4.6", - "eslint": "9.30.0", - "eslint-import-resolver-typescript": "4.4.4", + "eslint": "9.28.0", + "eslint-import-resolver-typescript": "4.4.3", "eslint-plugin-array-func": "5.0.2", - "eslint-plugin-import-x": "4.16.1", + "eslint-plugin-import-x": "4.15.1", "eslint-plugin-no-jquery": "3.1.1", "eslint-plugin-no-use-extend-native": "0.7.2", "eslint-plugin-playwright": "2.2.0", "eslint-plugin-regexp": "2.9.0", - "eslint-plugin-sonarjs": "3.0.4", + "eslint-plugin-sonarjs": "3.0.2", "eslint-plugin-toml": "0.12.0", "eslint-plugin-unicorn": "59.0.1", "eslint-plugin-vitest-globals": "1.5.0", @@ -86,18 +86,18 @@ "eslint-plugin-vue-scoped-css": "2.10.0", "eslint-plugin-wc": "3.0.1", "globals": "16.1.0", - "happy-dom": "18.0.1", + "happy-dom": "18.0.0", "license-checker-rseidelsohn": "4.4.2", "markdownlint-cli": "0.45.0", "postcss-html": "1.8.0", "sharp": "0.34.2", - "stylelint": "16.21.0", + "stylelint": "16.20.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.11", "stylelint-value-no-unknown-custom-properties": "6.0.1", - "svgo": "4.0.0", + "svgo": "3.2.0", "typescript": "5.8.3", - "typescript-eslint": "8.35.0", + "typescript-eslint": "8.34.0", "vite-string-plugin": "1.3.4", "vitest": "3.2.3" }, diff --git a/public/assets/img/svg/gitea-alt.svg b/public/assets/img/svg/gitea-alt.svg index efe4830a0b..53e3f17c13 100644 --- a/public/assets/img/svg/gitea-alt.svg +++ b/public/assets/img/svg/gitea-alt.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-chef.svg b/public/assets/img/svg/gitea-chef.svg index 8fd8ed325d..c5e8a721cc 100644 --- a/public/assets/img/svg/gitea-chef.svg +++ b/public/assets/img/svg/gitea-chef.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-debian.svg b/public/assets/img/svg/gitea-debian.svg index e92d0b6937..fa2f2f49dc 100644 --- a/public/assets/img/svg/gitea-debian.svg +++ b/public/assets/img/svg/gitea-debian.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-gitbucket.svg b/public/assets/img/svg/gitea-gitbucket.svg index b9e99724b2..62f603484e 100644 --- a/public/assets/img/svg/gitea-gitbucket.svg +++ b/public/assets/img/svg/gitea-gitbucket.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-gitlab.svg b/public/assets/img/svg/gitea-gitlab.svg index e2d708e7be..03fcb0b87e 100644 --- a/public/assets/img/svg/gitea-gitlab.svg +++ b/public/assets/img/svg/gitea-gitlab.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-google.svg b/public/assets/img/svg/gitea-google.svg index 26ee04cb64..7dd2622df6 100644 --- a/public/assets/img/svg/gitea-google.svg +++ b/public/assets/img/svg/gitea-google.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-maven.svg b/public/assets/img/svg/gitea-maven.svg index f6ece7dc28..320d01a234 100644 --- a/public/assets/img/svg/gitea-maven.svg +++ b/public/assets/img/svg/gitea-maven.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-microsoftonline.svg b/public/assets/img/svg/gitea-microsoftonline.svg index c143eccbb6..f2ce13ac22 100644 --- a/public/assets/img/svg/gitea-microsoftonline.svg +++ b/public/assets/img/svg/gitea-microsoftonline.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-npm.svg b/public/assets/img/svg/gitea-npm.svg index 2b05c79353..7ef74e72bd 100644 --- a/public/assets/img/svg/gitea-npm.svg +++ b/public/assets/img/svg/gitea-npm.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-onedev.svg b/public/assets/img/svg/gitea-onedev.svg index 7ecd18895d..94ad1bab31 100644 --- a/public/assets/img/svg/gitea-onedev.svg +++ b/public/assets/img/svg/gitea-onedev.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-openid.svg b/public/assets/img/svg/gitea-openid.svg index 10c37145a3..f4702d2cdf 100644 --- a/public/assets/img/svg/gitea-openid.svg +++ b/public/assets/img/svg/gitea-openid.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-rubygems.svg b/public/assets/img/svg/gitea-rubygems.svg index 7cd9d34e6a..4e43bdf2f4 100644 --- a/public/assets/img/svg/gitea-rubygems.svg +++ b/public/assets/img/svg/gitea-rubygems.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-swift.svg b/public/assets/img/svg/gitea-swift.svg index 891ac12b56..4182100185 100644 --- a/public/assets/img/svg/gitea-swift.svg +++ b/public/assets/img/svg/gitea-swift.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/gitea-vagrant.svg b/public/assets/img/svg/gitea-vagrant.svg index 18b05e900d..ba50101d52 100644 --- a/public/assets/img/svg/gitea-vagrant.svg +++ b/public/assets/img/svg/gitea-vagrant.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/routers/api/v1/repo/compare.go b/routers/api/v1/repo/compare.go index 7fc59ea171..9c941ea07f 100644 --- a/routers/api/v1/repo/compare.go +++ b/routers/api/v1/repo/compare.go @@ -64,7 +64,7 @@ func CompareDiff(ctx *context.APIContext) { } } - headRepository, headGitRepo, ci, _, _ := parseCompareInfo(ctx, api.CreatePullRequestOption{ + _, headGitRepo, ci, _, _ := parseCompareInfo(ctx, api.CreatePullRequestOption{ Base: infos[0], Head: infos[1], }) @@ -80,7 +80,7 @@ func CompareDiff(ctx *context.APIContext) { apiFiles := []*api.CommitAffectedFiles{} userCache := make(map[string]*user_model.User) for i := 0; i < len(ci.Commits); i++ { - apiCommit, err := convert.ToCommit(ctx, headRepository, headGitRepo, ci.Commits[i], userCache, + apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ci.Commits[i], userCache, convert.ToCommitOptions{ Stat: true, Verification: verification, diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 442e109843..5495c4a6ba 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -121,12 +121,6 @@ func SearchIssues(ctx *context.APIContext) { // description: Number of items per page // type: integer // minimum: 0 - // - name: sort - // in: query - // description: Type of sort - // type: string - // enum: [relevance, latest, oldest, recentupdate, leastupdate, mostcomment, leastcomment, nearduedate, farduedate] - // default: latest // responses: // "200": // "$ref": "#/responses/IssueList" @@ -282,7 +276,7 @@ func SearchIssues(ctx *context.APIContext) { IsClosed: isClosed, IncludedAnyLabelIDs: includedAnyLabels, MilestoneIDs: includedMilestones, - SortBy: issue_indexer.ParseSortBy(ctx.FormString("sort"), issue_indexer.SortByCreatedDesc), + SortBy: issue_indexer.SortByCreatedDesc, } if since != 0 { @@ -311,10 +305,9 @@ func SearchIssues(ctx *context.APIContext) { } } - priorityRepoID := ctx.FormInt64("priority_repo_id") - if priorityRepoID > 0 { - searchOpt.PriorityRepoID = optional.Some(priorityRepoID) - } + // FIXME: It's unsupported to sort by priority repo when searching by indexer, + // it's indeed an regression, but I think it is worth to support filtering by indexer first. + _ = ctx.FormInt64("priority_repo_id") ids, total, err := issue_indexer.SearchIssues(ctx, searchOpt) if err != nil { diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index e7ff533d6a..c9dda124de 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -1084,6 +1084,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) err error ) + // If there is no head repository, it means pull request between same repository. headInfos := strings.Split(form.Head, ":") if len(headInfos) == 1 { isSameRepo = true @@ -1093,7 +1094,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) headUser, err = user_model.GetUserByName(ctx, headInfos[0]) if err != nil { if user_model.IsErrUserNotExist(err) { - ctx.NotFound(fmt.Errorf("the owner %s does not exist", headInfos[0])) + ctx.NotFound("GetUserByName") } else { ctx.Error(http.StatusInternalServerError, "GetUserByName", err) } @@ -1103,7 +1104,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) // The head repository can also point to the same repo isSameRepo = ctx.Repo.Owner.ID == headUser.ID } else { - ctx.NotFound(fmt.Errorf("the head part of {basehead} %s must contain zero or one colon (:) but contains %d", form.Head, len(headInfos)-1)) + ctx.NotFound() return nil, nil, nil, "", "" } @@ -1115,10 +1116,16 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(baseBranch) baseIsTag := ctx.Repo.GitRepo.IsTagExist(baseBranch) if !baseIsCommit && !baseIsBranch && !baseIsTag { - ctx.NotFound(fmt.Errorf("could not find '%s' to be a commit, branch or tag in the base repository %s/%s", baseBranch, baseRepo.Owner.Name, baseRepo.Name)) - return nil, nil, nil, "", "" + // Check for short SHA usage + if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(baseBranch); baseCommit != nil { + baseBranch = baseCommit.ID.String() + } else { + ctx.NotFound("BaseNotExist") + return nil, nil, nil, "", "" + } } + // Check if current user has fork of repository or in the same repository. headRepo := repo_model.GetForkedRepo(ctx, headUser.ID, baseRepo.ID) if headRepo == nil && !isSameRepo { err := baseRepo.GetBaseRepo(ctx) @@ -1127,11 +1134,13 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) return nil, nil, nil, "", "" } + // Check if baseRepo's base repository is the same as headUser's repository. if baseRepo.BaseRepo == nil || baseRepo.BaseRepo.OwnerID != headUser.ID { log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID) - ctx.NotFound(fmt.Errorf("%[1]s does not have a fork of %[2]s/%[3]s and %[2]s/%[3]s is not a fork of a repository from %[1]s", headUser.Name, baseRepo.Owner.Name, baseRepo.Name)) + ctx.NotFound("GetBaseRepo") return nil, nil, nil, "", "" } + // Assign headRepo so it can be used below. headRepo = baseRepo.BaseRepo } @@ -1193,20 +1202,21 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } // Check if head branch is valid. - headIsCommit := headGitRepo.IsCommitExist(headBranch) - headIsBranch := headGitRepo.IsBranchExist(headBranch) - headIsTag := headGitRepo.IsTagExist(headBranch) + headIsCommit := ctx.Repo.GitRepo.IsCommitExist(headBranch) + headIsBranch := ctx.Repo.GitRepo.IsBranchExist(headBranch) + headIsTag := ctx.Repo.GitRepo.IsTagExist(headBranch) if !headIsCommit && !headIsBranch && !headIsTag { - ctx.NotFound(fmt.Errorf("could not find '%s' to be a commit, branch or tag in the head repository %s/%s", headBranch, headRepo.Owner.Name, headRepo.Name)) - return nil, nil, nil, "", "" + // Check if headBranch is short sha commit hash + if headCommit, _ := headGitRepo.GetCommit(headBranch); headCommit != nil { + headBranch = headCommit.ID.String() + } else { + headGitRepo.Close() + ctx.NotFound("IsRefExist", nil) + return nil, nil, nil, "", "" + } } headBranchRef := headBranch - if headIsBranch { - headBranchRef = git.BranchPrefix + headBranch - } else if headIsTag { - headBranchRef = git.TagPrefix + headBranch - } compareInfo, err := headGitRepo.GetCompareInfo(repo_model.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranchRef, headBranchRef, false, false) if err != nil { diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 7b6a00408a..bb4cf0f211 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -5,7 +5,6 @@ package repo import ( "encoding/base64" - "errors" "fmt" "net/http" "net/url" @@ -507,8 +506,11 @@ func findWikiRepoCommit(ctx *context.APIContext) (*git.Repository, *git.Commit) // given tree entry, encoded with base64. Writes to ctx if an error occurs. func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string { blob := entry.Blob() - content, err := blob.GetContentBase64(setting.API.DefaultMaxBlobSize) - if err != nil && !errors.As(err, &git.BlobTooLargeError{}) { + if blob.Size() > setting.API.DefaultMaxBlobSize { + return "" + } + content, err := blob.GetBlobContentBase64() + if err != nil { ctx.Error(http.StatusInternalServerError, "GetBlobContentBase64", err) return "" } diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index a856a7a00a..c7748b01c8 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -205,7 +205,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // post update for agit pull request // FIXME: use pr.Flow to test whether it's an Agit PR or a GH PR - if refFullName.IsPull() { + if git.SupportProcReceive && refFullName.IsPull() { if repo == nil { repo = loadRepository(ctx, ownerName, repoName) if ctx.Written() { diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 45992e8522..4c0e9a8551 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -205,7 +205,7 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName) case refFullName.IsTag(): preReceiveTag(ourCtx, oldCommitID, newCommitID, refFullName) - case refFullName.IsFor(): + case git.SupportProcReceive && refFullName.IsFor(): preReceiveFor(ourCtx, oldCommitID, newCommitID, refFullName) default: if ourCtx.isOverQuota { diff --git a/routers/private/hook_proc_receive.go b/routers/private/hook_proc_receive.go index 9f6e23f158..cd45794261 100644 --- a/routers/private/hook_proc_receive.go +++ b/routers/private/hook_proc_receive.go @@ -7,6 +7,7 @@ import ( "net/http" repo_model "forgejo.org/models/repo" + "forgejo.org/modules/git" "forgejo.org/modules/log" "forgejo.org/modules/private" "forgejo.org/modules/web" @@ -17,6 +18,10 @@ import ( // HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present func HookProcReceive(ctx *gitea_context.PrivateContext) { opts := web.GetForm(ctx).(*private.HookOptions) + if !git.SupportProcReceive { + ctx.Status(http.StatusNotFound) + return + } results, err := agit.ProcReceive(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, opts) if err != nil { diff --git a/routers/private/serv.go b/routers/private/serv.go index a4029e354c..4c5b7bbccb 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -14,6 +14,7 @@ import ( repo_model "forgejo.org/models/repo" "forgejo.org/models/unit" user_model "forgejo.org/models/user" + "forgejo.org/modules/git" "forgejo.org/modules/log" "forgejo.org/modules/private" "forgejo.org/modules/setting" @@ -302,7 +303,7 @@ func ServCommand(ctx *context.PrivateContext) { // the permission check to read. The pre-receive hook will do another // permission check which ensure for non AGit flow references the write // permission is checked. - if unitType == unit.TypeCode && ctx.FormString("verb") == "git-receive-pack" { + if git.SupportProcReceive && unitType == unit.TypeCode && ctx.FormString("verb") == "git-receive-pack" { mode = perm.AccessModeRead } diff --git a/routers/web/misc/misc.go b/routers/web/misc/misc.go index 22fdccf79f..87b5247599 100644 --- a/routers/web/misc/misc.go +++ b/routers/web/misc/misc.go @@ -7,6 +7,7 @@ import ( "net/http" "path" + "forgejo.org/modules/git" "forgejo.org/modules/httpcache" "forgejo.org/modules/log" "forgejo.org/modules/setting" @@ -14,6 +15,10 @@ import ( ) func SSHInfo(rw http.ResponseWriter, req *http.Request) { + if !git.SupportProcReceive { + rw.WriteHeader(http.StatusNotFound) + return + } rw.Header().Set("content-type", "text/json;charset=UTF-8") _, err := rw.Write([]byte(`{"type":"agit","version":1}`)) if err != nil { diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 59538d8a0e..de2e29ab9f 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -312,16 +312,22 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { baseIsTag := ctx.Repo.GitRepo.IsTagExist(ci.BaseBranch) if !baseIsCommit && !baseIsBranch && !baseIsTag { - if ci.BaseBranch == ctx.Repo.GetObjectFormat().EmptyObjectID().String() { + // Check if baseBranch is short sha commit hash + if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(ci.BaseBranch); baseCommit != nil { + ci.BaseBranch = baseCommit.ID.String() + ctx.Data["BaseBranch"] = ci.BaseBranch + baseIsCommit = true + } else if ci.BaseBranch == ctx.Repo.GetObjectFormat().EmptyObjectID().String() { if isSameRepo { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadRepo.FullName()) + ":" + util.PathEscapeSegments(ci.HeadBranch)) } + return nil } else { ctx.NotFound("IsRefExist", nil) + return nil } - return nil } ctx.Data["BaseIsCommit"] = baseIsCommit ctx.Data["BaseIsBranch"] = baseIsBranch @@ -508,8 +514,15 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { headIsBranch := ci.HeadGitRepo.IsBranchExist(ci.HeadBranch) headIsTag := ci.HeadGitRepo.IsTagExist(ci.HeadBranch) if !headIsCommit && !headIsBranch && !headIsTag { - ctx.NotFound("IsRefExist", nil) - return nil + // Check if headBranch is short sha commit hash + if headCommit, _ := ci.HeadGitRepo.GetCommit(ci.HeadBranch); headCommit != nil { + ci.HeadBranch = headCommit.ID.String() + ctx.Data["HeadBranch"] = ci.HeadBranch + headIsCommit = true + } else { + ctx.NotFound("IsRefExist", nil) + return nil + } } ctx.Data["HeadIsCommit"] = headIsCommit ctx.Data["HeadIsBranch"] = headIsBranch diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index 42302d0e02..650b1d88f4 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -183,7 +183,9 @@ func httpBase(ctx *context.Context) *serviceHandler { if repoExist { // Because of special ref "refs/for" .. , need delay write permission check - accessMode = perm.AccessModeRead + if git.SupportProcReceive { + accessMode = perm.AccessModeRead + } if ctx.Data["IsActionsToken"] == true { taskID := ctx.Data["ActionsTaskID"].(int64) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index a34e3b7c78..5e228507c0 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2775,7 +2775,7 @@ func SearchIssues(ctx *context.Context) { IncludedAnyLabelIDs: includedAnyLabels, MilestoneIDs: includedMilestones, ProjectID: projectID, - SortBy: issue_indexer.ParseSortBy(ctx.FormString("sort"), issue_indexer.SortByCreatedDesc), + SortBy: issue_indexer.SortByCreatedDesc, } if since != 0 { @@ -2804,10 +2804,9 @@ func SearchIssues(ctx *context.Context) { } } - priorityRepoID := ctx.FormInt64("priority_repo_id") - if priorityRepoID > 0 { - searchOpt.PriorityRepoID = optional.Some(priorityRepoID) - } + // FIXME: It's unsupported to sort by priority repo when searching by indexer, + // it's indeed an regression, but I think it is worth to support filtering by indexer first. + _ = ctx.FormInt64("priority_repo_id") ids, total, err := issue_indexer.SearchIssues(ctx, searchOpt) if err != nil { @@ -2945,7 +2944,7 @@ func ListIssues(ctx *context.Context) { IsPull: isPull, IsClosed: isClosed, ProjectID: projectID, - SortBy: issue_indexer.ParseSortBy(ctx.FormString("sort"), issue_indexer.SortByCreatedDesc), + SortBy: issue_indexer.SortByCreatedDesc, } if since != 0 { searchOpt.UpdatedAfterUnix = optional.Some(since) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 4e365f24ea..fd18646211 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -996,13 +996,6 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi ctx.Data["Verification"] = verification ctx.Data["Author"] = user_model.ValidateCommitWithEmail(ctx, curCommit) - if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) { - return repo_model.IsOwnerMemberCollaborator(ctx, ctx.Repo.Repository, user.ID) - }, nil); err != nil { - ctx.ServerError("CalculateTrustStatus", err) - return - } - note := &git.Note{} err = git.GetNote(ctx, ctx.Repo.GitRepo, specifiedEndCommit, note) if err == nil { diff --git a/services/context/repo.go b/services/context/repo.go index c8876d7166..cce3a5fa70 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -644,11 +644,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { ctx.Data["OpenGraphImageURL"] = repo.SummaryCardURL() ctx.Data["OpenGraphImageWidth"] = cardWidth ctx.Data["OpenGraphImageHeight"] = cardHeight - if util.IsEmptyString(repo.Description) { - ctx.Data["OpenGraphImageAltText"] = ctx.Tr("repo.summary_card_alt", repo.FullName()) - } else { - ctx.Data["OpenGraphImageAltText"] = ctx.Tr("og.repo.summary_card.alt_description", repo.FullName(), repo.Description) - } + ctx.Data["OpenGraphImageAltText"] = ctx.Tr("repo.summary_card_alt", repo.FullName()) if repo.IsFork { RetrieveBaseRepo(ctx, repo) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 7033264f18..6835dfbf36 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1157,7 +1157,7 @@ func GetDiffSimple(ctx context.Context, gitRepo *git.Repository, opts *DiffOptio // so if we are using at least this version of git we don't have to tell ParsePatch to do // the skipping for us parsePatchSkipToFile := opts.SkipTo - if opts.SkipTo != "" { + if opts.SkipTo != "" && git.CheckGitVersionAtLeast("2.31") == nil { cmdDiff.AddOptionFormat("--skip-to=%s", opts.SkipTo) parsePatchSkipToFile = "" } diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go index 76ae0df018..1805ffc527 100644 --- a/services/pull/temp_repo.go +++ b/services/pull/temp_repo.go @@ -103,7 +103,11 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest) remoteRepoName := "head_repo" baseBranch := "base" - fetchArgs := git.TrustedCmdArgs{"--no-tags", "--no-write-commit-graph"} + fetchArgs := git.TrustedCmdArgs{"--no-tags"} + if git.CheckGitVersionAtLeast("2.25.0") == nil { + // Writing the commit graph can be slow and is not needed here + fetchArgs = append(fetchArgs, "--no-write-commit-graph") + } // addCacheRepo adds git alternatives for the cacheRepoPath in the repoPath addCacheRepo := func(repoPath, cacheRepoPath string) error { diff --git a/services/repository/files/content.go b/services/repository/files/content.go index 5a6006e9f2..3d2217df18 100644 --- a/services/repository/files/content.go +++ b/services/repository/files/content.go @@ -5,7 +5,6 @@ package files import ( "context" - "errors" "fmt" "net/url" "path" @@ -206,7 +205,7 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref } else if entry.IsLink() { contentsResponse.Type = string(ContentTypeLink) // The target of a symlink file is the content of the file - targetFromContent, err := entry.LinkTarget() + targetFromContent, err := entry.Blob().GetBlobContent(1024) if err != nil { return nil, err } @@ -274,11 +273,13 @@ func GetBlobBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git if err != nil { return nil, err } - content, err := gitBlob.GetContentBase64(setting.API.DefaultMaxBlobSize) - if err != nil && !errors.As(err, &git.BlobTooLargeError{}) { - return nil, err + content := "" + if gitBlob.Size() <= setting.API.DefaultMaxBlobSize { + content, err = gitBlob.GetBlobContentBase64() + if err != nil { + return nil, err + } } - return &api.GitBlob{ SHA: gitBlob.ID.String(), URL: repo.APIURL() + "/git/blobs/" + url.PathEscape(gitBlob.ID.String()), diff --git a/services/repository/files/file.go b/services/repository/files/file.go index 5b93258840..ef9a87dbcf 100644 --- a/services/repository/files/file.go +++ b/services/repository/files/file.go @@ -104,35 +104,36 @@ func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_m // then we use bogus User objects for them to store their FullName and Email. // If only one of the two are provided, we set both of them to it. // If neither are provided, both are the doer. - getUser := func(identity *IdentityOptions) *user_model.User { - if identity == nil || identity.Email == "" { - return nil - } - - if doer != nil && strings.EqualFold(doer.Email, identity.Email) { - user := doer // the committer is the doer, so will use their user object - if identity.Name != "" { - user.FullName = identity.Name + if committer != nil && committer.Email != "" { + if doer != nil && strings.EqualFold(doer.Email, committer.Email) { + committerUser = doer // the committer is the doer, so will use their user object + if committer.Name != "" { + committerUser.FullName = committer.Name } // Use the provided email and not revert to placeholder mail. - user.KeepEmailPrivate = false - return user - } - - var id int64 - if doer != nil { - id = doer.ID - } - return &user_model.User{ - ID: id, // Needed to ensure the doer is checked to pass rules for instance signing of CRUD actions. - FullName: identity.Name, - Email: identity.Email, + committerUser.KeepEmailPrivate = false + } else { + committerUser = &user_model.User{ + FullName: committer.Name, + Email: committer.Email, + } + } + } + if author != nil && author.Email != "" { + if doer != nil && strings.EqualFold(doer.Email, author.Email) { + authorUser = doer // the author is the doer, so will use their user object + if authorUser.Name != "" { + authorUser.FullName = author.Name + } + // Use the provided email and not revert to placeholder mail. + authorUser.KeepEmailPrivate = false + } else { + authorUser = &user_model.User{ + FullName: author.Name, + Email: author.Email, + } } } - - committerUser = getUser(committer) - authorUser = getUser(author) - if authorUser == nil { if committerUser != nil { authorUser = committerUser // No valid author was given so use the committer diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index 18b5226c02..5b1dd65b5a 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -147,7 +147,11 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user stdout := &strings.Builder{} stderr := &strings.Builder{} - cmdApply := git.NewCommand(ctx, "apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary", "-3") + cmdApply := git.NewCommand(ctx, "apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary") + if git.CheckGitVersionAtLeast("2.32") == nil { + cmdApply.AddArguments("-3") + } + if err := cmdApply.Run(&git.RunOpts{ Dir: t.basePath, Stdout: stdout, diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 7259c4a995..db98d40583 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -350,7 +350,7 @@ func parseHookPullRequestEventType(event webhook_module.HookEventType) (string, case webhook_module.HookEventPullRequestReviewApproved: return "approved", nil case webhook_module.HookEventPullRequestReviewRejected: - return "requested changes", nil + return "rejected", nil case webhook_module.HookEventPullRequestReviewComment: return "comment", nil default: diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0e8382b8ab..59c13cd9e6 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4524,24 +4524,6 @@ "description": "Number of items per page", "name": "limit", "in": "query" - }, - { - "enum": [ - "relevance", - "latest", - "oldest", - "recentupdate", - "leastupdate", - "mostcomment", - "leastcomment", - "nearduedate", - "farduedate" - ], - "type": "string", - "default": "latest", - "description": "Type of sort", - "name": "sort", - "in": "query" } ], "responses": { diff --git a/tests/e2e/declare_repos_test.go b/tests/e2e/declare_repos_test.go index 0747d896f3..4c68566a48 100644 --- a/tests/e2e/declare_repos_test.go +++ b/tests/e2e/declare_repos_test.go @@ -9,23 +9,16 @@ import ( "testing" "time" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - repo_model "forgejo.org/models/repo" unit_model "forgejo.org/models/unit" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" "forgejo.org/modules/indexer/stats" - "forgejo.org/modules/optional" - "forgejo.org/modules/timeutil" - issue_service "forgejo.org/services/issue" files_service "forgejo.org/services/repository/files" "forgejo.org/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "xorm.io/xorm/convert" ) // first entry represents filename @@ -36,34 +29,19 @@ type FileChanges struct { Versions []string } -// performs additional repo setup as needed -type SetupRepo func(*user_model.User, *repo_model.Repository) - // put your Git repo declarations in here // feel free to amend the helper function below or use the raw variant directly func DeclareGitRepos(t *testing.T) func() { - now := timeutil.TimeStampNow() - postIssue := func(repo *repo_model.Repository, user *user_model.User, age int64, title, content string) { - issue := &issues_model.Issue{ - RepoID: repo.ID, - PosterID: user.ID, - Title: title, - Content: content, - CreatedUnix: now.Add(-age), - } - require.NoError(t, issue_service.NewIssue(db.DefaultContext, repo, issue, nil, nil, nil)) - } - cleanupFunctions := []func(){ - newRepo(t, 2, "diff-test", nil, []FileChanges{{ + newRepo(t, 2, "diff-test", []FileChanges{{ Filename: "testfile", Versions: []string{"hello", "hallo", "hola", "native", "ubuntu-latest", "- runs-on: ubuntu-latest", "- runs-on: debian-latest"}, - }}, nil), - newRepo(t, 2, "language-stats-test", nil, []FileChanges{{ + }}), + newRepo(t, 2, "language-stats-test", []FileChanges{{ Filename: "main.rs", Versions: []string{"fn main() {", "println!(\"Hello World!\");", "}"}, - }}, nil), - newRepo(t, 2, "mentions-highlighted", nil, []FileChanges{ + }}), + newRepo(t, 2, "mentions-highlighted", []FileChanges{ { Filename: "history1.md", Versions: []string{""}, @@ -74,38 +52,15 @@ func DeclareGitRepos(t *testing.T) func() { Versions: []string{""}, CommitMsg: "Another commit which mentions @user1 in the title\nand @user2 in the text", }, - }, nil), - newRepo(t, 2, "file-uploads", nil, []FileChanges{{ + }), + newRepo(t, 2, "file-uploads", []FileChanges{{ Filename: "UPLOAD_TEST.md", Versions: []string{"# File upload test\nUse this repo to test various file upload features in new branches."}, - }}, nil), - newRepo(t, 2, "unicode-escaping", nil, []FileChanges{{ + }}), + newRepo(t, 2, "unicode-escaping", []FileChanges{{ Filename: "a-file", Versions: []string{"{a}{а}"}, - }}, nil), - newRepo(t, 11, "dependency-test", &tests.DeclarativeRepoOptions{ - UnitConfig: optional.Some(map[unit_model.Type]convert.Conversion{ - unit_model.TypeIssues: &repo_model.IssuesConfig{ - EnableDependencies: true, - }, - }), - }, []FileChanges{}, func(user *user_model.User, repo *repo_model.Repository) { - postIssue(repo, user, 500, "first issue here", "an issue created earlier") - postIssue(repo, user, 400, "second issue here (not 1)", "not the right issue, but in the right repo") - postIssue(repo, user, 300, "third issue here", "depends on things") - postIssue(repo, user, 200, "unrelated issue", "shrug emoji") - postIssue(repo, user, 100, "newest issue", "very new") - }), - newRepo(t, 11, "dependency-test-2", &tests.DeclarativeRepoOptions{ - UnitConfig: optional.Some(map[unit_model.Type]convert.Conversion{ - unit_model.TypeIssues: &repo_model.IssuesConfig{ - EnableDependencies: true, - }, - }), - }, []FileChanges{}, func(user *user_model.User, repo *repo_model.Repository) { - postIssue(repo, user, 450, "right issue", "an issue containing word right") - postIssue(repo, user, 150, "left issue", "an issue containing word left") - }), + }}), // add your repo declarations here } @@ -116,18 +71,12 @@ func DeclareGitRepos(t *testing.T) func() { } } -func newRepo(t *testing.T, userID int64, repoName string, initOpts *tests.DeclarativeRepoOptions, fileChanges []FileChanges, setup SetupRepo) func() { +func newRepo(t *testing.T, userID int64, repoName string, fileChanges []FileChanges) func() { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) - - opts := tests.DeclarativeRepoOptions{} - if initOpts != nil { - opts = *initOpts - } - opts.Name = optional.Some(repoName) - if !opts.EnabledUnits.Has() { - opts.EnabledUnits = optional.Some([]unit_model.Type{unit_model.TypeCode, unit_model.TypeIssues}) - } - somerepo, _, cleanupFunc := tests.CreateDeclarativeRepoWithOptions(t, user, opts) + somerepo, _, cleanupFunc := tests.CreateDeclarativeRepo(t, user, repoName, + []unit_model.Type{unit_model.TypeCode, unit_model.TypeIssues}, nil, + nil, + ) var lastCommitID string for _, file := range fileChanges { @@ -173,10 +122,6 @@ func newRepo(t *testing.T, userID int64, repoName string, initOpts *tests.Declar } } - if setup != nil { - setup(user, somerepo) - } - err := stats.UpdateRepoIndexer(somerepo) require.NoError(t, err) diff --git a/tests/e2e/issue-sidebar.test.e2e.ts b/tests/e2e/issue-sidebar.test.e2e.ts index 34885d0d5d..bc65b0842c 100644 --- a/tests/e2e/issue-sidebar.test.e2e.ts +++ b/tests/e2e/issue-sidebar.test.e2e.ts @@ -262,91 +262,3 @@ test('New Issue: Milestone', async ({page}, workerInfo) => { await expect(selectedMilestone).toContainText('No milestone'); await save_visual(page); }); - -test.describe('Dependency dropdown', () => { - test.use({user: 'user11'}); - test('Issue: Dependencies', async ({page}) => { - const response = await page.goto('/user11/dependency-test/issues/3'); - expect(response?.status()).toBe(200); - - const depsBlock = page.locator('.issue-content-right .depending'); - const deleteDepBtn = page.locator('.issue-content-right .depending .delete-dependency-button'); - - const input = page.locator('#new-dependency-drop-list .search'); - const current = page.locator('#new-dependency-drop-list .text').first(); - const menu = page.locator('#new-dependency-drop-list .menu'); - const items = page.locator('#new-dependency-drop-list .menu .item'); - - const confirmDelete = async () => { - const modal = page.locator('.modal.remove-dependency'); - await expect(modal).toBeVisible(); - await expect(modal).toContainText('This will remove the dependency from this issue'); - await modal.locator('button.ok').click(); - }; - - // A kludge to set the dropdown to the *wrong* value so it lets us select the correct one next. - const resetDropdown = async () => { - if (await current.textContent().then((s) => s.includes('#4'))) return; - await input.click(); - await input.fill('unrelated'); - await expect(items.first()).toContainText('unrelated'); - await items.first().click(); - await expect(current).toContainText('#4'); - await input.click(); - }; - - await expect(depsBlock).toBeVisible(); - while (await deleteDepBtn.first().isVisible()) { - await deleteDepBtn.first().click(); // wipe added dependencies from any previously failed tests - await confirmDelete(); - } - await expect(depsBlock).toContainText('No dependencies set'); - - await input.scrollIntoViewIfNeeded(); - await input.click(); - - const first = 'first issue here'; - const second = 'second issue here'; - const newest = 'newest issue'; - - // Without query, it should show issues in the same repo, sorted by date, except current one. - await expect(menu).toBeVisible(); - await expect(items).toHaveCount(4); // 5 issues in this repo, minus current one - await expect(items.first()).toContainText(newest); - await expect(items.last()).toContainText(first); - await resetDropdown(); - - // With query, it should search all repos, but show current repo issues first. - await input.fill('right'); - await expect(items.first()).toContainText(second); - await expect.poll(() => items.count()).toBeGreaterThan(1); // there is an issue in user11/dependency-test-2 containing the word "right" - await resetDropdown(); - - // When entering an issue number, it should always show that one first, then all text matches. - await input.fill('1'); - await expect(items.first()).toContainText(first); - await expect(items.nth(1)).toBeVisible(); - await resetDropdown(); - - // Should behave the same with a prefix - await input.fill('#1'); - await expect(items.first()).toContainText(first); - - // Selecting an issue - await items.first().click(); - await expect(current).toContainText(first); - - // Add dependency - const link = page.locator('.issue-content-right .depending .dependency a.title'); - await page.locator('.issue-content-right .depending button').click(); - await expect(link).toHaveAttribute('href', '/user11/dependency-test/issues/1'); - - // Remove dependency - await expect(deleteDepBtn).toBeVisible(); - await deleteDepBtn.click(); - - await confirmDelete(); - - await expect(depsBlock).toContainText('No dependencies set'); - }); -}); diff --git a/tests/e2e/utils_e2e_test.go b/tests/e2e/utils_e2e_test.go index efa1657cee..e121c604c3 100644 --- a/tests/e2e/utils_e2e_test.go +++ b/tests/e2e/utils_e2e_test.go @@ -93,7 +93,6 @@ func createSessions(t testing.TB) { users := []string{ "user1", "user2", - "user11", "user12", "user18", "user29", diff --git a/tests/integration/api_block_test.go b/tests/integration/api_block_test.go index 0e2cf7ee25..8b25ce9283 100644 --- a/tests/integration/api_block_test.go +++ b/tests/integration/api_block_test.go @@ -4,10 +4,8 @@ package integration import ( - "cmp" "fmt" "net/http" - "slices" "testing" auth_model "forgejo.org/models/auth" @@ -48,7 +46,6 @@ func TestAPIUserBlock(t *testing.T) { var blockedUsers []api.BlockedUser DecodeJSON(t, resp, &blockedUsers) assert.Len(t, blockedUsers, 2) - slices.SortFunc(blockedUsers, func(a, b api.BlockedUser) int { return cmp.Compare(a.BlockID, b.BlockID) }) assert.EqualValues(t, 1, blockedUsers[0].BlockID) assert.EqualValues(t, 2, blockedUsers[1].BlockID) }) diff --git a/tests/integration/api_branch_test.go b/tests/integration/api_branch_test.go index d8800217d3..8e88501596 100644 --- a/tests/integration/api_branch_test.go +++ b/tests/integration/api_branch_test.go @@ -116,7 +116,7 @@ func testAPICreateBranches(t *testing.T, giteaURL *url.URL) { ctx := NewAPITestContext(t, "user2", "my-noo-repo-"+objectFormat.Name(), auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) giteaURL.Path = ctx.GitPath() - t.Run("CreateRepo", doAPICreateRepository(ctx, nil, objectFormat)) + t.Run("CreateRepo", doAPICreateRepository(ctx, false, objectFormat)) testCases := []struct { OldBranch string NewBranch string diff --git a/tests/integration/api_helper_for_declarative_test.go b/tests/integration/api_helper_for_declarative_test.go index ada6a2c311..c9b6f84f4f 100644 --- a/tests/integration/api_helper_for_declarative_test.go +++ b/tests/integration/api_helper_for_declarative_test.go @@ -48,22 +48,20 @@ func (ctx APITestContext) GitPath() string { return fmt.Sprintf("%s/%s.git", ctx.Username, ctx.Reponame) } -func doAPICreateRepository(ctx APITestContext, opts *api.CreateRepoOption, objectFormat git.ObjectFormat, callback ...func(*testing.T, api.Repository)) func(*testing.T) { +func doAPICreateRepository(ctx APITestContext, empty bool, objectFormat git.ObjectFormat, callback ...func(*testing.T, api.Repository)) func(*testing.T) { return func(t *testing.T) { - if opts == nil { - opts = &api.CreateRepoOption{ - AutoInit: true, - Description: "Temporary repo", - Name: ctx.Reponame, - Private: true, - Template: true, - Gitignores: "", - License: "WTFPL", - Readme: "Default", - } + createRepoOption := &api.CreateRepoOption{ + AutoInit: !empty, + Description: "Temporary repo", + Name: ctx.Reponame, + Private: true, + Template: true, + Gitignores: "", + License: "WTFPL", + Readme: "Default", + ObjectFormatName: objectFormat.Name(), } - opts.ObjectFormatName = objectFormat.Name() - req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", opts). + req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", createRepoOption). AddTokenAuth(ctx.Token) if ctx.ExpectedCode != 0 { ctx.Session.MakeRequest(t, req, ctx.ExpectedCode) @@ -239,8 +237,8 @@ func doAPICreatePullRequest(ctx APITestContext, owner, repo, baseBranch, headBra } } -func doAPIGetPullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) api.PullRequest { - return func(t *testing.T) api.PullRequest { +func doAPIGetPullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) (api.PullRequest, error) { + return func(t *testing.T) (api.PullRequest, error) { req := NewRequest(t, http.MethodGet, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner, repo, index)). AddTokenAuth(ctx.Token) @@ -250,9 +248,10 @@ func doAPIGetPullRequest(ctx APITestContext, owner, repo string, index int64) fu } resp := ctx.Session.MakeRequest(t, req, expected) + decoder := json.NewDecoder(resp.Body) pr := api.PullRequest{} - DecodeJSON(t, resp, &pr) - return pr + err := decoder.Decode(&pr) + return pr, err } } @@ -348,40 +347,20 @@ func doAPICancelAutoMergePullRequest(ctx APITestContext, owner, repo string, ind } } -func doAPIGetBranch(ctx APITestContext, branch string) func(*testing.T) api.Branch { - return func(t *testing.T) api.Branch { - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/branches/%s", ctx.Username, ctx.Reponame, branch). - AddTokenAuth(ctx.Token) - expected := http.StatusOK - if ctx.ExpectedCode != 0 { - expected = ctx.ExpectedCode - } - resp := ctx.Session.MakeRequest(t, req, expected) - - branch := api.Branch{} - DecodeJSON(t, resp, &branch) - return branch - } -} - -func doAPICreateTag(ctx APITestContext, tag, target, message string, callback ...func(*testing.T, api.Tag)) func(*testing.T) { +func doAPIGetBranch(ctx APITestContext, branch string, callback ...func(*testing.T, api.Branch)) func(*testing.T) { return func(t *testing.T) { - req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/tags", ctx.Username, ctx.Reponame), &api.CreateTagOption{ - TagName: tag, - Message: message, - Target: target, - }). + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/branches/%s", ctx.Username, ctx.Reponame, branch). AddTokenAuth(ctx.Token) if ctx.ExpectedCode != 0 { ctx.Session.MakeRequest(t, req, ctx.ExpectedCode) return } - resp := ctx.Session.MakeRequest(t, req, http.StatusCreated) + resp := ctx.Session.MakeRequest(t, req, http.StatusOK) - var tag api.Tag - DecodeJSON(t, resp, &tag) + var branch api.Branch + DecodeJSON(t, resp, &branch) if len(callback) > 0 { - callback[0](t, tag) + callback[0](t, branch) } } } diff --git a/tests/integration/api_repo_compare_test.go b/tests/integration/api_repo_compare_test.go index 1724924fdc..35f0a21d82 100644 --- a/tests/integration/api_repo_compare_test.go +++ b/tests/integration/api_repo_compare_test.go @@ -4,268 +4,56 @@ package integration import ( - "encoding/base64" - "fmt" "net/http" - "net/http/httptest" - "net/url" - "strings" "testing" - "time" auth_model "forgejo.org/models/auth" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" - "forgejo.org/modules/git" api "forgejo.org/modules/structs" + "forgejo.org/tests" "github.com/stretchr/testify/assert" ) +func TestAPICompareBranches(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + // Login as User2. + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + repoName := "repo20" + + req := NewRequestf(t, "GET", "/api/v1/repos/user2/%s/compare/add-csv...remove-files-b", repoName). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + + var apiResp *api.Compare + DecodeJSON(t, resp, &apiResp) + + assert.Equal(t, 2, apiResp.TotalCommits) + assert.Len(t, apiResp.Commits, 2) + assert.Len(t, apiResp.Files, 3) +} + func TestAPICompareCommits(t *testing.T) { - forEachObjectFormat(t, testAPICompareCommits) -} - -func testAPICompareCommits(t *testing.T, objectFormat git.ObjectFormat) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - newBranchAndFile := func(ctx APITestContext, user *user_model.User, branch, filename string) func(*testing.T) { - return func(t *testing.T) { - doAPICreateFile(ctx, filename, &api.CreateFileOptions{ - FileOptions: api.FileOptions{ - NewBranchName: branch, - Message: "create " + filename, - Author: api.Identity{ - Name: user.Name, - Email: user.Email, - }, - Committer: api.Identity{ - Name: user.Name, - Email: user.Email, - }, - Dates: api.CommitDateOptions{ - Author: time.Now(), - Committer: time.Now(), - }, - }, - ContentBase64: base64.StdEncoding.EncodeToString([]byte("content " + filename)), - })(t) - } - } - - requireErrorContains := func(t *testing.T, resp *httptest.ResponseRecorder, expected string) { - t.Helper() - - type response struct { - Message string `json:"message"` - Errors []string `json:"errors"` - } - var bodyResp response - DecodeJSON(t, resp, &bodyResp) - - if strings.Contains(bodyResp.Message, expected) { - return - } - for _, error := range bodyResp.Errors { - if strings.Contains(error, expected) { - return - } - } - t.Log(fmt.Sprintf("expected %s in %+v", expected, bodyResp)) - t.Fail() - } - - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - user2repo := "repoA" - user2Ctx := NewAPITestContext(t, user2.Name, user2repo, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateUser2Repository", doAPICreateRepository(user2Ctx, &api.CreateRepoOption{ - AutoInit: true, - Description: "Temporary repo", - Name: user2Ctx.Reponame, - }, objectFormat)) - user2branchName := "user2branch" - t.Run("CreateUser2RepositoryBranch", newBranchAndFile(user2Ctx, user2, user2branchName, "user2branchfilename.txt")) - user2branch := doAPIGetBranch(user2Ctx, user2branchName)(t) - user2master := doAPIGetBranch(user2Ctx, "master")(t) - user2tag1 := "tag1" - t.Run("CreateUser2RepositoryTag1", doAPICreateTag(user2Ctx, user2tag1, "master", "user2branchtag1")) - user2tag2 := "tag2" - t.Run("CreateUser2RepositoryTag1", doAPICreateTag(user2Ctx, user2tag2, user2branchName, "user2branchtag2")) - - shortCommitLength := 7 - - for _, testCase := range []struct { - name string - a string - b string - }{ - { - name: "Commits", - a: user2master.Commit.ID, - b: user2branch.Commit.ID, - }, - { - name: "ShortCommits", - a: user2master.Commit.ID[:shortCommitLength], - b: user2branch.Commit.ID[:shortCommitLength], - }, - { - name: "Branches", - a: "master", - b: user2branchName, - }, - { - name: "Tags", - a: user2tag1, - b: user2tag2, - }, - } { - t.Run("SameRepo"+testCase.name, func(t *testing.T) { - // a...b - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/%s...%s", user2.Name, user2repo, testCase.a, testCase.b). - AddTokenAuth(user2Ctx.Token) - resp := MakeRequest(t, req, http.StatusOK) - - var apiResp *api.Compare - DecodeJSON(t, resp, &apiResp) - - assert.Equal(t, 1, apiResp.TotalCommits) - assert.Len(t, apiResp.Commits, 1) - assert.Len(t, apiResp.Files, 1) - - // b...a - req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/%s...%s", user2.Name, user2repo, testCase.b, testCase.a). - AddTokenAuth(user2Ctx.Token) - resp = MakeRequest(t, req, http.StatusOK) - - DecodeJSON(t, resp, &apiResp) - - assert.Equal(t, 0, apiResp.TotalCommits) - assert.Empty(t, apiResp.Commits) - assert.Empty(t, apiResp.Files) - }) - } - - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) - user4Ctx := NewAPITestContext(t, user4.Name, user2repo, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - - t.Run("ForkNotFound", func(t *testing.T) { - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/%s...%s:%s", user2.Name, user2repo, "master", user4.Name, user2branchName). - AddTokenAuth(user2Ctx.Token) - resp := MakeRequest(t, req, http.StatusNotFound) - requireErrorContains(t, resp, "user4 does not have a fork of user2/repoA and user2/repoA is not a fork of a repository from user4") - }) - - t.Run("User4ForksUser2Repository", doAPIForkRepository(user4Ctx, user2.Name)) - user4branchName := "user4branch" - t.Run("CreateUser4RepositoryBranch", newBranchAndFile(user4Ctx, user4, user4branchName, "user4branchfilename.txt")) - user4branch := doAPIGetBranch(user4Ctx, user4branchName)(t) - user4tag4 := "tag4" - t.Run("CreateUser4RepositoryTag4", doAPICreateTag(user4Ctx, user4tag4, user4branchName, "user4branchtag4")) - - t.Run("FromTheForkedRepo", func(t *testing.T) { - // user4/repoA is a fork of user2/repoA and when evaluating - // - // user4/repoA/compare/master...user2:user2branch - // - // user2/repoA is not explicitly specified, it is implicitly the repository - // from which user4/repoA was forked - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/%s...%s:%s", user4.Name, user2repo, "master", user2.Name, user2branchName). - AddTokenAuth(user4Ctx.Token) - resp := MakeRequest(t, req, http.StatusOK) - - var apiResp *api.Compare - DecodeJSON(t, resp, &apiResp) - - assert.Equal(t, 1, apiResp.TotalCommits) - assert.Len(t, apiResp.Commits, 1) - assert.Len(t, apiResp.Files, 1) - }) - - for _, testCase := range []struct { - name string - a string - b string - }{ - { - name: "Commits", - a: user2master.Commit.ID, - b: fmt.Sprintf("%s:%s", user4.Name, user4branch.Commit.ID), - }, - { - name: "ShortCommits", - a: user2master.Commit.ID[:shortCommitLength], - b: fmt.Sprintf("%s:%s", user4.Name, user4branch.Commit.ID[:shortCommitLength]), - }, - { - name: "Branches", - a: "master", - b: fmt.Sprintf("%s:%s", user4.Name, user4branchName), - }, - { - name: "Tags", - a: user2tag1, - b: fmt.Sprintf("%s:%s", user4.Name, user4tag4), - }, - { - name: "SameRepo", - a: "master", - b: fmt.Sprintf("%s:%s", user2.Name, user2branchName), - }, - } { - t.Run("ForkedRepo"+testCase.name, func(t *testing.T) { - // user2/repoA is forked into user4/repoA and when evaluating - // - // user2/repoA/compare/a...user4:b - // - // user4/repoA is not explicitly specified, it is implicitly the repository - // owned by user4 which is a fork of repoA - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/%s...%s", user2.Name, user2repo, testCase.a, testCase.b). - AddTokenAuth(user2Ctx.Token) - resp := MakeRequest(t, req, http.StatusOK) - - var apiResp *api.Compare - DecodeJSON(t, resp, &apiResp) - - assert.Equal(t, 1, apiResp.TotalCommits) - assert.Len(t, apiResp.Commits, 1) - assert.Len(t, apiResp.Files, 1) - }) - } - - t.Run("ForkUserDoesNotExist", func(t *testing.T) { - notUser := "notauser" - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/master...%s:branchname", user2.Name, user2repo, notUser). - AddTokenAuth(user2Ctx.Token) - resp := MakeRequest(t, req, http.StatusNotFound) - requireErrorContains(t, resp, fmt.Sprintf("the owner %s does not exist", notUser)) - }) - - t.Run("HeadHasTooManyColon", func(t *testing.T) { - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/master...one:two:many", user2.Name, user2repo). - AddTokenAuth(user2Ctx.Token) - resp := MakeRequest(t, req, http.StatusNotFound) - requireErrorContains(t, resp, fmt.Sprintf("must contain zero or one colon (:) but contains 2")) - }) - - for _, testCase := range []struct { - what string - baseHead string - }{ - { - what: "base", - baseHead: "notexists...master", - }, - { - what: "head", - baseHead: "master...notexists", - }, - } { - t.Run("BaseHeadNotExists "+testCase.what, func(t *testing.T) { - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/compare/%s", user2.Name, user2repo, testCase.baseHead). - AddTokenAuth(user2Ctx.Token) - resp := MakeRequest(t, req, http.StatusNotFound) - requireErrorContains(t, resp, fmt.Sprintf("could not find 'notexists' to be a commit, branch or tag in the %s", testCase.what)) - }) - } - }) + defer tests.PrepareTestEnv(t)() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + // Login as User2. + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo20/compare/c8e31bc...8babce9"). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + + var apiResp *api.Compare + DecodeJSON(t, resp, &apiResp) + + assert.Equal(t, 2, apiResp.TotalCommits) + assert.Len(t, apiResp.Commits, 2) + assert.Len(t, apiResp.Files, 3) } diff --git a/tests/integration/api_repo_file_create_test.go b/tests/integration/api_repo_file_create_test.go index 4916ef97ef..c112653e11 100644 --- a/tests/integration/api_repo_file_create_test.go +++ b/tests/integration/api_repo_file_create_test.go @@ -287,14 +287,7 @@ func TestAPICreateFile(t *testing.T) { // Test creating a file in an empty repository forEachObjectFormat(t, func(t *testing.T, objectFormat git.ObjectFormat) { reponame := "empty-repo-" + objectFormat.Name() - ctx := NewAPITestContext(t, "user2", reponame, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - opts := &api.CreateRepoOption{ - Description: "Temporary repo", - Name: ctx.Reponame, - Private: true, - Template: true, - } - doAPICreateRepository(ctx, opts, objectFormat)(t) + doAPICreateRepository(NewAPITestContext(t, "user2", reponame, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser), true, objectFormat)(t) createFileOptions = getCreateFileOptions() fileID++ treePath = fmt.Sprintf("new/file%d.txt", fileID) diff --git a/tests/integration/api_repo_file_get_test.go b/tests/integration/api_repo_file_get_test.go index ab82e5cf15..7bd7393b01 100644 --- a/tests/integration/api_repo_file_get_test.go +++ b/tests/integration/api_repo_file_get_test.go @@ -17,40 +17,36 @@ import ( ) func TestAPIGetRawFileOrLFS(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + // Test with raw file + req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/README.md") + resp := MakeRequest(t, req, http.StatusOK) + assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String()) + + // Test with LFS onGiteaRun(t, func(t *testing.T, u *url.URL) { - t.Run("Normal raw file", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() + httpContext := NewAPITestContext(t, "user2", "repo-lfs-test", auth_model.AccessTokenScopeWriteRepository) + doAPICreateRepository(httpContext, false, git.Sha1ObjectFormat, func(t *testing.T, repository api.Repository) { // FIXME: use forEachObjectFormat + u.Path = httpContext.GitPath() + dstPath := t.TempDir() - req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/README.md") - resp := MakeRequest(t, req, http.StatusOK) - assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String()) - }) + u.Path = httpContext.GitPath() + u.User = url.UserPassword("user2", userPassword) - t.Run("LFS raw file", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() + t.Run("Clone", doGitClone(dstPath, u)) - httpContext := NewAPITestContext(t, "user2", "repo-lfs-test", auth_model.AccessTokenScopeWriteRepository) - doAPICreateRepository(httpContext, nil, git.Sha1ObjectFormat, func(t *testing.T, repository api.Repository) { // FIXME: use forEachObjectFormat - u.Path = httpContext.GitPath() - dstPath := t.TempDir() + dstPath2 := t.TempDir() - u.Path = httpContext.GitPath() - u.User = url.UserPassword("user2", userPassword) + t.Run("Partial Clone", doPartialGitClone(dstPath2, u)) - t.Run("Clone", doGitClone(dstPath, u)) + lfs, _ := lfsCommitAndPushTest(t, dstPath) - dstPath2 := t.TempDir() + reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/"+lfs) + respLFS := MakeRequestNilResponseRecorder(t, reqLFS, http.StatusOK) + assert.Equal(t, littleSize, respLFS.Length) - t.Run("Partial Clone", doPartialGitClone(dstPath2, u)) - - lfs, _ := lfsCommitAndPushTest(t, dstPath) - - reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/"+lfs) - respLFS := MakeRequestNilResponseRecorder(t, reqLFS, http.StatusOK) - assert.Equal(t, littleSize, respLFS.Length) - - doAPIDeleteRepository(httpContext) - }) + doAPIDeleteRepository(httpContext) }) }) } diff --git a/tests/integration/api_repo_lfs_test.go b/tests/integration/api_repo_lfs_test.go index b0edf7b854..b8ba54f876 100644 --- a/tests/integration/api_repo_lfs_test.go +++ b/tests/integration/api_repo_lfs_test.go @@ -64,7 +64,7 @@ func TestAPILFSMediaType(t *testing.T) { func createLFSTestRepository(t *testing.T, name string) *repo_model.Repository { ctx := NewAPITestContext(t, "user2", "lfs-"+name+"-repo", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepo", doAPICreateRepository(ctx, nil, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat + t.Run("CreateRepo", doAPICreateRepository(ctx, false, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat repo, err := repo_model.GetRepositoryByOwnerAndName(db.DefaultContext, "user2", "lfs-"+name+"-repo") require.NoError(t, err) diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go index e81f4307ee..fd62670eb3 100644 --- a/tests/integration/api_repo_test.go +++ b/tests/integration/api_repo_test.go @@ -415,7 +415,7 @@ func testAPIRepoMigrateConflict(t *testing.T, u *url.URL) { httpContext := baseAPITestContext httpContext.Reponame = "repo-tmp-17" - t.Run("CreateRepo", doAPICreateRepository(httpContext, nil, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat + t.Run("CreateRepo", doAPICreateRepository(httpContext, false, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat user, err := user_model.GetUserByName(db.DefaultContext, httpContext.Username) require.NoError(t, err) @@ -498,7 +498,7 @@ func testAPIRepoCreateConflict(t *testing.T, u *url.URL) { httpContext := baseAPITestContext httpContext.Reponame = "repo-tmp-17" - t.Run("CreateRepo", doAPICreateRepository(httpContext, nil, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat + t.Run("CreateRepo", doAPICreateRepository(httpContext, false, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{ diff --git a/tests/integration/db_collation_test.go b/tests/integration/db_collation_test.go index c41209f1fe..bf55bdd8ee 100644 --- a/tests/integration/db_collation_test.go +++ b/tests/integration/db_collation_test.go @@ -7,7 +7,6 @@ package integration import ( "net/http" "testing" - "time" "forgejo.org/models/db" "forgejo.org/modules/setting" @@ -98,13 +97,9 @@ func TestDatabaseCollation(t *testing.T) { defer test.MockVariableValue(&setting.Database.CharsetCollation, "utf8mb4_bin")() require.NoError(t, db.ConvertDatabaseTable()) - var r *db.CheckCollationsResult - assert.Eventually(t, func() bool { - r, err = db.CheckCollations(x) - require.NoError(t, err) - - return r.DatabaseCollation == "utf8mb4_bin" - }, time.Second*30, time.Second) + r, err := db.CheckCollations(x) + require.NoError(t, err) + assert.Equal(t, "utf8mb4_bin", r.DatabaseCollation) assert.True(t, r.CollationEquals(r.ExpectedCollation, r.DatabaseCollation)) assert.Empty(t, r.InconsistentCollationColumns) @@ -122,13 +117,9 @@ func TestDatabaseCollation(t *testing.T) { defer test.MockVariableValue(&setting.Database.CharsetCollation, "utf8mb4_general_ci")() require.NoError(t, db.ConvertDatabaseTable()) - var r *db.CheckCollationsResult - assert.Eventually(t, func() bool { - r, err = db.CheckCollations(x) - require.NoError(t, err) - - return r.DatabaseCollation == "utf8mb4_general_ci" - }, time.Second*30, time.Second) + r, err := db.CheckCollations(x) + require.NoError(t, err) + assert.Equal(t, "utf8mb4_general_ci", r.DatabaseCollation) assert.True(t, r.CollationEquals(r.ExpectedCollation, r.DatabaseCollation)) assert.Empty(t, r.InconsistentCollationColumns) @@ -146,15 +137,9 @@ func TestDatabaseCollation(t *testing.T) { defer test.MockVariableValue(&setting.Database.CharsetCollation, "")() require.NoError(t, db.ConvertDatabaseTable()) - var r *db.CheckCollationsResult r, err := db.CheckCollations(x) require.NoError(t, err) - assert.Eventually(t, func() bool { - r, err = db.CheckCollations(x) - require.NoError(t, err) - - return r.IsCollationCaseSensitive(r.DatabaseCollation) - }, time.Second*30, time.Second) + assert.True(t, r.IsCollationCaseSensitive(r.DatabaseCollation)) assert.True(t, r.CollationEquals(r.ExpectedCollation, r.DatabaseCollation)) assert.Empty(t, r.InconsistentCollationColumns) }) diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index 26cddf7288..e79f6fe802 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -69,7 +69,7 @@ func testGit(t *testing.T, u *url.URL) { dstPath := t.TempDir() - t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, nil, objectFormat)) + t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false, objectFormat)) t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, httpContext.Username, perm.AccessModeRead)) t.Run("ForkFromDifferentUser", doAPIForkRepository(httpContext, forkedUserCtx.Username)) @@ -110,7 +110,7 @@ func testGit(t *testing.T, u *url.URL) { sshContext.Reponame = "repo-tmp-18-" + objectFormat.Name() keyname := "my-testing-key" forkedUserCtx.Reponame = sshContext.Reponame - t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, nil, objectFormat)) + t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false, objectFormat)) t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, sshContext.Username, perm.AccessModeRead)) t.Run("ForkFromDifferentUser", doAPIForkRepository(sshContext, forkedUserCtx.Username)) @@ -529,7 +529,8 @@ func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) fun t.Run("EnsureCanSeePull", doEnsureCanSeePull(headCtx, pr, false)) t.Run("CheckPR", func(t *testing.T) { oldMergeBase := pr.MergeBase - pr2 := doAPIGetPullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + pr2, err := doAPIGetPullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + require.NoError(t, err) assert.Equal(t, oldMergeBase, pr2.MergeBase) }) t.Run("EnsurDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength)) @@ -729,21 +730,24 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { // Check pr status ctx.ExpectedCode = 0 - pr = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + require.NoError(t, err) assert.False(t, pr.HasMerged) // Call API to add Failure status for commit t.Run("CreateStatus", addCommitStatus(api.CommitStatusFailure)) // Check pr status - pr = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + require.NoError(t, err) assert.False(t, pr.HasMerged) // Call API to add Success status for commit t.Run("CreateStatus", addCommitStatus(api.CommitStatusSuccess)) // test pr status - pr = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) + require.NoError(t, err) assert.True(t, pr.HasMerged) } } @@ -771,6 +775,11 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string return func(t *testing.T) { defer tests.PrintCurrentTest(t)() + // skip this test if git version is low + if git.CheckGitVersionAtLeast("2.29") != nil { + return + } + gitRepo, err := git.OpenRepository(git.DefaultContext, dstPath) require.NoError(t, err) @@ -827,7 +836,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string assert.Equal(t, 1, pr1.CommitsAhead) assert.Equal(t, 0, pr1.CommitsBehind) - prMsg := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t) + prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t) + require.NoError(t, err) assert.Equal(t, "user2/"+headBranch, pr1.HeadBranch) assert.False(t, prMsg.HasMerged) @@ -848,7 +858,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string } assert.Equal(t, 1, pr2.CommitsAhead) assert.Equal(t, 0, pr2.CommitsBehind) - prMsg = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t) + prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t) + require.NoError(t, err) assert.Equal(t, "user2/test/"+headBranch, pr2.HeadBranch) assert.False(t, prMsg.HasMerged) @@ -899,7 +910,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string require.NoError(t, err) unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2) - prMsg := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t) + prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t) + require.NoError(t, err) assert.False(t, prMsg.HasMerged) assert.Equal(t, commit, prMsg.Head.Sha) @@ -916,7 +928,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string require.NoError(t, err) unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2) - prMsg = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t) + prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t) + require.NoError(t, err) assert.False(t, prMsg.HasMerged) assert.Equal(t, commit, prMsg.Head.Sha) @@ -940,7 +953,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string err := pr3.LoadIssue(db.DefaultContext) require.NoError(t, err) - doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr3.Index)(t) + _, err2 := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr3.Index)(t) + require.NoError(t, err2) assert.Equal(t, "Testing commit 2", pr3.Issue.Title) assert.Contains(t, pr3.Issue.Content, "Longer description.") @@ -961,7 +975,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string err := pr.LoadIssue(db.DefaultContext) require.NoError(t, err) - doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr.Index)(t) + _, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr.Index)(t) + require.NoError(t, err) assert.Equal(t, "my-shiny-title", pr.Issue.Title) assert.Contains(t, pr.Issue.Content, "Longer description.") @@ -983,7 +998,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string err := pr.LoadIssue(db.DefaultContext) require.NoError(t, err) - doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr.Index)(t) + _, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr.Index)(t) + require.NoError(t, err) assert.Equal(t, "Testing commit 2", pr.Issue.Title) assert.Contains(t, pr.Issue.Content, "custom") diff --git a/tests/integration/issue_comment_test.go b/tests/integration/issue_comment_test.go index 0c53c3028b..f77bfaa9bd 100644 --- a/tests/integration/issue_comment_test.go +++ b/tests/integration/issue_comment_test.go @@ -102,35 +102,11 @@ func TestIssueCommentChangeMilestone(t *testing.T) { []string{"user1 removed this from the milestone2 milestone"}, []string{"/user1", "/user2/repo1/milestone/2"}) - // Added milestone that in the meantime was deleted + // Deleted milestone testIssueCommentChangeEvent(t, htmlDoc, "2003", "octicon-milestone", "User One", "/user1", []string{"user1 added this to the (deleted) milestone"}, []string{"/user1"}) - - // Modified milestone - from a meantime deleted one to a valid one - testIssueCommentChangeEvent(t, htmlDoc, "2004", - "octicon-milestone", "User One", "/user1", - []string{"user1 modified the milestone from (deleted) to milestone1"}, - []string{"/user1", "/user2/repo1/milestone/1"}) - - // Modified milestone - from a valid one to a meantime deleted one - testIssueCommentChangeEvent(t, htmlDoc, "2005", - "octicon-milestone", "User One", "/user1", - []string{"user1 modified the milestone from milestone1 to (deleted)"}, - []string{"/user1", "/user2/repo1/milestone/1"}) - - // Modified milestone - from a meantime deleted one to a meantime deleted one - testIssueCommentChangeEvent(t, htmlDoc, "2006", - "octicon-milestone", "User One", "/user1", - []string{"user1 modified the milestone from (deleted) to (deleted)"}, - []string{"/user1"}) - - // Removed milestone that in the meantime was deleted - testIssueCommentChangeEvent(t, htmlDoc, "2007", - "octicon-milestone", "User One", "/user1", - []string{"user1 removed this from the (deleted) milestone"}, - []string{"/user1"}) } func TestIssueCommentChangeProject(t *testing.T) { diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 34a6e53a37..120fe6534e 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -1350,6 +1350,8 @@ body: func TestIssueUnsubscription(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { + defer tests.PrepareTestEnv(t)() + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ AutoInit: optional.Some(false), diff --git a/tests/integration/mirror_push_test.go b/tests/integration/mirror_push_test.go index fea552e3de..1377d1eb1b 100644 --- a/tests/integration/mirror_push_test.go +++ b/tests/integration/mirror_push_test.go @@ -43,6 +43,7 @@ func TestMirrorPush(t *testing.T) { } func testMirrorPush(t *testing.T, u *url.URL) { + defer tests.PrepareTestEnv(t)() defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)() require.NoError(t, migrations.Init()) diff --git a/tests/integration/opengraph_test.go b/tests/integration/opengraph_test.go index aa6d8daf5c..56fbedd351 100644 --- a/tests/integration/opengraph_test.go +++ b/tests/integration/opengraph_test.go @@ -98,7 +98,7 @@ func TestOpenGraphProperties(t *testing.T) { "og:url": setting.AppURL + "/user27/repo49/src/branch/master/test/test.txt", "og:type": "object", "og:image": setting.AppURL + "user27/repo49/-/summary-card", - "og:image:alt": "Summary card of repository user27/repo49, described as: A wonderful repository with more than just a README.md", + "og:image:alt": "Summary card of repository user27/repo49", "og:image:width": "1200", "og:image:height": "600", "og:site_name": siteName, @@ -141,7 +141,7 @@ func TestOpenGraphProperties(t *testing.T) { "og:description": "A wonderful repository with more than just a README.md", "og:type": "object", "og:image": setting.AppURL + "user27/repo49/-/summary-card", - "og:image:alt": "Summary card of repository user27/repo49, described as: A wonderful repository with more than just a README.md", + "og:image:alt": "Summary card of repository user27/repo49", "og:image:width": "1200", "og:image:height": "600", "og:site_name": siteName, diff --git a/tests/integration/pull_commit_test.go b/tests/integration/pull_commit_test.go index f82fc08df4..8ca78f8147 100644 --- a/tests/integration/pull_commit_test.go +++ b/tests/integration/pull_commit_test.go @@ -4,26 +4,13 @@ package integration import ( - "context" - "encoding/base64" - "fmt" "net/http" - "net/url" - "os" "testing" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" - "forgejo.org/modules/setting" - api "forgejo.org/modules/structs" - "forgejo.org/modules/test" pull_service "forgejo.org/services/pull" "forgejo.org/tests" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestListPullCommits(t *testing.T) { @@ -61,83 +48,3 @@ func TestPullCommitLinks(t *testing.T) { commitLinkHref, _ := commitLink.Attr("href") assert.Equal(t, "/user2/repo1/pulls/3/commits/5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commitLinkHref) } - -func TestPullCommitSignature(t *testing.T) { - t.Cleanup(func() { - // Cannot use t.Context(), it is in the done state. - require.NoError(t, git.InitFull(context.Background())) //nolint:usetesting - }) - - defer test.MockVariableValue(&setting.Repository.Signing.SigningName, "UwU")() - defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "fox@example.com")() - defer test.MockVariableValue(&setting.Repository.Signing.CRUDActions, []string{"always"})() - defer test.MockVariableValue(&setting.Repository.Signing.InitialCommit, []string{"always"})() - - filePath := "signed.txt" - fromBranch := "master" - toBranch := "branch-signed" - - onGiteaRun(t, func(t *testing.T, u *url.URL) { - // Use a new GNUPGPHOME to avoid messing with the existing GPG keyring. - tmpDir := t.TempDir() - require.NoError(t, os.Chmod(tmpDir, 0o700)) - t.Setenv("GNUPGHOME", tmpDir) - - rootKeyPair, err := importTestingKey() - require.NoError(t, err) - defer test.MockVariableValue(&setting.Repository.Signing.SigningKey, rootKeyPair.PrimaryKey.KeyIdShortString())() - defer test.MockVariableValue(&setting.Repository.Signing.Format, "openpgp")() - - // Ensure the git config is updated with the new signing format. - require.NoError(t, git.InitFull(t.Context())) - - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - testCtx := NewAPITestContext(t, user.Name, "pull-request-commit-header-signed", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - u.Path = testCtx.GitPath() - - t.Run("Create repository", doAPICreateRepository(testCtx, nil, git.Sha1ObjectFormat)) - - t.Run("Create commit", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - options := &api.CreateFileOptions{ - FileOptions: api.FileOptions{ - BranchName: fromBranch, - NewBranchName: toBranch, - Message: fmt.Sprintf("from:%s to:%s path:%s", fromBranch, toBranch, filePath), - Author: api.Identity{ - Name: user.FullName, - Email: user.Email, - }, - Committer: api.Identity{ - Name: user.FullName, - Email: user.Email, - }, - }, - ContentBase64: base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "This is new text for %s", filePath)), - } - - req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", testCtx.Username, testCtx.Reponame, filePath), &options). - AddTokenAuth(testCtx.Token) - resp := testCtx.Session.MakeRequest(t, req, http.StatusCreated) - - var contents api.FileResponse - DecodeJSON(t, resp, &contents) - - assert.True(t, contents.Verification.Verified) - }) - - t.Run("Create pull request", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - pr, err := doAPICreatePullRequest(testCtx, testCtx.Username, testCtx.Reponame, fromBranch, toBranch)(t) - require.NoError(t, err) - - req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits/%s", testCtx.Username, testCtx.Reponame, pr.Index, pr.Head.Sha)) - resp := testCtx.Session.MakeRequest(t, req, http.StatusOK) - - htmlDoc := NewHTMLParser(t, resp.Body) - htmlDoc.AssertElement(t, "#diff-commit-header .commit-header-row.message.isSigned.isVerified", true) - }) - }) -} diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 8c9bdcdfc6..43c9bef209 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -287,6 +287,8 @@ func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoNam func TestPullBranchDelete(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user1") testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther) diff --git a/tests/integration/pull_update_test.go b/tests/integration/pull_update_test.go index 692699d24f..975b21a239 100644 --- a/tests/integration/pull_update_test.go +++ b/tests/integration/pull_update_test.go @@ -89,6 +89,7 @@ func TestAPIPullUpdateByRebase(t *testing.T) { func TestAPIViewUpdateSettings(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + defer tests.PrepareTestEnv(t)() // Create PR to test user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}) @@ -135,6 +136,7 @@ func TestViewPullUpdateByRebase(t *testing.T) { func testViewPullUpdate(t *testing.T, updateStyle string) { defer test.MockVariableValue(&setting.Repository.PullRequest.DefaultUpdateStyle, updateStyle)() + defer tests.PrepareTestEnv(t)() // Create PR to test user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}) diff --git a/tests/integration/repo_signed_tag_test.go b/tests/integration/repo_signed_tag_test.go index 16d8841304..686690bd19 100644 --- a/tests/integration/repo_signed_tag_test.go +++ b/tests/integration/repo_signed_tag_test.go @@ -25,6 +25,10 @@ import ( ) func TestRepoSSHSignedTags(t *testing.T) { + if git.CheckGitVersionAtLeast("2.34") != nil { + t.Skip("Skipping, does not support SSH signing") + return + } defer tests.PrepareTestEnv(t)() // Preparations diff --git a/tests/integration/repo_test.go b/tests/integration/repo_test.go index 598a508294..b66726a3e6 100644 --- a/tests/integration/repo_test.go +++ b/tests/integration/repo_test.go @@ -5,19 +5,15 @@ package integration import ( - "context" - "encoding/base64" "fmt" "net/http" "net/url" - "os" "path" "regexp" "strings" "testing" "time" - auth_model "forgejo.org/models/auth" "forgejo.org/models/db" repo_model "forgejo.org/models/repo" unit_model "forgejo.org/models/unit" @@ -26,7 +22,6 @@ import ( "forgejo.org/modules/git" "forgejo.org/modules/optional" "forgejo.org/modules/setting" - api "forgejo.org/modules/structs" "forgejo.org/modules/test" "forgejo.org/modules/translation" repo_service "forgejo.org/services/repository" @@ -198,9 +193,9 @@ func TestViewRepoWithSymlinks(t *testing.T) { // TestViewAsRepoAdmin tests PR #2167 func TestViewAsRepoAdmin(t *testing.T) { - defer tests.PrepareTestEnv(t)() - for _, user := range []string{"user2", "user4"} { + defer tests.PrepareTestEnv(t)() + session := loginUser(t, user) req := NewRequest(t, "GET", "/user2/repo1.git") @@ -687,79 +682,6 @@ func TestViewCommit(t *testing.T) { assert.True(t, test.IsNormalPageCompleted(resp.Body.String()), "non-existing commit should render 404 page") } -func TestViewCommitSignature(t *testing.T) { - t.Cleanup(func() { - // Cannot use t.Context(), it is in the done state. - require.NoError(t, git.InitFull(context.Background())) //nolint:usetesting - }) - - defer test.MockVariableValue(&setting.Repository.Signing.SigningName, "UwU")() - defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "fox@example.com")() - defer test.MockVariableValue(&setting.Repository.Signing.CRUDActions, []string{"always"})() - defer test.MockVariableValue(&setting.Repository.Signing.InitialCommit, []string{"always"})() - - filePath := "signed.txt" - fromBranch := "master" - toBranch := "branch-signed" - - onGiteaRun(t, func(t *testing.T, u *url.URL) { - // Use a new GNUPGPHOME to avoid messing with the existing GPG keyring. - tmpDir := t.TempDir() - require.NoError(t, os.Chmod(tmpDir, 0o700)) - t.Setenv("GNUPGHOME", tmpDir) - - rootKeyPair, err := importTestingKey() - require.NoError(t, err) - defer test.MockVariableValue(&setting.Repository.Signing.SigningKey, rootKeyPair.PrimaryKey.KeyIdShortString())() - defer test.MockVariableValue(&setting.Repository.Signing.Format, "openpgp")() - - // Ensure the git config is updated with the new signing format. - require.NoError(t, git.InitFull(t.Context())) - - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - testCtx := NewAPITestContext(t, user.Name, "commit-header-signed", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - u.Path = testCtx.GitPath() - - t.Run("Create repository", doAPICreateRepository(testCtx, nil, git.Sha1ObjectFormat)) - - t.Run("Create commit", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - options := &api.CreateFileOptions{ - FileOptions: api.FileOptions{ - BranchName: fromBranch, - NewBranchName: toBranch, - Message: fmt.Sprintf("from:%s to:%s path:%s", fromBranch, toBranch, filePath), - Author: api.Identity{ - Name: user.FullName, - Email: user.Email, - }, - Committer: api.Identity{ - Name: user.FullName, - Email: user.Email, - }, - }, - ContentBase64: base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "This is new text for %s", filePath)), - } - - req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", testCtx.Username, testCtx.Reponame, filePath), &options). - AddTokenAuth(testCtx.Token) - resp := testCtx.Session.MakeRequest(t, req, http.StatusCreated) - - var contents api.FileResponse - DecodeJSON(t, resp, &contents) - - assert.True(t, contents.Verification.Verified) - - req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/commit/%s", testCtx.Username, testCtx.Reponame, contents.Commit.SHA)) - resp = testCtx.Session.MakeRequest(t, req, http.StatusOK) - - htmlDoc := NewHTMLParser(t, resp.Body) - htmlDoc.AssertElement(t, ".commit-header-row.message.isSigned.isVerified", true) - }) - }) -} - func TestCommitView(t *testing.T) { defer tests.PrepareTestEnv(t)() diff --git a/tests/integration/signing_git_test.go b/tests/integration/signing_git_test.go index 8b6b30ecab..9d69306e0a 100644 --- a/tests/integration/signing_git_test.go +++ b/tests/integration/signing_git_test.go @@ -42,6 +42,10 @@ func TestInstanceSigning(t *testing.T) { defer test.MockProtect(&setting.Repository.Signing.CRUDActions)() t.Run("SSH", func(t *testing.T) { + if git.CheckGitVersionAtLeast("2.34") != nil { + t.Skip("Skipping, does not support git SSH signing") + return + } defer tests.PrintCurrentTest(t)() pubKeyContent, err := os.ReadFile("tests/integration/ssh-signing-key.pub") @@ -105,14 +109,13 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O defer tests.PrintCurrentTest(t)() testCtx := NewAPITestContext(t, username, "initial-unsigned"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CheckMasterBranchUnsigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) + t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { assert.NotNil(t, branch.Commit) assert.NotNil(t, branch.Commit.Verification) assert.False(t, branch.Commit.Verification.Verified) assert.Empty(t, branch.Commit.Verification.Signature) - }) + })) t.Run("CreateCRUDFile-Never", crudActionCreateFile( t, testCtx, user, "master", "never", "unsigned-never.txt", func(t *testing.T, response api.FileResponse) { assert.False(t, response.Verification.Verified) @@ -188,27 +191,25 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O defer tests.PrintCurrentTest(t)() testCtx := NewAPITestContext(t, username, "initial-pubkey"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CheckMasterBranchSigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) + t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.True(t, branch.Commit.Verification.Verified) assert.Equal(t, "fox@example.com", branch.Commit.Verification.Signer.Email) - }) + })) }) t.Run("No publickey", func(t *testing.T) { defer tests.PrintCurrentTest(t)() testCtx := NewAPITestContext(t, "user4", "initial-no-pubkey"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CheckMasterBranchSigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) + t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.False(t, branch.Commit.Verification.Verified) - }) + })) }) }) @@ -225,27 +226,25 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O testCtx := NewAPITestContext(t, username, "initial-2fa"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) unittest.AssertSuccessfulInsert(t, &auth_model.WebAuthnCredential{UserID: user.ID}) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CheckMasterBranchSigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) + t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.True(t, branch.Commit.Verification.Verified) assert.Equal(t, "fox@example.com", branch.Commit.Verification.Signer.Email) - }) + })) }) - t.Run("No 2fa", func(t *testing.T) { + t.Run("No publickey", func(t *testing.T) { defer tests.PrintCurrentTest(t)() testCtx := NewAPITestContext(t, "user4", "initial-no-2fa"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CheckMasterBranchSigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) + t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.False(t, branch.Commit.Verification.Verified) - }) + })) }) }) @@ -254,14 +253,13 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O setting.Repository.Signing.InitialCommit = []string{"always"} testCtx := NewAPITestContext(t, username, "initial-always"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CheckMasterBranchSigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) + t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.True(t, branch.Commit.Verification.Verified) assert.Equal(t, "fox@example.com", branch.Commit.Verification.Signer.Email) - }) + })) }) t.Run("AlwaysSign-Initial-CRUD-Never", func(t *testing.T) { @@ -269,7 +267,7 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O setting.Repository.Signing.CRUDActions = []string{"never"} testCtx := NewAPITestContext(t, username, "initial-always-never"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) t.Run("CreateCRUDFile-Never", crudActionCreateFile( t, testCtx, user, "master", "never", "unsigned-never.txt", func(t *testing.T, response api.FileResponse) { assert.False(t, response.Verification.Verified) @@ -281,7 +279,7 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O setting.Repository.Signing.CRUDActions = []string{"parentsigned"} testCtx := NewAPITestContext(t, username, "initial-always-parent"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile( t, testCtx, user, "master", "parentsigned", "signed-parent.txt", func(t *testing.T, response api.FileResponse) { assert.True(t, response.Verification.Verified) @@ -289,71 +287,12 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O })) }) - t.Run("AlwaysSign-Initial-CRUD-Pubkey", func(t *testing.T) { - setting.Repository.Signing.CRUDActions = []string{"pubkey"} - - t.Run("Has publickey", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - testCtx := NewAPITestContext(t, username, "initial-always-pubkey"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CreateCRUDFile-Pubkey", crudActionCreateFile( - t, testCtx, user, "master", "pubkey", "signed-pubkey.txt", func(t *testing.T, response api.FileResponse) { - assert.True(t, response.Verification.Verified) - assert.Equal(t, "fox@example.com", response.Verification.Signer.Email) - })) - }) - - t.Run("No publickey", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - testCtx := NewAPITestContext(t, "user4", "initial-always-no-pubkey"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CreateCRUDFile-Pubkey", crudActionCreateFile( - t, testCtx, user, "master", "pubkey", "unsigned-pubkey.txt", func(t *testing.T, response api.FileResponse) { - assert.False(t, response.Verification.Verified) - })) - }) - }) - - t.Run("AlwaysSign-Initial-CRUD-Twofa", func(t *testing.T) { - setting.Repository.Signing.CRUDActions = []string{"twofa"} - - t.Run("Has 2fa", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - t.Cleanup(func() { - unittest.AssertSuccessfulDelete(t, &auth_model.WebAuthnCredential{UserID: user.ID}) - }) - - testCtx := NewAPITestContext(t, username, "initial-always-twofa"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - unittest.AssertSuccessfulInsert(t, &auth_model.WebAuthnCredential{UserID: user.ID}) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CreateCRUDFile-Twofa", crudActionCreateFile( - t, testCtx, user, "master", "twofa", "signed-twofa.txt", func(t *testing.T, response api.FileResponse) { - assert.True(t, response.Verification.Verified) - assert.Equal(t, "fox@example.com", response.Verification.Signer.Email) - })) - }) - - t.Run("No 2fa", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - testCtx := NewAPITestContext(t, "user4", "initial-always-no-twofa"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) - t.Run("CreateCRUDFile-Pubkey", crudActionCreateFile( - t, testCtx, user, "master", "twofa", "unsigned-twofa.txt", func(t *testing.T, response api.FileResponse) { - assert.False(t, response.Verification.Verified) - })) - }) - }) - t.Run("AlwaysSign-Initial-CRUD-Always", func(t *testing.T) { defer tests.PrintCurrentTest(t)() setting.Repository.Signing.CRUDActions = []string{"always"} testCtx := NewAPITestContext(t, username, "initial-always-always"+suffix, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - t.Run("CreateRepository", doAPICreateRepository(testCtx, nil, objectFormat)) + t.Run("CreateRepository", doAPICreateRepository(testCtx, false, objectFormat)) t.Run("CreateCRUDFile-Always", crudActionCreateFile( t, testCtx, user, "master", "always", "signed-always.txt", func(t *testing.T, response api.FileResponse) { assert.True(t, response.Verification.Verified) @@ -371,13 +310,12 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O require.NoError(t, err) t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index)) }) - t.Run("CheckMasterBranchUnsigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.False(t, branch.Commit.Verification.Verified) assert.Empty(t, branch.Commit.Verification.Signature) - }) + })) }) t.Run("BaseSignedMerging", func(t *testing.T) { @@ -390,13 +328,12 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O require.NoError(t, err) t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index)) }) - t.Run("CheckMasterBranchUnsigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.False(t, branch.Commit.Verification.Verified) assert.Empty(t, branch.Commit.Verification.Signature) - }) + })) }) t.Run("CommitsSignedMerging", func(t *testing.T) { @@ -409,12 +346,11 @@ func testCRUD(t *testing.T, u *url.URL, signingFormat string, objectFormat git.O require.NoError(t, err) t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index)) }) - t.Run("CheckMasterBranchUnsigned", func(t *testing.T) { - branch := doAPIGetBranch(testCtx, "master")(t) + t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { require.NotNil(t, branch.Commit) require.NotNil(t, branch.Commit.Verification) assert.True(t, branch.Commit.Verification.Verified) - }) + })) }) } diff --git a/tests/integration/ssh_key_test.go b/tests/integration/ssh_key_test.go index a92694d2fa..aece9c3fd9 100644 --- a/tests/integration/ssh_key_test.go +++ b/tests/integration/ssh_key_test.go @@ -55,13 +55,7 @@ func testPushDeployKeyOnEmptyRepo(t *testing.T, u *url.URL) { keyname := fmt.Sprintf("%s-push", ctx.Reponame) u.Path = ctx.GitPath() - opts := &api.CreateRepoOption{ - Description: "Temporary repo", - Name: ctx.Reponame, - Private: true, - Template: true, - } - t.Run("CreateEmptyRepository", doAPICreateRepository(ctx, opts, objectFormat)) + t.Run("CreateEmptyRepository", doAPICreateRepository(ctx, true, objectFormat)) t.Run("CheckIsEmpty", doCheckRepositoryEmptyStatus(ctx, true)) @@ -111,8 +105,8 @@ func testKeyOnlyOneType(t *testing.T, u *url.URL) { failCtx := ctx failCtx.ExpectedCode = http.StatusUnprocessableEntity - t.Run("CreateRepository", doAPICreateRepository(ctx, nil, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat - t.Run("CreateOtherRepository", doAPICreateRepository(otherCtx, nil, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat + t.Run("CreateRepository", doAPICreateRepository(ctx, false, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat + t.Run("CreateOtherRepository", doAPICreateRepository(otherCtx, false, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat withKeyFile(t, keyname, func(keyFile string) { var userKeyPublicKeyID int64 @@ -186,7 +180,7 @@ func testKeyOnlyOneType(t *testing.T, u *url.URL) { t.Run("DeleteOtherRepository", doAPIDeleteRepository(otherCtxWithDeleteRepo)) - t.Run("RecreateRepository", doAPICreateRepository(ctxWithDeleteRepo, nil, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat + t.Run("RecreateRepository", doAPICreateRepository(ctxWithDeleteRepo, false, git.Sha1ObjectFormat)) // FIXME: use forEachObjectFormat t.Run("CreateUserKey", doAPICreateUserKey(ctx, keyname, keyFile, func(t *testing.T, publicKey api.PublicKey) { userKeyPublicKeyID = publicKey.ID diff --git a/tests/test_utils.go b/tests/test_utils.go index ee786624a2..75d1f98914 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -13,7 +13,6 @@ import ( "path/filepath" "runtime" "strings" - "sync/atomic" "testing" "time" @@ -43,7 +42,6 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "xorm.io/xorm/convert" ) func exitf(format string, args ...any) { @@ -313,26 +311,9 @@ func PrepareCleanPackageData(t testing.TB) { require.NoError(t, storage.Clean(storage.Packages)) } -// inTestEnv keeps track if we are current inside a test environment, this is -// used to detect if testing code tries to prepare a test environment more than -// once. -var inTestEnv atomic.Bool - func PrepareTestEnv(t testing.TB, skip ...int) func() { t.Helper() - - if !inTestEnv.CompareAndSwap(false, true) { - t.Fatal("Cannot prepare a test environment if you are already in a test environment. This is a bug in your testing code.") - } - - deferPrintCurrentTest := PrintCurrentTest(t, util.OptionalArg(skip)+1) - deferFn := func() { - deferPrintCurrentTest() - - if !inTestEnv.CompareAndSwap(true, false) { - t.Fatal("Tried to leave test environment, but we are no longer in a test environment. This should not happen.") - } - } + deferFn := PrintCurrentTest(t, util.OptionalArg(skip)+1) cancelProcesses(t, 30*time.Second) t.Cleanup(func() { cancelProcesses(t, 0) }) // cancel remaining processes in a non-blocking way @@ -361,7 +342,6 @@ type DeclarativeRepoOptions struct { Name optional.Option[string] EnabledUnits optional.Option[[]unit_model.Type] DisabledUnits optional.Option[[]unit_model.Type] - UnitConfig optional.Option[map[unit_model.Type]convert.Conversion] Files optional.Option[[]*files_service.ChangeRepoFile] WikiBranch optional.Option[string] AutoInit optional.Option[bool] @@ -410,14 +390,9 @@ func CreateDeclarativeRepoWithOptions(t *testing.T, owner *user_model.User, opts enabledUnits = make([]repo_model.RepoUnit, len(units)) for i, unitType := range units { - var config convert.Conversion - if cfg, ok := opts.UnitConfig.Value()[unitType]; ok { - config = cfg - } enabledUnits[i] = repo_model.RepoUnit{ RepoID: repo.ID, Type: unitType, - Config: config, } } } diff --git a/web_src/fomantic/package-lock.json b/web_src/fomantic/package-lock.json index d91eb98866..cea707672e 100644 --- a/web_src/fomantic/package-lock.json +++ b/web_src/fomantic/package-lock.json @@ -494,9 +494,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.0.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.7.tgz", - "integrity": "sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw==", + "version": "24.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz", + "integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==", "license": "MIT", "dependencies": { "undici-types": "~7.8.0" @@ -1117,9 +1117,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", "funding": [ { "type": "opencollective", @@ -1136,8 +1136,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", + "caniuse-lite": "^1.0.30001718", + "electron-to-chromium": "^1.5.160", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -1249,9 +1249,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001726", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", - "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "version": "1.0.30001724", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz", + "integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==", "funding": [ { "type": "opencollective", @@ -2005,9 +2005,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.177", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.177.tgz", - "integrity": "sha512-7EH2G59nLsEMj97fpDuvVcYi6lwTcM1xuWw3PssD8xzboAW7zj7iB3COEEEATUfjLHrs5uKBLQT03V/8URx06g==", + "version": "1.5.171", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.171.tgz", + "integrity": "sha512-scWpzXEJEMrGJa4Y6m/tVotb0WuvNmasv3wWVzUAeCgKU0ToFOhUW6Z+xWnRQANMYGxN4ngJXIThgBJOqzVPCQ==", "license": "ISC" }, "node_modules/emoji-regex": { diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index 35f1082a93..58c5461baa 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -340,10 +340,10 @@ export default sfc; // activate the IDE's Vue plugin {{ textMyOrgs }} {{ organizationsTotalCount }}
-

-
+

+
{{ textMyRepos }} - {{ reposTotalCount }} + {{ reposTotalCount }}