diff --git a/.deadcode-out b/.deadcode-out index 61c5bcb055..e052892474 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -1,7 +1,7 @@ -forgejo.org/cmd +code.gitea.io/gitea/cmd NoMainListener -forgejo.org/cmd/forgejo +code.gitea.io/gitea/cmd/forgejo ContextSetNoInit ContextSetNoExit ContextSetStderr @@ -9,179 +9,240 @@ forgejo.org/cmd/forgejo ContextSetStdout ContextSetStdin -forgejo.org/models +code.gitea.io/gitea/models + IsErrUpdateTaskNotExist + ErrUpdateTaskNotExist.Error + ErrUpdateTaskNotExist.Unwrap IsErrSHANotFound IsErrMergeDivergingFastForwardOnly + GetYamlFixturesAccess -forgejo.org/models/activities - GetActivityByID - NewFederatedUserActivity - CreateUserActivity - GetFollowingFeeds - FederatedUserActivity.loadActor +code.gitea.io/gitea/models/actions + ScheduleList.GetUserIDs + ScheduleList.GetRepoIDs + ScheduleList.LoadTriggerUser + ScheduleList.LoadRepos -forgejo.org/models/auth +code.gitea.io/gitea/models/asymkey + ErrGPGKeyAccessDenied.Error + ErrGPGKeyAccessDenied.Unwrap + HasDeployKey + +code.gitea.io/gitea/models/auth + GetSourceByName + GetWebAuthnCredentialByID WebAuthnCredentials -forgejo.org/models/db +code.gitea.io/gitea/models/db TruncateBeans InTransaction DumpTables -forgejo.org/models/dbfs +code.gitea.io/gitea/models/dbfs file.renameTo Create Rename -forgejo.org/models/forgefed +code.gitea.io/gitea/models/forgefed GetFederationHost -forgejo.org/models/forgejo/semver +code.gitea.io/gitea/models/forgejo/semver GetVersion SetVersionString SetVersion -forgejo.org/models/git +code.gitea.io/gitea/models/git RemoveDeletedBranchByID -forgejo.org/models/issues +code.gitea.io/gitea/models/issues IsErrUnknownDependencyType + ErrNewIssueInsert.Error IsErrIssueWasClosed + ChangeMilestoneStatus -forgejo.org/models/organization +code.gitea.io/gitea/models/migrations/base + removeAllWithRetry + newXORMEngine + deleteDB + PrepareTestEnv + MainTest + +code.gitea.io/gitea/models/organization + GetTeamNamesByID + UpdateTeamUnits SearchMembersOptions.ToConds + UsersInTeamsCount -forgejo.org/models/perm/access +code.gitea.io/gitea/models/perm/access GetRepoWriters -forgejo.org/models/repo +code.gitea.io/gitea/models/project + UpdateColumnSorting + ChangeProjectStatus + +code.gitea.io/gitea/models/repo + DeleteAttachmentsByIssue + releaseSorter.Len + releaseSorter.Less + releaseSorter.Swap + SortReleases + FindReposMapByIDs + IsErrTopicNotExist + ErrTopicNotExist.Error + ErrTopicNotExist.Unwrap + GetTopicByName WatchRepoMode -forgejo.org/models/user +code.gitea.io/gitea/models/unittest + CheckConsistencyFor + checkForConsistency + GetXORMEngine + OverrideFixtures + InitFixtures + LoadFixtures + Copy + CopyDir + NewMockWebServer + NormalizedFullPath + FixturesDir + fatalTestError + InitSettings + MainTest + CreateTestEngine + PrepareTestDatabase + PrepareTestEnv + Cond + OrderBy + LoadBeanIfExists + BeanExists + AssertExistsAndLoadBean + GetCount + AssertNotExistsBean + AssertExistsIf + AssertSuccessfulInsert + AssertCount + AssertInt64InRange + +code.gitea.io/gitea/models/user + IsErrPrimaryEmailCannotDelete + ErrUserInactive.Error + ErrUserInactive.Unwrap IsErrExternalLoginUserAlreadyExist IsErrExternalLoginUserNotExist NewFederatedUser - NewFederatedUserFollower IsErrUserSettingIsNotExist GetUserAllSettings DeleteUserSetting - GetFederatedUser - GetFederatedUserByUserID - UpdateFederatedUser - GetFollowersForUser - AddFollower - RemoveFollower - IsFollowingAp + GetUserEmailsByNames + GetUserNamesByIDs -forgejo.org/modules/activitypub - NewContext - Context.APClientFactory - -forgejo.org/modules/assetfs +code.gitea.io/gitea/modules/assetfs Bindata -forgejo.org/modules/auth/password/hash +code.gitea.io/gitea/modules/auth/password/hash DummyHasher.HashWithSaltBytes NewDummyHasher -forgejo.org/modules/auth/password/pwn +code.gitea.io/gitea/modules/auth/password/pwn WithHTTP -forgejo.org/modules/base +code.gitea.io/gitea/modules/base SetupGiteaRoot -forgejo.org/modules/cache +code.gitea.io/gitea/modules/cache GetInt WithNoCacheContext RemoveContextData -forgejo.org/modules/emoji +code.gitea.io/gitea/modules/charset + BreakWriter.Write + +code.gitea.io/gitea/modules/emoji ReplaceCodes -forgejo.org/modules/eventsource +code.gitea.io/gitea/modules/eventsource Event.String -forgejo.org/modules/forgefed - NewForgeFollowFromAp - NewForgeFollow - ForgeFollow.MarshalJSON - ForgeFollow.UnmarshalJSON - ForgeFollow.Validate - NewForgeUndoLike - ForgeUndoLike.UnmarshalJSON - ForgeUndoLike.Validate - NewForgeUserActivityFromAp - NewForgeUserActivity - ForgeUserActivity.Validate - NewPersonIDFromModel +code.gitea.io/gitea/modules/forgefed GetItemByType JSONUnmarshalerFn NotEmpty - NewForgeUserActivityNoteFromAp - newNote - ForgeUserActivityNote.Validate ToRepository OnRepository -forgejo.org/modules/git +code.gitea.io/gitea/modules/git AllowLFSFiltersArgs AddChanges AddChangesWithArgs CommitChanges CommitChangesWithArgs + IsErrExecTimeout + ErrExecTimeout.Error + ErrUnsupportedVersion.Error SetUpdateHook openRepositoryWithDefaultContext + IsTagExist ToEntryMode + LimitedReaderCloser.Read + LimitedReaderCloser.Close -forgejo.org/modules/gitrepo +code.gitea.io/gitea/modules/gitgraph + Parser.Reset + +code.gitea.io/gitea/modules/gitrepo GetBranchCommitID GetWikiDefaultBranch -forgejo.org/modules/graceful +code.gitea.io/gitea/modules/graceful Manager.TerminateContext Manager.Err Manager.Value Manager.Deadline -forgejo.org/modules/hcaptcha +code.gitea.io/gitea/modules/hcaptcha WithHTTP -forgejo.org/modules/hostmatcher - HostMatchList.AppendPattern - -forgejo.org/modules/json +code.gitea.io/gitea/modules/json StdJSON.Marshal StdJSON.Unmarshal StdJSON.NewEncoder StdJSON.NewDecoder StdJSON.Indent -forgejo.org/modules/log - NewEventWriterBuffer - -forgejo.org/modules/markup +code.gitea.io/gitea/modules/markup GetRendererByType RenderString IsMarkupFile -forgejo.org/modules/markup/console +code.gitea.io/gitea/modules/markup/console Render RenderString -forgejo.org/modules/markup/markdown +code.gitea.io/gitea/modules/markup/markdown + IsDetails + IsSummary + IsTaskCheckBoxListItem + IsIcon RenderRawString -forgejo.org/modules/markup/mdstripper +code.gitea.io/gitea/modules/markup/markdown/math + WithInlineDollarParser + WithBlockDollarParser + +code.gitea.io/gitea/modules/markup/mdstripper stripRenderer.AddOptions StripMarkdown -forgejo.org/modules/markup/orgmode +code.gitea.io/gitea/modules/markup/orgmode RenderString -forgejo.org/modules/process +code.gitea.io/gitea/modules/private + ActionsRunnerRegister + +code.gitea.io/gitea/modules/process Manager.ExecTimeout -forgejo.org/modules/queue +code.gitea.io/gitea/modules/queue newBaseChannelSimple newBaseChannelUnique newBaseRedisSimple @@ -190,73 +251,100 @@ forgejo.org/modules/queue testStateRecorder.Reset newWorkerPoolQueueForTest -forgejo.org/modules/queue/lqinternal +code.gitea.io/gitea/modules/queue/lqinternal QueueItemIDBytes QueueItemKeyBytes ListLevelQueueKeys -forgejo.org/modules/setting +code.gitea.io/gitea/modules/setting NewConfigProviderFromData GitConfigType.GetOption InitLoggersForTest -forgejo.org/modules/sync +code.gitea.io/gitea/modules/storage + ErrInvalidConfiguration.Error + IsErrInvalidConfiguration + +code.gitea.io/gitea/modules/structs + ParseCreateHook + ParsePushHook + +code.gitea.io/gitea/modules/sync StatusTable.Start StatusTable.IsRunning -forgejo.org/modules/timeutil +code.gitea.io/gitea/modules/testlogger + testLoggerWriterCloser.pushT + testLoggerWriterCloser.Log + testLoggerWriterCloser.recordError + testLoggerWriterCloser.printMsg + testLoggerWriterCloser.popT + testLoggerWriterCloser.Reset + PrintCurrentTest + Printf + NewTestLoggerWriter + TestLogEventWriter.Base + TestLogEventWriter.GetLevel + TestLogEventWriter.GetWriterName + TestLogEventWriter.GetWriterType + TestLogEventWriter.Run + +code.gitea.io/gitea/modules/timeutil GetExecutableModTime MockSet MockUnset -forgejo.org/modules/translation +code.gitea.io/gitea/modules/translation MockLocale.Language MockLocale.TrString MockLocale.Tr MockLocale.TrN - MockLocale.TrPluralString - MockLocale.TrPluralStringAllForms MockLocale.TrSize - MockLocale.HasKey MockLocale.PrettyNumber -forgejo.org/modules/translation/localeiter - IterateMessagesContent - -forgejo.org/modules/util - OptionalArg - -forgejo.org/modules/util/filebuffer +code.gitea.io/gitea/modules/util/filebuffer CreateFromReader -forgejo.org/modules/validation +code.gitea.io/gitea/modules/validation IsErrNotValid - ValidateIDExists -forgejo.org/modules/web +code.gitea.io/gitea/modules/web RouteMock RouteMockReset -forgejo.org/modules/zstd - NewWriter - Writer.Write - Writer.Close +code.gitea.io/gitea/modules/web/middleware + DeleteLocaleCookie -forgejo.org/routers/web/org +code.gitea.io/gitea/routers/web + NotFound + +code.gitea.io/gitea/routers/web/org MustEnableProjects -forgejo.org/services/context +code.gitea.io/gitea/services/context GetPrivateContext -forgejo.org/services/repository +code.gitea.io/gitea/services/convert + ToSecret + +code.gitea.io/gitea/services/forms + DeadlineForm.Validate + +code.gitea.io/gitea/services/pull + IsCommitStatusContextSuccess + +code.gitea.io/gitea/services/repository IsErrForkAlreadyExist -forgejo.org/services/repository/files +code.gitea.io/gitea/services/repository/archiver + ArchiveRepository + +code.gitea.io/gitea/services/repository/files ContentType.String + GetFileResponseFromCommit + TemporaryUploadRepository.GetLastCommit + TemporaryUploadRepository.GetLastCommitByRef -forgejo.org/services/repository/gitgraph - Parser.Reset - -forgejo.org/services/webhook +code.gitea.io/gitea/services/webhook NewNotifier diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 28fa9e4555..73b3dcbd6b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,12 +1,16 @@ { "name": "Gitea DevContainer", - "image": "mcr.microsoft.com/devcontainers/go:1.24-bullseye", + "image": "mcr.microsoft.com/devcontainers/go:1.22-bullseye", "features": { // installs nodejs into container "ghcr.io/devcontainers/features/node:1": { - "version": "22" + "version": "20" + }, + "ghcr.io/devcontainers/features/git-lfs:1.2.1": {}, + "ghcr.io/devcontainers-contrib/features/poetry:2": {}, + "ghcr.io/devcontainers/features/python:1": { + "version": "3.12" }, - "ghcr.io/devcontainers/features/git-lfs:1.2.4": {}, "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {} }, "customizations": { diff --git a/.dockerignore b/.dockerignore index 807c70b000..a1611a1ca5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -34,12 +34,15 @@ _testmain.go *coverage.out coverage.all -coverage/ cpu.out +/modules/migration/bindata.go /modules/migration/bindata.go.hash +/modules/options/bindata.go /modules/options/bindata.go.hash +/modules/public/bindata.go /modules/public/bindata.go.hash +/modules/templates/bindata.go /modules/templates/bindata.go.hash *.db diff --git a/.editorconfig b/.editorconfig index 5476eb02fb..8e2234e64b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,9 +12,6 @@ insert_final_newline = true [{*.{go,tmpl,html},Makefile,go.mod}] indent_style = tab -[go.*] -indent_style = tab - [templates/custom/*.tmpl] insert_final_newline = false @@ -29,8 +26,3 @@ insert_final_newline = false [options/locale/locale_*.ini] insert_final_newline = false - -# Weblate JSON output defaults to four spaces -[options/locale_next/locale_*.json] -indent_style = space -indent_size = 4 diff --git a/.envrc.example b/.envrc.example deleted file mode 100644 index 3550a30f2d..0000000000 --- a/.envrc.example +++ /dev/null @@ -1 +0,0 @@ -use flake diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000000..e553499691 --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,846 @@ +root: true +reportUnusedDisableDirectives: true + +ignorePatterns: + - /web_src/js/vendor + - /web_src/fomantic + - /public/assets/js + +parserOptions: + sourceType: module + ecmaVersion: latest + +plugins: + - "@eslint-community/eslint-plugin-eslint-comments" + - "@stylistic/eslint-plugin-js" + - eslint-plugin-array-func + - eslint-plugin-github + - eslint-plugin-i + - eslint-plugin-jquery + - eslint-plugin-no-jquery + - eslint-plugin-no-use-extend-native + - eslint-plugin-regexp + - eslint-plugin-sonarjs + - eslint-plugin-unicorn + - eslint-plugin-vitest + - eslint-plugin-vitest-globals + - eslint-plugin-wc + +env: + es2024: true + node: true + +overrides: + - files: ["web_src/**/*"] + globals: + __webpack_public_path__: true + process: false # https://github.com/webpack/webpack/issues/15833 + - files: ["web_src/**/*", "docs/**/*"] + env: + browser: true + node: false + - files: ["web_src/**/*worker.*"] + env: + worker: true + rules: + no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top] + - files: ["*.config.*"] + rules: + i/no-unused-modules: [0] + - files: ["**/*.test.*", "web_src/js/test/setup.js"] + env: + vitest-globals/env: true + rules: + vitest/consistent-test-filename: [0] + vitest/consistent-test-it: [0] + vitest/expect-expect: [0] + vitest/max-expects: [0] + vitest/max-nested-describe: [0] + vitest/no-alias-methods: [0] + vitest/no-commented-out-tests: [0] + vitest/no-conditional-expect: [0] + vitest/no-conditional-in-test: [0] + vitest/no-conditional-tests: [0] + vitest/no-disabled-tests: [0] + vitest/no-done-callback: [0] + vitest/no-duplicate-hooks: [0] + vitest/no-focused-tests: [0] + vitest/no-hooks: [0] + vitest/no-identical-title: [2] + vitest/no-interpolation-in-snapshots: [0] + vitest/no-large-snapshots: [0] + vitest/no-mocks-import: [0] + vitest/no-restricted-matchers: [0] + vitest/no-restricted-vi-methods: [0] + vitest/no-standalone-expect: [0] + vitest/no-test-prefixes: [0] + vitest/no-test-return-statement: [0] + vitest/prefer-called-with: [0] + vitest/prefer-comparison-matcher: [0] + vitest/prefer-each: [0] + vitest/prefer-equality-matcher: [0] + vitest/prefer-expect-resolves: [0] + vitest/prefer-hooks-in-order: [0] + vitest/prefer-hooks-on-top: [2] + vitest/prefer-lowercase-title: [0] + vitest/prefer-mock-promise-shorthand: [0] + vitest/prefer-snapshot-hint: [0] + vitest/prefer-spy-on: [0] + vitest/prefer-strict-equal: [0] + vitest/prefer-to-be: [0] + vitest/prefer-to-be-falsy: [0] + vitest/prefer-to-be-object: [0] + vitest/prefer-to-be-truthy: [0] + vitest/prefer-to-contain: [0] + vitest/prefer-to-have-length: [0] + vitest/prefer-todo: [0] + vitest/require-hook: [0] + vitest/require-to-throw-message: [0] + vitest/require-top-level-describe: [0] + vitest/valid-describe-callback: [2] + vitest/valid-expect: [2] + vitest/valid-title: [2] + - files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"] + rules: + no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression] + +rules: + "@eslint-community/eslint-comments/disable-enable-pair": [2] + "@eslint-community/eslint-comments/no-aggregating-enable": [2] + "@eslint-community/eslint-comments/no-duplicate-disable": [2] + "@eslint-community/eslint-comments/no-restricted-disable": [0] + "@eslint-community/eslint-comments/no-unlimited-disable": [2] + "@eslint-community/eslint-comments/no-unused-disable": [2] + "@eslint-community/eslint-comments/no-unused-enable": [2] + "@eslint-community/eslint-comments/no-use": [0] + "@eslint-community/eslint-comments/require-description": [0] + "@stylistic/js/array-bracket-newline": [0] + "@stylistic/js/array-bracket-spacing": [2, never] + "@stylistic/js/array-element-newline": [0] + "@stylistic/js/arrow-parens": [2, always] + "@stylistic/js/arrow-spacing": [2, {before: true, after: true}] + "@stylistic/js/block-spacing": [0] + "@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}] + "@stylistic/js/comma-dangle": [2, always-multiline] + "@stylistic/js/comma-spacing": [2, {before: false, after: true}] + "@stylistic/js/comma-style": [2, last] + "@stylistic/js/computed-property-spacing": [2, never] + "@stylistic/js/dot-location": [2, property] + "@stylistic/js/eol-last": [2] + "@stylistic/js/function-call-spacing": [2, never] + "@stylistic/js/function-call-argument-newline": [0] + "@stylistic/js/function-paren-newline": [0] + "@stylistic/js/generator-star-spacing": [0] + "@stylistic/js/implicit-arrow-linebreak": [0] + "@stylistic/js/indent": [2, 2, {ignoreComments: true, SwitchCase: 1}] + "@stylistic/js/key-spacing": [2] + "@stylistic/js/keyword-spacing": [2] + "@stylistic/js/linebreak-style": [2, unix] + "@stylistic/js/lines-around-comment": [0] + "@stylistic/js/lines-between-class-members": [0] + "@stylistic/js/max-len": [0] + "@stylistic/js/max-statements-per-line": [0] + "@stylistic/js/multiline-ternary": [0] + "@stylistic/js/new-parens": [2] + "@stylistic/js/newline-per-chained-call": [0] + "@stylistic/js/no-confusing-arrow": [0] + "@stylistic/js/no-extra-parens": [0] + "@stylistic/js/no-extra-semi": [2] + "@stylistic/js/no-floating-decimal": [0] + "@stylistic/js/no-mixed-operators": [0] + "@stylistic/js/no-mixed-spaces-and-tabs": [2] + "@stylistic/js/no-multi-spaces": [2, {ignoreEOLComments: true, exceptions: {Property: true}}] + "@stylistic/js/no-multiple-empty-lines": [2, {max: 1, maxEOF: 0, maxBOF: 0}] + "@stylistic/js/no-tabs": [2] + "@stylistic/js/no-trailing-spaces": [2] + "@stylistic/js/no-whitespace-before-property": [2] + "@stylistic/js/nonblock-statement-body-position": [2] + "@stylistic/js/object-curly-newline": [0] + "@stylistic/js/object-curly-spacing": [2, never] + "@stylistic/js/object-property-newline": [0] + "@stylistic/js/one-var-declaration-per-line": [0] + "@stylistic/js/operator-linebreak": [2, after] + "@stylistic/js/padded-blocks": [2, never] + "@stylistic/js/padding-line-between-statements": [0] + "@stylistic/js/quote-props": [0] + "@stylistic/js/quotes": [2, single, {avoidEscape: true, allowTemplateLiterals: true}] + "@stylistic/js/rest-spread-spacing": [2, never] + "@stylistic/js/semi": [2, always, {omitLastInOneLineBlock: true}] + "@stylistic/js/semi-spacing": [2, {before: false, after: true}] + "@stylistic/js/semi-style": [2, last] + "@stylistic/js/space-before-blocks": [2, always] + "@stylistic/js/space-before-function-paren": [2, {anonymous: ignore, named: never, asyncArrow: always}] + "@stylistic/js/space-in-parens": [2, never] + "@stylistic/js/space-infix-ops": [2] + "@stylistic/js/space-unary-ops": [2] + "@stylistic/js/spaced-comment": [2, always] + "@stylistic/js/switch-colon-spacing": [2] + "@stylistic/js/template-curly-spacing": [2, never] + "@stylistic/js/template-tag-spacing": [2, never] + "@stylistic/js/wrap-iife": [2, inside] + "@stylistic/js/wrap-regex": [0] + "@stylistic/js/yield-star-spacing": [2, after] + accessor-pairs: [2] + array-callback-return: [2, {checkForEach: true}] + array-func/avoid-reverse: [2] + array-func/from-map: [2] + array-func/no-unnecessary-this-arg: [2] + array-func/prefer-array-from: [2] + array-func/prefer-flat-map: [0] # handled by unicorn/prefer-array-flat-map + array-func/prefer-flat: [0] # handled by unicorn/prefer-array-flat + arrow-body-style: [0] + block-scoped-var: [2] + camelcase: [0] + capitalized-comments: [0] + class-methods-use-this: [0] + complexity: [0] + consistent-return: [0] + consistent-this: [0] + constructor-super: [2] + curly: [0] + default-case-last: [2] + default-case: [0] + default-param-last: [0] + dot-notation: [0] + eqeqeq: [2] + for-direction: [2] + func-name-matching: [2] + func-names: [0] + func-style: [0] + getter-return: [2] + github/a11y-aria-label-is-well-formatted: [0] + github/a11y-no-title-attribute: [0] + github/a11y-no-visually-hidden-interactive-element: [0] + github/a11y-role-supports-aria-props: [0] + github/a11y-svg-has-accessible-name: [0] + github/array-foreach: [0] + github/async-currenttarget: [2] + github/async-preventdefault: [2] + github/authenticity-token: [0] + github/get-attribute: [0] + github/js-class-name: [0] + github/no-blur: [0] + github/no-d-none: [0] + github/no-dataset: [2] + github/no-dynamic-script-tag: [2] + github/no-implicit-buggy-globals: [2] + github/no-inner-html: [0] + github/no-innerText: [2] + github/no-then: [2] + github/no-useless-passive: [2] + github/prefer-observers: [2] + github/require-passive-events: [2] + github/unescaped-html-literal: [0] + grouped-accessor-pairs: [2] + guard-for-in: [0] + id-blacklist: [0] + id-length: [0] + id-match: [0] + i/consistent-type-specifier-style: [0] + i/default: [0] + i/dynamic-import-chunkname: [0] + i/export: [2] + i/exports-last: [0] + i/extensions: [2, always, {ignorePackages: true}] + i/first: [2] + i/group-exports: [0] + i/max-dependencies: [0] + i/named: [2] + i/namespace: [0] + i/newline-after-import: [0] + i/no-absolute-path: [0] + i/no-amd: [2] + i/no-anonymous-default-export: [0] + i/no-commonjs: [2] + i/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}] + i/no-default-export: [0] + i/no-deprecated: [0] + i/no-dynamic-require: [0] + i/no-empty-named-blocks: [2] + i/no-extraneous-dependencies: [2] + i/no-import-module-exports: [0] + i/no-internal-modules: [0] + i/no-mutable-exports: [0] + i/no-named-as-default-member: [0] + i/no-named-as-default: [2] + i/no-named-default: [0] + i/no-named-export: [0] + i/no-namespace: [0] + i/no-nodejs-modules: [0] + i/no-relative-packages: [0] + i/no-relative-parent-imports: [0] + i/no-restricted-paths: [0] + i/no-self-import: [2] + i/no-unassigned-import: [0] + i/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$", ^vitest/]}] + i/no-unused-modules: [2, {unusedExports: true}] + i/no-useless-path-segments: [2, {commonjs: true}] + i/no-webpack-loader-syntax: [2] + i/order: [0] + i/prefer-default-export: [0] + i/unambiguous: [0] + init-declarations: [0] + jquery/no-ajax-events: [2] + jquery/no-ajax: [2] + jquery/no-animate: [2] + jquery/no-attr: [2] + jquery/no-bind: [2] + jquery/no-class: [0] + jquery/no-clone: [2] + jquery/no-closest: [0] + jquery/no-css: [2] + jquery/no-data: [0] + jquery/no-deferred: [2] + jquery/no-delegate: [2] + jquery/no-each: [0] + jquery/no-extend: [2] + jquery/no-fade: [2] + jquery/no-filter: [0] + jquery/no-find: [0] + jquery/no-global-eval: [2] + jquery/no-grep: [2] + jquery/no-has: [2] + jquery/no-hide: [2] + jquery/no-html: [0] + jquery/no-in-array: [2] + jquery/no-is-array: [2] + jquery/no-is-function: [2] + jquery/no-is: [2] + jquery/no-load: [2] + jquery/no-map: [2] + jquery/no-merge: [2] + jquery/no-param: [2] + jquery/no-parent: [0] + jquery/no-parents: [2] + jquery/no-parse-html: [2] + jquery/no-prop: [2] + jquery/no-proxy: [2] + jquery/no-ready: [2] + jquery/no-serialize: [2] + jquery/no-show: [2] + jquery/no-size: [2] + jquery/no-sizzle: [0] + jquery/no-slide: [2] + jquery/no-submit: [2] + jquery/no-text: [0] + jquery/no-toggle: [2] + jquery/no-trigger: [0] + jquery/no-trim: [2] + jquery/no-val: [0] + jquery/no-when: [2] + jquery/no-wrap: [2] + line-comment-position: [0] + logical-assignment-operators: [0] + max-classes-per-file: [0] + max-depth: [0] + max-lines-per-function: [0] + max-lines: [0] + max-nested-callbacks: [0] + max-params: [0] + max-statements: [0] + multiline-comment-style: [2, separate-lines] + new-cap: [0] + no-alert: [0] + no-array-constructor: [2] + no-async-promise-executor: [0] + no-await-in-loop: [0] + no-bitwise: [0] + no-buffer-constructor: [0] + no-caller: [2] + no-case-declarations: [2] + no-class-assign: [2] + no-compare-neg-zero: [2] + no-cond-assign: [2, except-parens] + no-console: [1, {allow: [debug, info, warn, error]}] + no-const-assign: [2] + no-constant-binary-expression: [2] + no-constant-condition: [0] + no-constructor-return: [2] + no-continue: [0] + no-control-regex: [0] + no-debugger: [1] + no-delete-var: [2] + no-div-regex: [0] + no-dupe-args: [2] + no-dupe-class-members: [2] + no-dupe-else-if: [2] + no-dupe-keys: [2] + no-duplicate-case: [2] + no-duplicate-imports: [2] + no-else-return: [2] + no-empty-character-class: [2] + no-empty-function: [0] + no-empty-pattern: [2] + no-empty-static-block: [2] + no-empty: [2, {allowEmptyCatch: true}] + no-eq-null: [2] + no-eval: [2] + no-ex-assign: [2] + no-extend-native: [2] + no-extra-bind: [2] + no-extra-boolean-cast: [2] + no-extra-label: [0] + no-fallthrough: [2] + no-func-assign: [2] + no-global-assign: [2] + no-implicit-coercion: [2] + no-implicit-globals: [0] + no-implied-eval: [2] + no-import-assign: [2] + no-inline-comments: [0] + no-inner-declarations: [2] + no-invalid-regexp: [2] + no-invalid-this: [0] + no-irregular-whitespace: [2] + no-iterator: [2] + no-jquery/no-ajax-events: [2] + no-jquery/no-ajax: [2] + no-jquery/no-and-self: [2] + no-jquery/no-animate-toggle: [2] + no-jquery/no-animate: [2] + no-jquery/no-append-html: [2] + no-jquery/no-attr: [2] + no-jquery/no-bind: [2] + no-jquery/no-box-model: [2] + no-jquery/no-browser: [2] + no-jquery/no-camel-case: [2] + no-jquery/no-class-state: [0] + no-jquery/no-class: [0] + no-jquery/no-clone: [2] + no-jquery/no-closest: [0] + no-jquery/no-constructor-attributes: [2] + no-jquery/no-contains: [2] + no-jquery/no-context-prop: [2] + no-jquery/no-css: [2] + no-jquery/no-data: [0] + no-jquery/no-deferred: [2] + no-jquery/no-delegate: [2] + no-jquery/no-each-collection: [0] + no-jquery/no-each-util: [0] + no-jquery/no-each: [0] + no-jquery/no-error-shorthand: [2] + no-jquery/no-error: [2] + no-jquery/no-escape-selector: [2] + no-jquery/no-event-shorthand: [2] + no-jquery/no-extend: [2] + no-jquery/no-fade: [2] + no-jquery/no-filter: [0] + no-jquery/no-find-collection: [0] + no-jquery/no-find-util: [2] + no-jquery/no-find: [0] + no-jquery/no-fx-interval: [2] + no-jquery/no-global-eval: [2] + no-jquery/no-global-selector: [0] + no-jquery/no-grep: [2] + no-jquery/no-has: [2] + no-jquery/no-hold-ready: [2] + no-jquery/no-html: [0] + no-jquery/no-in-array: [2] + no-jquery/no-is-array: [2] + no-jquery/no-is-empty-object: [2] + no-jquery/no-is-function: [2] + no-jquery/no-is-numeric: [2] + no-jquery/no-is-plain-object: [2] + no-jquery/no-is-window: [2] + no-jquery/no-is: [2] + no-jquery/no-jquery-constructor: [0] + no-jquery/no-live: [2] + no-jquery/no-load-shorthand: [2] + no-jquery/no-load: [2] + no-jquery/no-map-collection: [0] + no-jquery/no-map-util: [2] + no-jquery/no-map: [2] + no-jquery/no-merge: [2] + no-jquery/no-node-name: [2] + no-jquery/no-noop: [2] + no-jquery/no-now: [2] + no-jquery/no-on-ready: [2] + no-jquery/no-other-methods: [0] + no-jquery/no-other-utils: [2] + no-jquery/no-param: [2] + no-jquery/no-parent: [0] + no-jquery/no-parents: [2] + no-jquery/no-parse-html-literal: [0] + no-jquery/no-parse-html: [2] + no-jquery/no-parse-json: [2] + no-jquery/no-parse-xml: [2] + no-jquery/no-prop: [2] + no-jquery/no-proxy: [2] + no-jquery/no-ready-shorthand: [2] + no-jquery/no-ready: [2] + no-jquery/no-selector-prop: [2] + no-jquery/no-serialize: [2] + no-jquery/no-size: [2] + no-jquery/no-sizzle: [0] + no-jquery/no-slide: [2] + no-jquery/no-sub: [2] + no-jquery/no-support: [2] + no-jquery/no-text: [0] + no-jquery/no-trigger: [0] + no-jquery/no-trim: [2] + no-jquery/no-type: [2] + no-jquery/no-unique: [2] + no-jquery/no-unload-shorthand: [2] + no-jquery/no-val: [0] + no-jquery/no-visibility: [2] + no-jquery/no-when: [2] + no-jquery/no-wrap: [2] + no-jquery/variable-pattern: [2] + no-label-var: [2] + no-labels: [0] # handled by no-restricted-syntax + no-lone-blocks: [2] + no-lonely-if: [0] + no-loop-func: [0] + no-loss-of-precision: [2] + no-magic-numbers: [0] + no-misleading-character-class: [2] + no-multi-assign: [0] + no-multi-str: [2] + no-negated-condition: [0] + no-nested-ternary: [0] + no-new-func: [2] + no-new-native-nonconstructor: [2] + no-new-object: [2] + no-new-symbol: [2] + no-new-wrappers: [2] + no-new: [0] + no-nonoctal-decimal-escape: [2] + no-obj-calls: [2] + no-octal-escape: [2] + no-octal: [2] + no-param-reassign: [0] + no-plusplus: [0] + no-promise-executor-return: [0] + no-proto: [2] + no-prototype-builtins: [2] + no-redeclare: [2] + no-regex-spaces: [2] + no-restricted-exports: [0] + no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename] + no-restricted-imports: [0] + no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.js instead"}] + no-return-assign: [0] + no-script-url: [2] + no-self-assign: [2, {props: true}] + no-self-compare: [2] + no-sequences: [2] + no-setter-return: [2] + no-shadow-restricted-names: [2] + no-shadow: [0] + no-sparse-arrays: [2] + no-template-curly-in-string: [2] + no-ternary: [0] + no-this-before-super: [2] + no-throw-literal: [2] + no-undef-init: [2] + no-undef: [2, {typeof: true}] + no-undefined: [0] + no-underscore-dangle: [0] + no-unexpected-multiline: [2] + no-unmodified-loop-condition: [2] + no-unneeded-ternary: [2] + no-unreachable-loop: [2] + no-unreachable: [2] + no-unsafe-finally: [2] + no-unsafe-negation: [2] + no-unused-expressions: [2] + no-unused-labels: [2] + no-unused-private-class-members: [2] + no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}] + no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}] + no-use-extend-native/no-use-extend-native: [2] + no-useless-backreference: [2] + no-useless-call: [2] + no-useless-catch: [2] + no-useless-computed-key: [2] + no-useless-concat: [2] + no-useless-constructor: [2] + no-useless-escape: [2] + no-useless-rename: [2] + no-useless-return: [2] + no-var: [2] + no-void: [2] + no-warning-comments: [0] + no-with: [0] # handled by no-restricted-syntax + object-shorthand: [2, always] + one-var-declaration-per-line: [0] + one-var: [0] + operator-assignment: [2, always] + operator-linebreak: [2, after] + prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}] + prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}] + prefer-destructuring: [0] + prefer-exponentiation-operator: [2] + prefer-named-capture-group: [0] + prefer-numeric-literals: [2] + prefer-object-has-own: [2] + prefer-object-spread: [2] + prefer-promise-reject-errors: [2, {allowEmptyReject: false}] + prefer-regex-literals: [2] + prefer-rest-params: [2] + prefer-spread: [2] + prefer-template: [2] + radix: [2, as-needed] + regexp/confusing-quantifier: [2] + regexp/control-character-escape: [2] + regexp/hexadecimal-escape: [0] + regexp/letter-case: [0] + regexp/match-any: [2] + regexp/negation: [2] + regexp/no-contradiction-with-assertion: [0] + regexp/no-control-character: [0] + regexp/no-dupe-characters-character-class: [2] + regexp/no-dupe-disjunctions: [2] + regexp/no-empty-alternative: [2] + regexp/no-empty-capturing-group: [2] + regexp/no-empty-character-class: [0] + regexp/no-empty-group: [2] + regexp/no-empty-lookarounds-assertion: [2] + regexp/no-empty-string-literal: [2] + regexp/no-escape-backspace: [2] + regexp/no-extra-lookaround-assertions: [0] + regexp/no-invalid-regexp: [2] + regexp/no-invisible-character: [2] + regexp/no-lazy-ends: [2] + regexp/no-legacy-features: [2] + regexp/no-misleading-capturing-group: [0] + regexp/no-misleading-unicode-character: [0] + regexp/no-missing-g-flag: [2] + regexp/no-non-standard-flag: [2] + regexp/no-obscure-range: [2] + regexp/no-octal: [2] + regexp/no-optional-assertion: [2] + regexp/no-potentially-useless-backreference: [2] + regexp/no-standalone-backslash: [2] + regexp/no-super-linear-backtracking: [0] + regexp/no-super-linear-move: [0] + regexp/no-trivially-nested-assertion: [2] + regexp/no-trivially-nested-quantifier: [2] + regexp/no-unused-capturing-group: [0] + regexp/no-useless-assertions: [2] + regexp/no-useless-backreference: [2] + regexp/no-useless-character-class: [2] + regexp/no-useless-dollar-replacements: [2] + regexp/no-useless-escape: [2] + regexp/no-useless-flag: [2] + regexp/no-useless-lazy: [2] + regexp/no-useless-non-capturing-group: [2] + regexp/no-useless-quantifier: [2] + regexp/no-useless-range: [2] + regexp/no-useless-set-operand: [2] + regexp/no-useless-string-literal: [2] + regexp/no-useless-two-nums-quantifier: [2] + regexp/no-zero-quantifier: [2] + regexp/optimal-lookaround-quantifier: [2] + regexp/optimal-quantifier-concatenation: [0] + regexp/prefer-character-class: [0] + regexp/prefer-d: [0] + regexp/prefer-escape-replacement-dollar-char: [0] + regexp/prefer-lookaround: [0] + regexp/prefer-named-backreference: [0] + regexp/prefer-named-capture-group: [0] + regexp/prefer-named-replacement: [0] + regexp/prefer-plus-quantifier: [2] + regexp/prefer-predefined-assertion: [2] + regexp/prefer-quantifier: [0] + regexp/prefer-question-quantifier: [2] + regexp/prefer-range: [2] + regexp/prefer-regexp-exec: [2] + regexp/prefer-regexp-test: [2] + regexp/prefer-result-array-groups: [0] + regexp/prefer-set-operation: [2] + regexp/prefer-star-quantifier: [2] + regexp/prefer-unicode-codepoint-escapes: [2] + regexp/prefer-w: [0] + regexp/require-unicode-regexp: [0] + regexp/simplify-set-operations: [2] + regexp/sort-alternatives: [0] + regexp/sort-character-class-elements: [0] + regexp/sort-flags: [0] + regexp/strict: [2] + regexp/unicode-escape: [0] + regexp/use-ignore-case: [0] + require-atomic-updates: [0] + require-await: [0] + require-unicode-regexp: [0] + require-yield: [2] + sonarjs/cognitive-complexity: [0] + sonarjs/elseif-without-else: [0] + sonarjs/max-switch-cases: [0] + sonarjs/no-all-duplicated-branches: [2] + sonarjs/no-collapsible-if: [0] + sonarjs/no-collection-size-mischeck: [2] + sonarjs/no-duplicate-string: [0] + sonarjs/no-duplicated-branches: [0] + sonarjs/no-element-overwrite: [2] + sonarjs/no-empty-collection: [2] + sonarjs/no-extra-arguments: [2] + sonarjs/no-gratuitous-expressions: [2] + sonarjs/no-identical-conditions: [2] + sonarjs/no-identical-expressions: [2] + sonarjs/no-identical-functions: [2, 5] + sonarjs/no-ignored-return: [2] + sonarjs/no-inverted-boolean-check: [2] + sonarjs/no-nested-switch: [0] + sonarjs/no-nested-template-literals: [0] + sonarjs/no-one-iteration-loop: [2] + sonarjs/no-redundant-boolean: [2] + sonarjs/no-redundant-jump: [2] + sonarjs/no-same-line-conditional: [2] + sonarjs/no-small-switch: [0] + sonarjs/no-unused-collection: [2] + sonarjs/no-use-of-empty-return-value: [2] + sonarjs/no-useless-catch: [2] + sonarjs/non-existent-operator: [2] + sonarjs/prefer-immediate-return: [0] + sonarjs/prefer-object-literal: [0] + sonarjs/prefer-single-boolean-return: [0] + sonarjs/prefer-while: [2] + sort-imports: [0] + sort-keys: [0] + sort-vars: [0] + strict: [0] + symbol-description: [2] + unicode-bom: [2, never] + unicorn/better-regex: [0] + unicorn/catch-error-name: [0] + unicorn/consistent-destructuring: [2] + unicorn/consistent-function-scoping: [2] + unicorn/custom-error-definition: [0] + unicorn/empty-brace-spaces: [2] + unicorn/error-message: [0] + unicorn/escape-case: [0] + unicorn/expiring-todo-comments: [0] + unicorn/explicit-length-check: [0] + unicorn/filename-case: [0] + unicorn/import-index: [0] + unicorn/import-style: [0] + unicorn/new-for-builtins: [2] + unicorn/no-abusive-eslint-disable: [0] + unicorn/no-anonymous-default-export: [0] + unicorn/no-array-callback-reference: [0] + unicorn/no-array-for-each: [2] + unicorn/no-array-method-this-argument: [2] + unicorn/no-array-push-push: [2] + unicorn/no-array-reduce: [2] + unicorn/no-await-expression-member: [0] + unicorn/no-await-in-promise-methods: [2] + unicorn/no-console-spaces: [0] + unicorn/no-document-cookie: [2] + unicorn/no-empty-file: [2] + unicorn/no-for-loop: [0] + unicorn/no-hex-escape: [0] + unicorn/no-instanceof-array: [0] + unicorn/no-invalid-remove-event-listener: [2] + unicorn/no-keyword-prefix: [0] + unicorn/no-lonely-if: [2] + unicorn/no-negated-condition: [0] + unicorn/no-nested-ternary: [0] + unicorn/no-new-array: [0] + unicorn/no-new-buffer: [0] + unicorn/no-null: [0] + unicorn/no-object-as-default-parameter: [0] + unicorn/no-process-exit: [0] + unicorn/no-single-promise-in-promise-methods: [2] + unicorn/no-static-only-class: [2] + unicorn/no-thenable: [2] + unicorn/no-this-assignment: [2] + unicorn/no-typeof-undefined: [2] + unicorn/no-unnecessary-await: [2] + unicorn/no-unnecessary-polyfills: [2] + unicorn/no-unreadable-array-destructuring: [0] + unicorn/no-unreadable-iife: [2] + unicorn/no-unused-properties: [2] + unicorn/no-useless-fallback-in-spread: [2] + unicorn/no-useless-length-check: [2] + unicorn/no-useless-promise-resolve-reject: [2] + unicorn/no-useless-spread: [2] + unicorn/no-useless-switch-case: [2] + unicorn/no-useless-undefined: [0] + unicorn/no-zero-fractions: [2] + unicorn/number-literal-case: [0] + unicorn/numeric-separators-style: [0] + unicorn/prefer-add-event-listener: [2] + unicorn/prefer-array-find: [2] + unicorn/prefer-array-flat-map: [2] + unicorn/prefer-array-flat: [2] + unicorn/prefer-array-index-of: [2] + unicorn/prefer-array-some: [2] + unicorn/prefer-at: [0] + unicorn/prefer-blob-reading-methods: [2] + unicorn/prefer-code-point: [0] + unicorn/prefer-date-now: [2] + unicorn/prefer-default-parameters: [0] + unicorn/prefer-dom-node-append: [2] + unicorn/prefer-dom-node-dataset: [0] + unicorn/prefer-dom-node-remove: [2] + unicorn/prefer-dom-node-text-content: [2] + unicorn/prefer-event-target: [2] + unicorn/prefer-export-from: [0] + unicorn/prefer-includes: [2] + unicorn/prefer-json-parse-buffer: [0] + unicorn/prefer-keyboard-event-key: [2] + unicorn/prefer-logical-operator-over-ternary: [2] + unicorn/prefer-math-trunc: [2] + unicorn/prefer-modern-dom-apis: [0] + unicorn/prefer-modern-math-apis: [2] + unicorn/prefer-module: [2] + unicorn/prefer-native-coercion-functions: [2] + unicorn/prefer-negative-index: [2] + unicorn/prefer-node-protocol: [2] + unicorn/prefer-number-properties: [0] + unicorn/prefer-object-from-entries: [2] + unicorn/prefer-object-has-own: [0] + unicorn/prefer-optional-catch-binding: [2] + unicorn/prefer-prototype-methods: [0] + unicorn/prefer-query-selector: [0] + unicorn/prefer-reflect-apply: [0] + unicorn/prefer-regexp-test: [2] + unicorn/prefer-set-has: [0] + unicorn/prefer-set-size: [2] + unicorn/prefer-spread: [0] + unicorn/prefer-string-replace-all: [0] + unicorn/prefer-string-slice: [0] + unicorn/prefer-string-starts-ends-with: [2] + unicorn/prefer-string-trim-start-end: [2] + unicorn/prefer-switch: [0] + unicorn/prefer-ternary: [0] + unicorn/prefer-text-content: [2] + unicorn/prefer-top-level-await: [0] + unicorn/prefer-type-error: [0] + unicorn/prevent-abbreviations: [0] + unicorn/relative-url-style: [2] + unicorn/require-array-join-separator: [2] + unicorn/require-number-to-fixed-digits-argument: [2] + unicorn/require-post-message-target-origin: [0] + unicorn/string-content: [0] + unicorn/switch-case-braces: [0] + unicorn/template-indent: [2] + unicorn/text-encoding-identifier-case: [0] + unicorn/throw-new-error: [2] + use-isnan: [2] + valid-typeof: [2, {requireStringLiterals: true}] + vars-on-top: [0] + wc/attach-shadow-constructor: [2] + wc/define-tag-after-class-definition: [0] + wc/expose-class-on-global: [0] + wc/file-name-matches-element: [2] + wc/guard-define-call: [0] + wc/guard-super-call: [2] + wc/max-elements-per-file: [0] + wc/no-child-traversal-in-attributechangedcallback: [2] + wc/no-child-traversal-in-connectedcallback: [2] + wc/no-closed-shadow-root: [2] + wc/no-constructor-attributes: [2] + wc/no-constructor-params: [2] + wc/no-constructor: [2] + wc/no-customized-built-in-elements: [2] + wc/no-exports-with-element: [0] + wc/no-invalid-element-name: [2] + wc/no-invalid-extends: [2] + wc/no-method-prefixed-with-on: [2] + wc/no-self-class: [2] + wc/no-typos: [2] + wc/require-listener-teardown: [2] + wc/tag-name-matches-class: [2] + yoda: [2, never] diff --git a/.forgejo/cascading-pr-end-to-end b/.forgejo/cascading-pr-end-to-end index 8013fde06a..d7a6b46b48 100755 --- a/.forgejo/cascading-pr-end-to-end +++ b/.forgejo/cascading-pr-end-to-end @@ -13,22 +13,21 @@ minor_version=$(make show-version-minor) cd $end_to_end -if ! test -f forgejo/sources/$minor_version; then - echo "FAIL: forgejo/sources/$minor_version does not exist in the end-to-end repository" - false +if ! test -f forgejo/sources/$minor_version ; then + echo "FAIL: forgejo/sources/$minor_version does not exist in the end-to-end repository" + false fi -echo -n $minor_version >forgejo/build-from-sources -date >last-upgrade +date > last-upgrade -if test -f "$forgejo_pr_or_ref"; then - forgejo_pr=$forgejo_pr_or_ref - head_url=$(jq --raw-output .head.repo.html_url <$forgejo_pr) - test "$head_url" != null - branch=$(jq --raw-output .head.ref <$forgejo_pr) - test "$branch" != null - echo $head_url $branch $full_version >forgejo/sources/$minor_version +if test -f "$forgejo_pr_or_ref" ; then + forgejo_pr=$forgejo_pr_or_ref + head_url=$(jq --raw-output .head.repo.html_url < $forgejo_pr) + test "$head_url" != null + branch=$(jq --raw-output .head.ref < $forgejo_pr) + test "$branch" != null + echo $head_url $branch $full_version > forgejo/sources/$minor_version else - forgejo_ref=$forgejo_pr_or_ref - echo $GITHUB_SERVER_URL/$GITHUB_REPOSITORY ${forgejo_ref#refs/heads/} $full_version >forgejo/sources/$minor_version + forgejo_ref=$forgejo_pr_or_ref + echo $GITHUB_SERVER_URL/$GITHUB_REPOSITORY ${forgejo_ref#refs/heads/} $full_version > forgejo/sources/$minor_version fi diff --git a/.forgejo/cascading-release-end-to-end b/.forgejo/cascading-release-end-to-end index 9be0737b0f..08ad8a4431 100755 --- a/.forgejo/cascading-release-end-to-end +++ b/.forgejo/cascading-release-end-to-end @@ -8,15 +8,15 @@ forgejo=$3 forgejo_ref=$4 cd $end_to_end -date >last-upgrade +date > last-upgrade organizations=lib/ORGANIZATIONS -if ! test -f $organizations; then - echo "$organizations file not found" - false +if ! test -f $organizations ; then + echo "$organizations file not found" + false fi # -# Inverse the order of lookup because the goal in the release built -# pipeline is to test the latest build, if available, instead of the -# stable version by the same version. +# do not include forgejo-experimental so that 7.0-test is found +# in forgejo-integration where it was just built instead of +# forgejo-experimental which was published by the previous build # -echo forgejo-integration forgejo-experimental forgejo >$organizations +echo forgejo forgejo-integration > $organizations diff --git a/.forgejo/pull_request_template.md b/.forgejo/pull_request_template.md deleted file mode 100644 index d30af48446..0000000000 --- a/.forgejo/pull_request_template.md +++ /dev/null @@ -1,33 +0,0 @@ ---- - -name: "Pull Request Template" -about: "Template for all Pull Requests" -labels: - -- test/needed - ---- - -## Checklist - -The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). - -### Tests - -- I added test coverage for Go changes... - - [ ] in their respective `*_test.go` for unit tests. - - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. -- I added test coverage for JavaScript changes... - - [ ] in `web_src/js/*.test.js` if it can be unit tested. - - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). - -### Documentation - -- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. -- [ ] I did not document these changes and I do not expect someone else to do it. - -### Release notes - -- [ ] I do not want this change to show in the release notes. -- [ ] I want the title to show in the release notes with a link to this pull request. -- [ ] I want the content of the `release-notes/.md` to be be used for the release notes instead of the title. diff --git a/.forgejo/testdata/build-release/Dockerfile b/.forgejo/testdata/build-release/Dockerfile index 09cce06c47..4ef67d34e0 100644 --- a/.forgejo/testdata/build-release/Dockerfile +++ b/.forgejo/testdata/build-release/Dockerfile @@ -1,4 +1,4 @@ -FROM data.forgejo.org/oci/alpine:3.22 +FROM code.forgejo.org/oci/alpine:3.20 ARG RELEASE_VERSION=unkown LABEL maintainer="contact@forgejo.org" \ org.opencontainers.image.version="${RELEASE_VERSION}" diff --git a/.forgejo/testdata/build-release/go.mod b/.forgejo/testdata/build-release/go.mod deleted file mode 100644 index 585dcc4f3d..0000000000 --- a/.forgejo/testdata/build-release/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module forgejo.org - -go 1.23.3 diff --git a/.forgejo/workflows-composite/apt-install-from/action.yaml b/.forgejo/workflows-composite/apt-install-from/action.yaml deleted file mode 100644 index 4ce4805cd7..0000000000 --- a/.forgejo/workflows-composite/apt-install-from/action.yaml +++ /dev/null @@ -1,32 +0,0 @@ -inputs: - packages: - description: 'Packages to install' - required: true - release: - description: 'Release to install from' - default: testing - -runs: - using: "composite" - steps: - - name: setup apt package source - run: | - export DEBIAN_FRONTEND=noninteractive - echo "deb http://deb.debian.org/debian/ ${RELEASE} main" > "/etc/apt/sources.list.d/${RELEASE}.list" - wget -O- http://neuro.debian.net/lists/bookworm.de-fzj.libre | tee /etc/apt/sources.list.d/neurodebian.sources.list - apt-key adv --recv-keys --keyserver hkps://keyserver.ubuntu.com 0xA5D32F012649A5A9 - env: - RELEASE: ${{inputs.release}} - - name: install packages - run: | - apt-get update -qq - apt-get -q install --allow-downgrades -qq -y ${PACKAGES} - env: - PACKAGES: ${{inputs.packages}} - - name: remove temporary package list to prevent using it in other steps - run: | - rm "/etc/apt/sources.list.d/${RELEASE}.list" - rm "/etc/apt/sources.list.d/neurodebian.sources.list" - apt-get update -qq - env: - RELEASE: ${{inputs.release}} diff --git a/.forgejo/workflows-composite/build-backend/action.yaml b/.forgejo/workflows-composite/build-backend/action.yaml deleted file mode 100644 index 68a99ffaf9..0000000000 --- a/.forgejo/workflows-composite/build-backend/action.yaml +++ /dev/null @@ -1,15 +0,0 @@ -runs: - using: "composite" - steps: - - run: | - su forgejo -c 'make deps-backend' - - uses: https://data.forgejo.org/actions/cache@v4 - id: cache-backend - with: - path: ${{github.workspace}}/gitea - key: backend-build-${{ github.sha }} - - if: steps.cache-backend.outputs.cache-hit != 'true' - run: | - su forgejo -c 'make backend' - env: - TAGS: bindata diff --git a/.forgejo/workflows-composite/setup-cache-go/action.yaml b/.forgejo/workflows-composite/setup-cache-go/action.yaml deleted file mode 100644 index f2818a7635..0000000000 --- a/.forgejo/workflows-composite/setup-cache-go/action.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-License-Identifier: MIT -name: 'Forgejo Actions to setup Go and cache dependencies' -author: 'Forgejo authors' -description: | - Wrap the setup-go with improved dependency caching. -inputs: - username: - description: 'User for which to manage the dependency cache' - default: root - -runs: - using: "composite" - steps: - - name: "Install zstd for faster caching" - run: | - apt-get update -qq - apt-get -q install -qq -y zstd - - - name: "Set up Go using setup-go" - uses: https://data.forgejo.org/actions/setup-go@v5 - id: go-version - with: - go-version-file: "go.mod" - # do not cache dependencies, we do this manually - cache: false - - - name: "Get go environment information" - id: go-environment - run: | - chmod 755 $HOME # ensure ${RUN_AS_USER} has permission when go is located in $HOME - export GOROOT="$(go env GOROOT)" - echo "modcache=$(su ${RUN_AS_USER} -c '${GOROOT}/bin/go env GOMODCACHE')" >> "$GITHUB_OUTPUT" - echo "cache=$(su ${RUN_AS_USER} -c '${GOROOT}/bin/go env GOCACHE')" >> "$GITHUB_OUTPUT" - env: - RUN_AS_USER: ${{ inputs.username }} - GO_VERSION: ${{ steps.go-version.outputs.go-version }} - - - name: "Create cache folders with correct permissions (for non-root users)" - if: inputs.username != 'root' - # when the cache is restored, only the permissions of the last part are restored - # so assuming that /home/user exists and we are restoring /home/user/go/pkg/mod, - # both folders will have the correct permissions, but - # /home/user/go and /home/user/go/pkg might be owned by root - run: | - su ${RUN_AS_USER} -c 'mkdir -p "${MODCACHE_DIR}" "${CACHE_DIR}"' - env: - RUN_AS_USER: ${{ inputs.username }} - MODCACHE_DIR: ${{ steps.go-environment.outputs.modcache }} - CACHE_DIR: ${{ steps.go-environment.outputs.cache }} - - - name: "Restore Go dependencies from cache or mark for later caching" - id: cache-deps - uses: https://data.forgejo.org/actions/cache@v4 - with: - key: setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}-${{ steps.go-version.outputs.go_version }}-${{ hashFiles('go.sum', 'go.mod') }} - restore-keys: | - setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}-${{ steps.go-version.outputs.go_version }}- - setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}- - path: | - ${{ steps.go-environment.outputs.modcache }} - ${{ steps.go-environment.outputs.cache }} diff --git a/.forgejo/workflows-composite/setup-env/action.yaml b/.forgejo/workflows-composite/setup-env/action.yaml deleted file mode 100644 index f19569a137..0000000000 --- a/.forgejo/workflows-composite/setup-env/action.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# TODO: -# - [ ] prepare a forgejo ci image with the necessary tools and forgejo user -runs: - using: "composite" - steps: - - name: setup user and permissions - run: | - git config --add safe.directory '*' - # ignore if the user already exists (like with the playwright image) - adduser --quiet --comment forgejo --disabled-password forgejo || true - chown -R forgejo:forgejo . - - - uses: ./.forgejo/workflows-composite/setup-cache-go - with: - username: forgejo - - - name: validate go version - run: | - set -ex - toolchain=$(grep -oP '(?<=toolchain ).+' go.mod) - version=$(go version | cut -d' ' -f3) - if dpkg --compare-versions ${version#go} lt ${toolchain#go}; then - echo "go version too low: $toolchain >= $version" - exit 1 - fi diff --git a/.forgejo/workflows/backport.yml b/.forgejo/workflows/backport.yml index 573c33f93b..6181dcf352 100644 --- a/.forgejo/workflows/backport.yml +++ b/.forgejo/workflows/backport.yml @@ -22,8 +22,6 @@ # `backport/v1.21` label on a merged pull request that can be backported # without conflict. # -name: issue-labels - on: pull_request_target: types: @@ -33,21 +31,21 @@ on: jobs: backporting: if: > - ( vars.ROLE == 'forgejo-coding' ) && ( + !startsWith(vars.ROLE, 'forgejo-') && ( github.event.pull_request.merged && contains(toJSON(github.event.pull_request.labels), 'backport/v') ) runs-on: docker container: - image: 'data.forgejo.org/oci/node:22-bookworm' + image: 'docker.io/node:20-bookworm' steps: - name: event info run: | cat <<'EOF' ${{ toJSON(github) }} EOF - - uses: https://data.forgejo.org/actions/git-backporting@v4.8.5 + - uses: https://code.forgejo.org/actions/git-backporting@v4.8.0 with: target-branch-pattern: "^backport/(?(v.*))$" strategy: ort @@ -57,5 +55,3 @@ jobs: pull-request: ${{ github.event.pull_request.url }} auto-no-squash: true enable-err-notification: true - git-user: forgejo-backport-action - git-email: forgejo-backport-action@noreply.codeberg.org diff --git a/.forgejo/workflows/build-oci-image.yml b/.forgejo/workflows/build-oci-image.yml deleted file mode 100644 index 8e843b41ee..0000000000 --- a/.forgejo/workflows/build-oci-image.yml +++ /dev/null @@ -1,41 +0,0 @@ -on: - push: - branches: - - 'forgejo' - tags: - - '*-git-annex*' - -jobs: - build-oci-image: - runs-on: docker - strategy: - matrix: - type: ["rootful", "rootless"] - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 # fetch the full history so that the Forgejo version is determined properly - - name: Determine registry and username - id: determine-registry-and-username - run: | - echo "registry=${GITHUB_SERVER_URL#https://}" >> "$GITHUB_OUTPUT" - echo "username=${GITHUB_REPOSITORY%/*}" >> "$GITHUB_OUTPUT" - - name: Install Docker - run: curl -fsSL https://get.docker.com | sh - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - registry: ${{ steps.determine-registry-and-username.outputs.registry }} - username: ${{ steps.determine-registry-and-username.outputs.username }} - password: ${{ secrets.REGISTRY_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - file: ${{ (matrix.type == 'rootful' && 'Dockerfile') || (matrix.type == 'rootless' && 'Dockerfile.rootless') }} - push: true - tags: ${{ steps.determine-registry-and-username.outputs.registry }}/${{ github.repository }}:${{ github.ref_name }}${{ (matrix.type == 'rootful' && ' ') || (matrix.type == 'rootless' && '-rootless') }} diff --git a/.forgejo/workflows/build-release-integration.yml b/.forgejo/workflows/build-release-integration.yml index 1af6d567dd..610b8f0520 100644 --- a/.forgejo/workflows/build-release-integration.yml +++ b/.forgejo/workflows/build-release-integration.yml @@ -22,13 +22,13 @@ on: jobs: release-simulation: - if: vars.ROLE == 'forgejo-coding' - runs-on: lxc-bookworm + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} + runs-on: self-hosted steps: - - uses: https://data.forgejo.org/actions/checkout@v4 + - uses: actions/checkout@v3 - id: forgejo - uses: https://data.forgejo.org/actions/setup-forgejo@v2.0.4 + uses: https://code.forgejo.org/actions/setup-forgejo@v1 with: user: root password: admin1234 diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml index 3ab63b0589..eb4297c7ef 100644 --- a/.forgejo/workflows/build-release.yml +++ b/.forgejo/workflows/build-release.yml @@ -1,5 +1,5 @@ # -# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process +# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process # # https://codeberg.org/forgejo-integration/forgejo # @@ -14,12 +14,6 @@ # secrets.CASCADE_DESTINATION_TOKEN: scope read:user, write:repository, write:issue # vars.CASCADE_DESTINATION_DOER: forgejo-ci # -# vars.SKIP_END_TO_END: `true` or `false` -# It must be `false` (or absent) so https://code.forgejo.org/forgejo/end-to-end is run -# with the newly built release. -# It must be set to `true` when a release is missing, for instance because it was -# removed and failed to upload. -# on: push: tags: 'v[0-9]+.[0-9]+.*' @@ -29,11 +23,11 @@ on: jobs: release: - runs-on: lxc-bookworm + runs-on: self-hosted # root is used for testing, allow it if: vars.ROLE == 'forgejo-integration' || github.repository_owner == 'root' steps: - - uses: https://data.forgejo.org/actions/checkout@v4 + - uses: actions/checkout@v3 with: fetch-depth: 0 @@ -43,13 +37,14 @@ jobs: repository="${{ github.repository }}" echo "value=${repository##*/}" >> "$GITHUB_OUTPUT" - - uses: https://data.forgejo.org/actions/setup-node@v4 + - uses: https://code.forgejo.org/actions/setup-node@v3 with: - node-version: 22 + node-version: 20 - - uses: https://data.forgejo.org/actions/setup-go@v5 + - uses: https://code.forgejo.org/actions/setup-go@v4 with: - go-version-file: "go.mod" + go-version: "1.22" + check-latest: true - name: version from ref id: release-info @@ -93,7 +88,7 @@ jobs: - name: cache node_modules id: node - uses: https://data.forgejo.org/actions/cache@v4 + uses: https://code.forgejo.org/actions/cache@v3 with: path: | node_modules @@ -164,7 +159,7 @@ jobs: - name: build container & release if: ${{ secrets.TOKEN != '' }} - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5 + uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v5.1.1 with: forgejo: "${{ env.GITHUB_SERVER_URL }}" owner: "${{ env.GITHUB_REPOSITORY_OWNER }}" @@ -183,7 +178,7 @@ jobs: - name: build rootless container if: ${{ secrets.TOKEN != '' }} - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5 + uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v5.1.1 with: forgejo: "${{ env.GITHUB_SERVER_URL }}" owner: "${{ env.GITHUB_REPOSITORY_OWNER }}" @@ -200,8 +195,8 @@ jobs: verbose: ${{ vars.VERBOSE || secrets.VERBOSE || 'false' }} - name: end-to-end tests - if: ${{ secrets.TOKEN != '' && vars.ROLE == 'forgejo-integration' && vars.SKIP_END_TO_END != 'true' }} - uses: https://data.forgejo.org/actions/cascading-pr@v2.2.0 + if: ${{ secrets.TOKEN != '' && vars.ROLE == 'forgejo-integration' }} + uses: https://code.forgejo.org/actions/cascading-pr@v2 with: origin-url: ${{ env.GITHUB_SERVER_URL }} origin-repo: ${{ github.repository }} diff --git a/.forgejo/workflows/cascade-setup-end-to-end.yml b/.forgejo/workflows/cascade-setup-end-to-end.yml index 7c8c56de13..dcca2404d9 100644 --- a/.forgejo/workflows/cascade-setup-end-to-end.yml +++ b/.forgejo/workflows/cascade-setup-end-to-end.yml @@ -12,10 +12,8 @@ # whatever is in the default branch instead # # - after it is merged, double check it works by setting the -# run-end-to-end-test on a pull request (any pull request will do) +# run-end-to-end-test on a pull request (any pull request will doe # -name: issue-labels - on: push: branches: @@ -25,23 +23,42 @@ on: - labeled jobs: + info: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} + runs-on: docker + container: + image: node:20-bookworm + steps: + - name: event + run: | + echo github.event.pull_request.head.repo.fork = ${{ github.event.pull_request.head.repo.fork }} + echo github.event.action = ${{ github.event.action }} + echo github.event.pull_request.merged = ${{ github.event.pull_request.merged }} + echo github.event.pull_request.labels.*.name + cat <<'EOF' + ${{ toJSON(github.event.pull_request.labels.*.name) }} + EOF + cat <<'EOF' + ${{ toJSON(github.event) }} + EOF + cascade: if: > - vars.ROLE == 'forgejo-coding' && ( + !startsWith(vars.ROLE, 'forgejo-') && ( github.event_name == 'push' || ( - github.event.action == 'label_updated' && github.event.label.name == 'run-end-to-end-tests' + github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') ) ) runs-on: docker container: - image: data.forgejo.org/oci/node:22-bookworm + image: node:20-bookworm steps: - - uses: https://data.forgejo.org/actions/checkout@v4 + - uses: actions/checkout@v4 with: fetch-depth: '0' show-progress: 'false' - - uses: https://data.forgejo.org/actions/cascading-pr@v2.2.0 + - uses: actions/cascading-pr@v2 with: origin-url: ${{ env.GITHUB_SERVER_URL }} origin-repo: ${{ github.repository }} diff --git a/.forgejo/workflows/e2e.yml b/.forgejo/workflows/e2e.yml new file mode 100644 index 0000000000..cda9991027 --- /dev/null +++ b/.forgejo/workflows/e2e.yml @@ -0,0 +1,39 @@ +name: e2e + +on: + pull_request: + paths: + - Makefile + - playwright.config.js + - .forgejo/workflows/e2e.yml + - tests/e2e/** + - web_src/js/** + +jobs: + test-e2e: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} + runs-on: docker + container: + image: 'docker.io/node:20-bookworm' + steps: + - uses: https://code.forgejo.org/actions/checkout@v4 + - uses: https://code.forgejo.org/actions/setup-go@v4 + with: + go-version: "1.22" + check-latest: true + - run: | + apt-get -qq update + apt-get -qq install -q sudo + sed -i -e 's/%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/' /etc/sudoers + git config --add safe.directory '*' + adduser --quiet --comment forgejo --disabled-password forgejo + adduser forgejo sudo + chown -R forgejo:forgejo . + - run: | + su forgejo -c 'make deps-frontend frontend deps-backend' + - run: | + su forgejo -c 'make generate test-e2e-sqlite' + timeout-minutes: 40 + env: + DEPS_PLAYWRIGHT: 1 + USE_REPO_TEST_DIR: 1 diff --git a/.forgejo/workflows/forgejo-integration-cleanup.yml b/.forgejo/workflows/forgejo-integration-cleanup.yml deleted file mode 100644 index d490e3b2f2..0000000000 --- a/.forgejo/workflows/forgejo-integration-cleanup.yml +++ /dev/null @@ -1,39 +0,0 @@ -on: - workflow_dispatch: - - schedule: - - cron: '@daily' - -jobs: - integration-cleanup: - if: vars.ROLE == 'forgejo-integration' - runs-on: docker - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - steps: - - - name: apt install curl jq - run: | - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq - apt-get -q install -qq -y curl jq - - - name: remove old releases and tags - run: | - url=https://any:${{ secrets.TOKEN }}@codeberg.org - curl -sS "$url/api/v1/repos/forgejo-integration/forgejo/releases" | jq -r '.[] | "\(.published_at) \(.tag_name)"' | sort | while read published_at version ; do - if echo $version | grep -e '-test$' >/dev/null; then - old="18 months" - else - old="1 day" - fi - too_old=$(env -i date --date="- $old" +%F) - too_old_seconds=$(env -i date --date="- $old" +%s) - published_at_seconds=$(env -i date --date="$published_at" +%s) - if test $published_at_seconds -le $too_old_seconds ; then - echo "$version was published more than $old ago ($published_at <= $too_old) and will be removed" - curl -X DELETE -sS "$url/api/v1/repos/forgejo-integration/forgejo/releases/tags/$version" - else - echo "$version was published less than $old ago" - fi - done diff --git a/.forgejo/workflows/merge-requirements.yml b/.forgejo/workflows/merge-requirements.yml deleted file mode 100644 index 9aaf2af68d..0000000000 --- a/.forgejo/workflows/merge-requirements.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2024 The Forgejo Authors -# SPDX-License-Identifier: MIT - -name: requirements - -on: - pull_request: - types: - - labeled - - edited - - opened - - synchronize - -jobs: - merge-conditions: - if: vars.ROLE == 'forgejo-coding' - runs-on: docker - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - steps: - - name: Debug output - run: | - cat <<'EOF' - ${{ toJSON(github) }} - EOF - - name: Missing test label - if: > - !( - contains(toJSON(github.event.pull_request.labels), 'test/present') - || contains(toJSON(github.event.pull_request.labels), 'test/not-needed') - || contains(toJSON(github.event.pull_request.labels), 'test/manual') - ) - run: | - echo "A team member must set the label to either 'present', 'not-needed' or 'manual'." - exit 1 - - name: Missing manual test instructions - if: > - ( - contains(toJSON(github.event.pull_request.labels), 'test/manual') - && !contains(toJSON(github.event.pull_request.body), '# Test') - ) - run: | - echo "Manual test label is set. The PR description needs to contain test steps introduced by a heading like:" - echo "# Testing" - exit 1 diff --git a/.forgejo/workflows/milestone.yml b/.forgejo/workflows/milestone.yml deleted file mode 100644 index 9a51c515d0..0000000000 --- a/.forgejo/workflows/milestone.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2024 The Forgejo Authors -# SPDX-License-Identifier: MIT -# -name: milestone - -on: - pull_request_target: - types: - - closed - -jobs: - set: - if: vars.ROLE == 'forgejo-coding' && github.event.pull_request.merged - runs-on: docker - container: - image: 'data.forgejo.org/oci/ci:1' - steps: - - uses: https://data.forgejo.org/forgejo/set-milestone@v1.0.0 - with: - forgejo: https://codeberg.org - repository: forgejo/forgejo - token: ${{ secrets.SET_MILESTONE_TOKEN }} - pr-number: ${{ github.event.pull_request.number }} - verbose: ${{ vars.SET_MILESTONE_VERBOSE }} diff --git a/.forgejo/workflows/mirror.yml b/.forgejo/workflows/mirror.yml index d45a2f6f77..599c8c01ff 100644 --- a/.forgejo/workflows/mirror.yml +++ b/.forgejo/workflows/mirror.yml @@ -1,8 +1,6 @@ name: mirror on: - workflow_dispatch: - schedule: - cron: '@daily' @@ -11,7 +9,7 @@ jobs: if: ${{ secrets.MIRROR_TOKEN != '' }} runs-on: docker container: - image: 'data.forgejo.org/oci/node:22-bookworm' + image: 'docker.io/node:20-bookworm' steps: - name: git push {v*/,}forgejo run: | diff --git a/.forgejo/workflows/publish-release.yml b/.forgejo/workflows/publish-release.yml index 3aec46fb03..19192615dc 100644 --- a/.forgejo/workflows/publish-release.yml +++ b/.forgejo/workflows/publish-release.yml @@ -1,8 +1,6 @@ # SPDX-License-Identifier: MIT # -# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process -# -# TOKEN_NEXT_DIGEST is a token with write repository access to https://invisible.forgejo.org/infrastructure/next-digest issued by https://invisible.forgejo.org/forgejo-next-digest +# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process # # https://codeberg.org/forgejo-experimental/forgejo # @@ -16,7 +14,7 @@ # vars.DOER: forgejo-experimental-ci # secrets.TOKEN: # -# http://invisible.forgejo.org/forgejo/forgejo +# http://private.forgejo.org/forgejo/forgejo # # Copies & sign a release from codeberg.org/forgejo-integration to codeberg.org/forgejo # @@ -38,20 +36,20 @@ on: jobs: publish: - runs-on: lxc-bookworm + runs-on: self-hosted if: vars.DOER != '' && vars.FORGEJO != '' && vars.TO_OWNER != '' && vars.FROM_OWNER != '' && secrets.TOKEN != '' steps: - - uses: https://data.forgejo.org/actions/checkout@v4 + - uses: actions/checkout@v3 - name: copy & sign - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.3.5 + uses: https://code.forgejo.org/forgejo/forgejo-build-publish/publish@v5 with: from-forgejo: ${{ vars.FORGEJO }} to-forgejo: ${{ vars.FORGEJO }} from-owner: ${{ vars.FROM_OWNER }} to-owner: ${{ vars.TO_OWNER }} repo: ${{ vars.REPO }} - release-notes: "See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/release-notes-published/{VERSION}.md" + release-notes: "See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#{ANCHOR}" ref-name: ${{ github.ref_name }} sha: ${{ github.sha }} from-token: ${{ secrets.TOKEN }} @@ -61,28 +59,31 @@ jobs: gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} verbose: ${{ vars.VERBOSE }} - - name: get trigger mirror issue - id: mirror - uses: https://data.forgejo.org/infrastructure/issue-action/get@v1.3.0 - with: - forgejo: https://code.forgejo.org - repository: forgejo/forgejo - labels: mirror-trigger - - - name: trigger the mirror - uses: https://data.forgejo.org/infrastructure/issue-action/set@v1.3.0 - with: - forgejo: https://code.forgejo.org - repository: forgejo/forgejo - token: ${{ secrets.LABEL_ISSUE_FORGEJO_MIRROR_TOKEN }} - numbers: ${{ steps.mirror.outputs.numbers }} - label-wait-if-exists: 3600 - label: trigger - - name: upgrade v*.next.forgejo.org - uses: https://data.forgejo.org/infrastructure/next-digest@v1.1.0 + run: | + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get -q install -y -qq curl + version="${{ github.ref_name }}" + version=${version##*v} + major=$(echo $version | sed -E -e 's/^([0-9]+).*/\1/') + # https://forgejo.org/docs/next/developer/infrastructure + curl -o /dev/null -sS https://v$major.next.forgejo.org/.well-known/wakeup-on-logs/forgejo-v$major + + - name: set up go for the DNS update below + if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != '' + uses: https://code.forgejo.org/actions/setup-go@v4 with: - url: https://placeholder:${{ secrets.TOKEN_NEXT_DIGEST }}@invisible.forgejo.org/infrastructure/next-digest - ref_name: '${{ github.ref_name }}' - image: 'codeberg.org/forgejo-experimental/forgejo' - tag_suffix: '-rootless' + go-version: "1.22" + check-latest: true + - name: update the _release.experimental DNS record + if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != '' + uses: https://code.forgejo.org/actions/ovh-dns-update@v1 + with: + subdomain: _release.experimental + domain: forgejo.com # there is a CNAME from .org to .com (for security reasons) + record-id: 5283602601 + value: v=${{ github.ref_name }} + ovh-app-key: ${{ secrets.OVH_APP_KEY }} + ovh-app-secret: ${{ secrets.OVH_APP_SECRET }} + ovh-consumer-key: ${{ secrets.OVH_CON_KEY }} diff --git a/.forgejo/workflows/release-notes-assistant-milestones.yml b/.forgejo/workflows/release-notes-assistant-milestones.yml deleted file mode 100644 index 7f77098357..0000000000 --- a/.forgejo/workflows/release-notes-assistant-milestones.yml +++ /dev/null @@ -1,36 +0,0 @@ -on: - workflow_dispatch: - - schedule: - - cron: '@daily' - -env: - RNA_VERSION: v1.2.5 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org - -jobs: - release-notes: - if: vars.ROLE == 'forgejo-coding' - runs-on: docker - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - - uses: https://data.forgejo.org/actions/setup-go@v5 - with: - go-version-file: "go.mod" - cache: false - - - name: apt install jq - run: | - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq - apt-get -q install -y -qq jq - - - name: update open milestones - run: | - set -x - curl -sS $GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/milestones?state=open | jq -r '.[] | .title' | while read forgejo version ; do - milestone="$forgejo $version" - go run code.forgejo.org/forgejo/release-notes-assistant@$RNA_VERSION --config .release-notes-assistant.yaml --storage milestone --storage-location "$milestone" --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} release $version - done diff --git a/.forgejo/workflows/release-notes-assistant.yml b/.forgejo/workflows/release-notes-assistant.yml deleted file mode 100644 index cdcd2e6fe4..0000000000 --- a/.forgejo/workflows/release-notes-assistant.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: issue-labels - -on: - pull_request_target: - types: - - edited - - synchronize - - labeled - -env: - RNA_VERSION: v1.2.5 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org - -jobs: - release-notes: - if: ( vars.ROLE == 'forgejo-coding' ) && contains(github.event.pull_request.labels.*.name, 'worth a release-note') - runs-on: docker - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - - name: event - run: | - cat <<'EOF' - ${{ toJSON(github.event.pull_request.labels.*.name) }} - EOF - cat <<'EOF' - ${{ toJSON(github.event) }} - EOF - - - uses: https://data.forgejo.org/actions/setup-go@v5 - with: - go-version-file: "go.mod" - cache: false - - - name: apt install jq - run: | - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq - apt-get -q install -y -qq jq - - - name: release-notes-assistant preview - run: | - go run code.forgejo.org/forgejo/release-notes-assistant@$RNA_VERSION --config .release-notes-assistant.yaml --storage pr --storage-location ${{ github.event.pull_request.number }} --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} preview ${{ github.event.pull_request.number }} diff --git a/.forgejo/workflows/renovate.yml b/.forgejo/workflows/renovate.yml index 5aa6c8cd98..a3c7c3d03d 100644 --- a/.forgejo/workflows/renovate.yml +++ b/.forgejo/workflows/renovate.yml @@ -8,31 +8,25 @@ name: renovate on: push: branches: - - renovate/** # self-test updates - paths: - - .forgejo/workflows/renovate.yml + - 'renovate/**' # self-test updates schedule: - cron: '0 0/2 * * *' - workflow_dispatch: env: RENOVATE_DRY_RUN: ${{ (github.event_name != 'schedule' && github.ref_name != github.event.repository.default_branch) && 'full' || '' }} RENOVATE_REPOSITORIES: ${{ github.repository }} - # fix because 10.0.0-58-7e1df53+gitea-1.22.0 < 10.0.0 for semver - # and codeberg api returns such versions from `git describe --tags` - # RENOVATE_X_PLATFORM_VERSION: 10.0.0+gitea-1.22.0 currently not needed jobs: renovate: - if: vars.ROLE == 'forgejo-coding' && secrets.RENOVATE_TOKEN != '' + if: ${{ secrets.RENOVATE_TOKEN != '' }} runs-on: docker container: - image: data.forgejo.org/renovate/renovate:41.1.4 + image: ghcr.io/visualon/renovate:37.421.2 steps: - name: Load renovate repo cache - uses: https://data.forgejo.org/actions/cache/restore@3624ceb22c1c5a301c8db4169662070a689d9ea8 # v4.1.1 + uses: https://code.forgejo.org/actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | .tmp/cache/renovate/repository @@ -65,7 +59,7 @@ jobs: - name: Save renovate repo cache if: always() && env.RENOVATE_DRY_RUN != 'full' - uses: https://data.forgejo.org/actions/cache/save@3624ceb22c1c5a301c8db4169662070a689d9ea8 # v4.1.1 + uses: https://code.forgejo.org/actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | .tmp/cache/renovate/repository diff --git a/.forgejo/workflows/testing-integration.yml b/.forgejo/workflows/testing-integration.yml deleted file mode 100644 index 9e5cfb92ed..0000000000 --- a/.forgejo/workflows/testing-integration.yml +++ /dev/null @@ -1,71 +0,0 @@ -# -# Additional integration tests designed to run once a day when -# `mirror.yml` pushes to https://codeberg.org/forgejo-integration/forgejo -# and send a notification via email should they fail. -# -# For debug purposes: -# -# - uncomment [on].pull_request -# - swap 'forgejo-integration' and 'forgejo-coding' -# - open a pull request at https://codeberg.org/forgejo/forgejo and fix things -# - swap 'forgejo-integration' and 'forgejo-coding' -# - comment [on].pull_request -# - -name: testing-integration - -on: -# pull_request: - push: - tags: 'v[0-9]+.[0-9]+.*' - branches: - - 'forgejo' - - 'v*/forgejo' - -jobs: - test-unit: -# if: vars.ROLE == 'forgejo-coding' - if: vars.ROLE == 'forgejo-integration' - runs-on: docker - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - 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' - timeout-minutes: 120 - env: - RACE_ENABLED: 'true' - TAGS: bindata - test-sqlite: -# if: vars.ROLE == 'forgejo-coding' - if: vars.ROLE == 'forgejo-integration' - runs-on: docker - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - 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' - timeout-minutes: 120 - env: - TAGS: sqlite sqlite_unlock_notify - RACE_ENABLED: true - TEST_TAGS: sqlite sqlite_unlock_notify - USE_REPO_TEST_DIR: 1 diff --git a/.forgejo/workflows/testing.yml b/.forgejo/workflows/testing.yml index 3897b7ed51..a0736434d2 100644 --- a/.forgejo/workflows/testing.yml +++ b/.forgejo/workflows/testing.yml @@ -6,278 +6,303 @@ on: branches: - 'forgejo*' - 'v*/forgejo*' - workflow_dispatch: jobs: backend-checks: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime + image: 'docker.io/node:20-bookworm' steps: - name: event info run: | cat <<'EOF' ${{ toJSON(github) }} EOF - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - run: su forgejo -c 'make deps-backend deps-tools' - - run: su forgejo -c 'make --always-make -j$(nproc) lint-backend tidy-check swagger-check lint-swagger fmt-check swagger-validate' # ensure the "go-licenses" make target runs - - uses: ./.forgejo/workflows-composite/build-backend + - uses: https://code.forgejo.org/actions/checkout@v3 + - uses: https://code.forgejo.org/actions/setup-go@v4 + with: + go-version: "1.22" + check-latest: true + - run: make deps-backend deps-tools + - run: make --always-make -j$(nproc) lint-backend tidy-check swagger-check fmt-check swagger-validate # ensure the "go-licenses" make target runs frontend-checks: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime + image: 'docker.io/node:20-bookworm' steps: - - uses: https://data.forgejo.org/actions/checkout@v4 + - uses: https://code.forgejo.org/actions/checkout@v3 - run: make deps-frontend - run: make lint-frontend - run: make checks-frontend - run: make test-frontend-coverage - run: make frontend - - name: Install zstd for cache saving - # works around https://github.com/actions/cache/issues/1169, because the - # consuming job has zstd and doesn't restore the cache otherwise - run: | - apt-get update -qq - apt-get -q install -qq -y zstd - - name: "Cache frontend build for playwright testing" - uses: https://data.forgejo.org/actions/cache/save@v4 - with: - path: ${{github.workspace}}/public/assets - key: frontend-build-${{ github.sha }} test-unit: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker needs: [backend-checks, frontend-checks] container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime + image: 'docker.io/node:20-bookworm' services: elasticsearch: - image: data.forgejo.org/oci/bitnami/elasticsearch:7 - options: --tmpfs /bitnami/elasticsearch/data + image: elasticsearch:7.17.22 env: discovery.type: single-node ES_JAVA_OPTS: "-Xms512m -Xmx512m" minio: - image: data.forgejo.org/oci/bitnami/minio:2024.8.17 + image: bitnami/minio:2024.3.30 options: >- - --hostname gitea.minio --tmpfs /bitnami/minio/data:noatime + --hostname gitea.minio env: MINIO_DOMAIN: minio MINIO_ROOT_USER: 123456 MINIO_ROOT_PASSWORD: 12345678 steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - name: install git >= 2.42 - uses: ./.forgejo/workflows-composite/apt-install-from + - uses: https://code.forgejo.org/actions/checkout@v3 + - uses: https://code.forgejo.org/actions/setup-go@v4 with: - packages: git - - name: test release-notes-assistant.sh + go-version: "1.22" + - run: | + git config --add safe.directory '*' + adduser --quiet --comment forgejo --disabled-password forgejo + chown -R forgejo:forgejo . + - name: install git >= 2.42 run: | - apt-get -q install -qq -y jq - ./release-notes-assistant.sh test_main - - uses: ./.forgejo/workflows-composite/build-backend + export DEBIAN_FRONTEND=noninteractive + echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list + apt-get update -qq + apt-get -q install -qq -y git + rm /etc/apt/sources.list.d/testing.list + apt-get update -qq + - run: | + su forgejo -c 'make deps-backend' + - run: | + su forgejo -c 'make backend' + env: + TAGS: bindata - run: | su forgejo -c 'make test-backend test-check' - timeout-minutes: 120 + timeout-minutes: 50 env: RACE_ENABLED: 'true' TAGS: bindata TEST_ELASTICSEARCH_URL: http://elasticsearch:9200 - TEST_MINIO_ENDPOINT: minio:9000 - test-e2e: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' + test-remote-cacher: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker needs: [backend-checks, frontend-checks] container: - image: 'data.forgejo.org/oci/playwright:latest' - options: --tmpfs /tmp:exec,noatime - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - with: - fetch-depth: 20 - - uses: ./.forgejo/workflows-composite/setup-env - - name: "Restore frontend build" - uses: https://data.forgejo.org/actions/cache/restore@v4 - id: cache-frontend - with: - path: ${{github.workspace}}/public/assets - key: frontend-build-${{ github.sha }} - - name: "Build frontend (if not cached)" - if: steps.cache-frontend.outputs.cache-hit != 'true' - run: | - su forgejo -c 'make deps-frontend frontend' - - uses: ./.forgejo/workflows-composite/build-backend - - name: Decide to run all tests - id: run-all - if: contains(github.event.pull_request.labels.*.name, 'run-all-playwright-tests') || contains(github.event.pull_request.title, 'playwright') - run: | - echo "all=1" >> "$GITHUB_OUTPUT" - - name: Get changed files - id: changed-files - uses: https://data.forgejo.org/tj-actions/changed-files@v46 - with: - separator: '\n' - - run: | - su forgejo -c 'make generate test-e2e-sqlite' - timeout-minutes: 120 - env: - USE_REPO_TEST_DIR: 1 - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 - CHANGED_FILES: ${{steps.changed-files.outputs.all_changed_files}} - RUN_ALL: ${{steps.run-all.all}} - - name: Upload test artifacts on failure - if: failure() - uses: https://data.forgejo.org/forgejo/upload-artifact@v4 - with: - name: test-artifacts.zip - path: tests/e2e/test-artifacts/ - retention-days: 3 - test-remote-cacher: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' - runs-on: docker - needs: [backend-checks, frontend-checks, test-unit] - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime - name: ${{ format('test-remote-cacher ({0})', matrix.cacher.name) }} + image: 'docker.io/node:20-bookworm' strategy: matrix: cacher: - - name: redis - image: data.forgejo.org/oci/bitnami/redis:7.2 - options: --tmpfs /bitnami/redis/data:noatime - - name: redict - image: registry.redict.io/redict:7.3.0-scratch - options: --tmpfs /data:noatime - - name: valkey - image: data.forgejo.org/oci/bitnami/valkey:7.2 - options: --tmpfs /bitnami/redis/data:noatime - - name: garnet - image: ghcr.io/microsoft/garnet-alpine:1.0.14 - options: --tmpfs /data:noatime + # redis + - image: redis:7.2 + port: 6379 + # redict + - image: registry.redict.io/redict:7.3.0-scratch + port: 6379 + # garnet + - image: ghcr.io/microsoft/garnet-alpine:1.0.14 + port: 6379 services: cacher: image: ${{ matrix.cacher.image }} options: ${{ matrix.cacher.options }} steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - name: install git >= 2.42 - uses: ./.forgejo/workflows-composite/apt-install-from + - uses: https://code.forgejo.org/actions/checkout@v3 + - uses: https://code.forgejo.org/actions/setup-go@v4 with: - packages: git - - uses: ./.forgejo/workflows-composite/build-backend + go-version: "1.22" + - run: | + git config --add safe.directory '*' + adduser --quiet --comment forgejo --disabled-password forgejo + chown -R forgejo:forgejo . + - name: install git >= 2.42 + run: | + export DEBIAN_FRONTEND=noninteractive + echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list + apt-get update -qq + apt-get -q install -qq -y git + rm /etc/apt/sources.list.d/testing.list + apt-get update -qq + - run: | + su forgejo -c 'make deps-backend' + - run: | + su forgejo -c 'make backend' + env: + TAGS: bindata - run: | su forgejo -c 'make test-remote-cacher test-check' - timeout-minutes: 120 + timeout-minutes: 50 env: RACE_ENABLED: 'true' TAGS: bindata TEST_REDIS_SERVER: cacher:${{ matrix.cacher.port }} test-mysql: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker needs: [backend-checks, frontend-checks] container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime + image: 'docker.io/node:20-bookworm' services: mysql: - image: 'data.forgejo.org/oci/bitnami/mysql:8.4' + image: 'docker.io/mysql:8-debian' env: - ALLOW_EMPTY_PASSWORD: yes + MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_DATABASE: testgitea - # - # See also https://codeberg.org/forgejo/forgejo/issues/976 - # - MYSQL_EXTRA_FLAGS: --innodb-adaptive-flushing=OFF --innodb-buffer-pool-size=4G --innodb-log-buffer-size=128M --innodb-flush-log-at-trx-commit=0 --innodb-flush-log-at-timeout=30 --innodb-flush-method=nosync --innodb-fsync-threshold=1000000000 --disable-log-bin - options: --tmpfs /bitnami/mysql/data:noatime + # + # See also https://codeberg.org/forgejo/forgejo/issues/976 + # + cmd: ['mysqld', '--innodb-adaptive-flushing=OFF', '--innodb-buffer-pool-size=4G', '--innodb-log-buffer-size=128M', '--innodb-flush-log-at-trx-commit=0', '--innodb-flush-log-at-timeout=30', '--innodb-flush-method=nosync', '--innodb-fsync-threshold=1000000000'] steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - name: install dependencies & git >= 2.42 - uses: ./.forgejo/workflows-composite/apt-install-from + - uses: https://code.forgejo.org/actions/checkout@v3 + - uses: https://code.forgejo.org/actions/setup-go@v4 with: - packages: git git-annex-standalone git-lfs - - uses: ./.forgejo/workflows-composite/build-backend + go-version: "1.22" + - name: install dependencies & git >= 2.42 + run: | + export DEBIAN_FRONTEND=noninteractive + echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list + apt-get update -qq + apt-get install --no-install-recommends -qq -y git git-lfs + rm /etc/apt/sources.list.d/testing.list + apt-get update -qq + wget -O- http://neuro.debian.net/lists/bookworm.de-fzj.libre | tee /etc/apt/sources.list.d/neurodebian.sources.list + apt-key adv --recv-keys --keyserver hkps://keyserver.ubuntu.com 0xA5D32F012649A5A9 + apt-get update -qq + apt-get install --no-install-recommends -qq -y git-annex-standalone + - name: setup user and permissions + run: | + git config --add safe.directory '*' + adduser --quiet --comment forgejo --disabled-password forgejo + chown -R forgejo:forgejo . + - run: | + su forgejo -c 'make deps-backend' + - run: | + su forgejo -c 'make backend' + env: + TAGS: bindata - run: | su forgejo -c 'make test-mysql-migration test-mysql' + timeout-minutes: 50 env: + TAGS: bindata USE_REPO_TEST_DIR: 1 test-pgsql: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker needs: [backend-checks, frontend-checks] container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime + image: 'docker.io/node:20-bookworm' services: minio: - image: data.forgejo.org/oci/bitnami/minio:2024.8.17 + image: bitnami/minio:2024.3.30 env: MINIO_ROOT_USER: 123456 MINIO_ROOT_PASSWORD: 12345678 - options: --tmpfs /bitnami/minio/data ldap: - image: data.forgejo.org/oci/test-openldap:latest + image: docker.io/gitea/test-openldap:latest pgsql: - image: data.forgejo.org/oci/bitnami/postgresql:16 + image: 'docker.io/postgres:15' env: - POSTGRESQL_DATABASE: test - POSTGRESQL_PASSWORD: postgres - POSTGRESQL_FSYNC: off - POSTGRESQL_EXTRA_FLAGS: -c full_page_writes=off - options: --tmpfs /bitnami/postgresql + POSTGRES_DB: test + POSTGRES_PASSWORD: postgres steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - name: install dependencies & git >= 2.42 - uses: ./.forgejo/workflows-composite/apt-install-from + - uses: https://code.forgejo.org/actions/checkout@v3 + - uses: https://code.forgejo.org/actions/setup-go@v4 with: - packages: git git-annex-standalone git-lfs - - uses: ./.forgejo/workflows-composite/build-backend + go-version: "1.22" + - name: install dependencies & git >= 2.42 + run: | + export DEBIAN_FRONTEND=noninteractive + echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list + apt-get update -qq + apt-get install --no-install-recommends -qq -y git git-lfs + rm /etc/apt/sources.list.d/testing.list + apt-get update -qq + wget -O- http://neuro.debian.net/lists/bookworm.de-fzj.libre | tee /etc/apt/sources.list.d/neurodebian.sources.list + apt-key adv --recv-keys --keyserver hkps://keyserver.ubuntu.com 0xA5D32F012649A5A9 + apt-get update -qq + apt-get install --no-install-recommends -qq -y git-annex-standalone + - name: setup user and permissions + run: | + git config --add safe.directory '*' + adduser --quiet --comment forgejo --disabled-password forgejo + chown -R forgejo:forgejo . + - run: | + su forgejo -c 'make deps-backend' + - run: | + su forgejo -c 'make backend' + env: + TAGS: bindata - run: | su forgejo -c 'make test-pgsql-migration test-pgsql' + timeout-minutes: 50 env: + TAGS: bindata RACE_ENABLED: true USE_REPO_TEST_DIR: 1 TEST_LDAP: 1 test-sqlite: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker needs: [backend-checks, frontend-checks] container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime + image: 'docker.io/node:20-bookworm' steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - name: install dependencies & git >= 2.42 - uses: ./.forgejo/workflows-composite/apt-install-from + - uses: https://code.forgejo.org/actions/checkout@v3 + - uses: https://code.forgejo.org/actions/setup-go@v4 with: - packages: git git-annex-standalone git-lfs - - uses: ./.forgejo/workflows-composite/build-backend + go-version: "1.22" + - name: install dependencies & git >= 2.42 + run: | + export DEBIAN_FRONTEND=noninteractive + echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list + apt-get update -qq + apt-get install --no-install-recommends -qq -y git git-lfs + rm /etc/apt/sources.list.d/testing.list + apt-get update -qq + wget -O- http://neuro.debian.net/lists/bookworm.de-fzj.libre | tee /etc/apt/sources.list.d/neurodebian.sources.list + apt-key adv --recv-keys --keyserver hkps://keyserver.ubuntu.com 0xA5D32F012649A5A9 + apt-get update -qq + apt-get install --no-install-recommends -qq -y git-annex-standalone + - name: setup user and permissions + run: | + git config --add safe.directory '*' + adduser --quiet --comment forgejo --disabled-password forgejo + chown -R forgejo:forgejo . + - run: | + su forgejo -c 'make deps-backend' + - run: | + su forgejo -c 'make backend' + env: + TAGS: bindata sqlite sqlite_unlock_notify - run: | su forgejo -c 'make test-sqlite-migration test-sqlite' + timeout-minutes: 50 env: - TAGS: sqlite sqlite_unlock_notify + TAGS: bindata sqlite sqlite_unlock_notify RACE_ENABLED: true TEST_TAGS: sqlite sqlite_unlock_notify USE_REPO_TEST_DIR: 1 security-check: + if: ${{ !startsWith(vars.ROLE, 'forgejo-') }} runs-on: docker needs: - test-sqlite - test-pgsql - test-mysql + - test-remote-cacher + - test-unit container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime + image: 'docker.io/node:20-bookworm' steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - run: su forgejo -c 'make deps-backend deps-tools' - - run: su forgejo -c 'make security-check' + - uses: https://code.forgejo.org/actions/checkout@v3 + - uses: https://code.forgejo.org/actions/setup-go@v4 + with: + go-version: "1.22" + check-latest: true + - run: make deps-backend deps-tools + - run: make security-check diff --git a/.forgejo/issue_template/bug-report-ui.yaml b/.gitea/issue_template/bug-report-ui.yaml similarity index 57% rename from .forgejo/issue_template/bug-report-ui.yaml rename to .gitea/issue_template/bug-report-ui.yaml index 8bb7bf1d49..09513d08e7 100644 --- a/.forgejo/issue_template/bug-report-ui.yaml +++ b/.gitea/issue_template/bug-report-ui.yaml @@ -1,41 +1,28 @@ name: 🦋 Bug Report (web interface / frontend) description: Something doesn't look quite as it should? Report it here! -title: "bug: " +title: "[BUG] " labels: ["bug/new-report", "forgejo/ui"] body: - type: markdown attributes: value: | - **NOTE: If your issue is a security concern, please email ([security.txt](https://forgejo.org/.well-known/security.txt)) instead of opening a public issue.** + **NOTE: If your issue is a security concern, please email (GPG: `A4676E79`) instead of opening a public issue.** - type: markdown attributes: value: | - Please speak English, as this is the language all maintainers can speak and write. - Be as clear and concise as possible. A very verbose report is harder to interpret in a concrete way. - Be civil, and follow the [Forgejo Code of Conduct](https://codeberg.org/forgejo/code-of-conduct). - - Take a moment to [check that your issue hasn't been reported before](https://codeberg.org/forgejo/forgejo/issues?q=&type=all&labels=78137). -- type: dropdown - id: can-reproduce - attributes: - label: Can you reproduce the bug on the Forgejo test instance? - description: | - Please try reproducing your issue at https://dev.next.forgejo.org. - It is running the latest development branch and will confirm the problem is not already fixed. - If you can reproduce it, provide a URL in the description. - options: - - "Yes" - - "No" - validations: - required: true + - Please make sure you are using the latest release of Forgejo and take a moment to [check that your issue hasn't been reported before](https://codeberg.org/forgejo/forgejo/issues?q=&type=all&labels=78137). + - Please give all relevant information below for bug reports, as incomplete details may result in the issue not being considered. - type: textarea id: description attributes: label: Description description: | - Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see above). - If you think this is a JavaScript error, include a copy of the JavaScript console. - validations: - required: true + Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below). + If you think this is a JavaScript error, show us the JavaScript console. + If the error appears to relate to Forgejo the server, please also give us `DEBUG` level logs. (See https://forgejo.org/docs/latest/admin/logging-documentation/) - type: textarea id: screenshots attributes: @@ -48,6 +35,20 @@ body: attributes: label: Forgejo Version description: Forgejo version (or commit reference) your instance is running + validations: + required: true +- type: dropdown + id: can-reproduce + attributes: + label: Can you reproduce the bug on Forgejo Next? + description: | + Please try reproducing your issue at [Forgejo Next](https://next.forgejo.org). + If you can reproduce it, please provide a URL in the Description field. + options: + - "Yes" + - "No" + validations: + required: true - type: input id: browser-ver attributes: @@ -55,3 +56,8 @@ body: description: The browser and version that you are using to access Forgejo validations: required: true +- type: input + id: os-ver + attributes: + label: Operating System + description: The operating system you are using to access Forgejo diff --git a/.forgejo/issue_template/bug-report.yaml b/.gitea/issue_template/bug-report.yaml similarity index 64% rename from .forgejo/issue_template/bug-report.yaml rename to .gitea/issue_template/bug-report.yaml index a2b50dbca2..6fab61fcdc 100644 --- a/.forgejo/issue_template/bug-report.yaml +++ b/.gitea/issue_template/bug-report.yaml @@ -1,38 +1,26 @@ name: 🐛 Bug Report (server / backend) description: Found something you weren't expecting? Report it here! -title: "bug: " +title: "[BUG] " labels: bug/new-report body: - type: markdown attributes: value: | - **NOTE: If your issue is a security concern, please email ([security.txt](https://forgejo.org/.well-known/security.txt)) instead of opening a public issue.** + **NOTE: If your issue is a security concern, please email (GPG: `A4676E79`) instead of opening a public issue.** - type: markdown attributes: value: | - Please speak English, as this is the language all maintainers can speak and write. - Be as clear and concise as possible. A very verbose report is harder to interpret in a concrete way. - Be civil, and follow the [Forgejo Code of Conduct](https://codeberg.org/forgejo/code-of-conduct). - - Take a moment to [check that your issue hasn't been reported before](https://codeberg.org/forgejo/forgejo/issues?q=&type=all&labels=78137). -- type: dropdown - id: can-reproduce - attributes: - label: Can you reproduce the bug on the Forgejo test instance? - description: | - Please try reproducing your issue at https://dev.next.forgejo.org. - It is running the latest development branch and will confirm the problem is not already fixed. - If you can reproduce it, provide a URL in the description. - options: - - "Yes" - - "No" - validations: - required: true + - Please make sure you are using the latest release of Forgejo and take a moment to [check that your issue hasn't been reported before](https://codeberg.org/forgejo/forgejo/issues?q=&type=all&labels=78137). + - Please give all relevant information below for bug reports, as incomplete details may result in the issue not being considered. - type: textarea id: description attributes: label: Description description: | - Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see above). + Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below). validations: required: true - type: input @@ -40,14 +28,18 @@ body: attributes: label: Forgejo Version description: Forgejo version (or commit reference) of your instance -- type: textarea - id: run-info + validations: + required: true +- type: dropdown + id: can-reproduce attributes: - label: How are you running Forgejo? + label: Can you reproduce the bug on Forgejo Next? description: | - Please include information on whether you built Forgejo yourself, used one of our downloads, or are using some other package. - Please also tell us how you are running Forgejo, e.g. if it is being run from a container, a command-line, systemd etc. - If you are using a package or systemd tell us what distribution you are using. + Please try reproducing your issue at [Forgejo Next](https://next.forgejo.org). + If you can reproduce it, please provide a URL in the Description field. + options: + - "Yes" + - "No" validations: required: true - type: textarea @@ -61,6 +53,31 @@ body: Please copy and paste your logs here, with any sensitive information (e.g. API keys) removed/hidden. You can wrap your logs in `
...
` tags so it doesn't take up too much space in the issue. +- type: textarea + id: screenshots + attributes: + label: Screenshots + description: If this issue involves the Web Interface, please provide one or more screenshots +- type: input + id: git-ver + attributes: + label: Git Version + description: The version of git running on the server +- type: input + id: os-ver + attributes: + label: Operating System + description: The operating system you are using to run Forgejo +- type: textarea + id: run-info + attributes: + label: How are you running Forgejo? + description: | + Please include information on whether you built Forgejo yourself, used one of our downloads, or are using some other package. + Please also tell us how you are running Forgejo, e.g. if it is being run from docker, a command-line, systemd etc. + If you are using a package or systemd tell us what distribution you are using. + validations: + required: true - type: dropdown id: database attributes: diff --git a/.forgejo/issue_template/config.yml b/.gitea/issue_template/config.yml similarity index 86% rename from .forgejo/issue_template/config.yml rename to .gitea/issue_template/config.yml index f2ea8d945a..0e3caf9280 100644 --- a/.forgejo/issue_template/config.yml +++ b/.gitea/issue_template/config.yml @@ -1,7 +1,7 @@ contact_links: - name: 🔓 Security Reports url: mailto:security@forgejo.org - about: "Please email (See https://forgejo.org/.well-known/security.txt)." + about: "Please email (GPG: `A4676E79`) instead of opening a public issue." - name: 💬 Matrix Chat Room url: https://matrix.to/#/#forgejo-chat:matrix.org about: Please ask questions and discuss configuration or deployment problems here. diff --git a/.forgejo/issue_template/feature-request.yaml b/.gitea/issue_template/feature-request.yaml similarity index 98% rename from .forgejo/issue_template/feature-request.yaml rename to .gitea/issue_template/feature-request.yaml index 0996680cb4..4b10bea145 100644 --- a/.forgejo/issue_template/feature-request.yaml +++ b/.gitea/issue_template/feature-request.yaml @@ -1,6 +1,6 @@ name: 💡 Feature Request description: Got an idea for a feature that Forgejo doesn't have yet? Suggest it here! -title: "feat: " +title: "[FEAT] " labels: ["enhancement/feature"] body: - type: markdown diff --git a/.gitea/pull_request_template.md b/.gitea/pull_request_template.md new file mode 100644 index 0000000000..00b874fd5b --- /dev/null +++ b/.gitea/pull_request_template.md @@ -0,0 +1,13 @@ +--- + +name: "Pull Request Template" +about: "Template for all Pull Requests" +labels: + +- test/needed + +--- + diff --git a/.gitignore b/.gitignore index 744e24a09a..ebbed981e1 100644 --- a/.gitignore +++ b/.gitignore @@ -37,7 +37,6 @@ _testmain.go *coverage.out coverage.all -coverage/ cpu.out /modules/migration/bindata.go @@ -57,7 +56,6 @@ cpu.out /gitea-vet /debug /integrations.test -/forgejo /bin /dist @@ -74,7 +72,6 @@ cpu.out /tests/e2e/reports /tests/e2e/test-artifacts /tests/e2e/test-snapshots -/tests/e2e/.auth /tests/*.ini /tests/**/*.git/**/*.sample /node_modules @@ -118,12 +115,6 @@ prime/ *_source.tar.bz2 .DS_Store -# Direnv configuration -/.envrc - -# nix-direnv generated files -.direnv/ - # Make evidence files /.make_evidence diff --git a/.golangci.yml b/.golangci.yml index 532132838d..57f3c86f05 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,9 +1,7 @@ -version: "2" -output: - sort-order: - - file linters: - default: none + enable-all: false + disable-all: true + fast: false enable: - bidichk - depguard @@ -11,155 +9,140 @@ linters: - errcheck - forbidigo - gocritic + - gofmt + - gofumpt + - gosimple - govet - ineffassign - nakedret - nolintlint - revive - staticcheck - - testifylint + - stylecheck + - typecheck - unconvert - - unparam - unused - - usetesting + - unparam - wastedassign - settings: - depguard: - rules: - main: - deny: - - pkg: encoding/json - desc: use gitea's modules/json instead of encoding/json - - pkg: github.com/unknwon/com - desc: use gitea's util and replacements - - pkg: io/ioutil - desc: use os or io instead - - pkg: golang.org/x/exp - desc: it's experimental and unreliable - - pkg: forgejo.org/modules/git/internal - desc: do not use the internal package, use AddXxx function instead - - pkg: gopkg.in/ini.v1 - desc: do not use the ini package, use gitea's config system instead - - pkg: github.com/minio/sha256-simd - desc: use crypto/sha256 instead, see https://codeberg.org/forgejo/forgejo/pulls/1528 - gocritic: - disabled-checks: - - ifElseChain - revive: - severity: error - rules: - - name: atomic - - name: bare-return - - name: blank-imports - - name: constant-logical-expr - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: duplicated-imports - - name: empty-lines - - name: error-naming - - name: error-return - - name: error-strings - - name: errorf - - name: exported - - name: identical-branches - - name: if-return - - name: increment-decrement - - name: indent-error-flow - - name: modifies-value-receiver - - name: package-comments - - name: range - - name: receiver-naming - - name: redefines-builtin-id - - name: string-of-int - - name: superfluous-else - - name: time-naming - - name: unconditional-recursion - - name: unexported-return - - name: unreachable-code - - name: var-declaration - - name: var-naming - - name: redefines-builtin-id - disabled: true - staticcheck: - checks: - - all - testifylint: - disable: - - go-require - exclusions: - generated: lax - presets: - - comments - - common-false-positives - - legacy - - std-error-handling + +run: + timeout: 10m + skip-dirs: + - node_modules + - public + - web_src + +output: + sort-results: true + sort-order: [file] + show-stats: true + +linters-settings: + stylecheck: + checks: ["all", "-ST1005", "-ST1003"] + nakedret: + max-func-lines: 0 + gocritic: + disabled-checks: + - ifElseChain + - singleCaseSwitch # Every time this occurred in the code, there was no other way. + revive: + severity: error rules: - - linters: - - nolintlint - path: models/db/sql_postgres_with_schema.go - - linters: - - dupl - - errcheck - - gocyclo - - gosec - - staticcheck - - unparam - path: _test\.go - - linters: - - dupl - - errcheck - - gocyclo - - gosec - path: models/migrations/v - - linters: - - forbidigo - path: cmd - - linters: - - dupl - text: (?i)webhook - - linters: - - gocritic - text: (?i)`ID' should not be capitalized - - linters: - - deadcode - - unused - text: (?i)swagger - - linters: - - staticcheck - text: (?i)argument x is overwritten before first use - - linters: - - gocritic - text: '(?i)commentFormatting: put a space between `//` and comment text' - - linters: - - gocritic - text: '(?i)exitAfterDefer:' - - linters: - - staticcheck - text: "(ST1005|ST1003|QF1001):" - paths: - - node_modules - - public - - web_src - - third_party$ - - builtin$ - - examples$ + - name: atomic + - name: bare-return + - name: blank-imports + - name: constant-logical-expr + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: duplicated-imports + - name: empty-lines + - name: error-naming + - name: error-return + - name: error-strings + - name: errorf + - name: exported + - name: identical-branches + - name: if-return + - name: increment-decrement + - name: indent-error-flow + - name: modifies-value-receiver + - name: package-comments + - name: range + - name: receiver-naming + - name: redefines-builtin-id + - name: string-of-int + - name: superfluous-else + - name: time-naming + - name: unconditional-recursion + - name: unexported-return + - name: unreachable-code + - name: var-declaration + - name: var-naming + gofumpt: + extra-rules: true + depguard: + rules: + main: + deny: + - pkg: encoding/json + desc: use gitea's modules/json instead of encoding/json + - pkg: github.com/unknwon/com + desc: use gitea's util and replacements + - pkg: io/ioutil + desc: use os or io instead + - pkg: golang.org/x/exp + desc: it's experimental and unreliable + - pkg: code.gitea.io/gitea/modules/git/internal + desc: do not use the internal package, use AddXxx function instead + - pkg: gopkg.in/ini.v1 + desc: do not use the ini package, use gitea's config system instead + - pkg: github.com/minio/sha256-simd + desc: use crypto/sha256 instead, see https://codeberg.org/forgejo/forgejo/pulls/1528 + issues: max-issues-per-linter: 0 max-same-issues: 0 -formatters: - enable: - - gofmt - - gofumpt - settings: - gofumpt: - extra-rules: true - exclusions: - generated: lax - paths: - - node_modules - - public - - web_src - - third_party$ - - builtin$ - - examples$ + exclude-dirs: [node_modules, public, web_src] + exclude-case-sensitive: true + exclude-rules: + - path: models/db/sql_postgres_with_schema.go + linters: + - nolintlint + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + - unparam + - staticcheck + - path: models/migrations/v + linters: + - gocyclo + - errcheck + - dupl + - gosec + - path: cmd + linters: + - forbidigo + - text: "webhook" + linters: + - dupl + - text: "`ID' should not be capitalized" + linters: + - gocritic + - text: "swagger" + linters: + - unused + - deadcode + - text: "argument x is overwritten before first use" + linters: + - staticcheck + - text: "commentFormatting: put a space between `//` and comment text" + linters: + - gocritic + - text: "exitAfterDefer:" + linters: + - gocritic diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 88ff1591a4..0000000000 --- a/.mailmap +++ /dev/null @@ -1,2 +0,0 @@ -Unknwon -Unknwon 无闻 diff --git a/.release-notes-assistant.yaml b/.release-notes-assistant.yaml deleted file mode 100644 index b3e5a8e665..0000000000 --- a/.release-notes-assistant.yaml +++ /dev/null @@ -1,27 +0,0 @@ -categorize: './release-notes-assistant.sh' -branch-development: 'forgejo' -branch-pattern: 'v*/forgejo' -branch-find-version: 'v(?P\d+\.\d+)/forgejo' -branch-to-version: '${version}.0' -branch-from-version: 'v%[1]d.%[2]d/forgejo' -tag-from-version: 'v%[1]d.%[2]d.%[3]d' -branch-known: - - 'v7.0/forgejo' -cleanup-line: 'sed -Ee "s/^(feat|fix):\s*//g" -e "s/^\[WIP\] //" -e "s/^WIP: //" -e "s;\[(UI|BUG|FEAT|v.*?/forgejo)\]\s*;;g"' -render-header: | - - ## Release notes -comment: | -
- Where does that come from? - The following is a preview of the release notes for this pull request, as they will appear in the upcoming release. They are derived from the content of the `%[2]s/%[3]s.md` file, if it exists, or the title of the pull request. They were also added at the bottom of the description of this pull request for easier reference. - - This message and the release notes originate from a call to the [release-notes-assistant](https://code.forgejo.org/forgejo/release-notes-assistant). - - ```diff - %[4]s - ``` - -
- - %[1]s diff --git a/BSDmakefile b/BSDmakefile index f4a819ff93..79696eadcf 100644 --- a/BSDmakefile +++ b/BSDmakefile @@ -36,6 +36,10 @@ GARGS = "--no-print-directory" JARG = -j$(.MAKE.JOBS) .endif +# bmake prefers out-of-source builds and tries to cd into ./obj (among others) +# where possible. GNU Make doesn't, so override that value. +.OBJDIR: ./ + # The GNU convention is to use the lowercased `prefix` variable/macro to # specify the installation directory. Humor them. GPREFIX = @@ -44,12 +48,11 @@ GPREFIX = .endif .BEGIN: .SILENT - which $(GMAKE) >/dev/null || (printf "Error: GNU Make is required!\n\n" 1>&2 && false) + which $(GMAKE) || (printf "Error: GNU Make is required!\n\n" 1>&2 && false) -.PHONY: EMPTY -EMPTY: .SILENT - $(GMAKE) $(GPREFIX) $(GARGS) $(JARG) +.PHONY: FRC +$(.TARGETS): FRC + $(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG) -.PHONY: $(.TARGETS) -$(.TARGETS): .SILENT - $(GMAKE) $(GPREFIX) $(GARGS) $(JARG) $@ +.DONE .DEFAULT: .SILENT + $(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG) diff --git a/CODEOWNERS b/CODEOWNERS index 34cdceca09..e30d2c42b4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,37 +6,35 @@ # Please mind the alphabetic order of reviewers. +# Files related to the CI of the Forgejo project. +.forgejo/.* @dachary @earl-warren + # Files related to frontend development. # Javascript and CSS code. -web_src/.* @beowulf @gusted -web_src/css/.* @0ko +web_src/.* @caesar @crystal @gusted # HTML templates used by the backend. -templates/.* @beowulf @gusted +templates/.* @caesar @crystal @gusted ## the issue sidebar was touched by fnetx templates/repo/issue/view_content/sidebar.* @fnetx -# Playwright tests -tests/e2e/.* @fnetx - # Files related to Go development. # The modules usually don't require much knowledge about Forgejo and could # be reviewed by Go developers. -modules/.* @gusted +modules/.* @dachary @earl-warren @gusted # Models has code related to SQL queries, general database knowledge and XORM. -models/.* @gusted +models/.* @dachary @earl-warren @gusted # The routers directory contains the most amount code that requires a good grasp # of how Forgejo comes together. It's tedious to write good integration testing # for code that lives in here. -routers/.* @gusted +routers/.* @dachary @earl-warren @gusted -# Let locale changes be checked by the translation team. -options/locale/.* @0ko -options/locale_next/.* @0ko +# Let new strings be checked by the translation team. +options/locale/locale_en-US.ini @0ko # Personal interest .*/webhook.* @oliverpool diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 18b613d3bd..77c6463fbf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,4 +4,4 @@ The Forgejo project is run by a community of people who are expected to follow t Sensitive security-related issues should be reported to [security@forgejo.org](mailto:security@forgejo.org) using [encryption](https://keyoxide.org/security@forgejo.org). -You can find links to the different aspects of Developer documentation on this page: [Forgejo Contributor Guide](https://forgejo.org/docs/next/contributor/). +You can find links to the different aspects of Developer documentation on this page: [Forgejo developer guide](https://forgejo.org/docs/next/developer/). diff --git a/Dockerfile b/Dockerfile index ebd4e4f5e3..b97ee4b6ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx +FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx -FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.22 AS build-env +FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.22-alpine3.20 as build-env ARG GOPROXY -ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct} +ENV GOPROXY=${GOPROXY:-direct} ARG RELEASE_VERSION ARG TAGS="sqlite sqlite_unlock_notify" @@ -30,13 +30,13 @@ RUN cp /*-alpine-linux-musl*/lib/ld-musl-*.so.1 /lib || true RUN apk --no-cache add build-base git nodejs npm -COPY . ${GOPATH}/src/forgejo.org -WORKDIR ${GOPATH}/src/forgejo.org +COPY . ${GOPATH}/src/code.gitea.io/gitea +WORKDIR ${GOPATH}/src/code.gitea.io/gitea -RUN make clean-no-bindata +RUN make clean RUN make frontend RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini -RUN LDFLAGS="-buildid=" make FORGEJO_GENERATE_SKIP_HASH=true RELEASE_VERSION=$RELEASE_VERSION GOFLAGS="-trimpath" go-check generate-backend static-executable && xx-verify gitea +RUN make RELEASE_VERSION=$RELEASE_VERSION go-check generate-backend static-executable && xx-verify gitea # Copy local files COPY docker/root /tmp/local @@ -47,11 +47,11 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \ /tmp/local/etc/s6/gitea/* \ /tmp/local/etc/s6/openssh/* \ /tmp/local/etc/s6/.s6-svscan/* \ - /go/src/forgejo.org/gitea \ - /go/src/forgejo.org/environment-to-ini -RUN chmod 644 /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete + /go/src/code.gitea.io/gitea/gitea \ + /go/src/code.gitea.io/gitea/environment-to-ini +RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM data.forgejo.org/oci/alpine:3.22 +FROM code.forgejo.org/oci/golang:1.22-alpine3.20 ARG RELEASE_VERSION LABEL maintainer="contact@forgejo.org" \ org.opencontainers.image.authors="Forgejo" \ @@ -60,7 +60,7 @@ LABEL maintainer="contact@forgejo.org" \ org.opencontainers.image.source="https://codeberg.org/forgejo/forgejo" \ org.opencontainers.image.version="${RELEASE_VERSION}" \ org.opencontainers.image.vendor="Forgejo" \ - org.opencontainers.image.licenses="GPL-3.0-or-later" \ + org.opencontainers.image.licenses="MIT" \ org.opencontainers.image.title="Forgejo. Beyond coding. We forge." \ org.opencontainers.image.description="Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job." @@ -99,11 +99,10 @@ ENV GITEA_CUSTOM=/data/gitea VOLUME ["/data"] ENTRYPOINT ["/usr/bin/entrypoint"] -CMD ["/usr/bin/s6-svscan", "/etc/s6"] +CMD ["/bin/s6-svscan", "/etc/s6"] COPY --from=build-env /tmp/local / RUN cd /usr/local/bin ; ln -s gitea forgejo -COPY --from=build-env /go/src/forgejo.org/gitea /app/gitea/gitea -RUN ln -s /app/gitea/gitea /app/gitea/forgejo-cli -COPY --from=build-env /go/src/forgejo.org/environment-to-ini /usr/local/bin/environment-to-ini -COPY --from=build-env /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh +COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea +COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini +COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh diff --git a/Dockerfile.rootless b/Dockerfile.rootless index b347ab6f7e..4e0ce11270 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,9 +1,9 @@ -FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx +FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx -FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.22 AS build-env +FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.22-alpine3.20 as build-env ARG GOPROXY -ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct} +ENV GOPROXY=${GOPROXY:-direct} ARG RELEASE_VERSION ARG TAGS="sqlite sqlite_unlock_notify" @@ -30,13 +30,13 @@ RUN cp /*-alpine-linux-musl*/lib/ld-musl-*.so.1 /lib || true RUN apk --no-cache add build-base git nodejs npm -COPY . ${GOPATH}/src/forgejo.org -WORKDIR ${GOPATH}/src/forgejo.org +COPY . ${GOPATH}/src/code.gitea.io/gitea +WORKDIR ${GOPATH}/src/code.gitea.io/gitea -RUN make clean-no-bindata +RUN make clean RUN make frontend RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini -RUN make FORGEJO_GENERATE_SKIP_HASH=true RELEASE_VERSION=$RELEASE_VERSION go-check generate-backend static-executable && xx-verify gitea +RUN make RELEASE_VERSION=$RELEASE_VERSION go-check generate-backend static-executable && xx-verify gitea # Copy local files COPY docker/rootless /tmp/local @@ -45,12 +45,11 @@ COPY docker/rootless /tmp/local RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \ /tmp/local/usr/local/bin/docker-setup.sh \ /tmp/local/usr/local/bin/gitea \ - /go/src/forgejo.org/gitea \ - /go/src/forgejo.org/environment-to-ini -RUN chmod 644 /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete + /go/src/code.gitea.io/gitea/gitea \ + /go/src/code.gitea.io/gitea/environment-to-ini +RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM data.forgejo.org/oci/alpine:3.22 -ARG RELEASE_VERSION +FROM code.forgejo.org/oci/golang:1.22-alpine3.20 LABEL maintainer="contact@forgejo.org" \ org.opencontainers.image.authors="Forgejo" \ org.opencontainers.image.url="https://forgejo.org" \ @@ -58,7 +57,7 @@ LABEL maintainer="contact@forgejo.org" \ org.opencontainers.image.source="https://codeberg.org/forgejo/forgejo" \ org.opencontainers.image.version="${RELEASE_VERSION}" \ org.opencontainers.image.vendor="Forgejo" \ - org.opencontainers.image.licenses="GPL-3.0-or-later" \ + org.opencontainers.image.licenses="MIT" \ org.opencontainers.image.title="Forgejo. Beyond coding. We forge." \ org.opencontainers.image.description="Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job." @@ -72,7 +71,6 @@ RUN apk --no-cache add \ git \ curl \ gnupg \ - openssh-client \ git-annex \ && rm -rf /var/cache/apk/* @@ -92,10 +90,9 @@ RUN chown git:git /var/lib/gitea /etc/gitea COPY --from=build-env /tmp/local / RUN cd /usr/local/bin ; ln -s gitea forgejo -COPY --from=build-env --chown=root:root /go/src/forgejo.org/gitea /app/gitea/gitea -RUN ln -s /app/gitea/gitea /app/gitea/forgejo-cli -COPY --from=build-env --chown=root:root /go/src/forgejo.org/environment-to-ini /usr/local/bin/environment-to-ini -COPY --from=build-env /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh +COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea +COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini +COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh #git:git USER 1000:1000 @@ -115,3 +112,4 @@ WORKDIR /var/lib/gitea ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"] CMD [] + diff --git a/LICENSE b/LICENSE index f288702d2f..eeefaa717a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,21 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +Copyright (c) 2022 The Forgejo Authors +Copyright (c) 2016 The Gitea Authors +Copyright (c) 2015 The Gogs Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile b/Makefile index 82a1fe4d56..0819c914fa 100644 --- a/Makefile +++ b/Makefile @@ -16,49 +16,54 @@ else DIST := dist DIST_DIRS := $(DIST)/binaries $(DIST)/release -IMPORT := forgejo.org +IMPORT := code.gitea.io/gitea -GO ?= $(shell go env GOROOT)/bin/go +GO ?= go SHASUM ?= shasum -a 256 HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) COMMA := , DIFF ?= diff --unified -ifeq ($(USE_GOTESTSUM), yes) - GOTEST ?= gotestsum -- - GOTESTCOMPILEDRUNPREFIX ?= gotestsum --raw-command -- go tool test2json -t - GOTESTCOMPILEDRUNSUFFIX ?= -test.v=test2json -else - GOTEST ?= $(GO) test - GOTESTCOMPILEDRUNPREFIX ?= - GOTESTCOMPILEDRUNSUFFIX ?= -endif - XGO_VERSION := go-1.21.x AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go -EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.3.0 # renovate: datasource=go -GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.8.0 # renovate: datasource=go -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 # renovate: datasource=go +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v2/cmd/editorconfig-checker@2.8.0 # renovate: datasource=go +GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 # renovate: datasource=go +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.1 # renovate: datasource=go GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go +MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0 # renovate: datasource=go SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasource=go 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.1.4 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate +DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.22.0 # renovate: datasource=go +GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go +GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.16.0 # renovate: datasource=go +RENOVATE_NPM_PACKAGE ?= renovate@37.421.2 # renovate: datasource=docker packageName=ghcr.io/visualon/renovate -# https://github.com/disposable-email-domains/disposable-email-domains/commits/main/ -DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ... +DOCKER_IMAGE ?= gitea/gitea +DOCKER_TAG ?= latest +DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG) ifeq ($(HAS_GO), yes) CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766 CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS) endif -GOFLAGS := -v -EXECUTABLE ?= gitea +ifeq ($(GOOS),windows) + IS_WINDOWS := yes +else ifeq ($(patsubst Windows%,Windows,$(OS)),Windows) + ifeq ($(GOOS),) + IS_WINDOWS := yes + endif +endif +ifeq ($(IS_WINDOWS),yes) + GOFLAGS := -v -buildmode=exe + EXECUTABLE ?= gitea.exe +else + GOFLAGS := -v + EXECUTABLE ?= gitea +endif ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu) SED_INPLACE := sed -i @@ -90,36 +95,38 @@ else FORGEJO_VERSION_API ?= $(GITEA_VERSION)+${GITEA_COMPATIBILITY} else # drop the "g" prefix prepended by git describe to the commit hash - FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always 2>/dev/null | sed 's/^v//' | sed 's/\-g/-/2') - ifneq ($(FORGEJO_VERSION),) - ifeq ($(findstring $(GITEA_COMPATIBILITY),$(FORGEJO_VERSION)),) - FORGEJO_VERSION := $(FORGEJO_VERSION)+$(GITEA_COMPATIBILITY) - endif - endif + FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always | sed 's/^v//' | sed 's/\-g/-/')+${GITEA_COMPATIBILITY} endif endif FORGEJO_VERSION_MAJOR=$(shell echo $(FORGEJO_VERSION) | sed -e 's/\..*//') FORGEJO_VERSION_MINOR=$(shell echo $(FORGEJO_VERSION) | sed -E -e 's/^([0-9]+\.[0-9]+).*/\1/') +show-version-full: + @echo ${FORGEJO_VERSION} + +show-version-major: + @echo ${FORGEJO_VERSION_MAJOR} + +show-version-minor: + @echo ${FORGEJO_VERSION_MINOR} + RELEASE_VERSION ?= ${FORGEJO_VERSION} VERSION ?= ${RELEASE_VERSION} FORGEJO_VERSION_API ?= ${FORGEJO_VERSION} -# Strip binaries by default to reduce size, allow overriding for debugging -STRIP ?= 1 -ifeq ($(STRIP),1) - LDFLAGS := $(LDFLAGS) -s -w -endif +show-version-api: + @echo ${FORGEJO_VERSION_API} + LDFLAGS := $(LDFLAGS) -X "main.ReleaseVersion=$(RELEASE_VERSION)" -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(FORGEJO_VERSION)" -X "main.Tags=$(TAGS)" -X "main.ForgejoVersion=$(FORGEJO_VERSION_API)" LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64 ifeq ($(HAS_GO), yes) - GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list forgejo.org/models/migrations/...) $(shell $(GO) list forgejo.org/models/forgejo_migrations/...) forgejo.org/tests/integration/migration-test forgejo.org/tests forgejo.org/tests/integration forgejo.org/tests/e2e,$(shell $(GO) list ./...)) + GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) $(shell $(GO) list code.gitea.io/gitea/models/forgejo_migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/)) endif REMOTE_CACHER_MODULES ?= cache nosql session queue -GO_TEST_REMOTE_CACHER_PACKAGES ?= $(addprefix forgejo.org/modules/,$(REMOTE_CACHER_MODULES)) +GO_TEST_REMOTE_CACHER_PACKAGES ?= $(addprefix code.gitea.io/gitea/modules/,$(REMOTE_CACHER_MODULES)) FOMANTIC_WORK_DIR := web_src/fomantic @@ -128,7 +135,7 @@ WEBPACK_CONFIGS := webpack.config.js tailwind.config.js WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts -BINDATA_DEST := modules/migration/bindata.go modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go +BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST)) GENERATED_GO_DEST := modules/charset/invisible_gen.go modules/charset/ambiguous_gen.go @@ -151,8 +158,9 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN GO_DIRS := build cmd models modules routers services tests WEB_DIRS := web_src/js web_src/css +ESLINT_FILES := web_src/js tools *.js tests/e2e STYLELINT_FILES := web_src/css web_src/js/components/*.vue -SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(wildcard *.go *.js *.ts *.vue *.md *.yml *.yaml) +SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(wildcard *.go *.js *.md *.yml *.yaml *.toml) GO_SOURCES := $(wildcard *.go) GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go) @@ -160,7 +168,7 @@ GO_SOURCES += $(GENERATED_GO_DEST) GO_SOURCES_NO_BINDATA := $(GO_SOURCES) ifeq ($(HAS_GO), yes) - MIGRATION_PACKAGES := $(shell $(GO) list forgejo.org/models/migrations/... forgejo.org/models/forgejo_migrations/...) + MIGRATION_PACKAGES := $(shell $(GO) list code.gitea.io/gitea/models/migrations/... code.gitea.io/gitea/models/forgejo_migrations/...) endif ifeq ($(filter $(TAGS_SPLIT),bindata),bindata) @@ -181,10 +189,9 @@ SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape}}/api/v1"|"basePa SWAGGER_EXCLUDE := code.gitea.io/sdk SWAGGER_NEWLINE_COMMAND := -e '$$a\' SWAGGER_SPEC_BRANDING := s|Gitea API|Forgejo API|g -SWAGGER_SPEC_LICENSE := s|"name": "MIT"|"name": "This file is distributed under the MIT license for the purpose of interoperability"| TEST_MYSQL_HOST ?= mysql:3306 -TEST_MYSQL_DBNAME ?= testgitea?multiStatements=true +TEST_MYSQL_DBNAME ?= testgitea TEST_MYSQL_USERNAME ?= root TEST_MYSQL_PASSWORD ?= TEST_PGSQL_HOST ?= pgsql:5432 @@ -212,22 +219,31 @@ help: @echo " - deps-frontend install frontend dependencies" @echo " - deps-backend install backend dependencies" @echo " - deps-tools install tool dependencies" + @echo " - deps-py install python dependencies" @echo " - lint lint everything" @echo " - lint-fix lint everything and fix issues" @echo " - lint-frontend lint frontend files" @echo " - lint-frontend-fix lint frontend files and fix issues" @echo " - lint-backend lint backend files" @echo " - lint-backend-fix lint backend files and fix issues" + @echo " - lint-codespell lint typos" + @echo " - lint-codespell-fix lint typos and fix them automatically" + @echo " - lint-codespell-fix-i lint typos and fix them interactively" @echo " - lint-go lint go files" @echo " - lint-go-fix lint go files and fix issues" @echo " - lint-go-vet lint go files with vet" + @echo " - lint-go-gopls lint go files with gopls" @echo " - lint-js lint js files" @echo " - lint-js-fix lint js files and fix issues" @echo " - lint-css lint css files" @echo " - lint-css-fix lint css files and fix issues" @echo " - lint-md lint markdown files" @echo " - lint-swagger lint swagger files" + @echo " - lint-templates lint template files" @echo " - lint-renovate lint renovate files" + @echo " - lint-yaml lint yaml files" + @echo " - lint-spell lint spelling" + @echo " - lint-spell-fix lint spelling and fix issues" @echo " - checks run various consistency checks" @echo " - checks-frontend check frontend files" @echo " - checks-backend check backend files" @@ -254,37 +270,8 @@ help: @echo " - swagger-validate check if the swagger spec is valid" @echo " - go-licenses regenerate go licenses" @echo " - tidy run go mod tidy" - @echo " - test[\#TestSpecificName] run unit test" + @echo " - test[\#TestSpecificName] run unit test" @echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite" - @echo " - reproduce-build\#version build a reproducible binary for the specified release version" - -.PHONY: verify-version -verify-version: -ifeq ($(FORGEJO_VERSION),) - @echo "Error: Could not determine FORGEJO_VERSION; version file $(STORED_VERSION_FILE) not present and no suitable git tag found" - @echo 'In most cases this likely means you forgot to fetch git tags, you can fix this by executing `git fetch --tags`. If this is not possible and this is part of a custom build process, then you can set a specific version by writing it to $(STORED_VERSION_FILE) (This must be a semver compatible version).' - @false -endif - -.PHONY: show-version-full -show-version-full: verify-version - @echo ${FORGEJO_VERSION} - -.PHONY: show-version-major -show-version-major: verify-version - @echo ${FORGEJO_VERSION_MAJOR} - -.PHONY: show-version-minor -show-version-minor: verify-version - @echo ${FORGEJO_VERSION_MINOR} - -.PHONY: show-version-api -show-version-api: verify-version - @echo ${FORGEJO_VERSION_API} - -### -# Check system and environment requirements -### .PHONY: go-check go-check: @@ -292,14 +279,14 @@ go-check: $(eval MIN_GO_VERSION := $(shell printf "%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' '))) $(eval GO_VERSION := $(shell printf "%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9]+' | tr '.' ' ');)) @if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \ - echo "Forgejo requires Go $(MIN_GO_VERSION_STR) or greater to build. You can get it at https://go.dev/dl/"; \ + echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build. You can get it at https://go.dev/dl/"; \ exit 1; \ fi .PHONY: git-check git-check: @if git lfs >/dev/null 2>&1 ; then : ; else \ - echo "Forgejo requires git with lfs support to run tests." ; \ + echo "Gitea requires git with lfs support to run tests." ; \ exit 1; \ fi @@ -310,25 +297,17 @@ node-check: $(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | cut -c2- | tr '.' ' ');)) $(eval NPM_MISSING := $(shell hash npm > /dev/null 2>&1 || echo 1)) @if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" -o "$(NPM_MISSING)" = "1" ]; then \ - echo "Forgejo requires Node.js $(MIN_NODE_VERSION_STR) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \ + echo "Gitea requires Node.js $(MIN_NODE_VERSION_STR) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \ exit 1; \ fi -### -# Basic maintenance, check and lint targets -### - .PHONY: clean-all clean-all: clean rm -rf $(WEBPACK_DEST_ENTRIES) node_modules .PHONY: clean -clean: clean-no-bindata - rm -rf $(BINDATA_DEST) $(BINDATA_HASH) - -.PHONY: clean-no-bindata -clean-no-bindata: - rm -rf $(EXECUTABLE) $(DIST) \ +clean: + rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \ integrations*.test \ e2e*.test \ tests/integration/gitea-integration-* \ @@ -388,7 +367,6 @@ $(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' $(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)' $(SED_INPLACE) '$(SWAGGER_SPEC_BRANDING)' './$(SWAGGER_SPEC)' - $(SED_INPLACE) '$(SWAGGER_SPEC_LICENSE)' './$(SWAGGER_SPEC)' .PHONY: swagger-check swagger-check: generate-swagger @@ -411,10 +389,10 @@ checks-frontend: lockfile-check svg-check checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check .PHONY: lint -lint: lint-frontend lint-backend +lint: lint-frontend lint-backend lint-spell .PHONY: lint-fix -lint-fix: lint-frontend-fix lint-backend-fix +lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix .PHONY: lint-frontend lint-frontend: lint-js lint-css @@ -423,18 +401,30 @@ lint-frontend: lint-js lint-css lint-frontend-fix: lint-js-fix lint-css-fix .PHONY: lint-backend -lint-backend: lint-go lint-go-vet lint-editorconfig lint-renovate lint-locale lint-locale-usage lint-disposable-emails +lint-backend: lint-go lint-go-vet lint-editorconfig lint-renovate .PHONY: lint-backend-fix -lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig lint-disposable-emails-fix +lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig + +.PHONY: lint-codespell +lint-codespell: + codespell + +.PHONY: lint-codespell-fix +lint-codespell-fix: + codespell -w + +.PHONY: lint-codespell-fix-i +lint-codespell-fix-i: + codespell -w -i 3 -C 2 .PHONY: lint-js lint-js: node_modules - npx eslint --color --max-warnings=0 + npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES) .PHONY: lint-js-fix lint-js-fix: node_modules - npx eslint --color --max-warnings=0 --fix + npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES) --fix .PHONY: lint-css lint-css: node_modules @@ -450,23 +440,23 @@ lint-swagger: node_modules .PHONY: lint-renovate lint-renovate: node_modules - npx --yes --package $(RENOVATE_NPM_PACKAGE) -- renovate-config-validator > .lint-renovate 2>&1 || true - @if grep --quiet --extended-regexp -e '^( ERROR:)' .lint-renovate ; then cat .lint-renovate ; rm .lint-renovate ; exit 1 ; fi + npx --yes --package $(RENOVATE_NPM_PACKAGE) -- renovate-config-validator --strict > .lint-renovate 2>&1 || true + @if grep --quiet --extended-regexp -e '^( WARN:|ERROR:)' .lint-renovate ; then cat .lint-renovate ; rm .lint-renovate ; exit 1 ; fi @rm .lint-renovate -.PHONY: lint-locale -lint-locale: - $(GO) run build/lint-locale/lint-locale.go - -.PHONY: lint-locale-usage -lint-locale-usage: - $(GO) run build/lint-locale-usage/lint-locale-usage.go - .PHONY: lint-md lint-md: node_modules npx markdownlint docs *.md -RUN_DEADCODE = $(GO) run $(DEADCODE_PACKAGE) -generated=false -f='{{println .Path}}{{range .Funcs}}{{printf "\t%s\n" .Name}}{{end}}{{println}}' -test forgejo.org +.PHONY: lint-spell +lint-spell: lint-codespell + @go run $(MISSPELL_PACKAGE) -error $(SPELLCHECK_FILES) + +.PHONY: lint-spell-fix +lint-spell-fix: lint-codespell-fix + @go run $(MISSPELL_PACKAGE) -w $(SPELLCHECK_FILES) + +RUN_DEADCODE = $(GO) run $(DEADCODE_PACKAGE) -generated=false -f='{{println .Path}}{{range .Funcs}}{{printf "\t%s\n" .Name}}{{end}}{{println}}' -test code.gitea.io/gitea .PHONY: lint-go lint-go: @@ -480,30 +470,35 @@ lint-go-fix: $(GO) run $(GOLANGCI_LINT_PACKAGE) run $(GOLANGCI_LINT_ARGS) --fix $(RUN_DEADCODE) > .deadcode-out +# workaround step for the lint-go-windows CI task because 'go run' can not +# have distinct GOOS/GOARCH for its build and run steps +.PHONY: lint-go-windows +lint-go-windows: + @GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE) + golangci-lint run + .PHONY: lint-go-vet lint-go-vet: @echo "Running go vet..." @$(GO) vet ./... +.PHONY: lint-go-gopls +lint-go-gopls: + @echo "Running gopls check..." + @GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA) + .PHONY: lint-editorconfig lint-editorconfig: $(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .forgejo/workflows -.PHONY: lint-disposable-emails -lint-disposable-emails: - $(GO) run build/generate-disposable-email.go -check -r $(DISPOSABLE_EMAILS_SHA) +.PHONY: lint-templates +lint-templates: .venv node_modules + @node tools/lint-templates-svg.js + @poetry run djlint $(shell find templates -type f -iname '*.tmpl') -.PHONY: lint-disposable-emails-fix -lint-disposable-emails-fix: - $(GO) run build/generate-disposable-email.go -r $(DISPOSABLE_EMAILS_SHA) - -.PHONY: security-check -security-check: - go run $(GOVULNCHECK_PACKAGE) -show color ./... - -### -# Development and testing targets -### +.PHONY: lint-yaml +lint-yaml: .venv + @poetry run yamllint . .PHONY: watch watch: @@ -524,12 +519,12 @@ test: test-frontend test-backend .PHONY: test-backend test-backend: @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES) + @$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES) .PHONY: test-remote-cacher test-remote-cacher: @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_REMOTE_CACHER_PACKAGES) + @$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_REMOTE_CACHER_PACKAGES) .PHONY: test-frontend test-frontend: node_modules @@ -553,8 +548,8 @@ test-check: .PHONY: test\#% test\#%: - @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES) + @echo "Running go test with -tags '$(TEST_TAGS)'..." + @$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES) .PHONY: coverage coverage: @@ -565,7 +560,7 @@ coverage: .PHONY: unit-test-coverage unit-test-coverage: @echo "Running unit-test-coverage $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @$(GOTEST) $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 + @$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 .PHONY: tidy tidy: @@ -586,7 +581,7 @@ tidy-check: tidy go-licenses: $(GO_LICENSE_FILE) $(GO_LICENSE_FILE): go.mod go.sum - -$(GO) run $(GO_LICENSES_PACKAGE) save . --force --ignore forgejo.org --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null + -$(shell $(GO) env GOROOT)/bin/go run $(GO_LICENSES_PACKAGE) save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null $(GO) run build/generate-go-licenses.go $(GO_LICENSE_TMP_DIR) $(GO_LICENSE_FILE) @rm -rf $(GO_LICENSE_TMP_DIR) @@ -598,11 +593,11 @@ generate-ini-sqlite: .PHONY: test-sqlite test-sqlite: integrations.sqlite.test generate-ini-sqlite - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTESTCOMPILEDRUNPREFIX) ./integrations.sqlite.test $(GOTESTCOMPILEDRUNSUFFIX) + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test .PHONY: test-sqlite\#% test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTESTCOMPILEDRUNPREFIX) ./integrations.sqlite.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run $(subst .,/,$*) + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*) .PHONY: test-sqlite-migration test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test @@ -619,11 +614,11 @@ generate-ini-mysql: .PHONY: test-mysql test-mysql: integrations.mysql.test generate-ini-mysql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTESTCOMPILEDRUNPREFIX) ./integrations.mysql.test $(GOTESTCOMPILEDRUNSUFFIX) + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test .PHONY: test-mysql\#% test-mysql\#%: integrations.mysql.test generate-ini-mysql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTESTCOMPILEDRUNPREFIX) ./integrations.mysql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run $(subst .,/,$*) + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*) .PHONY: test-mysql-migration test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test @@ -637,16 +632,15 @@ generate-ini-pgsql: -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ - -e 's|{{TEST_STORAGE_TYPE}}|$(or $(TEST_STORAGE_TYPE),minio)|g' \ tests/pgsql.ini.tmpl > tests/pgsql.ini .PHONY: test-pgsql test-pgsql: integrations.pgsql.test generate-ini-pgsql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTESTCOMPILEDRUNPREFIX) ./integrations.pgsql.test $(GOTESTCOMPILEDRUNSUFFIX) + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test .PHONY: test-pgsql\#% test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTESTCOMPILEDRUNPREFIX) ./integrations.pgsql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run $(subst .,/,$*) + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*) .PHONY: test-pgsql-migration test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test @@ -665,34 +659,35 @@ test-e2e: test-e2e-sqlite .PHONY: test-e2e-sqlite test-e2e-sqlite: playwright e2e.sqlite.test generate-ini-sqlite - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.sqlite.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestE2e .PHONY: test-e2e-sqlite\#% test-e2e-sqlite\#%: playwright e2e.sqlite.test generate-ini-sqlite - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.sqlite.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e/$* + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestE2e/$* .PHONY: test-e2e-sqlite-firefox\#% test-e2e-sqlite-firefox\#%: playwright e2e.sqlite.test generate-ini-sqlite - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini PLAYWRIGHT_PROJECT=firefox $(GOTESTCOMPILEDRUNPREFIX) ./e2e.sqlite.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e/$* + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini PLAYWRIGHT_PROJECT=firefox ./e2e.sqlite.test -test.run TestE2e/$* .PHONY: test-e2e-mysql test-e2e-mysql: playwright e2e.mysql.test generate-ini-mysql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.mysql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e .PHONY: test-e2e-mysql\#% test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.mysql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e/$* + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e/$* .PHONY: test-e2e-pgsql test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.pgsql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e .PHONY: test-e2e-pgsql\#% test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.pgsql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e/$* + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e/$* .PHONY: test-e2e-debugserver test-e2e-debugserver: e2e.sqlite.test generate-ini-sqlite + sed -i s/3003/3000/g tests/sqlite.ini GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestDebugserver -test.timeout 24h .PHONY: bench-sqlite @@ -716,84 +711,80 @@ integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sq GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out integrations.mysql.test: git-check $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -o integrations.mysql.test + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test integrations.pgsql.test: git-check $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -o integrations.pgsql.test + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test integrations.sqlite.test: git-check $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)' + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)' integrations.cover.test: git-check $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.test + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.test integrations.cover.sqlite.test: git-check $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)' + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)' .PHONY: migrations.mysql.test migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration/migration-test -o migrations.mysql.test - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTESTCOMPILEDRUNPREFIX) ./migrations.mysql.test $(GOTESTCOMPILEDRUNSUFFIX) + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test .PHONY: migrations.pgsql.test migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration/migration-test -o migrations.pgsql.test - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTESTCOMPILEDRUNPREFIX) ./migrations.pgsql.test $(GOTESTCOMPILEDRUNSUFFIX) + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test .PHONY: migrations.sqlite.test migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)' - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTESTCOMPILEDRUNPREFIX) ./migrations.sqlite.test $(GOTESTCOMPILEDRUNSUFFIX) + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)' + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.sqlite.test .PHONY: migrations.individual.mysql.test migrations.individual.mysql.test: $(GO_SOURCES) for pkg in $(MIGRATION_PACKAGES); do \ - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1; \ + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1; \ done .PHONY: migrations.individual.sqlite.test\#% migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' forgejo.org/models/migrations/$* + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* .PHONY: migrations.individual.pgsql.test migrations.individual.pgsql.test: $(GO_SOURCES) for pkg in $(MIGRATION_PACKAGES); do \ - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1;\ + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1;\ done .PHONY: migrations.individual.pgsql.test\#% migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' forgejo.org/models/migrations/$* + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* .PHONY: migrations.individual.sqlite.test migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite for pkg in $(MIGRATION_PACKAGES); do \ - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1; \ + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1; \ done .PHONY: migrations.individual.sqlite.test\#% migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' forgejo.org/models/migrations/$* + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* e2e.mysql.test: $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/e2e -o e2e.mysql.test + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql.test e2e.pgsql.test: $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/e2e -o e2e.pgsql.test + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.pgsql.test e2e.sqlite.test: $(GO_SOURCES) - $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/e2e -o e2e.sqlite.test -tags '$(TEST_TAGS)' + $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.sqlite.test -tags '$(TEST_TAGS)' .PHONY: check check: test -### -# Production / build targets -### - .PHONY: install $(TAGS_PREREQ) -install: $(wildcard *.go) | verify-version - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)' +install: $(wildcard *.go) + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' .PHONY: build build: frontend backend @@ -820,14 +811,18 @@ generate-go: $(TAGS_PREREQ) merge-locales: @echo "NOT NEEDED: THIS IS A NOOP AS OF Forgejo 7.0 BUT KEPT FOR BACKWARD COMPATIBILITY" -$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) | verify-version - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $@ +.PHONY: security-check +security-check: + go run $(GOVULNCHECK_PACKAGE) ./... + +$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@ forgejo: $(EXECUTABLE) ln -f $(EXECUTABLE) forgejo -static-executable: $(GO_SOURCES) $(TAGS_PREREQ) | verify-version - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -o $(EXECUTABLE) +static-executable: $(GO_SOURCES) $(TAGS_PREREQ) + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -o $(EXECUTABLE) .PHONY: release release: frontend generate release-linux release-copy release-compress vendor release-sources release-check @@ -838,19 +833,26 @@ sources-tarbal: frontend generate vendor release-sources release-check $(DIST_DIRS): mkdir -p $(DIST_DIRS) +.PHONY: release-windows +release-windows: | $(DIST_DIRS) + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . +ifeq (,$(findstring gogit,$(TAGS))) + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . +endif + .PHONY: release-linux -release-linux: | $(DIST_DIRS) verify-version +release-linux: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out forgejo-$(VERSION) . ifeq ($(CI),true) cp /build/* $(DIST)/binaries endif .PHONY: release-darwin -release-darwin: | $(DIST_DIRS) verify-version +release-darwin: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) . .PHONY: release-freebsd -release-freebsd: | $(DIST_DIRS) verify-version +release-freebsd: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) . .PHONY: release-copy @@ -879,32 +881,11 @@ release-sources: | $(DIST_DIRS) release-docs: | $(DIST_DIRS) docs tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs . -.PHONY: reproduce-build -reproduce-build: -# Start building the Dockerfile with the RELEASE_VERSION tag set. GOPROXY is set -# for convenience, because the default of the Dockerfile is `direct` which can be -# quite slow. - @docker build --build-arg="RELEASE_VERSION=$(RELEASE_VERSION)" --build-arg="GOPROXY=$(shell $(GO) env GOPROXY)" --tag "forgejo-reproducibility" . - @id=$$(docker create forgejo-reproducibility); \ - docker cp $$id:/app/gitea/gitea ./forgejo; \ - docker rm -v $$id; \ - docker image rm forgejo-reproducibility:latest - -.PHONY: reproduce-build\#% -reproduce-build\#%: - @git switch -d "$*" -# All the current variables are based on information before the git checkout happened. -# Call the makefile again, so these variables are correct and can be used for building -# a reproducible binary. Always execute git switch -, to go back to the previous branch. - @make reproduce-build; \ - (code=$$?; git switch -; exit $${code}) - -### -# Dependency management -### - .PHONY: deps -deps: deps-frontend deps-backend deps-tools +deps: deps-frontend deps-backend deps-tools deps-py + +.PHONY: deps-py +deps-py: .venv .PHONY: deps-frontend deps-frontend: node_modules @@ -920,11 +901,13 @@ deps-tools: $(GO) install $(GOFUMPT_PACKAGE) $(GO) install $(GOLANGCI_LINT_PACKAGE) $(GO) install $(GXZ_PACKAGE) + $(GO) install $(MISSPELL_PACKAGE) $(GO) install $(SWAGGER_PACKAGE) $(GO) install $(XGO_PACKAGE) $(GO) install $(GO_LICENSES_PACKAGE) $(GO) install $(GOVULNCHECK_PACKAGE) $(GO) install $(GOMOCK_PACKAGE) + $(GO) install $(GOPLS_PACKAGE) node_modules: package-lock.json npm install --no-save @@ -974,6 +957,16 @@ lockfile-check: @git diff --exit-code --color=always package-lock.json \ || (code=$$?; echo "Please run 'npm install --package-lock-only' and commit the result"; exit $${code}) +.PHONY: update-translations +update-translations: + mkdir -p ./translations + cd ./translations && curl -L https://crowdin.com/download/project/gitea.zip > gitea.zip && unzip gitea.zip + rm ./translations/gitea.zip + $(SED_INPLACE) -e 's/="/=/g' -e 's/"$$//g' ./translations/*.ini + $(SED_INPLACE) -e 's/\\"/"/g' ./translations/*.ini + mv ./translations/*.ini ./options/locale/ + rmdir ./translations + .PHONY: generate-license generate-license: $(GO) run build/generate-licenses.go @@ -984,11 +977,12 @@ generate-gitignore: .PHONY: generate-gomock generate-gomock: - $(GO) run $(GOMOCK_PACKAGE) -package mock -destination ./modules/queue/mock/redisuniversalclient.go forgejo.org/modules/nosql RedisClient + $(GO) run $(GOMOCK_PACKAGE) -package mock -destination ./modules/queue/mock/redisuniversalclient.go github.com/redis/go-redis/v9 UniversalClient .PHONY: generate-images generate-images: | node_modules - node tools/generate-images.js + npm install --no-save fabric@6.0.0-beta20 imagemin-zopfli@7 + node tools/generate-images.js $(TAGS) .PHONY: generate-manpage generate-manpage: @@ -998,6 +992,11 @@ generate-manpage: @gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created @#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page +.PHONY: docker +docker: + docker build --disable-content-trust=false -t $(DOCKER_REF) . +# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . + # This endif closes the if at the top of the file endif diff --git a/README.md b/README.md index f95aebadeb..2d04e6891f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +

Welcome to Forgejo

@@ -15,6 +16,11 @@ Our promise: **Independent Free/Libre Software forever!** ## What does Forgejo offer? + + If you like any of the following, Forgejo is literally meant for you: - Lightweight: Forgejo can easily be hosted on nearly **every machine**. @@ -35,11 +41,6 @@ If you like any of the following, Forgejo is literally meant for you: Dive into the [documentation](https://forgejo.org/docs/latest/), subscribe to releases and blog post on [our website](https://forgejo.org), find us on the Fediverse or hop into [our Matrix room](https://matrix.to/#/#forgejo-chat:matrix.org) if you have any questions or want to get involved. -## License - -Forgejo is distributed under the terms of the [GPL version 3.0](LICENSE) or any later version. - -The agreement for this license [was documented in June 2023](https://codeberg.org/forgejo/governance/pulls/24) and implemented during the development of Forgejo v9.0. All Forgejo versions before v9.0 are distributed under the MIT license. ## Get involved diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 32f7b8c264..82b7c6107e 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -4,242 +4,9 @@ A minor or major Forgejo release is published every [three months](https://forge A [patch or minor release](https://semver.org/spec/v2.0.0.html) (e.g. upgrading from v7.0.0 to v7.0.1 or v7.1.0) does not require manual intervention. But [major releases](https://semver.org/spec/v2.0.0.html#spec-item-8) where the first version number changes (e.g. upgrading from v1.21 to v7.0) contain breaking changes and the release notes explain how to deal with them. -The release notes of each release [are available in the release-notes-published directory of this repository](release-notes-published), starting with [Forgejo 7.0.7](release-notes-published/7.0.7.md) and [Forgejo 8.0.1](release-notes-published/8.0.1.md). +## Upcoming releases (not available yet) -## 9.0.2 - -See the [Forgejo 9.0.2 release notes](release-notes-published/9.0.2.md). - -## 9.0.1 - -See the [Forgejo 9.0.1 release notes](release-notes-published/9.0.1.md). - -## 9.0.0 - -See the [Forgejo 9.0.0 release notes](release-notes-published/9.0.0.md). - -## 8.0.3 - -See the [Forgejo 8.0.3 release notes](release-notes-published/8.0.3.md). - -## 8.0.2 - -See the [Forgejo 8.0.2 release notes](release-notes-published/8.0.2.md). - -## 8.0.1 - -See the [Forgejo 8.0.1 release notes](release-notes-published/8.0.1.md). - -## 8.0.0 - -A [companion blog post](https://forgejo.org/2024-07-release-v8-0/) provides additional context on this release. In addition to the pull requests listed below, you will find a complete list in the [v8.0 milestone](https://codeberg.org/forgejo/forgejo/milestone/6042). - -- Two frontend features were removed because a license incompatibility was discovered. [Read more in the dedicated blog post](https://forgejo.org/2024-07-non-free-dependency-found/). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4670): [Mermaid](https://mermaid.js.org/) rendering: `%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%` will now fail because [ELK](https://github.com/kieler/elkjs) is no longer included. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4595): Repository citation: Removed the ability to export citations in APA format. - - -- **Breaking** - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3040): remove Microsoft SQL Server support see [the discussion](https://codeberg.org/forgejo/discussions/issues/122). -- **User interface features & enhancements** - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4590) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4571)): Replace `vue-bar-graph` with `chart.js` - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4201): make the tooltip of the author label in comments clearer. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4189): only show the RSS feed button and Public activity tab in user profiles when the activity can be accessed and add messages about visibility. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4139): reorder repo tabs for better UX: (i) `Actions` is now the last tab (ii) `Packages` are located after Releases (iii) this puts Projects after Pull requests. (tab positions may depend on which units are enabled in the repo). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4134): code search results are now displayed in a foldable box. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4095): disable the `Subscribe` button for guest users. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4072): - - Added Enter key handling to the new Markdown editor: Pressing Enter while in a list, quote or code block will copy the prefix to the new line - Ordered list index will be increased for the new line, and task list "checkbox" will be unchecked. - - Added indent/unindent function for a line or selection. Currently available as toolbar buttons ([#4263](https://codeberg.org/forgejo/forgejo/pulls/4263)). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3985): added support for displaying images based on the users current color code by using an anchor of `#dark-mode-only` or `#light-mode-only` respectively. Also supporting the github variants (e.g. `#gh-dark-mode-only`). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3870): use CSS-native pattern for image diff background, add dark theme support. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3642): allow navigating to the organization dashboard from the organization view. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3434): when PDFs are displayed in the repository, the full height of the screen is now used instead of a predefined fixed height. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3337): added support for grouping of log-lines inside steps between the special `::group::{title}` and `::endgroup::` workflow commands. A runner of v3.4.2 or later is needed. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3285): the default for `[repository].USE_COMPAT_SSH_URI` has been changed to `true`. With this change, Forgejo defaults to using the same URL style for SSH clone URLs as for HTTPS ones, instead of the former scp-style. -- **Features & Enhancements** - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4283) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4266)): add support for LFS server implementations which have batch API responses in an older/deprecated schema. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4262): introduce a branch/tag dropdown in the code search page if using git-grep. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4160): added support for fuzzy searching in `/user/repo/issues` and `/user/repo/pulls`. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4145): - - feat(perf): [commit](https://codeberg.org/forgejo/forgejo/commit/358cd67c4f316f2d4f1d3be6dcb891dc04a2ff07) reduce memory usage for chunked artifact uploads to S3. - - feat: [commit](https://codeberg.org/forgejo/forgejo/commit/b60e3ac7b4aeeb9b8760f43eea9576c0e23309e9) allow downloading draft releases assets. - - feat: [commit](https://codeberg.org/forgejo/forgejo/commit/1fca15529ac8fefb60d86b0c1f4bec8dae9a8566) API endpoints for managing tag protection. - - feat: [commit](https://codeberg.org/forgejo/forgejo/commit/4334c705b5f9388b16af23c7e75a69d027d07d5e) extract and display readme and comments for Composer packages. - - fix: [commit](https://codeberg.org/forgejo/forgejo/commit/364922c6e4f28264add9e2501a352c25ad6a0993) when a repository is adopted, its object format is not set in the database. - - fix: [commit](https://codeberg.org/forgejo/forgejo/commit/e7f332a55d6a48a3f3b4f2bfa43d18455ac00acc) during a migration from bitbucket, LFS downloads fail. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4143): a help overlay, triggered by "?" key can be displayed when viewing [asciinema](https://asciinema.org/) files (.cast extension) and [SGR color sequence](https://github.com/asciinema/avt/issues/9) are supported. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4136): strikethrough in markdown can be achieved with [a single ~ in addition to ~~](https://github.github.com/gfm/#strikethrough-extension-). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4083): - - feat: add [Reviewed-on and Reviewed-by variables](https://codeberg.org/forgejo/forgejo/commit/4ddd9af50fbfcfb2ebf629697a803b3bce56c4af) to the merge template. - - feat(perf): [add the `[ui.csv].MAX_ROWS` setting](https://codeberg.org/forgejo/forgejo/commit/433b6c6910f8699dc41787ef8f5148b122b4677e) to avoid displaying a large number of lines (defaults to 2500). - - feat: [add a setting to override or add headers of all outgoing emails](https://codeberg.org/forgejo/forgejo/commit/1d4bff4f65d5e4a3969871ef91d3612daf272b45), for instance `Reply-To` or `In-Reply-To`. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4027): the Gitea/Forgejo webhook payload includes additional fields (`html_url`, `additions`, `deletions`, `review_comments`...) for better compatibility with [OpenProject](https://www.openproject.org/). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4026): when an OAuth grant request submitted to a Forgejo user is denied, the server from which the request originates is notified that it has been denied. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3989): - - feat: API endpoints that return a repository now [also include the topics](https://codeberg.org/forgejo/forgejo/commit/ee2247d77c0b13b0b45df704d7589b541db03899). - - feat: display an error when an issue comment is [edited simultaneously by two users](https://codeberg.org/forgejo/forgejo/commit/ca0921a95aa9a37d8820538458c15fd0a3b0c97c) instead of silently overriding one of them. - - feat: add [support for a credentials chain for minio](https://codeberg.org/forgejo/forgejo/commit/73706ae26d138684ef9da9e1164846a040fd4a7d). - - feat(perf): improve performances when [retrieving pull requests via the API](https://codeberg.org/forgejo/forgejo/commit/47a2102694c47bc30a2a7c673c328471839ef206). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3934): when installing Forgejo through the built-in installer, open (self-) registration is now disabled by default. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3917): support [setting the default attribute of the issue template dropdown field](https://codeberg.org/forgejo/forgejo/commit/df15abd07264138fd07e003d0cf056f7da514b8f) - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3886): For federated-star we introduce a new repository setting to define following repositories. That is a workaround till we find a better way to express repository federation. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3847): Basic wiki content search using git-grep. The search results include the first ten matched files. Only the first three matches per file are displayed. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3838): support using label names when changing issue labels. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3836): parse prefix parameter from redis URI for queues and use that as prefix to keys. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3830): neutralize delete runners' UUID to prevent collisions with new records. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3811): implement a non-caching version of the [RubyGems compact API](https://guides.rubygems.org/rubygems-org-compact-index-api/) for bundler dependency resolution. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3808): add support for the [reddit](https://github.com/markbates/goth/pull/523) and [Hubspot](https://github.com/markbates/goth/pull/531) OAuth providers. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3791): when parsing [incoming emails](https://forgejo.org/docs/v8.0/user/incoming/), [remove tspecials from type/subtype](https://github.com/jhillyerd/enmime/pull/317). According to the RFC, content type and subtype cannot contain special characters and any such character will fail parsing. Removing the characters from the type/subtype can help successfully parsing the content type that contains some extra garbage. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3752): there are a couple of new configs to define the name of the instance. The more important is `APP_SLOGAN`. It permits to configure a slogan for the site and it is optional. The other is `APP_DISPLAY_NAME_FORMAT` and permits to customize the aspect of the full display name for the instance used in some parts of the UI as: (i) Title page, (ii) Homepage head title (ii) Open Graph site and title meta tags. Its default value is `APP_NAME: APP_SLOGAN`. The config `APP_DISPLAY_NAME_FORMAT` is used only if `APP_SLOGAN` is set otherwise the full display name shows only `APP_NAME` value. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3729): - - feat: [commit](https://codeberg.org/forgejo/forgejo/commit/7028fe0b4d89c045b64ae891d2716e89965bc012): add actions-artifacts to the [storage migrate CLI](https://forgejo.org/docs/v8.0/admin/command-line/#migrate). - - fix: [commit](https://codeberg.org/forgejo/forgejo/commit/8f0f6bf89cdcd12cd4daa761aa259fdba7e32b50): pull request search shows closed pull requests in the open tab. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3724): - - [CERT management was improved](https://codeberg.org/forgejo/forgejo/pulls/3724) when [`ENABLE_ACME=true`](https://forgejo.org/docs/v7.0/admin/config-cheat-sheet/#server-server) - - Draft support for draft-03 of [ACME Renewal Information (ARI)](https://datatracker.ietf.org/doc/draft-ietf-acme-ari/) which assists with deciding when to renew certificates. This augments CertMagic's already-advanced logic using cert lifetime and OCSP/revocation status. - - New [`ZeroSSLIssuer`](https://pkg.go.dev/github.com/caddyserver/certmagic@v0.21.0#ZeroSSLIssuer) uses the [ZeroSSL API](https://zerossl.com/documentation/api/) to get certificates. ZeroSSL also has an ACME endpoint, which can still be accessed using the existing ACMEIssuer, as always. Their proprietary API is paid, but has extra features like IP certificates, better reliability, and support. - - DNS challenges should be smoother in some cases as we've improved propagation checking. - - In the odd case your ACME account disappears from the ACME server, CertMagic will automatically retry with a new account. (This happens in some test/dev environments.) - - ACME accounts are identified only by their public keys, but CertMagic maps accounts by CA+email for practical/storage reasons. So now you can "pin" an account key to use by specifying your email and the account public key in your config, which is useful if you need to absolutely be sure to use a specific account (like if you get rate limit exemptions from a CA). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3723): - - With the go-enry upgrade to [v2.8.8](https://github.com/go-enry/go-enry/releases/tag/v2.8.8), language detection in the repository [now includes](https://github.com/github-linguist/linguist/releases/tag/v7.29.0): - - New languages - - [Roc](https://github.com/github-linguist/linguist/pull/6633) - - [BitBake](https://github.com/github-linguist/linguist/pull/6665) with `.bbappend`, `.bbclass` and `.inc` extensions - - [Glimmer TS](https://github.com/github-linguist/linguist/pull/6680) - - [Edge](https://github.com/github-linguist/linguist/pull/6695) - - [Pip Requirements](https://github.com/github-linguist/linguist/pull/6739) - - [Mojo](https://github.com/github-linguist/linguist/pull/6400) - - [Slint](https://github.com/github-linguist/linguist/pull/6750) - - [Oberon](https://github.com/github-linguist/linguist/pull/4645) - - New data formats - - [TextGrid](https://github.com/github-linguist/linguist/pull/6719) - - File names and extensions: - - The [rebornix.Ruby extension is deprecated in favor of Shopify.ruby-lsp](https://github.com/github-linguist/linguist/pull/6738) - - [Add .bicepparam to list of Bicep file extensions](https://github.com/github-linguist/linguist/pull/6664) - - [Add cs.pp extension to C#](https://github.com/github-linguist/linguist/pull/6679) - - [Add tmux.conf and .tmux.conf as shell filenames](https://github.com/github-linguist/linguist/pull/6726) - - [Add .env.sample as Dotenv filename](https://github.com/github-linguist/linguist/pull/6732) - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3654): support Code Search for non-default branches and tags when the repository indexer is disabled. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3615): add an immutable tarball link to archive download headers for Nix. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3414): allow to customize the domain name used as a fallback when synchronizing sources from ldap default domain name. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3383): the default config for `database.MAX_OPEN_CONNS` changed from 0 (unlimited) to 100 to avoid problems if it exceeds the limit by the database server. If you require high concurrency, try to increase this value for both Forgejo **and your database server**. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3366): infer the `[email.incoming].PORT` setting from `.USE_TLS`. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3363): reverted the rootless container image path in `GITEA_APP_INI` from `/etc/gitea/app.ini` to its default value of `/var/lib/gitea/custom/conf/app.ini`. This allows container users to not have to mount two separate volumes (one for the configuration data and one for the configuration `.ini` file). A warning is issued for users with the legacy configuration on how to update to the new path. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3334): added support for the [`workflow_dispatch` trigger](https://forgejo.org/docs/v8.0/user/actions/#onworkflow_dispatch) in Forgejo Actions. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3307): support [Proof Key for Code Exchange (PKCE - RFC7636)](https://www.rfc-editor.org/rfc/rfc7636) for external login using the OpenID Connect authentication source. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3139): allow hiding auto generated release archives. -- **Bug fixes** - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4732) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4715)): Show the AGit label on merged pull requests. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4689) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4687)): Fixed: issue state change via the API is not idempotent. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4547) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4546)): The milestone section in the sidebar on the issue and pull request page now uses HTMX. If you update the milestone of a issue or pull request it will no longer reload the whole page and instead update the current page with the new information about the milestone update. This should provide a smoother user experience. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4402) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4382)): Fix mobile UI for organisation creation. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4621) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4618)): Fixes: Forgejo Actions does not trigger an edited event when the title of an issue or pull request is changed. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4529) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4523)): Load attachments for `/issues/comments/{id}`. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4423) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4375)): Fixed: the "View command line instructions" link in pull requests and the "Copy content" button in file editor are not accessible. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4380) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4377)): Use correct SHA in `GetCommitPullRequest` - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4288) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4253)): Fixed: unknown git push options are rejected instead of being ignored. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4240): Fixed: markdown `[*[a]*](b)` [is incorrectly rendered as `

[a]

`](https://github.com/yuin/goldmark/issues/457). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4222): Fixed: markdown files displayed in the UI that have an unescaped backtick in the image alt [could (accidentally) trigger an inline code](https://github.com/yuin/goldmark/issues/456). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3562): Fixed: when the git repository is empty, it is not possible to unsubscribe from an issue. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3442): Fixed: it is not possible to remove attachments from an empty comment. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3430): Fixed: the `/api/v1/repos/{owner}/{repo}/wiki` API endpoints is using a hardcoded "master" branch for the wiki, rather than the branch they really use. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3379): Fixed: using the API to search for users, the results are not paged by default an the default paging limits are not respected. -- **Localization** - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4661) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4568)): 24 July updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4565) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4451)): 19 July updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4445) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4330)): 11 July updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4316) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4251)): 4 July updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4168): 18 June updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4098): 10 June updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3992): 2 June updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3908): 25 May updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3851): 20 May updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3759): 14 May updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3637): 5 May updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3508): 28 April updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3359): 22 April updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3244): 15 April updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3138): 10 April updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/3064): 5 April updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/2982): 3 April updates - - [PR](https://codeberg.org/forgejo/forgejo/pulls/2937): 31 March updates - - -## 7.0.11 - -See the [Forgejo 7.0.11 release notes](release-notes-published/7.0.11.md). - -## 7.0.10 - -See the [Forgejo 7.0.10 release notes](release-notes-published/7.0.10.md). - -## 7.0.9 - -See the [Forgejo 7.0.9 release notes](release-notes-published/7.0.9.md). - -## 7.0.8 - -See the [Forgejo 7.0.8 release notes](release-notes-published/7.0.8.md). - -## 7.0.7 - -See the [Forgejo 7.0.7 release notes](release-notes-published/7.0.7.md). - -## 7.0.6 - -This is a bug fix release. See the documentation for more information on the [upgrade procedure](https://forgejo.org/docs/v7.0/admin/upgrade/). In addition to the pull requests listed below, you will find a complete list in the [v7.0.6 milestone](https://codeberg.org/forgejo/forgejo/milestone/7252). - -- Two frontend features were removed because a license incompatibility was discovered. [Read more in the companion blog post](https://forgejo.org/2024-07-non-free-dependency-found/). - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4679) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4670)): [Mermaid](https://mermaid.js.org/) rendering: `%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%` will now fail because [ELK](https://github.com/kieler/elkjs) is no longer included. - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4600) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4595)): Repository citation: Removed the ability to export citations in APA format. -- **User Interface bug fixes** - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4593) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4571)): Replace `vue-bar-graph` with `chart.js` - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4731) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4715)): Show AGit label on merged PR - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4424) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4382)): Fix mobile UI for organisation creation -- **Bug fixes** - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4688) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4687)): fix(api): issue state change is not idempotent - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4647) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4638)): Reserve the `devtest` username - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4620) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4618)): fix(actions): no edited event triggered when a title is changed - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4528) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4523)): Load attachments for `/issues/comments/{id}` - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4526) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/3379)): When searching for users, page the results by default, and respect the default paging limits - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4422) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4375)): the "View command line instructions" link in pull requests and the "Copy content" button in file editor are not accessible - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4379) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4377)): Use correct SHA in `GetCommitPullRequest` -- Localization - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4594) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4451)): Update of translations from Weblate - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4447): Update of translations from Weblate - - [PR](https://codeberg.org/forgejo/forgejo/pulls/4420) ([backported from](https://codeberg.org/forgejo/forgejo/pulls/4098)): 3 translation updates from Weblate - [PR 1](https://codeberg.org/forgejo/forgejo/pulls/4098), [PR 2](https://codeberg.org/forgejo/forgejo/pulls/4168), [PR 3](https://codeberg.org/forgejo/forgejo/pulls/4251) - -## 7.0.5 - -This is a security release. See the documentation for more information on the [upgrade procedure](https://forgejo.org/docs/v7.0/admin/upgrade/). - -In addition to the following notable bug fixes, you can browse the [full list of pull requests](https://codeberg.org/forgejo/forgejo/pulls?milestone=6654) included in this release. - -* **regreSSHion** - - Recommended action when running Forgejo from a: - * binary - upgrade the OpenSSH server that was installed independently. - * root OCI image - upgrade to [Forgejo 7.0.5](https://codeberg.org/forgejo/-/packages/container/forgejo/7.0.5). - * rootless OCI image - no upgrade is necessary. - - [CVE-2024-6387](https://nvd.nist.gov/vuln/detail/CVE-2024-6387) also known as [regreSSHion](https://www.qualys.com/regresshion-cve-2024-6387/) is an Unauthenticated Remote Code Execution (RCE) vulnerability in OpenSSH’s server (sshd) on glibc-based Linux systems. It is **strongly recommended** that an OpenSSH server installed independently of Forgejo is upgraded as soon as possible. - - All Forgejo OCI root images, including [7.0.5](https://codeberg.org/forgejo/-/packages/container/forgejo/7.0.5) contain an OpenSSH server. They are based on https://alpinelinux.org/ which relies on https://musl.libc.org/ and not https://en.wikipedia.org/wiki/Glibc. As a precaution the [Forgejo v7.0.5 root OCI image](https://codeberg.org/forgejo/-/packages/container/forgejo/7.0.5) contains an [updated OpenSSH server](https://pkgs.alpinelinux.org/packages?name=openssh&branch=v3.19) patched for [CVE-2024-6387](https://nvd.nist.gov/vuln/detail/CVE-2024-6387). - - The Forgejo OCI rootless images, including [7.0.5](https://codeberg.org/forgejo/-/packages/container/forgejo/7.0.5-rootless), do not contain an OpenSSH server, they rely on the internal Forgejo implementation of the SSH protocol. - -* **Security:** - * Compiled with Go v1.22.5. Fixed: [CVE-2024-24791](https://nvd.nist.gov/vuln/detail/CVE-2024-24791) - [GO-2024-2963](https://pkg.go.dev/vuln/GO-2024-2963): Denial of service due to improper 100-continue handling in net/http. The net/http HTTP/1.1 client mishandled the case where a server responds to a request with an "Expect: 100-continue" header with a non-informational (200 or higher) status. This mishandling could leave a client connection in an invalid state, where the next request sent on the connection will fail. An attacker sending a request to a net/http/httputil.ReverseProxy proxy can exploit this mishandling to cause a denial of service by sending "Expect: 100-continue" requests which elicit a non-informational response from the backend. Each such request leaves the proxy with an invalid connection, and causes one subsequent request using that connection to fail. - -* **Bug fixes:** - * [backport](https://codeberg.org/forgejo/forgejo/pulls/4059) - [PR](https://codeberg.org/forgejo/forgejo/pulls/4194): Fixed: authentication Source Administration page wrongfully handles the "Custom URLs Instead of Default URLs" checkbox (missing checkbox, irrelevant fields). - * [backport](https://codeberg.org/forgejo/forgejo/pulls/4151) - [PR](https://codeberg.org/forgejo/forgejo/pulls/4149): Fixed: git push to an adopted repository fails. - * [backport](https://codeberg.org/forgejo/forgejo/pulls/4215) - [PR](https://codeberg.org/forgejo/forgejo/pulls/4213) - [commit](https://codeberg.org/forgejo/forgejo/commit/4ed5044dea94872e025f585debf7a16e6bd6bbdb): Fixed: markdown doesn't render math within brackets - * [backport](https://codeberg.org/forgejo/forgejo/pulls/4219) - [PR](https://codeberg.org/forgejo/forgejo/pulls/4145) - [commit](https://codeberg.org/forgejo/forgejo/commit/9aa3ae955ff506d883737e576dd62f674a3ee372): Fixed: selecting the "No Project" filter in the issue/pull request list has no effect - * [backport](https://codeberg.org/forgejo/forgejo/pulls/4248) - [PR](https://codeberg.org/forgejo/forgejo/pulls/4241): Fixed: error 500 when processing crafted TIFF files. - * [backport](https://codeberg.org/forgejo/forgejo/pulls/4261) - [PR](https://codeberg.org/forgejo/forgejo/pulls/4258): Fixed: wrong placeholder text in the form for adding repository collaborator. +- [8.0.0](release-notes/8.0.0/) ## 7.0.4 @@ -376,7 +143,7 @@ $ git -C forgejo log --oneline --no-merges origin/v1.21/forgejo..origin/v7.0/for * `process-description` to `processDescription` This allows for those endpoints to be scraped by services requiring prometheus style labels such as [grafana-agent](https://grafana.com/docs/agent/latest/). * The repository description [imposes additional restrictions on what it contains](https://codeberg.org/forgejo/forgejo/commit/1075ff74b5050f671c5f9824ae39390230b3c85d) to prevent abuse. You may use [the v7.0 test instance](https://v7.next.forgejo.org/) to check how it will be modified. - * The [Gitea themes were renamed](https://codeberg.org/forgejo/forgejo/commit/023e937141dd891bce3370c869d4db2c60f971ed) and the `[ui].THEMES` setting must be changed as follows: + * The [Gitea themes were renamed](https://codeberg.org/forgejo/forgejo/commit/023e937141dd891bce3370c869d4db2c60f971ed) and the `[ui].THEMES` setting must be changed as follows: * `gitea` is replaced by `gitea-light` * `arc-green` is replaced by `gitea-dark` * `auto` is replaced by `gitea-auto` @@ -1590,7 +1357,7 @@ this situation, [follow the instructions in the companion blog post](https://for The most prominent ones are described here, others can be found in the list of commits included in the release as described above. - * [Fix links to pull request reviews sent via mail](https://codeberg.org/forgejo/forgejo/commit/88e179d5ef8ee41f71d068195685ff098b38ca31). The pull request link was correct but it did not go the review and stayed at the beginning of the page + * [Fix links to pull request reviews sent via mail](https://codeberg.org/forgejo/forgejo/commit/88e179d5ef8ee41f71d068195685ff098b38ca31). The pull request link was correct but it did not go the the review and stayed at the beginning of the page * [Recognize OGG as an audio format](https://codeberg.org/forgejo/forgejo/commit/622ec5c79f299c32ac2667a1aa7b4bf5d7c2d6cf) * [Consistently show the last time a cron job was run in the admin panel](https://codeberg.org/forgejo/forgejo/commit/5f769ef20) * [Fix NuGet registry v2 & v3 API search endpoints](https://codeberg.org/forgejo/forgejo/commit/471138829b0c24fe8c621dbb866ae8bb45ebc674) @@ -1609,7 +1376,7 @@ this situation, [follow the instructions in the companion blog post](https://for * [Fix pull request check list when there are more than 30](https://codeberg.org/forgejo/forgejo/commit/e226b9646) * [Fix attachment clipboard copy on insecure origin](https://codeberg.org/forgejo/forgejo/commit/12ac84c26) * [Fix the profile README rendering](https://codeberg.org/forgejo/forgejo/commit/84c3b60a4) that [was inconsistent with other markdown files renderings](https://codeberg.org/forgejo/forgejo/issues/833) - * [Fix API leaking the user email when the caller is not authenticated](https://codeberg.org/forgejo/forgejo/commit/d89003cc1) + * [Fix API leaking the user email when the caller is not authentified](https://codeberg.org/forgejo/forgejo/commit/d89003cc1) ## 1.20.2-0 @@ -1667,7 +1434,7 @@ $ git -C forgejo log --oneline --no-merges origin/v1.19/forgejo..origin/v1.20/fo The semantic version was updated to `5.0.0+0-gitea-1.20.1` because it contains breaking changes. - **Breaking:** - [Scoped access tokens](https://codeberg.org/forgejo/forgejo/commit/18de83b2a3fc120922096b7348d6375094ae1532) or (Personal Access Tokens), were refactored and although existing tokens are still valid, they may have a different scope than before. To ensure that no tokens have a larger scope than expected they must be removed and recreated. - - If your `app.ini` has one of the following `[indexer].ISSUE_INDEXER_QUEUE_TYPE`, `[indexer].ISSUE_INDEXER_QUEUE_BATCH_NUMBER`, `[indexer].`, `[indexer].ISSUE_INDEXER_QUEUE_DIR`, `[indexer].ISSUE_INDEXER_QUEUE_CONN_STR`, `[indexer].UPDATE_BUFFER_LEN`, `[mailer].SEND_BUFFER_LEN`, `[repository].PULL_REQUEST_QUEUE_LENGTH` or `[repository].MIRROR_QUEUE_LENGTH`, Forgejo will abort immediately. Unless you know exactly what you're doing, you must comment them out so the default values are used. + - If your `app.ini` has one of the the following `[indexer].ISSUE_INDEXER_QUEUE_TYPE`, `[indexer].ISSUE_INDEXER_QUEUE_BATCH_NUMBER`, `[indexer].`, `[indexer].ISSUE_INDEXER_QUEUE_DIR`, `[indexer].ISSUE_INDEXER_QUEUE_CONN_STR`, `[indexer].UPDATE_BUFFER_LEN`, `[mailer].SEND_BUFFER_LEN`, `[repository].PULL_REQUEST_QUEUE_LENGTH` or `[repository].MIRROR_QUEUE_LENGTH`, Forgejo will abort immediately. Unless you know exactly what you're doing, you must comment them out so the default values are used. - The `-p` option of `environment-to-ini` is [no longer supported](https://codeberg.org/forgejo/forgejo/commit/fa0b5b14c2faa6a5f76bb2e7bc9241a5e4354189) - The ".png" suffix for [user and organizations is now reserved](https://codeberg.org/forgejo/forgejo/commit/2b91841cd3e1213ff3e4ed4209d6a4be89c2fa79) - The section `[git.reflog]` is [now obsolete and its keys have been moved](https://codeberg.org/forgejo/forgejo/commit/2f149c5c9db97f20fbbc65e32d1f3133048b11a2) to the following replacements: @@ -1761,7 +1528,7 @@ $ git -C forgejo log --oneline --no-merges origin/v1.19/forgejo..origin/v1.20/fo - [The repository migration can be canceled](https://codeberg.org/forgejo/forgejo/commit/f6e029e6c7849d4361abf7f1d749b5d528364ac4) - [Add button on the diff header to copy the file name](https://codeberg.org/forgejo/forgejo/commit/c5ede35124c8d5280219c24049bb0ad7da9f02ed) - [Add --quiet option to the dump CLI](https://codeberg.org/forgejo/forgejo/commit/cb1536471bcef4d78a3fe5cbd738b9f60fabbcc2) - - [Support searching for an issue with its number in the list of issues](https://codeberg.org/forgejo/forgejo/commit/1144b1d129de530b2c07dfdfaf55de383cd82212) + - [Support searching for an issue with its number in the the list of issues](https://codeberg.org/forgejo/forgejo/commit/1144b1d129de530b2c07dfdfaf55de383cd82212) - [Improve the list of notifications](https://codeberg.org/forgejo/forgejo/commit/f7ede92f82f7f3ec7bb31a1249f9524e5b728f34) - [When editing a file in the web UI, allow for a preview whenever possible](https://codeberg.org/forgejo/forgejo/commit/ac64c8297444ade63a2a364c4afb7e6c1de5a75f) - [Make release download URLs human readable](https://codeberg.org/forgejo/forgejo/commit/42919ccb7cd32ab67d0878baf2bac6cd007899a8) @@ -1798,7 +1565,7 @@ $ git -C forgejo log --oneline --no-merges origin/v1.19/forgejo..origin/v1.20/fo - [Add API for gitignore templates](https://codeberg.org/forgejo/forgejo/commit/36a5d4c2f3b5670e5e921034cd5d25817534a6d4) - [Add API to upuload a file to an empty repository](https://codeberg.org/forgejo/forgejo/commit/cf465b472166ccf6d3e001e3043e4bf43e16e6b3) - [Allow for --not when listing the commits of a repo](https://codeberg.org/forgejo/forgejo/commit/f766b002938b5c81e343c81fda3c0669fa09809f) - - [Add `files` and `verification` parameters to improve performances when listing the commits of a repo](https://codeberg.org/forgejo/forgejo/commit/1dd83dbb917d55bd253001646d6743f247a4d98b) + - [Add `files` and `verification` parameters to improve performances when listing the commits of a a repo](https://codeberg.org/forgejo/forgejo/commit/1dd83dbb917d55bd253001646d6743f247a4d98b) - [Allow for listing a single commit in a repository](https://codeberg.org/forgejo/forgejo/commit/5930ab5fdf7a970fcca3cd50b44cf1cacb615a54) - [Create a branch directly from commit on the create branch API](https://codeberg.org/forgejo/forgejo/commit/cd9a13ebb47d32f46b38439a524e3b2e0c619490) - [Add API for Label templates](https://codeberg.org/forgejo/forgejo/commit/25dc1556cd70b567a4920beb002a0addfbfd6ef2) @@ -2261,7 +2028,7 @@ This stable release includes a security fix for `git` and bug fixes. ### Git -Git [recently announced](https://github.blog/2023-02-14-git-security-vulnerabilities-announced-3/) new versions to address two CVEs ([CVE-2023-22490](https://cve.circl.lu/cve/CVE-2023-22490), [CVE-2023-23946](https://cve.circl.lu/cve/CVE-2023-23946)). On 14 February 2023, Git published the maintenance release v2.39.2, together with releases for older maintenance tracks v2.38.4, v2.37.6, v2.36.5, v2.35.7, v2.34.7, v2.33.7, v2.32.6, v2.31.7, and v2.30.8. All major GNU/Linux distributions also provide updated packages via their security update channels. +Git [recently announced](https://github.blog/2023-02-14-git-security-vulnerabilities-announced-3/) new versions to address two CVEs ([CVE-2023-22490](https://cve.circl.lu/cve/CVE-2023-22490), [CVE-2023-23946](https://cve.circl.lu/cve/CVE-2023-23946)). On 14 Februrary 2023, Git published the maintenance release v2.39.2, together with releases for older maintenance tracks v2.38.4, v2.37.6, v2.36.5, v2.35.7, v2.34.7, v2.33.7, v2.32.6, v2.31.7, and v2.30.8. All major GNU/Linux distributions also provide updated packages via their security update channels. We recommend that all installations running a version affected by the issues described below are upgraded to the latest version as soon as possible. diff --git a/assets/favicon.svg b/assets/favicon.svg index bb0031b93d..bcacdc0200 100644 --- a/assets/favicon.svg +++ b/assets/favicon.svg @@ -1,33 +1,27 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + diff --git a/assets/go-licenses.json b/assets/go-licenses.json index fb6c201a5e..8dc0d008f6 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -1,9 +1,4 @@ [ - { - "name": "codeberg.org/forgejo/forgejo", - "path": "codeberg.org/forgejo/forgejo/GPL-3.0-or-later", - "licenseText": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. \u003chttps://fsf.org/\u003e\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n Preamble\n\n The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works. By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users. We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors. You can apply it to\nyour programs, too.\n\n When we speak of free software, we are referring to freedom, not\nprice. Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights. Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received. You must make sure that they, too, receive\nor can get the source code. And you must show them these terms so they\nknow their rights.\n\n Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software. For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so. This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software. The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable. Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts. If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary. To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n The precise terms and conditions for copying, distribution and\nmodification follow.\n\n TERMS AND CONDITIONS\n\n 0. Definitions.\n\n \"This License\" refers to version 3 of the GNU General Public License.\n\n \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n \"The Program\" refers to any copyrightable work licensed under this\nLicense. Each licensee is addressed as \"you\". \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy. The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy. Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies. Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License. If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n 1. Source Code.\n\n The \"source code\" for a work means the preferred form of the work\nfor making modifications to it. \"Object code\" means any non-source\nform of a work.\n\n A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form. A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities. However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work. For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n The Corresponding Source for a work in source code form is that\nsame work.\n\n 2. Basic Permissions.\n\n All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met. This License explicitly affirms your unlimited\npermission to run the unmodified Program. The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work. This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force. You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright. Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n Conveying under any other circumstances is permitted solely under\nthe conditions stated below. Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n 4. Conveying Verbatim Copies.\n\n You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n 5. Conveying Modified Source Versions.\n\n You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n a) The work must carry prominent notices stating that you modified\n it, and giving a relevant date.\n\n b) The work must carry prominent notices stating that it is\n released under this License and any conditions added under section\n 7. This requirement modifies the requirement in section 4 to\n \"keep intact all notices\".\n\n c) You must license the entire work, as a whole, under this\n License to anyone who comes into possession of a copy. This\n License will therefore apply, along with any applicable section 7\n additional terms, to the whole of the work, and all its parts,\n regardless of how they are packaged. This License gives no\n permission to license the work in any other way, but it does not\n invalidate such permission if you have separately received it.\n\n d) If the work has interactive user interfaces, each must display\n Appropriate Legal Notices; however, if the Program has interactive\n interfaces that do not display Appropriate Legal Notices, your\n work need not make them do so.\n\n A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit. Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n 6. Conveying Non-Source Forms.\n\n You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n a) Convey the object code in, or embodied in, a physical product\n (including a physical distribution medium), accompanied by the\n Corresponding Source fixed on a durable physical medium\n customarily used for software interchange.\n\n b) Convey the object code in, or embodied in, a physical product\n (including a physical distribution medium), accompanied by a\n written offer, valid for at least three years and valid for as\n long as you offer spare parts or customer support for that product\n model, to give anyone who possesses the object code either (1) a\n copy of the Corresponding Source for all the software in the\n product that is covered by this License, on a durable physical\n medium customarily used for software interchange, for a price no\n more than your reasonable cost of physically performing this\n conveying of source, or (2) access to copy the\n Corresponding Source from a network server at no charge.\n\n c) Convey individual copies of the object code with a copy of the\n written offer to provide the Corresponding Source. This\n alternative is allowed only occasionally and noncommercially, and\n only if you received the object code with such an offer, in accord\n with subsection 6b.\n\n d) Convey the object code by offering access from a designated\n place (gratis or for a charge), and offer equivalent access to the\n Corresponding Source in the same way through the same place at no\n further charge. You need not require recipients to copy the\n Corresponding Source along with the object code. If the place to\n copy the object code is a network server, the Corresponding Source\n may be on a different server (operated by you or a third party)\n that supports equivalent copying facilities, provided you maintain\n clear directions next to the object code saying where to find the\n Corresponding Source. Regardless of what server hosts the\n Corresponding Source, you remain obligated to ensure that it is\n available for as long as needed to satisfy these requirements.\n\n e) Convey the object code using peer-to-peer transmission, provided\n you inform other peers where the object code and Corresponding\n Source of the work are being offered to the general public at no\n charge under subsection 6d.\n\n A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling. In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage. For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product. A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source. The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information. But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed. Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n 7. Additional Terms.\n\n \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law. If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit. (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.) You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n a) Disclaiming warranty or limiting liability differently from the\n terms of sections 15 and 16 of this License; or\n\n b) Requiring preservation of specified reasonable legal notices or\n author attributions in that material or in the Appropriate Legal\n Notices displayed by works containing it; or\n\n c) Prohibiting misrepresentation of the origin of that material, or\n requiring that modified versions of such material be marked in\n reasonable ways as different from the original version; or\n\n d) Limiting the use for publicity purposes of names of licensors or\n authors of the material; or\n\n e) Declining to grant rights under trademark law for use of some\n trade names, trademarks, or service marks; or\n\n f) Requiring indemnification of licensors and authors of that\n material by anyone who conveys the material (or modified versions of\n it) with contractual assumptions of liability to the recipient, for\n any liability that these contractual assumptions directly impose on\n those licensors and authors.\n\n All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10. If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term. If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n 8. Termination.\n\n You may not propagate or modify a covered work except as expressly\nprovided under this License. Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License. If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n 9. Acceptance Not Required for Having Copies.\n\n You are not required to accept this License in order to receive or\nrun a copy of the Program. Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance. However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work. These actions infringe copyright if you do\nnot accept this License. Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n 10. Automatic Licensing of Downstream Recipients.\n\n Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License. You are not responsible\nfor enforcing compliance by third parties with this License.\n\n An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations. If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License. For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n 11. Patents.\n\n A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based. The\nwork thus licensed is called the contributor's \"contributor version\".\n\n A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version. For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement). To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients. \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License. You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n 12. No Surrender of Others' Freedom.\n\n If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License. If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all. For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n 13. Use with the GNU Affero General Public License.\n\n Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work. The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n 14. Revised Versions of this License.\n\n The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time. Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n Each version is given a distinguishing version number. If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation. If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n Later license versions may give you additional or different\npermissions. However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n 15. Disclaimer of Warranty.\n\n THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n 16. Limitation of Liability.\n\n IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n 17. Interpretation of Sections 15 and 16.\n\n If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n END OF TERMS AND CONDITIONS\n\n How to Apply These Terms to Your New Programs\n\n If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n To do so, attach the following notices to the program. It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n \u003cone line to give the program's name and a brief idea of what it does.\u003e\n Copyright (C) \u003cyear\u003e \u003cname of author\u003e\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n \u003cprogram\u003e Copyright (C) \u003cyear\u003e \u003cname of author\u003e\n This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n This is free software, and you are welcome to redistribute it\n under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License. Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n\u003chttps://www.gnu.org/licenses/\u003e.\n\n The GNU General Public License does not permit incorporating your program\ninto proprietary programs. If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library. If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License. But first, please read\n\u003chttps://www.gnu.org/licenses/why-not-lgpl.html\u003e.\n" - }, { "name": "cloud.google.com/go/compute/metadata", "path": "cloud.google.com/go/compute/metadata/LICENSE", @@ -14,51 +9,21 @@ "path": "code.forgejo.org/f3/gof3/v3/LICENSE", "licenseText": "Copyright Earl Warren \u003ccontact@earl-warren.org\u003e\nCopyright Loïc Dachary \u003cloic@dachary.org\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" }, - { - "name": "code.forgejo.org/forgejo-contrib/go-libravatar", - "path": "code.forgejo.org/forgejo-contrib/go-libravatar/LICENSE", - "licenseText": "Copyright (c) 2016 Sandro Santilli \u003cstrk@kbt.io\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/go-rpmutils", - "path": "code.forgejo.org/forgejo/go-rpmutils/LICENSE", - "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, - { - "name": "code.forgejo.org/forgejo/levelqueue", - "path": "code.forgejo.org/forgejo/levelqueue/LICENSE", - "licenseText": "Copyright (c) 2019 Lunny Xiao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, { "name": "code.forgejo.org/forgejo/reply", "path": "code.forgejo.org/forgejo/reply/LICENSE", "licenseText": "MIT License\n\nCopyright (c) The Forgejo Authors\nCopyright (c) Discourse\nCopyright (c) Claudemiro\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "code.forgejo.org/go-chi/binding", - "path": "code.forgejo.org/go-chi/binding/LICENSE", - "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." - }, - { - "name": "code.forgejo.org/go-chi/cache", - "path": "code.forgejo.org/go-chi/cache/LICENSE", - "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." - }, - { - "name": "code.forgejo.org/go-chi/captcha", - "path": "code.forgejo.org/go-chi/captcha/LICENSE", - "licenseText": "Copyright (c) 2011-2014 Dmitry Chestnykh \u003cdmitry@codingrobots.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/go-chi/session", - "path": "code.forgejo.org/go-chi/session/LICENSE", - "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." - }, { "name": "code.gitea.io/actions-proto-go", "path": "code.gitea.io/actions-proto-go/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2022 The Gitea Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, + { + "name": "code.gitea.io/gitea/modules/lfs", + "path": "code.gitea.io/gitea/modules/lfs/LICENSE", + "licenseText": "Copyright (c) 2016 The Gitea Authors\nCopyright (c) GitHub, Inc. and LFS Test Server contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, { "name": "code.gitea.io/sdk/gitea", "path": "code.gitea.io/sdk/gitea/LICENSE", @@ -90,9 +55,29 @@ "licenseText": "MIT License\n\nCopyright (c) 2019 Go xsd:duration\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "name": "github.com/42wim/httpsig", - "path": "github.com/42wim/httpsig/LICENSE", - "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2018, go-fed\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "name": "gitea.com/go-chi/binding", + "path": "gitea.com/go-chi/binding/LICENSE", + "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." + }, + { + "name": "gitea.com/go-chi/cache", + "path": "gitea.com/go-chi/cache/LICENSE", + "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." + }, + { + "name": "gitea.com/go-chi/captcha", + "path": "gitea.com/go-chi/captcha/LICENSE", + "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." + }, + { + "name": "gitea.com/go-chi/session", + "path": "gitea.com/go-chi/session/LICENSE", + "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." + }, + { + "name": "gitea.com/lunny/levelqueue", + "path": "gitea.com/lunny/levelqueue/LICENSE", + "licenseText": "Copyright (c) 2019 Lunny Xiao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" }, { "name": "github.com/42wim/sshsig", @@ -104,21 +89,31 @@ "path": "github.com/Azure/go-ntlmssp/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, + { + "name": "github.com/ClickHouse/ch-go", + "path": "github.com/ClickHouse/ch-go/LICENSE", + "licenseText": "Copyright 2016-2023 ClickHouse, Inc.\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016-2023 ClickHouse, Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "name": "github.com/ClickHouse/clickhouse-go/v2", + "path": "github.com/ClickHouse/clickhouse-go/v2/LICENSE", + "licenseText": "Copyright 2016-2023 ClickHouse, Inc.\n\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016-2023 ClickHouse, Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "name": "github.com/DataDog/zstd", + "path": "github.com/DataDog/zstd/LICENSE", + "licenseText": "Simplified BSD License\n\nCopyright (c) 2016, Datadog \u003cinfo@datadoghq.com\u003e\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n * Neither the name of the copyright holder nor the names of its contributors\n may be used to endorse or promote products derived from this software\n without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, { "name": "github.com/ProtonMail/go-crypto", "path": "github.com/ProtonMail/go-crypto/LICENSE", "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { - "name": "github.com/RoaringBitmap/roaring/v2", - "path": "github.com/RoaringBitmap/roaring/v2/LICENSE", + "name": "github.com/RoaringBitmap/roaring", + "path": "github.com/RoaringBitmap/roaring/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016 by the authors\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n================================================================================\n\nPortions of runcontainer.go are from the Go standard library, which is licensed\nunder:\n\nCopyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "github.com/SaveTheRbtz/zstd-seekable-format-go/pkg", - "path": "github.com/SaveTheRbtz/zstd-seekable-format-go/pkg/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2022 Alexey Ivanov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "github.com/alecthomas/chroma/v2", "path": "github.com/alecthomas/chroma/v2/COPYING", @@ -289,10 +284,30 @@ "path": "github.com/cloudflare/circl/LICENSE", "licenseText": "Copyright (c) 2019 Cloudflare. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Cloudflare nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n========================================================================\n\nCopyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, + { + "name": "github.com/couchbase/go-couchbase", + "path": "github.com/couchbase/go-couchbase/LICENSE", + "licenseText": "Copyright (c) 2013 Couchbase, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "name": "github.com/couchbase/gomemcached", + "path": "github.com/couchbase/gomemcached/LICENSE", + "licenseText": "Copyright (c) 2013 Dustin Sallings\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" + }, + { + "name": "github.com/couchbase/goutils", + "path": "github.com/couchbase/goutils/LICENSE.md", + "licenseText": "Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n" + }, + { + "name": "github.com/cpuguy83/go-md2man/v2/md2man", + "path": "github.com/cpuguy83/go-md2man/v2/md2man/LICENSE.md", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014 Brian Goff\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, { "name": "github.com/cyphar/filepath-securejoin", "path": "github.com/cyphar/filepath-securejoin/LICENSE", - "licenseText": "Copyright (C) 2014-2015 Docker Inc \u0026 Go Authors. All rights reserved.\nCopyright (C) 2017-2024 SUSE LLC. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (C) 2014-2015 Docker Inc \u0026 Go Authors. All rights reserved.\nCopyright (C) 2017 SUSE LLC. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "github.com/davecgh/go-spew/spew", @@ -414,6 +429,16 @@ "path": "github.com/go-enry/go-enry/v2/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." }, + { + "name": "github.com/go-faster/city", + "path": "github.com/go-faster/city/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2018 tenfy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "name": "github.com/go-faster/errors", + "path": "github.com/go-faster/errors/LICENSE", + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, { "name": "github.com/go-fed/httpsig", "path": "github.com/go-fed/httpsig/LICENSE", @@ -434,11 +459,6 @@ "path": "github.com/go-git/go-git/v5/LICENSE", "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2018 Sourced Technologies, S.L.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, - { - "name": "github.com/go-ini/ini", - "path": "github.com/go-ini/ini/LICENSE", - "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright 2014 Unknwon\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, { "name": "github.com/go-ldap/ldap/v3", "path": "github.com/go-ldap/ldap/v3/LICENSE", @@ -449,6 +469,11 @@ "path": "github.com/go-sql-driver/mysql/LICENSE", "licenseText": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n means each individual or legal entity that creates, contributes to\n the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n means the combination of the Contributions of others (if any) used\n by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n means Source Code Form to which the initial Contributor has attached\n the notice in Exhibit A, the Executable Form of such Source Code\n Form, and Modifications of such Source Code Form, in each case\n including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n means\n\n (a) that the initial Contributor has attached the notice described\n in Exhibit B to the Covered Software; or\n\n (b) that the Covered Software was made available under the terms of\n version 1.1 or earlier of the License, but not also under the\n terms of a Secondary License.\n\n1.6. \"Executable Form\"\n means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n means a work that combines Covered Software with other material, in \n a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n means this document.\n\n1.9. \"Licensable\"\n means having the right to grant, to the maximum extent possible,\n whether at the time of the initial grant or subsequently, any and\n all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n means any of the following:\n\n (a) any file in Source Code Form that results from an addition to,\n deletion from, or modification of the contents of Covered\n Software; or\n\n (b) any new file in Source Code Form that contains any Covered\n Software.\n\n1.11. \"Patent Claims\" of a Contributor\n means any patent claim(s), including without limitation, method,\n process, and apparatus claims, in any patent Licensable by such\n Contributor that would be infringed, but for the grant of the\n License, by the making, using, selling, offering for sale, having\n made, import, or transfer of either its Contributions or its\n Contributor Version.\n\n1.12. \"Secondary License\"\n means either the GNU General Public License, Version 2.0, the GNU\n Lesser General Public License, Version 2.1, the GNU Affero General\n Public License, Version 3.0, or any later versions of those\n licenses.\n\n1.13. \"Source Code Form\"\n means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n means an individual or a legal entity exercising rights under this\n License. For legal entities, \"You\" includes any entity that\n controls, is controlled by, or is under common control with You. For\n purposes of this definition, \"control\" means (a) the power, direct\n or indirect, to cause the direction or management of such entity,\n whether by contract or otherwise, or (b) ownership of more than\n fifty percent (50%) of the outstanding shares or beneficial\n ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n Licensable by such Contributor to use, reproduce, make available,\n modify, display, perform, distribute, and otherwise exploit its\n Contributions, either on an unmodified basis, with Modifications, or\n as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n for sale, have made, import, and otherwise transfer either its\n Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n or\n\n(b) for infringements caused by: (i) Your and any other third party's\n modifications of Covered Software, or (ii) the combination of its\n Contributions with other software (except as part of its Contributor\n Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n Form, as described in Section 3.1, and You must inform recipients of\n the Executable Form how they can obtain a copy of such Source Code\n Form by reasonable means in a timely manner, at a charge no more\n than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n License, or sublicense it under different terms, provided that the\n license for the Executable Form does not attempt to limit or alter\n the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n* *\n* 6. Disclaimer of Warranty *\n* ------------------------- *\n* *\n* Covered Software is provided under this License on an \"as is\" *\n* basis, without warranty of any kind, either expressed, implied, or *\n* statutory, including, without limitation, warranties that the *\n* Covered Software is free of defects, merchantable, fit for a *\n* particular purpose or non-infringing. The entire risk as to the *\n* quality and performance of the Covered Software is with You. *\n* Should any Covered Software prove defective in any respect, You *\n* (not any Contributor) assume the cost of any necessary servicing, *\n* repair, or correction. This disclaimer of warranty constitutes an *\n* essential part of this License. No use of any Covered Software is *\n* authorized under this License except under this disclaimer. *\n* *\n************************************************************************\n\n************************************************************************\n* *\n* 7. Limitation of Liability *\n* -------------------------- *\n* *\n* Under no circumstances and under no legal theory, whether tort *\n* (including negligence), contract, or otherwise, shall any *\n* Contributor, or anyone who distributes Covered Software as *\n* permitted above, be liable to You for any direct, indirect, *\n* special, incidental, or consequential damages of any character *\n* including, without limitation, damages for lost profits, loss of *\n* goodwill, work stoppage, computer failure or malfunction, or any *\n* and all other commercial damages or losses, even if such party *\n* shall have been informed of the possibility of such damages. This *\n* limitation of liability shall not apply to liability for death or *\n* personal injury resulting from such party's negligence to the *\n* extent applicable law prohibits such limitation. Some *\n* jurisdictions do not allow the exclusion or limitation of *\n* incidental or consequential damages, so this exclusion and *\n* limitation may not apply to You. *\n* *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n This Source Code Form is subject to the terms of the Mozilla Public\n License, v. 2.0. If a copy of the MPL was not distributed with this\n file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n This Source Code Form is \"Incompatible With Secondary Licenses\", as\n defined by the Mozilla Public License, v. 2.0.\n" }, + { + "name": "github.com/go-testfixtures/testfixtures/v3", + "path": "github.com/go-testfixtures/testfixtures/v3/LICENSE", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Andrey Nering\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, { "name": "github.com/go-webauthn/webauthn", "path": "github.com/go-webauthn/webauthn/LICENSE", @@ -489,14 +514,19 @@ "path": "github.com/golang-jwt/jwt/v5/LICENSE", "licenseText": "Copyright (c) 2012 Dave Grijalva\nCopyright (c) 2021 golang-jwt maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n" }, + { + "name": "github.com/golang/geo", + "path": "github.com/golang/geo/LICENSE", + "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, { "name": "github.com/golang/groupcache/lru", "path": "github.com/golang/groupcache/lru/LICENSE", "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { - "name": "github.com/golang/protobuf/proto", - "path": "github.com/golang/protobuf/proto/LICENSE", + "name": "github.com/golang/protobuf", + "path": "github.com/golang/protobuf/LICENSE", "licenseText": "Copyright 2010 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" }, { @@ -504,19 +534,14 @@ "path": "github.com/golang/snappy/LICENSE", "licenseText": "Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "github.com/google/btree", - "path": "github.com/google/btree/LICENSE", - "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, { "name": "github.com/google/go-cmp/cmp", "path": "github.com/google/go-cmp/cmp/LICENSE", "licenseText": "Copyright (c) 2017 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { - "name": "github.com/google/go-github/v64/github", - "path": "github.com/google/go-github/v64/github/LICENSE", + "name": "github.com/google/go-github/v57/github", + "path": "github.com/google/go-github/v57/github/LICENSE", "licenseText": "Copyright (c) 2013 The go-github AUTHORS. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { @@ -562,7 +587,7 @@ { "name": "github.com/gorilla/sessions", "path": "github.com/gorilla/sessions/LICENSE", - "licenseText": "Copyright (c) 2024 The Gorilla Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n\t * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\t * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2023 The Gorilla Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n\t * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\t * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "github.com/hashicorp/go-cleanhttp", @@ -605,8 +630,8 @@ "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014 Juan Batiz-Benet\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" }, { - "name": "github.com/jhillyerd/enmime/v2", - "path": "github.com/jhillyerd/enmime/v2/LICENSE", + "name": "github.com/jhillyerd/enmime", + "path": "github.com/jhillyerd/enmime/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2012-2016 James Hillyerd, All Rights Reserved\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, { @@ -629,6 +654,11 @@ "path": "github.com/kevinburke/ssh_config/LICENSE", "licenseText": "Copyright (c) 2017 Kevin Burke.\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\n===================\n\nThe lexer and parser borrow heavily from github.com/pelletier/go-toml. The\nlicense for that project is copied below.\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, + { + "name": "github.com/keybase/go-crypto", + "path": "github.com/keybase/go-crypto/LICENSE", + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, { "name": "github.com/klauspost/compress", "path": "github.com/klauspost/compress/LICENSE", @@ -707,11 +737,11 @@ { "name": "github.com/meilisearch/meilisearch-go", "path": "github.com/meilisearch/meilisearch-go/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2020-2025 Meili SAS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + "licenseText": "MIT License\n\nCopyright (c) 2020-2024 Meili SAS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "name": "github.com/mholt/acmez/v3", - "path": "github.com/mholt/acmez/v3/LICENSE", + "name": "github.com/mholt/acmez/v2", + "path": "github.com/mholt/acmez/v2/LICENSE", "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { @@ -722,18 +752,13 @@ { "name": "github.com/microcosm-cc/bluemonday", "path": "github.com/microcosm-cc/bluemonday/LICENSE.md", - "licenseText": "Copyright (c) 2014, David Kitchen \u003cdavid@buro9.com\u003e\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the organisation (Microcosm) nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "SPDX short identifier: BSD-3-Clause\nhttps://opensource.org/licenses/BSD-3-Clause\n\nCopyright (c) 2014, David Kitchen \u003cdavid@buro9.com\u003e\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the organisation (Microcosm) nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "github.com/miekg/dns", "path": "github.com/miekg/dns/LICENSE", "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2009, The Go Authors. Extensions copyright (c) 2011, Miek Gieben. \nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "github.com/minio/crc64nvme", - "path": "github.com/minio/crc64nvme/LICENSE", - "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, { "name": "github.com/minio/md5-simd", "path": "github.com/minio/md5-simd/LICENSE", @@ -759,11 +784,6 @@ "path": "github.com/modern-go/reflect2/LICENSE", "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, - { - "name": "github.com/munnerz/goautoneg", - "path": "github.com/munnerz/goautoneg/LICENSE", - "licenseText": "Copyright (c) 2011, Open Knowledge Foundation Ltd.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n\n Neither the name of the Open Knowledge Foundation Ltd. nor the\n names of its contributors may be used to endorse or promote\n products derived from this software without specific prior written\n permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - }, { "name": "github.com/nektos/act/pkg", "path": "github.com/nektos/act/pkg/LICENSE", @@ -805,9 +825,9 @@ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n Copyright 2016 The Linux Foundation.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { - "name": "github.com/philhofer/fwd", - "path": "github.com/philhofer/fwd/LICENSE.md", - "licenseText": "Copyright (c) 2014-2015, Philip Hofer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + "name": "github.com/paulmach/orb", + "path": "github.com/paulmach/orb/LICENSE.md", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 Paul Mach\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, { "name": "github.com/pierrec/lz4/v4", @@ -817,7 +837,7 @@ { "name": "github.com/pjbgf/sha1cd", "path": "github.com/pjbgf/sha1cd/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2023 pjbgf\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { "name": "github.com/pkg/errors", @@ -834,11 +854,6 @@ "path": "github.com/pquerna/otp/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, - { - "name": "github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil", - "path": "github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/LICENSE", - "licenseText": "Copyright (c) 2013 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - }, { "name": "github.com/prometheus/client_golang/prometheus", "path": "github.com/prometheus/client_golang/prometheus/LICENSE", @@ -884,16 +899,41 @@ "path": "github.com/rs/xid/LICENSE", "licenseText": "Copyright (c) 2015 Olivier Poitrey \u003crs@dailymotion.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" }, + { + "name": "github.com/russross/blackfriday/v2", + "path": "github.com/russross/blackfriday/v2/LICENSE.txt", + "licenseText": "Blackfriday is distributed under the Simplified BSD License:\n\n\u003e Copyright © 2011 Russ Ross\n\u003e All rights reserved.\n\u003e\n\u003e Redistribution and use in source and binary forms, with or without\n\u003e modification, are permitted provided that the following conditions\n\u003e are met:\n\u003e\n\u003e 1. Redistributions of source code must retain the above copyright\n\u003e notice, this list of conditions and the following disclaimer.\n\u003e\n\u003e 2. Redistributions in binary form must reproduce the above\n\u003e copyright notice, this list of conditions and the following\n\u003e disclaimer in the documentation and/or other materials provided with\n\u003e the distribution.\n\u003e\n\u003e THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\u003e \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\u003e LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n\u003e FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n\u003e COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n\u003e INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n\u003e BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n\u003e LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n\u003e CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n\u003e LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n\u003e ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n\u003e POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "name": "github.com/santhosh-tekuri/jsonschema/v5", + "path": "github.com/santhosh-tekuri/jsonschema/v5/LICENSE", + "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability." + }, { "name": "github.com/santhosh-tekuri/jsonschema/v6", "path": "github.com/santhosh-tekuri/jsonschema/v6/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability." }, + { + "name": "github.com/sassoftware/go-rpmutils", + "path": "github.com/sassoftware/go-rpmutils/LICENSE", + "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "name": "github.com/segmentio/asm", + "path": "github.com/segmentio/asm/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2021 Segment\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, { "name": "github.com/sergi/go-diff/diffmatchpatch", "path": "github.com/sergi/go-diff/diffmatchpatch/LICENSE", "licenseText": "Copyright (c) 2012-2016 The go-diff Authors. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\n" }, + { + "name": "github.com/shopspring/decimal", + "path": "github.com/shopspring/decimal/LICENSE", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015 Spring, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n- Based on https://github.com/oguzbilgic/fpd, which has the following license:\n\"\"\"\nThe MIT License (MIT)\n\nCopyright (c) 2013 Oguz Bilgic\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\n" + }, { "name": "github.com/sirupsen/logrus", "path": "github.com/sirupsen/logrus/LICENSE", @@ -919,20 +959,30 @@ "path": "github.com/syndtr/goleveldb/leveldb/LICENSE", "licenseText": "Copyright 2012 Suryandaru Triandana \u003csyndtr@gmail.com\u003e\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "github.com/tinylib/msgp/msgp", - "path": "github.com/tinylib/msgp/msgp/LICENSE", - "licenseText": "Copyright (c) 2014 Philip Hofer\nPortions Copyright (c) 2009 The Go Authors (license at http://golang.org) where indicated\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - }, { "name": "github.com/ulikunitz/xz", "path": "github.com/ulikunitz/xz/LICENSE", "licenseText": "Copyright (c) 2014-2022 Ulrich Kunitz\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* My name, Ulrich Kunitz, may not be used to endorse or promote products\n derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { - "name": "github.com/urfave/cli/v3", - "path": "github.com/urfave/cli/v3/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2023 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + "name": "github.com/unknwon/com", + "path": "github.com/unknwon/com/LICENSE", + "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." + }, + { + "name": "github.com/urfave/cli/v2", + "path": "github.com/urfave/cli/v2/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2022 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "name": "github.com/valyala/bytebufferpool", + "path": "github.com/valyala/bytebufferpool/LICENSE", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Aliaksandr Valialkin, VertaMedia\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" + }, + { + "name": "github.com/valyala/fasthttp", + "path": "github.com/valyala/fasthttp/LICENSE", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, { "name": "github.com/valyala/fastjson", @@ -944,11 +994,21 @@ "path": "github.com/x448/float16/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2019 Montgomery Edwards⁴⁴⁸ and Faye Amacker\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" }, + { + "name": "github.com/xanzy/go-gitlab", + "path": "github.com/xanzy/go-gitlab/LICENSE", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, { "name": "github.com/xanzy/ssh-agent", "path": "github.com/xanzy/ssh-agent/LICENSE", "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n" }, + { + "name": "github.com/xrash/smetrics", + "path": "github.com/xrash/smetrics/LICENSE", + "licenseText": "Copyright (C) 2016 Felipe da Cunha Gonçalves\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" + }, { "name": "github.com/yohcop/openid-go", "path": "github.com/yohcop/openid-go/LICENSE", @@ -959,6 +1019,11 @@ "path": "github.com/yuin/goldmark-highlighting/v2/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2019 Yusuke Inuzuka\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, + { + "name": "github.com/yuin/goldmark-meta", + "path": "github.com/yuin/goldmark-meta/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2019 Yusuke Inuzuka\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, { "name": "github.com/yuin/goldmark", "path": "github.com/yuin/goldmark/LICENSE", @@ -969,16 +1034,21 @@ "path": "github.com/zeebo/blake3/LICENSE", "licenseText": "This work is released into the public domain with CC0 1.0.\n\n-------------------------------------------------------------------------------\n\nCreative Commons Legal Code\n\nCC0 1.0 Universal\n\n CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE\n LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN\n ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS\n INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES\n REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS\n PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM\n THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED\n HEREUNDER.\n\nStatement of Purpose\n\nThe laws of most jurisdictions throughout the world automatically confer\nexclusive Copyright and Related Rights (defined below) upon the creator\nand subsequent owner(s) (each and all, an \"owner\") of an original work of\nauthorship and/or a database (each, a \"Work\").\n\nCertain owners wish to permanently relinquish those rights to a Work for\nthe purpose of contributing to a commons of creative, cultural and\nscientific works (\"Commons\") that the public can reliably and without fear\nof later claims of infringement build upon, modify, incorporate in other\nworks, reuse and redistribute as freely as possible in any form whatsoever\nand for any purposes, including without limitation commercial purposes.\nThese owners may contribute to the Commons to promote the ideal of a free\nculture and the further production of creative, cultural and scientific\nworks, or to gain reputation or greater distribution for their Work in\npart through the use and efforts of others.\n\nFor these and/or other purposes and motivations, and without any\nexpectation of additional consideration or compensation, the person\nassociating CC0 with a Work (the \"Affirmer\"), to the extent that he or she\nis an owner of Copyright and Related Rights in the Work, voluntarily\nelects to apply CC0 to the Work and publicly distribute the Work under its\nterms, with knowledge of his or her Copyright and Related Rights in the\nWork and the meaning and intended legal effect of CC0 on those rights.\n\n1. Copyright and Related Rights. A Work made available under CC0 may be\nprotected by copyright and related or neighboring rights (\"Copyright and\nRelated Rights\"). Copyright and Related Rights include, but are not\nlimited to, the following:\n\n i. the right to reproduce, adapt, distribute, perform, display,\n communicate, and translate a Work;\n ii. moral rights retained by the original author(s) and/or performer(s);\niii. publicity and privacy rights pertaining to a person's image or\n likeness depicted in a Work;\n iv. rights protecting against unfair competition in regards to a Work,\n subject to the limitations in paragraph 4(a), below;\n v. rights protecting the extraction, dissemination, use and reuse of data\n in a Work;\n vi. database rights (such as those arising under Directive 96/9/EC of the\n European Parliament and of the Council of 11 March 1996 on the legal\n protection of databases, and under any national implementation\n thereof, including any amended or successor version of such\n directive); and\nvii. other similar, equivalent or corresponding rights throughout the\n world based on applicable law or treaty, and any national\n implementations thereof.\n\n2. Waiver. To the greatest extent permitted by, but not in contravention\nof, applicable law, Affirmer hereby overtly, fully, permanently,\nirrevocably and unconditionally waives, abandons, and surrenders all of\nAffirmer's Copyright and Related Rights and associated claims and causes\nof action, whether now known or unknown (including existing as well as\nfuture claims and causes of action), in the Work (i) in all territories\nworldwide, (ii) for the maximum duration provided by applicable law or\ntreaty (including future time extensions), (iii) in any current or future\nmedium and for any number of copies, and (iv) for any purpose whatsoever,\nincluding without limitation commercial, advertising or promotional\npurposes (the \"Waiver\"). Affirmer makes the Waiver for the benefit of each\nmember of the public at large and to the detriment of Affirmer's heirs and\nsuccessors, fully intending that such Waiver shall not be subject to\nrevocation, rescission, cancellation, termination, or any other legal or\nequitable action to disrupt the quiet enjoyment of the Work by the public\nas contemplated by Affirmer's express Statement of Purpose.\n\n3. Public License Fallback. Should any part of the Waiver for any reason\nbe judged legally invalid or ineffective under applicable law, then the\nWaiver shall be preserved to the maximum extent permitted taking into\naccount Affirmer's express Statement of Purpose. In addition, to the\nextent the Waiver is so judged Affirmer hereby grants to each affected\nperson a royalty-free, non transferable, non sublicensable, non exclusive,\nirrevocable and unconditional license to exercise Affirmer's Copyright and\nRelated Rights in the Work (i) in all territories worldwide, (ii) for the\nmaximum duration provided by applicable law or treaty (including future\ntime extensions), (iii) in any current or future medium and for any number\nof copies, and (iv) for any purpose whatsoever, including without\nlimitation commercial, advertising or promotional purposes (the\n\"License\"). The License shall be deemed effective as of the date CC0 was\napplied by Affirmer to the Work. Should any part of the License for any\nreason be judged legally invalid or ineffective under applicable law, such\npartial invalidity or ineffectiveness shall not invalidate the remainder\nof the License, and in such case Affirmer hereby affirms that he or she\nwill not (i) exercise any of his or her remaining Copyright and Related\nRights in the Work or (ii) assert any associated claims and causes of\naction with respect to the Work, in either case contrary to Affirmer's\nexpress Statement of Purpose.\n\n4. Limitations and Disclaimers.\n\n a. No trademark or patent rights held by Affirmer are waived, abandoned,\n surrendered, licensed or otherwise affected by this document.\n b. Affirmer offers the Work as-is and makes no representations or\n warranties of any kind concerning the Work, express, implied,\n statutory or otherwise, including without limitation warranties of\n title, merchantability, fitness for a particular purpose, non\n infringement, or the absence of latent or other defects, accuracy, or\n the present or absence of errors, whether or not discoverable, all to\n the greatest extent permissible under applicable law.\n c. Affirmer disclaims responsibility for clearing rights of other persons\n that may apply to the Work or any use thereof, including without\n limitation any person's Copyright and Related Rights in the Work.\n Further, Affirmer disclaims responsibility for obtaining any necessary\n consents, permissions or other rights required for any use of the\n Work.\n d. Affirmer understands and acknowledges that Creative Commons is not a\n party to this document and has no duty or obligation with respect to\n this CC0 or use of the Work.\n" }, - { - "name": "gitlab.com/gitlab-org/api/client-go", - "path": "gitlab.com/gitlab-org/api/client-go/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, { "name": "go.etcd.io/bbolt", "path": "go.etcd.io/bbolt/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2013 Ben Johnson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, + { + "name": "go.opentelemetry.io/otel", + "path": "go.opentelemetry.io/otel/LICENSE", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "name": "go.opentelemetry.io/otel/trace", + "path": "go.opentelemetry.io/otel/trace/LICENSE", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, { "name": "go.uber.org/atomic", "path": "go.uber.org/atomic/LICENSE.txt", @@ -994,55 +1064,65 @@ "path": "go.uber.org/zap/LICENSE", "licenseText": "Copyright (c) 2016-2017 Uber Technologies, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" }, - { - "name": "go.uber.org/zap/exp/zapslog", - "path": "go.uber.org/zap/exp/zapslog/LICENSE", - "licenseText": "Copyright (c) 2016-2024 Uber Technologies, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, { "name": "golang.org/x/crypto", "path": "golang.org/x/crypto/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "name": "golang.org/x/exp", + "path": "golang.org/x/exp/LICENSE", + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/image", "path": "golang.org/x/image/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/mod/semver", "path": "golang.org/x/mod/semver/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/net", "path": "golang.org/x/net/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/oauth2", "path": "golang.org/x/oauth2/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/sync", "path": "golang.org/x/sync/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/sys", "path": "golang.org/x/sys/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/text", "path": "golang.org/x/text/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "golang.org/x/time/rate", "path": "golang.org/x/time/rate/LICENSE", - "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "name": "google.golang.org/genproto/googleapis/rpc/status", + "path": "google.golang.org/genproto/googleapis/rpc/status/LICENSE", + "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "name": "google.golang.org/grpc", + "path": "google.golang.org/grpc/LICENSE", + "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { "name": "google.golang.org/protobuf", @@ -1064,6 +1144,11 @@ "path": "gopkg.in/warnings.v0/LICENSE", "licenseText": "Copyright (c) 2016 Péter Surányi.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, + { + "name": "gopkg.in/yaml.v2", + "path": "gopkg.in/yaml.v2/LICENSE", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, { "name": "gopkg.in/yaml.v3", "path": "gopkg.in/yaml.v3/LICENSE", @@ -1074,6 +1159,11 @@ "path": "mvdan.cc/xurls/v2/LICENSE", "licenseText": "Copyright (c) 2015, Daniel Martí. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of the copyright holder nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, + { + "name": "strk.kbt.io/projects/go/libravatar", + "path": "strk.kbt.io/projects/go/libravatar/LICENSE", + "licenseText": "Copyright (c) 2016 Sandro Santilli \u003cstrk@kbt.io\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" + }, { "name": "xorm.io/builder", "path": "xorm.io/builder/LICENSE", diff --git a/assets/logo.svg b/assets/logo.svg index bb0031b93d..bcacdc0200 100644 --- a/assets/logo.svg +++ b/assets/logo.svg @@ -1,33 +1,27 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + diff --git a/build.go b/build.go new file mode 100644 index 0000000000..234579b514 --- /dev/null +++ b/build.go @@ -0,0 +1,23 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build vendor + +package main + +// Libraries that are included to vendor utilities used during build. +// These libraries will not be included in a normal compilation. + +import ( + // for embed + _ "github.com/shurcooL/vfsgen" + + // for cover merge + _ "golang.org/x/tools/cover" + + // for vet + _ "code.gitea.io/gitea-vet" + + // for swagger + _ "github.com/go-swagger/go-swagger/cmd/swagger" +) diff --git a/build/backport-locales.go b/build/backport-locales.go index 3125f19014..3df83ea6d9 100644 --- a/build/backport-locales.go +++ b/build/backport-locales.go @@ -12,8 +12,8 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/container" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/setting" ) func main() { diff --git a/build/code-batch-process.go b/build/code-batch-process.go index 516736b65c..cc2ab68026 100644 --- a/build/code-batch-process.go +++ b/build/code-batch-process.go @@ -15,7 +15,7 @@ import ( "strconv" "strings" - "forgejo.org/build/codeformat" + "code.gitea.io/gitea/build/codeformat" ) // Windows has a limitation for command line arguments, the size can not exceed 32KB. diff --git a/build/codeformat/formatimports.go b/build/codeformat/formatimports.go index acedd13234..c9fc2a27b4 100644 --- a/build/codeformat/formatimports.go +++ b/build/codeformat/formatimports.go @@ -13,8 +13,8 @@ import ( ) var importPackageGroupOrders = map[string]int{ - "": 1, // internal - "forgejo.org/": 2, + "": 1, // internal + "code.gitea.io/gitea/": 2, } var errInvalidCommentBetweenImports = errors.New("comments between imported packages are invalid, please move comments to the end of the package line") diff --git a/build/codeformat/formatimports_test.go b/build/codeformat/formatimports_test.go index 03c780911f..c66181d351 100644 --- a/build/codeformat/formatimports_test.go +++ b/build/codeformat/formatimports_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestFormatImportsSimple(t *testing.T) { @@ -30,7 +29,7 @@ import ( ) ` - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, expected, string(formatted)) } @@ -58,8 +57,8 @@ import ( "code.gitea.io/other/package" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "xorm.io/the/package" @@ -82,8 +81,8 @@ import ( _ "image/jpeg" // for processing jpeg images _ "image/png" // for processing png images - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/other/package" "github.com/issue9/identicon" @@ -93,7 +92,7 @@ import ( ) ` - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, expected, string(formatted)) } @@ -121,5 +120,5 @@ import ( "image/gif" ) `)) - require.ErrorIs(t, err, errInvalidCommentBetweenImports) + assert.ErrorIs(t, err, errInvalidCommentBetweenImports) } diff --git a/build/generate-bindata.go b/build/generate-bindata.go index 67d3776847..2fcb7c2f2a 100644 --- a/build/generate-bindata.go +++ b/build/generate-bindata.go @@ -1,6 +1,5 @@ // Copyright 2020 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT //go:build ignore @@ -8,40 +7,30 @@ package main import ( "bytes" - "crypto/sha256" + "crypto/sha1" "fmt" - "io" - "io/fs" "log" + "net/http" "os" - "path" "path/filepath" "strconv" - "text/template" - "github.com/klauspost/compress/zstd" + "github.com/shurcooL/vfsgen" ) -func fileExists(filename string) bool { - _, err := os.Stat(filename) - if err == nil { - return true - } - if os.IsNotExist(err) { - return false - } - panic(err) -} - func needsUpdate(dir, filename string) (bool, []byte) { - needRegen := !fileExists(filename) + needRegen := false + _, err := os.Stat(filename) + if err != nil { + needRegen = true + } oldHash, err := os.ReadFile(filename + ".hash") if err != nil { oldHash = []byte{} } - hasher := sha256.New() + hasher := sha1.New() err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { if err != nil { @@ -62,7 +51,7 @@ func needsUpdate(dir, filename string) (bool, []byte) { newHash := hasher.Sum([]byte{}) - if !bytes.Equal(oldHash, newHash) { + if bytes.Compare(oldHash, newHash) != 0 { return true, newHash } @@ -80,280 +69,24 @@ func main() { useGlobalModTime, _ = strconv.ParseBool(os.Args[4]) } - if os.Getenv("FORGEJO_GENERATE_SKIP_HASH") == "true" && fileExists(filename) { - fmt.Printf("bindata %s already exists and FORGEJO_GENERATE_SKIP_HASH=true\n", packageName) - return - } - update, newHash := needsUpdate(dir, filename) + if !update { - fmt.Printf("bindata %s already exists and the checksum is a match\n", packageName) + fmt.Printf("bindata for %s already up-to-date\n", packageName) return } fmt.Printf("generating bindata for %s\n", packageName) - - root, err := os.OpenRoot(dir) + var fsTemplates http.FileSystem = http.Dir(dir) + err := vfsgen.Generate(fsTemplates, vfsgen.Options{ + PackageName: packageName, + BuildTags: "bindata", + VariableName: "Assets", + Filename: filename, + UseGlobalModTime: useGlobalModTime, + }) if err != nil { - log.Fatal(err) - } - - out, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644) - if err != nil { - log.Fatal(err) - } - defer out.Close() - - if err := generate(root.FS(), packageName, useGlobalModTime, out); err != nil { - log.Fatal(err) + log.Fatalf("%v\n", err) } _ = os.WriteFile(filename+".hash", newHash, 0o666) } - -type file struct { - Path string - Name string - UncompressedSize int - CompressedData []byte - UncompressedData []byte -} - -type direntry struct { - Name string - IsDir bool -} - -func generate(fsRoot fs.FS, packageName string, globalTime bool, output io.Writer) error { - enc, err := zstd.NewWriter(nil, zstd.WithEncoderLevel(zstd.SpeedBestCompression)) - if err != nil { - return err - } - - files := []file{} - - dirs := map[string][]direntry{} - - if err := fs.WalkDir(fsRoot, ".", func(filePath string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - - if d.IsDir() { - entries, err := fs.ReadDir(fsRoot, filePath) - if err != nil { - return err - } - dirEntries := make([]direntry, 0, len(entries)) - for _, entry := range entries { - dirEntries = append(dirEntries, direntry{Name: entry.Name(), IsDir: entry.IsDir()}) - } - dirs[filePath] = dirEntries - return nil - } - - src, err := fs.ReadFile(fsRoot, filePath) - if err != nil { - return err - } - - dst := enc.EncodeAll(src, nil) - if len(dst) < len(src) { - files = append(files, file{ - Path: filePath, - Name: path.Base(filePath), - UncompressedSize: len(src), - CompressedData: dst, - }) - } else { - files = append(files, file{ - Path: filePath, - Name: path.Base(filePath), - UncompressedData: src, - }) - } - return nil - }); err != nil { - return err - } - - return generatedTmpl.Execute(output, map[string]any{ - "Packagename": packageName, - "GlobalTime": globalTime, - "Files": files, - "Dirs": dirs, - }) -} - -var generatedTmpl = template.Must(template.New("").Parse(`// Code generated by efs-gen. DO NOT EDIT. - -//go:build bindata - -package {{.Packagename}} - -import ( - "bytes" - "time" - "io" - "io/fs" - - "github.com/klauspost/compress/zstd" -) - -type normalFile struct { - name string - content []byte -} - -type compressedFile struct { - name string - uncompressedSize int64 - data []byte -} - -var files = map[string]any{ -{{- range .Files}} - "{{.Path}}": {{if .CompressedData}}compressedFile{"{{.Name}}", {{.UncompressedSize}}, []byte({{printf "%+q" .CompressedData}})}{{else}}normalFile{"{{.Name}}", []byte({{printf "%+q" .UncompressedData}})}{{end}}, -{{- end}} -} - -var dirs = map[string][]fs.DirEntry{ -{{- range $key, $entry := .Dirs}} - "{{$key}}": { -{{- range $entry}} - direntry{"{{.Name}}", {{.IsDir}}}, -{{- end}} - }, -{{- end}} -} - -type assets struct{} - -var Assets = assets{} - -func (a assets) Open(name string) (fs.File, error) { - f, ok := files[name] - if !ok { - return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} - } - - switch f := f.(type) { - case normalFile: - return file{name: f.name, size: int64(len(f.content)), data: bytes.NewReader(f.content)}, nil - case compressedFile: - r, _ := zstd.NewReader(bytes.NewReader(f.data)) - return &compressFile{name: f.name, size: f.uncompressedSize, data: r, content: f.data}, nil - default: - panic("unknown file type") - } -} - -func (a assets) ReadDir(name string) ([]fs.DirEntry, error) { - d, ok := dirs[name] - if !ok { - return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} - } - return d, nil -} - -type file struct { - name string - size int64 - data io.ReadSeeker -} - -var _ io.ReadSeeker = (*file)(nil) - -func (f file) Stat() (fs.FileInfo, error) { - return fileinfo{name: f.name, size: f.size}, nil -} - -func (f file) Read(p []byte) (int, error) { - return f.data.Read(p) -} - -func (f file) Seek(offset int64, whence int) (int64, error) { - return f.data.Seek(offset, whence) -} - -func (f file) Close() error { return nil } - -type compressFile struct { - name string - size int64 - data *zstd.Decoder - content []byte - zstdPos int64 - seekPos int64 -} - -var _ io.ReadSeeker = (*compressFile)(nil) - -func (f *compressFile) Stat() (fs.FileInfo, error) { - return fileinfo{name: f.name, size: f.size}, nil -} - -func (f *compressFile) Read(p []byte) (int, error) { - if f.zstdPos > f.seekPos { - if err := f.data.Reset(bytes.NewReader(f.content)); err != nil { - return 0, err - } - f.zstdPos = 0 - } - if f.zstdPos < f.seekPos { - if _, err := io.CopyN(io.Discard, f.data, f.seekPos - f.zstdPos); err != nil { - return 0, err - } - f.zstdPos = f.seekPos - } - n, err := f.data.Read(p) - f.zstdPos += int64(n) - f.seekPos = f.zstdPos - return n, err -} - -func (f *compressFile) Seek(offset int64, whence int) (int64, error) { - switch whence { - case io.SeekStart: - f.seekPos = 0 + offset - case io.SeekCurrent: - f.seekPos += offset - case io.SeekEnd: - f.seekPos = f.size + offset - } - return f.seekPos, nil -} - -func (f *compressFile) Close() error { - f.data.Close() - return nil -} - -func (f *compressFile) ZstdBytes() []byte { return f.content } - -type fileinfo struct { - name string - size int64 -} - -func (f fileinfo) Name() string { return f.name } -func (f fileinfo) Size() int64 { return f.size } -func (f fileinfo) Mode() fs.FileMode { return 0o444 } -func (f fileinfo) ModTime() time.Time { return {{if .GlobalTime}}GlobalModTime(f.name){{else}}time.Unix(0, 0){{end}} } -func (f fileinfo) IsDir() bool { return false } -func (f fileinfo) Sys() any { return nil } - -type direntry struct { - name string - isDir bool -} - -func (d direntry) Name() string { return d.name } -func (d direntry) IsDir() bool { return d.isDir } -func (d direntry) Type() fs.FileMode { - if d.isDir { - return 0o755 | fs.ModeDir - } - return 0o444 -} -func (direntry) Info() (fs.FileInfo, error) { return nil, fs.ErrNotExist } -`)) diff --git a/build/generate-disposable-email.go b/build/generate-disposable-email.go deleted file mode 100644 index f87df088c5..0000000000 --- a/build/generate-disposable-email.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2024 James Hatfield -// SPDX-License-Identifier: MIT - -//go:build ignore - -package main - -import ( - "bufio" - "bytes" - "crypto" - "flag" - "fmt" - "go/format" - "io" - "log" - "net/http" - "os" - "regexp" - "strings" -) - -const disposableEmailListURL string = "https://raw.githubusercontent.com/disposable-email-domains/disposable-email-domains/%s/disposable_email_blocklist.conf" - -var ( - gitRef *string = flag.String("r", "master", "Git reference of the domain list version") - outPat *string = flag.String("o", "modules/setting/disposable_email_domain_data.go", "Output path") - check *bool = flag.Bool("check", false, "Check if the current output file matches the current upstream list") -) - -func main() { - flag.Parse() - - if *check { - // read in the local copy of the domain list - local, err := get_local_file() - if err != nil { - log.Fatalf("File Read Error: %v", err) - } - - // generate the remote copy of the domain list - remote, err := generate() - if err != nil { - log.Fatalf("Generation Error: %v", err) - } - - // strip the comments from both (so we dont fail simply due to git ref difference) - local = strip_comments(local) - remote = strip_comments(remote) - - // generate the hash of the local copy - local_sha, err := hash(local) - if err != nil { - log.Fatalf("Local Hash Generation Error: %v", err) - } - - // generate the hash of the remote copy - remote_sha, err := hash(remote) - if err != nil { - log.Fatalf("Remote Hash Generation Error: %v", err) - } - - // if the hashes dont match then the local copy needs to be updated - if local_sha != remote_sha { - log.Fatalf("Disposable email domain list needs to be updated!! \"make lint-disposable-emails-fix\"") - } - } else { - // generate the source code (array of domains) - res, err := generate() - if err != nil { - log.Fatalf("Generation Error: %v", err) - } - - // write result to a file - err = os.WriteFile(*outPat, res, 0o644) - if err != nil { - log.Fatalf("File Write Error: %v", err) - } - } -} - -func strip_comments(data []byte) []byte { - result := make([]byte, 0, len(data)) - - re := regexp.MustCompile(`^\W*//.*$`) - - for _, line := range bytes.Split(data, []byte("\n")) { - if !re.Match(line) { - result = append(result, line...) - } - } - - return result -} - -func hash(data []byte) (string, error) { - var err error - - hash := crypto.SHA3_256.New() - - _, err = hash.Write(data) - if err != nil { - return "", err - } - - return fmt.Sprintf("%x", hash.Sum(nil)), err -} - -func get_local_file() ([]byte, error) { - var err error - - f, err := os.Open(*outPat) - if err != nil { - return nil, err - } - defer f.Close() - - data, err := io.ReadAll(f) - if err != nil { - return nil, err - } - - return data, err -} - -func get_remote() ([]string, error) { - var err error - var url string = fmt.Sprintf(disposableEmailListURL, *gitRef) - - // download the domain list - res, err := http.Get(url) - if err != nil { - return nil, err - } - defer res.Body.Close() - - body, err := io.ReadAll(res.Body) - if err != nil { - return nil, err - } - - // go through all entries (1 domain per line) - scanner := bufio.NewScanner(bytes.NewReader(body)) - - var arrDomains []string - for scanner.Scan() { - line := scanner.Text() - arrDomains = append(arrDomains, line) - } - - return arrDomains, err -} - -func generate() ([]byte, error) { - var err error - var url string = fmt.Sprintf(disposableEmailListURL, *gitRef) - - // download the domains list - arrDomains, err := get_remote() - if err != nil { - return nil, err - } - - // build the string in a readable way - var sb strings.Builder - - _, err = sb.WriteString("[]string{\n") - if err != nil { - return nil, err - } - - for _, item := range arrDomains { - _, err = sb.WriteString(fmt.Sprintf("\t%q,\n", item)) - if err != nil { - return nil, err - } - } - - _, err = sb.WriteString("}") - if err != nil { - return nil, err - } - - // insert the values into file - final := fmt.Sprintf(hdr, url, sb.String()) - - return format.Source([]byte(final)) -} - -const hdr = ` -// Copyright 2024 James Hatfield -// SPDX-License-Identifier: MIT -// -// Code generated by build/generate-disposable-email.go. DO NOT EDIT -// Sourced from %s -package setting - -import "sync" - -var DisposableEmailDomains = sync.OnceValue(func() []string { - return %s -}) -` diff --git a/build/generate-emoji.go b/build/generate-emoji.go index 0ad49a6541..5a88e456ee 100644 --- a/build/generate-emoji.go +++ b/build/generate-emoji.go @@ -20,7 +20,7 @@ import ( "strings" "unicode/utf8" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" ) const ( @@ -53,6 +53,8 @@ func (e Emoji) MarshalJSON() ([]byte, error) { } func main() { + var err error + flag.Parse() // generate data @@ -81,6 +83,8 @@ var replacer = strings.NewReplacer( var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`) func generate() ([]byte, error) { + var err error + // load gemoji data res, err := http.Get(gemojiURL) if err != nil { diff --git a/build/generate-gitignores.go b/build/generate-gitignores.go index 7acfd6cbe4..1e09c83a6a 100644 --- a/build/generate-gitignores.go +++ b/build/generate-gitignores.go @@ -15,7 +15,7 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) func main() { diff --git a/build/generate-go-licenses.go b/build/generate-go-licenses.go index 3f4d62a2cc..84ba39025c 100644 --- a/build/generate-go-licenses.go +++ b/build/generate-go-licenses.go @@ -16,7 +16,7 @@ import ( "sort" "strings" - "forgejo.org/modules/container" + "code.gitea.io/gitea/modules/container" ) // regexp is based on go-license, excluding README and NOTICE @@ -77,20 +77,6 @@ func main() { sort.Strings(paths) var entries []LicenseEntry - - { - licenseText, err := os.ReadFile("LICENSE") - if err != nil { - panic(err) - } - - entries = append(entries, LicenseEntry{ - Name: "codeberg.org/forgejo/forgejo", - Path: "codeberg.org/forgejo/forgejo/GPL-3.0-or-later", - LicenseText: string(licenseText), - }) - } - for _, filePath := range paths { licenseText, err := os.ReadFile(filePath) if err != nil { @@ -102,9 +88,9 @@ func main() { pkgName := path.Dir(pkgPath) // There might be a bug somewhere in go-licenses that sometimes interprets the - // root package as "." and sometimes as "forgejo.org". Workaround by + // root package as "." and sometimes as "code.gitea.io/gitea". Workaround by // removing both of them for the sake of stable output. - if pkgName == "." || pkgName == "forgejo.org" { + if pkgName == "." || pkgName == "code.gitea.io/gitea" { continue } diff --git a/build/generate-licenses.go b/build/generate-licenses.go index e925d8af02..9a111bc811 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -15,7 +15,7 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) func main() { diff --git a/build/gocovmerge.go b/build/gocovmerge.go new file mode 100644 index 0000000000..c6f74ed85c --- /dev/null +++ b/build/gocovmerge.go @@ -0,0 +1,118 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Copyright (c) 2015, Wade Simmons +// SPDX-License-Identifier: MIT + +// gocovmerge takes the results from multiple `go test -coverprofile` runs and +// merges them into one profile + +//go:build ignore + +package main + +import ( + "flag" + "fmt" + "io" + "log" + "os" + "sort" + + "golang.org/x/tools/cover" +) + +func mergeProfiles(p, merge *cover.Profile) { + if p.Mode != merge.Mode { + log.Fatalf("cannot merge profiles with different modes") + } + // Since the blocks are sorted, we can keep track of where the last block + // was inserted and only look at the blocks after that as targets for merge + startIndex := 0 + for _, b := range merge.Blocks { + startIndex = mergeProfileBlock(p, b, startIndex) + } +} + +func mergeProfileBlock(p *cover.Profile, pb cover.ProfileBlock, startIndex int) int { + sortFunc := func(i int) bool { + pi := p.Blocks[i+startIndex] + return pi.StartLine >= pb.StartLine && (pi.StartLine != pb.StartLine || pi.StartCol >= pb.StartCol) + } + + i := 0 + if sortFunc(i) != true { + i = sort.Search(len(p.Blocks)-startIndex, sortFunc) + } + i += startIndex + if i < len(p.Blocks) && p.Blocks[i].StartLine == pb.StartLine && p.Blocks[i].StartCol == pb.StartCol { + if p.Blocks[i].EndLine != pb.EndLine || p.Blocks[i].EndCol != pb.EndCol { + log.Fatalf("OVERLAP MERGE: %v %v %v", p.FileName, p.Blocks[i], pb) + } + switch p.Mode { + case "set": + p.Blocks[i].Count |= pb.Count + case "count", "atomic": + p.Blocks[i].Count += pb.Count + default: + log.Fatalf("unsupported covermode: '%s'", p.Mode) + } + } else { + if i > 0 { + pa := p.Blocks[i-1] + if pa.EndLine >= pb.EndLine && (pa.EndLine != pb.EndLine || pa.EndCol > pb.EndCol) { + log.Fatalf("OVERLAP BEFORE: %v %v %v", p.FileName, pa, pb) + } + } + if i < len(p.Blocks)-1 { + pa := p.Blocks[i+1] + if pa.StartLine <= pb.StartLine && (pa.StartLine != pb.StartLine || pa.StartCol < pb.StartCol) { + log.Fatalf("OVERLAP AFTER: %v %v %v", p.FileName, pa, pb) + } + } + p.Blocks = append(p.Blocks, cover.ProfileBlock{}) + copy(p.Blocks[i+1:], p.Blocks[i:]) + p.Blocks[i] = pb + } + return i + 1 +} + +func addProfile(profiles []*cover.Profile, p *cover.Profile) []*cover.Profile { + i := sort.Search(len(profiles), func(i int) bool { return profiles[i].FileName >= p.FileName }) + if i < len(profiles) && profiles[i].FileName == p.FileName { + mergeProfiles(profiles[i], p) + } else { + profiles = append(profiles, nil) + copy(profiles[i+1:], profiles[i:]) + profiles[i] = p + } + return profiles +} + +func dumpProfiles(profiles []*cover.Profile, out io.Writer) { + if len(profiles) == 0 { + return + } + fmt.Fprintf(out, "mode: %s\n", profiles[0].Mode) + for _, p := range profiles { + for _, b := range p.Blocks { + fmt.Fprintf(out, "%s:%d.%d,%d.%d %d %d\n", p.FileName, b.StartLine, b.StartCol, b.EndLine, b.EndCol, b.NumStmt, b.Count) + } + } +} + +func main() { + flag.Parse() + + var merged []*cover.Profile + + for _, file := range flag.Args() { + profiles, err := cover.ParseProfiles(file) + if err != nil { + log.Fatalf("failed to parse profile '%s': %v", file, err) + } + for _, p := range profiles { + merged = addProfile(merged, p) + } + } + + dumpProfiles(merged, os.Stdout) +} diff --git a/build/lint-locale-usage/lint-locale-usage.go b/build/lint-locale-usage/lint-locale-usage.go deleted file mode 100644 index 88375c1c36..0000000000 --- a/build/lint-locale-usage/lint-locale-usage.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package main - -import ( - "fmt" - "go/ast" - goParser "go/parser" - "go/token" - "io/fs" - "os" - "path/filepath" - "strconv" - "strings" - "text/template" - tmplParser "text/template/parse" - - "forgejo.org/modules/container" - fjTemplates "forgejo.org/modules/templates" - "forgejo.org/modules/translation/localeiter" - "forgejo.org/modules/util" -) - -// this works by first gathering all valid source string IDs from `en-US` reference files -// and then checking if all used source strings are actually defined - -type LocatedError struct { - Location string - Kind string - Err error -} - -func (e LocatedError) Error() string { - var sb strings.Builder - - sb.WriteString(e.Location) - sb.WriteString(":\t") - if e.Kind != "" { - sb.WriteString(e.Kind) - sb.WriteString(": ") - } - sb.WriteString("ERROR: ") - sb.WriteString(e.Err.Error()) - - return sb.String() -} - -func InitLocaleTrFunctions() map[string][]uint { - ret := make(map[string][]uint) - - f0 := []uint{0} - ret["Tr"] = f0 - ret["TrString"] = f0 - ret["TrHTML"] = f0 - - ret["TrPluralString"] = []uint{1} - ret["TrN"] = []uint{1, 2} - - return ret -} - -type Handler struct { - OnMsgid func(fset *token.FileSet, pos token.Pos, msgid string) - OnUnexpectedInvoke func(fset *token.FileSet, pos token.Pos, funcname string, argc int) - LocaleTrFunctions map[string][]uint -} - -// the `Handle*File` functions follow the following calling convention: -// * `fname` is the name of the input file -// * `src` is either `nil` (then the function invokes `ReadFile` to read the file) -// or the contents of the file as {`[]byte`, or a `string`} - -func (handler Handler) HandleGoFile(fname string, src any) error { - fset := token.NewFileSet() - node, err := goParser.ParseFile(fset, fname, src, goParser.SkipObjectResolution) - if err != nil { - return LocatedError{ - Location: fname, - Kind: "Go parser", - Err: err, - } - } - - ast.Inspect(node, func(n ast.Node) bool { - // search for function calls of the form `anything.Tr(any-string-lit, ...)` - - call, ok := n.(*ast.CallExpr) - if !ok || len(call.Args) < 1 { - return true - } - - funSel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - return true - } - - ltf, ok := handler.LocaleTrFunctions[funSel.Sel.Name] - if !ok { - return true - } - - var gotUnexpectedInvoke *int - - for _, argNum := range ltf { - if len(call.Args) >= int(argNum+1) { - argLit, ok := call.Args[int(argNum)].(*ast.BasicLit) - if !ok || argLit.Kind != token.STRING { - continue - } - - // extract string content - arg, err := strconv.Unquote(argLit.Value) - if err == nil { - // found interesting strings - handler.OnMsgid(fset, argLit.ValuePos, arg) - } - } else { - argc := len(call.Args) - gotUnexpectedInvoke = &argc - } - } - - if gotUnexpectedInvoke != nil { - handler.OnUnexpectedInvoke(fset, funSel.Sel.NamePos, funSel.Sel.Name, *gotUnexpectedInvoke) - } - - return true - }) - - return nil -} - -// derived from source: modules/templates/scopedtmpl/scopedtmpl.go, L169-L213 -func (handler Handler) handleTemplateNode(fset *token.FileSet, node tmplParser.Node) { - switch node.Type() { - case tmplParser.NodeAction: - handler.handleTemplatePipeNode(fset, node.(*tmplParser.ActionNode).Pipe) - case tmplParser.NodeList: - nodeList := node.(*tmplParser.ListNode) - handler.handleTemplateFileNodes(fset, nodeList.Nodes) - case tmplParser.NodePipe: - handler.handleTemplatePipeNode(fset, node.(*tmplParser.PipeNode)) - case tmplParser.NodeTemplate: - handler.handleTemplatePipeNode(fset, node.(*tmplParser.TemplateNode).Pipe) - case tmplParser.NodeIf: - nodeIf := node.(*tmplParser.IfNode) - handler.handleTemplateBranchNode(fset, nodeIf.BranchNode) - case tmplParser.NodeRange: - nodeRange := node.(*tmplParser.RangeNode) - handler.handleTemplateBranchNode(fset, nodeRange.BranchNode) - case tmplParser.NodeWith: - nodeWith := node.(*tmplParser.WithNode) - handler.handleTemplateBranchNode(fset, nodeWith.BranchNode) - - case tmplParser.NodeCommand: - nodeCommand := node.(*tmplParser.CommandNode) - - handler.handleTemplateFileNodes(fset, nodeCommand.Args) - - if len(nodeCommand.Args) < 2 { - return - } - - nodeChain, ok := nodeCommand.Args[0].(*tmplParser.ChainNode) - if !ok { - return - } - - nodeIdent, ok := nodeChain.Node.(*tmplParser.IdentifierNode) - if !ok || nodeIdent.Ident != "ctx" || len(nodeChain.Field) != 2 || nodeChain.Field[0] != "Locale" { - return - } - - ltf, ok := handler.LocaleTrFunctions[nodeChain.Field[1]] - if !ok { - return - } - - var gotUnexpectedInvoke *int - - for _, argNum := range ltf { - if len(nodeCommand.Args) >= int(argNum+2) { - nodeString, ok := nodeCommand.Args[int(argNum+1)].(*tmplParser.StringNode) - if ok { - // found interesting strings - // the column numbers are a bit "off", but much better than nothing - handler.OnMsgid(fset, token.Pos(nodeString.Pos), nodeString.Text) - } - } else { - argc := len(nodeCommand.Args) - 1 - gotUnexpectedInvoke = &argc - } - } - - if gotUnexpectedInvoke != nil { - handler.OnUnexpectedInvoke(fset, token.Pos(nodeChain.Pos), nodeChain.Field[1], *gotUnexpectedInvoke) - } - - default: - } -} - -func (handler Handler) handleTemplatePipeNode(fset *token.FileSet, pipeNode *tmplParser.PipeNode) { - if pipeNode == nil { - return - } - - // NOTE: we can't pass `pipeNode.Cmds` to handleTemplateFileNodes due to incompatible argument types - for _, node := range pipeNode.Cmds { - handler.handleTemplateNode(fset, node) - } -} - -func (handler Handler) handleTemplateBranchNode(fset *token.FileSet, branchNode tmplParser.BranchNode) { - handler.handleTemplatePipeNode(fset, branchNode.Pipe) - handler.handleTemplateFileNodes(fset, branchNode.List.Nodes) - if branchNode.ElseList != nil { - handler.handleTemplateFileNodes(fset, branchNode.ElseList.Nodes) - } -} - -func (handler Handler) handleTemplateFileNodes(fset *token.FileSet, nodes []tmplParser.Node) { - for _, node := range nodes { - handler.handleTemplateNode(fset, node) - } -} - -func (handler Handler) HandleTemplateFile(fname string, src any) error { - var tmplContent []byte - switch src2 := src.(type) { - case nil: - var err error - tmplContent, err = os.ReadFile(fname) - if err != nil { - return LocatedError{ - Location: fname, - Kind: "ReadFile", - Err: err, - } - } - case []byte: - tmplContent = src2 - case string: - // SAFETY: we do not modify tmplContent below - tmplContent = util.UnsafeStringToBytes(src2) - default: - panic("invalid type for 'src'") - } - - fset := token.NewFileSet() - fset.AddFile(fname, 1, len(tmplContent)).SetLinesForContent(tmplContent) - // SAFETY: we do not modify tmplContent2 below - tmplContent2 := util.UnsafeBytesToString(tmplContent) - - tmpl := template.New(fname) - tmpl.Funcs(fjTemplates.NewFuncMap()) - tmplParsed, err := tmpl.Parse(tmplContent2) - if err != nil { - return LocatedError{ - Location: fname, - Kind: "Template parser", - Err: err, - } - } - handler.handleTemplateFileNodes(fset, tmplParsed.Root.Nodes) - return nil -} - -// This command assumes that we get started from the project root directory -// -// Possible command line flags: -// -// --allow-missing-msgids don't return an error code if missing message IDs are found -// -// EXIT CODES: -// -// 0 success, no issues found -// 1 unable to walk directory tree -// 2 unable to parse locale ini/json files -// 3 unable to parse go or text/template files -// 4 found missing message IDs -// -//nolint:forbidigo -func main() { - allowMissingMsgids := false - for _, arg := range os.Args[1:] { - if arg == "--allow-missing-msgids" { - allowMissingMsgids = true - } - } - - onError := func(err error) { - if err == nil { - return - } - fmt.Println(err.Error()) - os.Exit(3) - } - - msgids := make(container.Set[string]) - - localeFile := filepath.Join(filepath.Join("options", "locale"), "locale_en-US.ini") - localeContent, err := os.ReadFile(localeFile) - if err != nil { - fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error()) - os.Exit(2) - } - - if err = localeiter.IterateMessagesContent(localeContent, func(trKey, trValue string) error { - msgids[trKey] = struct{}{} - return nil - }); err != nil { - fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error()) - os.Exit(2) - } - - localeFile = filepath.Join(filepath.Join("options", "locale_next"), "locale_en-US.json") - localeContent, err = os.ReadFile(localeFile) - if err != nil { - fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error()) - os.Exit(2) - } - - if err := localeiter.IterateMessagesNextContent(localeContent, func(trKey, pluralForm, trValue string) error { - // ignore plural form - msgids[trKey] = struct{}{} - return nil - }); err != nil { - fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error()) - os.Exit(2) - } - - gotAnyMsgidError := false - - handler := Handler{ - OnMsgid: func(fset *token.FileSet, pos token.Pos, msgid string) { - if !msgids.Contains(msgid) { - gotAnyMsgidError = true - fmt.Printf("%s:\tmissing msgid: %s\n", fset.Position(pos).String(), msgid) - } - }, - OnUnexpectedInvoke: func(fset *token.FileSet, pos token.Pos, funcname string, argc int) { - gotAnyMsgidError = true - fmt.Printf("%s:\tunexpected invocation of %s with %d arguments\n", fset.Position(pos).String(), funcname, argc) - }, - LocaleTrFunctions: InitLocaleTrFunctions(), - } - - if err := filepath.WalkDir(".", func(fpath string, d fs.DirEntry, err error) error { - if err != nil { - if os.IsNotExist(err) { - return nil - } - return err - } - name := d.Name() - if d.IsDir() { - if name == "docker" || name == ".git" || name == "node_modules" { - return fs.SkipDir - } - } else if name == "bindata.go" || fpath == "modules/translation/i18n/i18n_test.go" { - // skip false positives - } else if strings.HasSuffix(name, ".go") { - onError(handler.HandleGoFile(fpath, nil)) - } else if strings.HasSuffix(name, ".tmpl") { - if strings.HasPrefix(fpath, "tests") && strings.HasSuffix(name, ".ini.tmpl") { - // skip false positives - } else { - onError(handler.HandleTemplateFile(fpath, nil)) - } - } - return nil - }); err != nil { - fmt.Printf("walkdir ERROR: %s\n", err.Error()) - os.Exit(1) - } - - if !allowMissingMsgids && gotAnyMsgidError { - os.Exit(4) - } -} diff --git a/build/lint-locale-usage/lint-locale-usage_test.go b/build/lint-locale-usage/lint-locale-usage_test.go deleted file mode 100644 index 81ca12c6db..0000000000 --- a/build/lint-locale-usage/lint-locale-usage_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package main - -import ( - "go/token" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func buildHandler(ret *[]string) Handler { - return Handler{ - OnMsgid: func(fset *token.FileSet, pos token.Pos, msgid string) { - *ret = append(*ret, msgid) - }, - OnUnexpectedInvoke: func(fset *token.FileSet, pos token.Pos, funcname string, argc int) {}, - LocaleTrFunctions: InitLocaleTrFunctions(), - } -} - -func HandleGoFileWrapped(t *testing.T, fname, src string) []string { - var ret []string - handler := buildHandler(&ret) - require.NoError(t, handler.HandleGoFile(fname, src)) - return ret -} - -func HandleTemplateFileWrapped(t *testing.T, fname, src string) []string { - var ret []string - handler := buildHandler(&ret) - require.NoError(t, handler.HandleTemplateFile(fname, src)) - return ret -} - -func TestUsagesParser(t *testing.T) { - t.Run("go, simple", func(t *testing.T) { - assert.Equal(t, - []string{"what.an.example"}, - HandleGoFileWrapped(t, "", "package main\nfunc Render(ctx *context.Context) string { return ctx.Tr(\"what.an.example\"); }\n")) - }) - - t.Run("template, simple", func(t *testing.T) { - assert.Equal(t, - []string{"what.an.example"}, - HandleTemplateFileWrapped(t, "", "{{ ctx.Locale.Tr \"what.an.example\" }}\n")) - }) -} diff --git a/build/lint-locale/lint-locale.go b/build/lint-locale/lint-locale.go deleted file mode 100644 index dc4088c73c..0000000000 --- a/build/lint-locale/lint-locale.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//nolint:forbidigo -package main - -import ( - "fmt" - "html" - "io/fs" - "os" - "path/filepath" - "regexp" - "slices" - "strings" - - "forgejo.org/modules/translation/localeiter" - - "github.com/microcosm-cc/bluemonday" - "github.com/sergi/go-diff/diffmatchpatch" -) - -var ( - policy *bluemonday.Policy - tagRemover *strings.Replacer - safeURL = "https://TO-BE-REPLACED.COM" - - // Matches href="", href="#", href="%s", href="#%s", href="%[1]s" and href="#%[1]s". - placeHolderRegex = regexp.MustCompile(`href="#?(%s|%\[\d\]s)?"`) - - dmp = diffmatchpatch.New() -) - -func initBlueMondayPolicy() { - policy = bluemonday.NewPolicy() - - policy.RequireParseableURLs(true) - policy.AllowURLSchemes("https") - - // Only allow safe URL on href. - // Only allow target="_blank". - // Only allow rel="nopener noreferrer", rel="noopener" and rel="noreferrer". - // Only allow placeholder on id and class. - policy.AllowAttrs("href").Matching(regexp.MustCompile("^" + regexp.QuoteMeta(safeURL) + "$")).OnElements("a") - policy.AllowAttrs("target").Matching(regexp.MustCompile("^_blank$")).OnElements("a") - policy.AllowAttrs("rel").Matching(regexp.MustCompile("^(noopener|noreferrer|noopener noreferrer)$")).OnElements("a") - policy.AllowAttrs("id", "class").Matching(regexp.MustCompile(`^%s|%\[\d\]s$`)).OnElements("a") - - // Only allow positional placeholder as class. - positionalPlaceholderRe := regexp.MustCompile(`^%\[\d\]s$`) - policy.AllowAttrs("class").Matching(positionalPlaceholderRe).OnElements("strong") - policy.AllowAttrs("id").Matching(positionalPlaceholderRe).OnElements("code") - - // Allowed elements with no attributes. Must be a recognized tagname. - policy.AllowElements("strong", "br", "b", "strike", "code", "i", "kbd") - - // TODO: Remove in `actions.workflow.dispatch.trigger_found`. - policy.AllowNoAttrs().OnElements("c") -} - -func initRemoveTags() { - oldnew := []string{} - for _, el := range []string{ - "email@example.com", "correu@example.com", "epasts@domens.lv", "email@exemplo.com", "eposta@ornek.com", "email@példa.hu", "email@esempio.it", - "user", "utente", "lietotājs", "gebruiker", "usuário", "Benutzer", "Bruker", "bruger", "użytkownik", - "server", "servidor", "kiszolgáló", "serveris", - "label", "etichetta", "etiķete", "rótulo", "Label", "utilizador", "etiket", "iezīme", "etykieta", - } { - oldnew = append(oldnew, "<"+el+">", "REPLACED-TAG") - } - - tagRemover = strings.NewReplacer(oldnew...) -} - -func preprocessTranslationValue(value string) string { - // href should be a parsable URL, replace placeholder strings with a safe url. - value = placeHolderRegex.ReplaceAllString(value, `href="`+safeURL+`"`) - - // Remove tags that aren't tags but will be parsed as tags. We already know they are safe and sound. - value = tagRemover.Replace(value) - - return value -} - -func checkValue(trKey, value string) []string { - keyValue := preprocessTranslationValue(value) - - if html.UnescapeString(policy.Sanitize(keyValue)) == keyValue { - return nil - } - - // Create a nice diff of the difference. - diffs := dmp.DiffMain(keyValue, html.UnescapeString(policy.Sanitize(keyValue)), false) - diffs = dmp.DiffCleanupSemantic(diffs) - diffs = dmp.DiffCleanupEfficiency(diffs) - - return []string{trKey + ": " + dmp.DiffPrettyText(diffs)} -} - -func checkLocaleContent(localeContent []byte) []string { - errors := []string{} - - if err := localeiter.IterateMessagesContent(localeContent, func(trKey, trValue string) error { - errors = append(errors, checkValue(trKey, trValue)...) - return nil - }); err != nil { - panic(err) - } - - return errors -} - -func checkLocaleNextContent(localeContent []byte) []string { - errors := []string{} - - if err := localeiter.IterateMessagesNextContent(localeContent, func(trKey, pluralForm, trValue string) error { - fullKey := trKey - if pluralForm != "" { - fullKey = trKey + "." + pluralForm - } - errors = append(errors, checkValue(fullKey, trValue)...) - return nil - }); err != nil { - panic(err) - } - - return errors -} - -func main() { - initBlueMondayPolicy() - initRemoveTags() - - localeDir := filepath.Join("options", "locale") - localeFiles, err := os.ReadDir(localeDir) - if err != nil { - panic(err) - } - - // Safety check that we are not reading the wrong directory. - if !slices.ContainsFunc(localeFiles, func(e fs.DirEntry) bool { return strings.HasSuffix(e.Name(), ".ini") }) { - fmt.Println("No locale files found") - os.Exit(1) - } - - exitCode := 0 - for _, localeFile := range localeFiles { - if !strings.HasSuffix(localeFile.Name(), ".ini") { - continue - } - - localeContent, err := os.ReadFile(filepath.Join(localeDir, localeFile.Name())) - if err != nil { - fmt.Println(localeFile.Name()) - panic(err) - } - - if err := checkLocaleContent(localeContent); len(err) > 0 { - fmt.Println(localeFile.Name()) - fmt.Println(strings.Join(err, "\n")) - fmt.Println() - exitCode = 1 - } - } - - // Check the locale next. - localeDir = filepath.Join("options", "locale_next") - localeFiles, err = os.ReadDir(localeDir) - if err != nil { - panic(err) - } - - // Safety check that we are not reading the wrong directory. - if !slices.ContainsFunc(localeFiles, func(e fs.DirEntry) bool { return strings.HasSuffix(e.Name(), ".json") }) { - fmt.Println("No locale_next files found") - os.Exit(1) - } - - for _, localeFile := range localeFiles { - localeContent, err := os.ReadFile(filepath.Join(localeDir, localeFile.Name())) - if err != nil { - fmt.Println(localeFile.Name()) - panic(err) - } - - if err := checkLocaleNextContent(localeContent); len(err) > 0 { - fmt.Println(localeFile.Name()) - fmt.Println(strings.Join(err, "\n")) - fmt.Println() - exitCode = 1 - } - } - - os.Exit(exitCode) -} diff --git a/build/lint-locale/lint-locale_test.go b/build/lint-locale/lint-locale_test.go deleted file mode 100644 index dd146c0d70..0000000000 --- a/build/lint-locale/lint-locale_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT -package main - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLocalizationPolicy(t *testing.T) { - initBlueMondayPolicy() - initRemoveTags() - - t.Run("Remove tags", func(t *testing.T) { - assert.Empty(t, checkLocaleContent([]byte(`hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all " added/removed %[2]s into %[3]s`))) - assert.Empty(t, checkLocaleContent([]byte(`editor.commit_directly_to_this_branch = Commit directly to the %[1]s branch.`))) - - assert.Equal(t, []string{"workflow.dispatch.trigger_found: This workflow has a \x1b[31m\x1b[0mworkflow_dispatch\x1b[31m\x1b[0m event trigger."}, checkLocaleContent([]byte(`workflow.dispatch.trigger_found = This workflow has a workflow_dispatch event trigger.`))) - assert.Equal(t, []string{"key: %[3]s"}, checkLocaleContent([]byte(`key = %[3]s`))) - assert.Equal(t, []string{"key: "}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: "}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: %[1]s"}, checkLocaleContent([]byte(`key = %[1]s`))) - }) - - t.Run("General safe tags", func(t *testing.T) { - assert.Empty(t, checkLocaleContent([]byte("error404 = The page you are trying to reach either does not exist or you are not authorized to view it."))) - assert.Empty(t, checkLocaleContent([]byte("teams.specific_repositories_helper = Members will only have access to repositories explicitly added to the team. Selecting this will not automatically remove repositories already added with All repositories."))) - assert.Empty(t, checkLocaleContent([]byte("sqlite_helper = File path for the SQLite3 database.
Enter an absolute path if you run Forgejo as a service."))) - assert.Empty(t, checkLocaleContent([]byte("hi_user_x = Hi %s,"))) - assert.Empty(t, checkLocaleContent([]byte("key = Press Shift"))) - - assert.Equal(t, []string{"error404: The page you are trying to reach either does not exist or you are not authorized to view it."}, checkLocaleContent([]byte("error404 = The page you are trying to reach either does not exist or you are not authorized to view it."))) - }) - - t.Run("
", func(t *testing.T) { - assert.Empty(t, checkLocaleContent([]byte(`admin.new_user.text = Please click here to manage this user from the admin panel.`))) - assert.Empty(t, checkLocaleContent([]byte(`access_token_desc = Selected token permissions limit authorization only to the corresponding API routes. Read the documentation for more information.`))) - assert.Empty(t, checkLocaleContent([]byte(`webauthn_desc = Security keys are hardware devices containing cryptographic keys. They can be used for two-factor authentication. Security keys must support the WebAuthn Authenticator standard.`))) - assert.Empty(t, checkLocaleContent([]byte("issues.closed_at = `closed this issue %[2]s`"))) - - assert.Equal(t, []string{"key: \x1b[31m\x1b[0m"}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: \x1b[31m\x1b[0m"}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: "}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: "}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: \x1b[31m\x1b[0m"}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: \x1b[31m\x1b[0m"}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: \x1b[31m\x1b[0m"}, checkLocaleContent([]byte(`key = `))) - assert.Equal(t, []string{"key: \x1b[31m\x1b[0m"}, checkLocaleContent([]byte(`key = `))) - }) - - t.Run("Escaped HTML characters", func(t *testing.T) { - assert.Empty(t, checkLocaleContent([]byte("activity.git_stats_push_to_branch = `إلى %s و\"`"))) - - assert.Equal(t, []string{"key: و\x1b[31m \x1b[0m\x1b[32m\u00a0\x1b[0m"}, checkLocaleContent([]byte(`key = و `))) - }) -} - -func TestNextLocalizationPolicy(t *testing.T) { - initBlueMondayPolicy() - initRemoveTags() - - t.Run("Nested locales", func(t *testing.T) { - assert.Empty(t, checkLocaleNextContent([]byte(`{ - "settings": { - "hidden_comment_types_description": "Comment types checked here will not be shown inside issue pages. Checking \"Label\" for example removes all \" added/removed \x1b[0m"}, checkLocaleNextContent([]byte(`{"repo.pulls.title_desc": { - "few": "key = ", - "other": "key = " - }}`))) - - assert.Equal(t, []string{"repo.pulls.title_desc.few: key = \x1b[31m\x1b[0m"}, checkLocaleNextContent([]byte(`{"repo.pulls.title_desc": { - "few": "key = ", - "other": "key = " - }}`))) - }) -} diff --git a/build/update-locales.sh b/build/update-locales.sh new file mode 100755 index 0000000000..6f9ee334be --- /dev/null +++ b/build/update-locales.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# this script runs in alpine image which only has `sh` shell + +set +e +if sed --version 2>/dev/null | grep -q GNU; then + SED_INPLACE="sed -i" +else + SED_INPLACE="sed -i ''" +fi +set -e + +if [ ! -f ./options/locale/locale_en-US.ini ]; then + echo "please run this script in the root directory of the project" + exit 1 +fi + +mv ./options/locale/locale_en-US.ini ./options/ + +# the "ini" library for locale has many quirks, its behavior is different from Crowdin. +# see i18n_test.go for more details + +# this script helps to unquote the Crowdin outputs for the quirky ini library +# * find all `key="...\"..."` lines +# * remove the leading quote +# * remove the trailing quote +# * unescape the quotes +# * eg: key="...\"..." => key=..."... +$SED_INPLACE -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ { + s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/ + s/"$// + s/\\"/"/g + }' ./options/locale/*.ini + +# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks +# * eg: key="... => key=`"...` +# * eg: key=..." => key=`..."` +$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini +$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini + +# Remove translation under 25% of en_us +baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1) +baselines=$((baselines / 4)) +for filename in ./options/locale/*.ini; do + lines=$(wc -l "$filename" | cut -d" " -f1) + if [ $lines -lt $baselines ]; then + echo "Removing $filename: $lines/$baselines" + rm "$filename" + fi +done + +mv ./options/locale_en-US.ini ./options/locale/ diff --git a/cmd/actions.go b/cmd/actions.go index 12af2c8e86..10ae6243c3 100644 --- a/cmd/actions.go +++ b/cmd/actions.go @@ -4,28 +4,25 @@ package cmd import ( - "context" "fmt" - "forgejo.org/modules/private" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -// CmdActions represents the available actions sub-commands. -func cmdActions() *cli.Command { - return &cli.Command{ +var ( + // CmdActions represents the available actions sub-commands. + CmdActions = &cli.Command{ Name: "actions", Usage: "Manage Forgejo Actions", - Commands: []*cli.Command{ - subcmdActionsGenRunnerToken(), + Subcommands: []*cli.Command{ + subcmdActionsGenRunnerToken, }, } -} -func subcmdActionsGenRunnerToken() *cli.Command { - return &cli.Command{ + subcmdActionsGenRunnerToken = &cli.Command{ Name: "generate-runner-token", Usage: "Generate a new token for a runner to use to register with the server", Action: runGenerateActionsRunnerToken, @@ -39,10 +36,10 @@ func subcmdActionsGenRunnerToken() *cli.Command { }, }, } -} +) -func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runGenerateActionsRunnerToken(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() setting.MustInstalled() diff --git a/cmd/admin.go b/cmd/admin.go index 7e06a99cda..6c9480e76e 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -8,71 +8,63 @@ import ( "context" "fmt" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/modules/git" - "forgejo.org/modules/gitrepo" - "forgejo.org/modules/log" - repo_module "forgejo.org/modules/repository" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -// CmdAdmin represents the available admin sub-command. -func cmdAdmin() *cli.Command { - return &cli.Command{ +var ( + // CmdAdmin represents the available admin sub-command. + CmdAdmin = &cli.Command{ Name: "admin", Usage: "Perform common administrative operations", - Commands: []*cli.Command{ - subcmdUser(), - subcmdRepoSyncReleases(), - subcmdRegenerate(), - subcmdAuth(), - subcmdSendMail(), + Subcommands: []*cli.Command{ + subcmdUser, + subcmdRepoSyncReleases, + subcmdRegenerate, + subcmdAuth, + subcmdSendMail, }, } -} -func subcmdRepoSyncReleases() *cli.Command { - return &cli.Command{ + subcmdRepoSyncReleases = &cli.Command{ Name: "repo-sync-releases", Usage: "Synchronize repository releases with tags", Action: runRepoSyncReleases, } -} -func subcmdRegenerate() *cli.Command { - return &cli.Command{ + subcmdRegenerate = &cli.Command{ Name: "regenerate", Usage: "Regenerate specific files", - Commands: []*cli.Command{ + Subcommands: []*cli.Command{ microcmdRegenHooks, microcmdRegenKeys, }, } -} -func subcmdAuth() *cli.Command { - return &cli.Command{ + subcmdAuth = &cli.Command{ Name: "auth", Usage: "Modify external auth providers", - Commands: []*cli.Command{ - microcmdAuthAddOauth(), - microcmdAuthUpdateOauth(), - microcmdAuthAddLdapBindDn(), - microcmdAuthUpdateLdapBindDn(), - microcmdAuthAddLdapSimpleAuth(), - microcmdAuthUpdateLdapSimpleAuth(), - microcmdAuthAddSMTP(), - microcmdAuthUpdateSMTP(), - microcmdAuthList(), - microcmdAuthDelete(), + Subcommands: []*cli.Command{ + microcmdAuthAddOauth, + microcmdAuthUpdateOauth, + microcmdAuthAddLdapBindDn, + microcmdAuthUpdateLdapBindDn, + microcmdAuthAddLdapSimpleAuth, + microcmdAuthUpdateLdapSimpleAuth, + microcmdAuthAddSMTP, + microcmdAuthUpdateSMTP, + microcmdAuthList, + microcmdAuthDelete, }, } -} -func subcmdSendMail() *cli.Command { - return &cli.Command{ + subcmdSendMail = &cli.Command{ Name: "sendmail", Usage: "Send a message to all users", Action: runSendMail, @@ -94,17 +86,15 @@ func subcmdSendMail() *cli.Command { }, }, } -} -func idFlag() *cli.Int64Flag { - return &cli.Int64Flag{ + idFlag = &cli.Int64Flag{ Name: "id", Usage: "ID of authentication source", } -} +) -func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runRepoSyncReleases(_ *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { diff --git a/cmd/admin_auth.go b/cmd/admin_auth.go index cb95b3b3c8..4777a92908 100644 --- a/cmd/admin_auth.go +++ b/cmd/admin_auth.go @@ -4,30 +4,26 @@ package cmd import ( - "context" "errors" "fmt" "os" "text/tabwriter" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - auth_service "forgejo.org/services/auth" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + auth_service "code.gitea.io/gitea/services/auth" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func microcmdAuthDelete() *cli.Command { - return &cli.Command{ +var ( + microcmdAuthDelete = &cli.Command{ Name: "delete", Usage: "Delete specific auth source", - Flags: []cli.Flag{idFlag()}, + Flags: []cli.Flag{idFlag}, Action: runDeleteAuth, } -} - -func microcmdAuthList() *cli.Command { - return &cli.Command{ + microcmdAuthList = &cli.Command{ Name: "list", Usage: "List auth sources", Action: runListAuth, @@ -58,10 +54,10 @@ func microcmdAuthList() *cli.Command { }, }, } -} +) -func runListAuth(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runListAuth(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { @@ -85,7 +81,7 @@ func runListAuth(ctx context.Context, c *cli.Command) error { // loop through each source and print w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags) - fmt.Fprint(w, "ID\tName\tType\tEnabled\n") + fmt.Fprintf(w, "ID\tName\tType\tEnabled\n") for _, source := range authSources { fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive) } @@ -94,12 +90,12 @@ func runListAuth(ctx context.Context, c *cli.Command) error { return nil } -func runDeleteAuth(ctx context.Context, c *cli.Command) error { +func runDeleteAuth(c *cli.Context) error { if !c.IsSet("id") { return errors.New("--id flag is missing") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index 997d6b3a16..e3c81809f8 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -8,10 +8,10 @@ import ( "fmt" "strings" - "forgejo.org/models/auth" - "forgejo.org/services/auth/source/ldap" + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/services/auth/source/ldap" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) type ( @@ -23,8 +23,8 @@ type ( } ) -func commonLdapCLIFlags() []cli.Flag { - return []cli.Flag{ +var ( + commonLdapCLIFlags = []cli.Flag{ &cli.StringFlag{ Name: "name", Usage: "Authentication name.", @@ -102,10 +102,8 @@ func commonLdapCLIFlags() []cli.Flag { Usage: "The attribute of the user’s LDAP record containing the user’s avatar.", }, } -} -func ldapBindDnCLIFlags() []cli.Flag { - return append(commonLdapCLIFlags(), + ldapBindDnCLIFlags = append(commonLdapCLIFlags, &cli.StringFlag{ Name: "bind-dn", Usage: "The DN to bind to the LDAP server with when searching for the user.", @@ -130,59 +128,49 @@ func ldapBindDnCLIFlags() []cli.Flag { Name: "page-size", Usage: "Search page size.", }) -} -func ldapSimpleAuthCLIFlags() []cli.Flag { - return append(commonLdapCLIFlags(), + ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags, &cli.StringFlag{ Name: "user-dn", Usage: "The user's DN.", }) -} -func microcmdAuthAddLdapBindDn() *cli.Command { - return &cli.Command{ + microcmdAuthAddLdapBindDn = &cli.Command{ Name: "add-ldap", Usage: "Add new LDAP (via Bind DN) authentication source", - Action: func(ctx context.Context, cli *cli.Command) error { - return newAuthService().addLdapBindDn(ctx, cli) + Action: func(c *cli.Context) error { + return newAuthService().addLdapBindDn(c) }, - Flags: ldapBindDnCLIFlags(), + Flags: ldapBindDnCLIFlags, } -} -func microcmdAuthUpdateLdapBindDn() *cli.Command { - return &cli.Command{ + microcmdAuthUpdateLdapBindDn = &cli.Command{ Name: "update-ldap", Usage: "Update existing LDAP (via Bind DN) authentication source", - Action: func(ctx context.Context, cli *cli.Command) error { - return newAuthService().updateLdapBindDn(ctx, cli) + Action: func(c *cli.Context) error { + return newAuthService().updateLdapBindDn(c) }, - Flags: append([]cli.Flag{idFlag()}, ldapBindDnCLIFlags()...), + Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...), } -} -func microcmdAuthAddLdapSimpleAuth() *cli.Command { - return &cli.Command{ + microcmdAuthAddLdapSimpleAuth = &cli.Command{ Name: "add-ldap-simple", Usage: "Add new LDAP (simple auth) authentication source", - Action: func(ctx context.Context, cli *cli.Command) error { - return newAuthService().addLdapSimpleAuth(ctx, cli) + Action: func(c *cli.Context) error { + return newAuthService().addLdapSimpleAuth(c) }, - Flags: ldapSimpleAuthCLIFlags(), + Flags: ldapSimpleAuthCLIFlags, } -} -func microcmdAuthUpdateLdapSimpleAuth() *cli.Command { - return &cli.Command{ + microcmdAuthUpdateLdapSimpleAuth = &cli.Command{ Name: "update-ldap-simple", Usage: "Update existing LDAP (simple auth) authentication source", - Action: func(ctx context.Context, cli *cli.Command) error { - return newAuthService().updateLdapSimpleAuth(ctx, cli) + Action: func(c *cli.Context) error { + return newAuthService().updateLdapSimpleAuth(c) }, - Flags: append([]cli.Flag{idFlag()}, ldapSimpleAuthCLIFlags()...), + Flags: append([]cli.Flag{idFlag}, ldapSimpleAuthCLIFlags...), } -} +) // newAuthService creates a service with default functions. func newAuthService() *authService { @@ -195,7 +183,7 @@ func newAuthService() *authService { } // parseAuthSource assigns values on authSource according to command line flags. -func parseAuthSource(c *cli.Command, authSource *auth.Source) { +func parseAuthSource(c *cli.Context, authSource *auth.Source) { if c.IsSet("name") { authSource.Name = c.String("name") } @@ -214,7 +202,7 @@ func parseAuthSource(c *cli.Command, authSource *auth.Source) { } // parseLdapConfig assigns values on config according to command line flags. -func parseLdapConfig(c *cli.Command, config *ldap.Source) error { +func parseLdapConfig(c *cli.Context, config *ldap.Source) error { if c.IsSet("name") { config.Name = c.String("name") } @@ -301,7 +289,7 @@ func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) { // getAuthSource gets the login source by its id defined in the command line flags. // It returns an error if the id is not set, does not match any source or if the source is not of expected type. -func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authType auth.Type) (*auth.Source, error) { +func (a *authService) getAuthSource(ctx context.Context, c *cli.Context, authType auth.Type) (*auth.Source, error) { if err := argsSet(c, "id"); err != nil { return nil, err } @@ -319,12 +307,12 @@ func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authTyp } // addLdapBindDn adds a new LDAP via Bind DN authentication source. -func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error { +func (a *authService) addLdapBindDn(c *cli.Context) error { if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil { return err } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := a.initDB(ctx); err != nil { @@ -348,8 +336,8 @@ func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error { } // updateLdapBindDn updates a new LDAP via Bind DN authentication source. -func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func (a *authService) updateLdapBindDn(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := a.initDB(ctx); err != nil { @@ -370,12 +358,12 @@ func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) erro } // addLdapSimpleAuth adds a new LDAP (simple auth) authentication source. -func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) error { +func (a *authService) addLdapSimpleAuth(c *cli.Context) error { if err := argsSet(c, "name", "security-protocol", "host", "port", "user-dn", "user-filter", "email-attribute"); err != nil { return err } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := a.initDB(ctx); err != nil { @@ -398,9 +386,9 @@ func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) err return a.createAuthSource(ctx, authSource) } -// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source. -func (a *authService) updateLdapSimpleAuth(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +// updateLdapBindDn updates a new LDAP (simple auth) authentication source. +func (a *authService) updateLdapSimpleAuth(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := a.initDB(ctx); err != nil { diff --git a/cmd/admin_auth_ldap_test.go b/cmd/admin_auth_ldap_test.go index 89ce5f4f08..7791f3a9cc 100644 --- a/cmd/admin_auth_ldap_test.go +++ b/cmd/admin_auth_ldap_test.go @@ -7,18 +7,18 @@ import ( "context" "testing" - "forgejo.org/models/auth" - "forgejo.org/modules/test" - "forgejo.org/services/auth/source/ldap" + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/services/auth/source/ldap" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) func TestAddLdapBindDn(t *testing.T) { // Mock cli functions to do not exit on error - defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() + osExiter := cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} // Test cases cases := []struct { @@ -215,26 +215,26 @@ func TestAddLdapBindDn(t *testing.T) { return nil }, updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { - assert.FailNow(t, "should not call updateAuthSource", "case: %d", n) + assert.FailNow(t, "case %d: should not call updateAuthSource", n) return nil }, getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { - assert.FailNow(t, "should not call getAuthSourceByID", "case: %d", n) + assert.FailNow(t, "case %d: should not call getAuthSourceByID", n) return nil, nil }, } // Create a copy of command to test - app := cli.Command{} - app.Flags = microcmdAuthAddLdapBindDn().Flags + app := cli.NewApp() + app.Flags = microcmdAuthAddLdapBindDn.Flags app.Action = service.addLdapBindDn // Run it - err := app.Run(t.Context(), c.args) + err := app.Run(c.args) if c.errMsg != "" { assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) } else { - require.NoError(t, err, "case %d: should have no errors", n) + assert.NoError(t, err, "case %d: should have no errors", n) assert.Equal(t, c.source, createdAuthSource, "case %d: wrong authSource", n) } } @@ -242,7 +242,9 @@ func TestAddLdapBindDn(t *testing.T) { func TestAddLdapSimpleAuth(t *testing.T) { // Mock cli functions to do not exit on error - defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() + osExiter := cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} // Test cases cases := []struct { @@ -444,26 +446,26 @@ func TestAddLdapSimpleAuth(t *testing.T) { return nil }, updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { - assert.FailNow(t, "should not call updateAuthSource", "case: %d", n) + assert.FailNow(t, "case %d: should not call updateAuthSource", n) return nil }, getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { - assert.FailNow(t, "should not call getAuthSourceByID", "case: %d", n) + assert.FailNow(t, "case %d: should not call getAuthSourceByID", n) return nil, nil }, } // Create a copy of command to test - app := cli.Command{} - app.Flags = microcmdAuthAddLdapSimpleAuth().Flags + app := cli.NewApp() + app.Flags = microcmdAuthAddLdapSimpleAuth.Flags app.Action = service.addLdapSimpleAuth // Run it - err := app.Run(t.Context(), c.args) + err := app.Run(c.args) if c.errMsg != "" { assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) } else { - require.NoError(t, err, "case %d: should have no errors", n) + assert.NoError(t, err, "case %d: should have no errors", n) assert.Equal(t, c.authSource, createdAuthSource, "case %d: wrong authSource", n) } } @@ -471,7 +473,9 @@ func TestAddLdapSimpleAuth(t *testing.T) { func TestUpdateLdapBindDn(t *testing.T) { // Mock cli functions to do not exit on error - defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() + osExiter := cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} // Test cases cases := []struct { @@ -893,7 +897,7 @@ func TestUpdateLdapBindDn(t *testing.T) { return nil }, createAuthSource: func(ctx context.Context, authSource *auth.Source) error { - assert.FailNow(t, "should not call createAuthSource", "case: %d", n) + assert.FailNow(t, "case %d: should not call createAuthSource", n) return nil }, updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { @@ -915,16 +919,16 @@ func TestUpdateLdapBindDn(t *testing.T) { } // Create a copy of command to test - app := cli.Command{} - app.Flags = microcmdAuthUpdateLdapBindDn().Flags + app := cli.NewApp() + app.Flags = microcmdAuthUpdateLdapBindDn.Flags app.Action = service.updateLdapBindDn // Run it - err := app.Run(t.Context(), c.args) + err := app.Run(c.args) if c.errMsg != "" { assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) } else { - require.NoError(t, err, "case %d: should have no errors", n) + assert.NoError(t, err, "case %d: should have no errors", n) assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n) } } @@ -932,7 +936,9 @@ func TestUpdateLdapBindDn(t *testing.T) { func TestUpdateLdapSimpleAuth(t *testing.T) { // Mock cli functions to do not exit on error - defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() + osExiter := cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} // Test cases cases := []struct { @@ -1281,7 +1287,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) { return nil }, createAuthSource: func(ctx context.Context, authSource *auth.Source) error { - assert.FailNow(t, "should not call createAuthSource", "case: %d", n) + assert.FailNow(t, "case %d: should not call createAuthSource", n) return nil }, updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { @@ -1303,16 +1309,16 @@ func TestUpdateLdapSimpleAuth(t *testing.T) { } // Create a copy of command to test - app := cli.Command{} - app.Flags = microcmdAuthUpdateLdapSimpleAuth().Flags + app := cli.NewApp() + app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags app.Action = service.updateLdapSimpleAuth // Run it - err := app.Run(t.Context(), c.args) + err := app.Run(c.args) if c.errMsg != "" { assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) } else { - require.NoError(t, err, "case %d: should have no errors", n) + assert.NoError(t, err, "case %d: should have no errors", n) assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n) } } diff --git a/cmd/admin_auth_oauth.go b/cmd/admin_auth_oauth.go index abdcd5d48a..8e6239ac33 100644 --- a/cmd/admin_auth_oauth.go +++ b/cmd/admin_auth_oauth.go @@ -4,19 +4,18 @@ package cmd import ( - "context" "errors" "fmt" "net/url" - auth_model "forgejo.org/models/auth" - "forgejo.org/services/auth/source/oauth2" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/services/auth/source/oauth2" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func oauthCLIFlags() []cli.Flag { - return []cli.Flag{ +var ( + oauthCLIFlags = []cli.Flag{ &cli.StringFlag{ Name: "name", Value: "", @@ -121,27 +120,23 @@ func oauthCLIFlags() []cli.Flag { Usage: "Activate automatic team membership removal depending on groups", }, } -} -func microcmdAuthAddOauth() *cli.Command { - return &cli.Command{ + microcmdAuthAddOauth = &cli.Command{ Name: "add-oauth", Usage: "Add new Oauth authentication source", Action: runAddOauth, - Flags: oauthCLIFlags(), + Flags: oauthCLIFlags, } -} -func microcmdAuthUpdateOauth() *cli.Command { - return &cli.Command{ + microcmdAuthUpdateOauth = &cli.Command{ Name: "update-oauth", Usage: "Update existing Oauth authentication source", Action: runUpdateOauth, - Flags: append(oauthCLIFlags()[:1], append([]cli.Flag{idFlag()}, oauthCLIFlags()[1:]...)...), + Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...), } -} +) -func parseOAuth2Config(_ context.Context, c *cli.Command) *oauth2.Source { +func parseOAuth2Config(c *cli.Context) *oauth2.Source { var customURLMapping *oauth2.CustomURLMapping if c.IsSet("use-custom-urls") { customURLMapping = &oauth2.CustomURLMapping{ @@ -173,15 +168,15 @@ func parseOAuth2Config(_ context.Context, c *cli.Command) *oauth2.Source { } } -func runAddOauth(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runAddOauth(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { return err } - config := parseOAuth2Config(ctx, c) + config := parseOAuth2Config(c) if config.Provider == "openidConnect" { discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL) if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") { @@ -197,12 +192,12 @@ func runAddOauth(ctx context.Context, c *cli.Command) error { }) } -func runUpdateOauth(ctx context.Context, c *cli.Command) error { +func runUpdateOauth(c *cli.Context) error { if !c.IsSet("id") { return errors.New("--id flag is missing") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { diff --git a/cmd/admin_auth_stmp.go b/cmd/admin_auth_stmp.go index 48b3adaac3..d724746905 100644 --- a/cmd/admin_auth_stmp.go +++ b/cmd/admin_auth_stmp.go @@ -4,19 +4,18 @@ package cmd import ( - "context" "errors" "strings" - auth_model "forgejo.org/models/auth" - "forgejo.org/modules/util" - "forgejo.org/services/auth/source/smtp" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/auth/source/smtp" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func smtpCLIFlags() []cli.Flag { - return []cli.Flag{ +var ( + smtpCLIFlags = []cli.Flag{ &cli.StringFlag{ Name: "name", Value: "", @@ -72,27 +71,23 @@ func smtpCLIFlags() []cli.Flag { Value: true, }, } -} -func microcmdAuthAddSMTP() *cli.Command { - return &cli.Command{ + microcmdAuthAddSMTP = &cli.Command{ Name: "add-smtp", Usage: "Add new SMTP authentication source", Action: runAddSMTP, - Flags: smtpCLIFlags(), + Flags: smtpCLIFlags, } -} -func microcmdAuthUpdateSMTP() *cli.Command { - return &cli.Command{ + microcmdAuthUpdateSMTP = &cli.Command{ Name: "update-smtp", Usage: "Update existing SMTP authentication source", Action: runUpdateSMTP, - Flags: append(smtpCLIFlags()[:1], append([]cli.Flag{idFlag()}, smtpCLIFlags()[1:]...)...), + Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...), } -} +) -func parseSMTPConfig(c *cli.Command, conf *smtp.Source) error { +func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error { if c.IsSet("auth-type") { conf.Auth = c.String("auth-type") validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"} @@ -128,8 +123,8 @@ func parseSMTPConfig(c *cli.Command, conf *smtp.Source) error { return nil } -func runAddSMTP(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runAddSMTP(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { @@ -168,12 +163,12 @@ func runAddSMTP(ctx context.Context, c *cli.Command) error { }) } -func runUpdateSMTP(ctx context.Context, c *cli.Command) error { +func runUpdateSMTP(c *cli.Context) error { if !c.IsSet("id") { return errors.New("--id flag is missing") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { diff --git a/cmd/admin_regenerate.go b/cmd/admin_regenerate.go index 7bfd12f8f4..0db505ff9c 100644 --- a/cmd/admin_regenerate.go +++ b/cmd/admin_regenerate.go @@ -4,13 +4,11 @@ package cmd import ( - "context" + asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/modules/graceful" + repo_service "code.gitea.io/gitea/services/repository" - asymkey_model "forgejo.org/models/asymkey" - "forgejo.org/modules/graceful" - repo_service "forgejo.org/services/repository" - - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) var ( @@ -27,8 +25,8 @@ var ( } ) -func runRegenerateHooks(ctx context.Context, _ *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runRegenerateHooks(_ *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { @@ -37,8 +35,8 @@ func runRegenerateHooks(ctx context.Context, _ *cli.Command) error { return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext()) } -func runRegenerateKeys(ctx context.Context, _ *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runRegenerateKeys(_ *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { diff --git a/cmd/admin_user.go b/cmd/admin_user.go index f4f6fb49af..967a6ed88a 100644 --- a/cmd/admin_user.go +++ b/cmd/admin_user.go @@ -4,21 +4,18 @@ package cmd import ( - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func subcmdUser() *cli.Command { - return &cli.Command{ - Name: "user", - Usage: "Modify users", - Commands: []*cli.Command{ - microcmdUserCreate(), - microcmdUserList(), - microcmdUserChangePassword(), - microcmdUserDelete(), - microcmdUserGenerateAccessToken(), - microcmdUserMustChangePassword(), - microcmdUserResetMFA(), - }, - } +var subcmdUser = &cli.Command{ + Name: "user", + Usage: "Modify users", + Subcommands: []*cli.Command{ + microcmdUserCreate, + microcmdUserList, + microcmdUserChangePassword, + microcmdUserDelete, + microcmdUserGenerateAccessToken, + microcmdUserMustChangePassword, + }, } diff --git a/cmd/admin_user_change_password.go b/cmd/admin_user_change_password.go index dd8c9d378a..bd9063a8e4 100644 --- a/cmd/admin_user_change_password.go +++ b/cmd/admin_user_change_password.go @@ -4,52 +4,49 @@ package cmd import ( - "context" "errors" "fmt" - user_model "forgejo.org/models/user" - "forgejo.org/modules/auth/password" - "forgejo.org/modules/optional" - "forgejo.org/modules/setting" - user_service "forgejo.org/services/user" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/auth/password" + "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/setting" + user_service "code.gitea.io/gitea/services/user" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func microcmdUserChangePassword() *cli.Command { - return &cli.Command{ - Name: "change-password", - Usage: "Change a user's password", - Action: runChangePassword, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "username", - Aliases: []string{"u"}, - Value: "", - Usage: "The user to change password for", - }, - &cli.StringFlag{ - Name: "password", - Aliases: []string{"p"}, - Value: "", - Usage: "New password to set for user", - }, - &cli.BoolFlag{ - Name: "must-change-password", - Usage: "User must change password", - Value: true, - }, +var microcmdUserChangePassword = &cli.Command{ + Name: "change-password", + Usage: "Change a user's password", + Action: runChangePassword, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Value: "", + Usage: "The user to change password for", }, - } + &cli.StringFlag{ + Name: "password", + Aliases: []string{"p"}, + Value: "", + Usage: "New password to set for user", + }, + &cli.BoolFlag{ + Name: "must-change-password", + Usage: "User must change password", + Value: true, + }, + }, } -func runChangePassword(ctx context.Context, c *cli.Command) error { +func runChangePassword(c *cli.Context) error { if err := argsSet(c, "username", "password"); err != nil { return err } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index 96431412f6..dfc484aeb2 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -4,92 +4,71 @@ package cmd import ( - "context" "errors" "fmt" - "strings" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - user_model "forgejo.org/models/user" - pwd "forgejo.org/modules/auth/password" - "forgejo.org/modules/optional" - "forgejo.org/modules/setting" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + pwd "code.gitea.io/gitea/modules/auth/password" + "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func microcmdUserCreate() *cli.Command { - return &cli.Command{ - Name: "create", - Usage: "Create a new user in database", - Action: runCreateUser, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "name", - Usage: "Username. DEPRECATED: use username instead", - }, - &cli.StringFlag{ - Name: "username", - Usage: "Username", - }, - &cli.StringFlag{ - Name: "password", - Usage: "User password", - }, - &cli.StringFlag{ - Name: "email", - Usage: "User email address", - }, - &cli.BoolFlag{ - Name: "admin", - Usage: "User is an admin", - }, - &cli.BoolFlag{ - Name: "random-password", - Usage: "Generate a random password for the user", - }, - &cli.BoolFlag{ - Name: "must-change-password", - Usage: "Set this option to false to prevent forcing the user to change their password after initial login", - Value: true, - }, - &cli.IntFlag{ - Name: "random-password-length", - Usage: "Length of the random password to be generated", - Value: 12, - }, - &cli.BoolFlag{ - Name: "access-token", - Usage: "Generate access token for the user", - }, - &cli.StringFlag{ - Name: "access-token-name", - Usage: `Name of the generated access token`, - Value: "gitea-admin", - }, - &cli.StringFlag{ - Name: "access-token-scopes", - Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`, - Value: "all", - }, - &cli.BoolFlag{ - Name: "restricted", - Usage: "Make a restricted user account", - }, - &cli.StringFlag{ - Name: "fullname", - Usage: `The full, human-readable name of the user`, - }, +var microcmdUserCreate = &cli.Command{ + Name: "create", + Usage: "Create a new user in database", + Action: runCreateUser, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Usage: "Username. DEPRECATED: use username instead", }, - } + &cli.StringFlag{ + Name: "username", + Usage: "Username", + }, + &cli.StringFlag{ + Name: "password", + Usage: "User password", + }, + &cli.StringFlag{ + Name: "email", + Usage: "User email address", + }, + &cli.BoolFlag{ + Name: "admin", + Usage: "User is an admin", + }, + &cli.BoolFlag{ + Name: "random-password", + Usage: "Generate a random password for the user", + }, + &cli.BoolFlag{ + Name: "must-change-password", + Usage: "Set this option to false to prevent forcing the user to change their password after initial login", + Value: true, + DisableDefaultText: true, + }, + &cli.IntFlag{ + Name: "random-password-length", + Usage: "Length of the random password to be generated", + Value: 12, + }, + &cli.BoolFlag{ + Name: "access-token", + Usage: "Generate access token for the user", + }, + &cli.BoolFlag{ + Name: "restricted", + Usage: "Make a restricted user account", + }, + }, } -func runCreateUser(ctx context.Context, c *cli.Command) error { - // this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first - // duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future. - setting.LoadSettings() - +func runCreateUser(c *cli.Context) error { if err := argsSet(c, "email"); err != nil { return err } @@ -110,10 +89,10 @@ func runCreateUser(ctx context.Context, c *cli.Command) error { username = c.String("username") } else { username = c.String("name") - _, _ = fmt.Fprint(c.Root().ErrWriter, "--name flag is deprecated. Use --username instead.\n") + _, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { @@ -167,7 +146,6 @@ func runCreateUser(ctx context.Context, c *cli.Command) error { IsAdmin: isAdmin, MustChangePassword: mustChangePassword, Visibility: visibility, - FullName: c.String("fullname"), } overwriteDefault := &user_model.CreateUserOverwriteOptions{ @@ -175,40 +153,23 @@ func runCreateUser(ctx context.Context, c *cli.Command) error { IsRestricted: restricted, } - var accessTokenName string - var accessTokenScope auth_model.AccessTokenScope - if c.IsSet("access-token") { - accessTokenName = strings.TrimSpace(c.String("access-token-name")) - if accessTokenName == "" { - return errors.New("access-token-name cannot be empty") - } - var err error - accessTokenScope, err = auth_model.AccessTokenScope(c.String("access-token-scopes")).Normalize() - if err != nil { - return fmt.Errorf("invalid access token scope provided: %w", err) - } - if !accessTokenScope.HasPermissionScope() { - return errors.New("access token does not have any permission") - } - } else if c.IsSet("access-token-name") || c.IsSet("access-token-scopes") { - return errors.New("access-token-name and access-token-scopes flags are only valid when access-token flag is set") - } - - // arguments should be prepared before creating the user & access token, in case there is anything wrong - - // create the user if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil { return fmt.Errorf("CreateUser: %w", err) } - fmt.Printf("New user '%s' has been successfully created!\n", username) - // create the access token - if accessTokenScope != "" { - t := &auth_model.AccessToken{Name: accessTokenName, UID: u.ID, Scope: accessTokenScope} + if c.Bool("access-token") { + t := &auth_model.AccessToken{ + Name: "gitea-admin", + UID: u.ID, + } + if err := auth_model.NewAccessToken(ctx, t); err != nil { return err } + fmt.Printf("Access token was successfully created... %s\n", t.Token) } + + fmt.Printf("New user '%s' has been successfully created!\n", username) return nil } diff --git a/cmd/admin_user_delete.go b/cmd/admin_user_delete.go index 3382c53e5f..520557554a 100644 --- a/cmd/admin_user_delete.go +++ b/cmd/admin_user_delete.go @@ -4,52 +4,49 @@ package cmd import ( - "context" "errors" "fmt" "strings" - user_model "forgejo.org/models/user" - "forgejo.org/modules/storage" - user_service "forgejo.org/services/user" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/storage" + user_service "code.gitea.io/gitea/services/user" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func microcmdUserDelete() *cli.Command { - return &cli.Command{ - Name: "delete", - Usage: "Delete specific user by id, name or email", - Flags: []cli.Flag{ - &cli.Int64Flag{ - Name: "id", - Usage: "ID of user of the user to delete", - }, - &cli.StringFlag{ - Name: "username", - Aliases: []string{"u"}, - Usage: "Username of the user to delete", - }, - &cli.StringFlag{ - Name: "email", - Aliases: []string{"e"}, - Usage: "Email of the user to delete", - }, - &cli.BoolFlag{ - Name: "purge", - Usage: "Purge user, all their repositories, organizations and comments", - }, +var microcmdUserDelete = &cli.Command{ + Name: "delete", + Usage: "Delete specific user by id, name or email", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "id", + Usage: "ID of user of the user to delete", }, - Action: runDeleteUser, - } + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Usage: "Username of the user to delete", + }, + &cli.StringFlag{ + Name: "email", + Aliases: []string{"e"}, + Usage: "Email of the user to delete", + }, + &cli.BoolFlag{ + Name: "purge", + Usage: "Purge user, all their repositories, organizations and comments", + }, + }, + Action: runDeleteUser, } -func runDeleteUser(ctx context.Context, c *cli.Command) error { +func runDeleteUser(c *cli.Context) error { if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") { return errors.New("You must provide the id, username or email of a user to delete") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { diff --git a/cmd/admin_user_generate_access_token.go b/cmd/admin_user_generate_access_token.go index d0f2878297..6c2c10494e 100644 --- a/cmd/admin_user_generate_access_token.go +++ b/cmd/admin_user_generate_access_token.go @@ -4,52 +4,49 @@ package cmd import ( - "context" "errors" "fmt" - auth_model "forgejo.org/models/auth" - user_model "forgejo.org/models/user" + auth_model "code.gitea.io/gitea/models/auth" + user_model "code.gitea.io/gitea/models/user" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func microcmdUserGenerateAccessToken() *cli.Command { - return &cli.Command{ - Name: "generate-access-token", - Usage: "Generate an access token for a specific user", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "username", - Aliases: []string{"u"}, - Usage: "Username", - }, - &cli.StringFlag{ - Name: "token-name", - Aliases: []string{"t"}, - Usage: "Token name", - Value: "gitea-admin", - }, - &cli.BoolFlag{ - Name: "raw", - Usage: "Display only the token value", - }, - &cli.StringFlag{ - Name: "scopes", - Value: "all", - Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`, - }, +var microcmdUserGenerateAccessToken = &cli.Command{ + Name: "generate-access-token", + Usage: "Generate an access token for a specific user", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Usage: "Username", }, - Action: runGenerateAccessToken, - } + &cli.StringFlag{ + Name: "token-name", + Aliases: []string{"t"}, + Usage: "Token name", + Value: "gitea-admin", + }, + &cli.BoolFlag{ + Name: "raw", + Usage: "Display only the token value", + }, + &cli.StringFlag{ + Name: "scopes", + Value: "", + Usage: "Comma separated list of scopes to apply to access token", + }, + }, + Action: runGenerateAccessToken, } -func runGenerateAccessToken(ctx context.Context, c *cli.Command) error { +func runGenerateAccessToken(c *cli.Context) error { if !c.IsSet("username") { - return errors.New("you must provide a username to generate a token for") + return errors.New("You must provide a username to generate a token for") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { @@ -80,9 +77,6 @@ func runGenerateAccessToken(ctx context.Context, c *cli.Command) error { if err != nil { return fmt.Errorf("invalid access token scope provided: %w", err) } - if !accessTokenScope.HasPermissionScope() { - return errors.New("access token does not have any permission") - } t.Scope = accessTokenScope // create the token diff --git a/cmd/admin_user_list.go b/cmd/admin_user_list.go index ccc4b8c917..4c2b26d1df 100644 --- a/cmd/admin_user_list.go +++ b/cmd/admin_user_list.go @@ -4,32 +4,29 @@ package cmd import ( - "context" "fmt" "os" "text/tabwriter" - user_model "forgejo.org/models/user" + user_model "code.gitea.io/gitea/models/user" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func microcmdUserList() *cli.Command { - return &cli.Command{ - Name: "list", - Usage: "List users", - Action: runListUsers, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "admin", - Usage: "List only admin users", - }, +var microcmdUserList = &cli.Command{ + Name: "list", + Usage: "List users", + Action: runListUsers, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "admin", + Usage: "List only admin users", }, - } + }, } -func runListUsers(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runListUsers(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if err := initDB(ctx); err != nil { @@ -44,7 +41,7 @@ func runListUsers(ctx context.Context, c *cli.Command) error { w := tabwriter.NewWriter(os.Stdout, 5, 0, 1, ' ', 0) if c.IsSet("admin") { - fmt.Fprint(w, "ID\tUsername\tEmail\tIsActive\n") + fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\n") for _, u := range users { if u.IsAdmin { fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", u.ID, u.Name, u.Email, u.IsActive) @@ -52,7 +49,7 @@ func runListUsers(ctx context.Context, c *cli.Command) error { } } else { twofa := user_model.UserList(users).GetTwoFaStatus(ctx) - fmt.Fprint(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n") + fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n") for _, u := range users { fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID]) } diff --git a/cmd/admin_user_must_change_password.go b/cmd/admin_user_must_change_password.go index 2ccad56eb9..2794414259 100644 --- a/cmd/admin_user_must_change_password.go +++ b/cmd/admin_user_must_change_password.go @@ -4,41 +4,38 @@ package cmd import ( - "context" "errors" "fmt" - user_model "forgejo.org/models/user" + user_model "code.gitea.io/gitea/models/user" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func microcmdUserMustChangePassword() *cli.Command { - return &cli.Command{ - Name: "must-change-password", - Usage: "Set the must change password flag for the provided users or all users", - Action: runMustChangePassword, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "all", - Aliases: []string{"A"}, - Usage: "All users must change password, except those explicitly excluded with --exclude", - }, - &cli.StringSliceFlag{ - Name: "exclude", - Aliases: []string{"e"}, - Usage: "Do not change the must-change-password flag for these users", - }, - &cli.BoolFlag{ - Name: "unset", - Usage: "Instead of setting the must-change-password flag, unset it", - }, +var microcmdUserMustChangePassword = &cli.Command{ + Name: "must-change-password", + Usage: "Set the must change password flag for the provided users or all users", + Action: runMustChangePassword, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Aliases: []string{"A"}, + Usage: "All users must change password, except those explicitly excluded with --exclude", }, - } + &cli.StringSliceFlag{ + Name: "exclude", + Aliases: []string{"e"}, + Usage: "Do not change the must-change-password flag for these users", + }, + &cli.BoolFlag{ + Name: "unset", + Usage: "Instead of setting the must-change-password flag, unset it", + }, + }, } -func runMustChangePassword(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runMustChangePassword(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() if c.NArg() == 0 && !c.IsSet("all") { diff --git a/cmd/admin_user_reset_mfa.go b/cmd/admin_user_reset_mfa.go deleted file mode 100644 index 8107fd97bf..0000000000 --- a/cmd/admin_user_reset_mfa.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package cmd - -import ( - "context" - "fmt" - - auth_model "forgejo.org/models/auth" - user_model "forgejo.org/models/user" - - "github.com/urfave/cli/v3" -) - -func microcmdUserResetMFA() *cli.Command { - return &cli.Command{ - Name: "reset-mfa", - Usage: "Remove all two-factor authentication configurations for a user", - Action: runResetMFA, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "username", - Aliases: []string{"u"}, - Value: "", - Usage: "The user to update", - }, - }, - } -} - -func runResetMFA(ctx context.Context, c *cli.Command) error { - if err := argsSet(c, "username"); err != nil { - return err - } - - ctx, cancel := installSignals(ctx) - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - - user, err := user_model.GetUserByName(ctx, c.String("username")) - if err != nil { - return err - } - - webAuthnList, err := auth_model.GetWebAuthnCredentialsByUID(ctx, user.ID) - if err != nil { - return err - } - - for _, credential := range webAuthnList { - if _, err := auth_model.DeleteCredential(ctx, credential.ID, user.ID); err != nil { - return err - } - } - - tfaModes, err := auth_model.GetTwoFactorByUID(ctx, user.ID) - if err == nil && tfaModes != nil { - if err := auth_model.DeleteTwoFactorByID(ctx, tfaModes.ID, user.ID); err != nil { - return err - } - } else { - if _, is := err.(auth_model.ErrTwoFactorNotEnrolled); !is { - return err - } - } - - fmt.Printf("%s's two-factor authentication settings have been removed!\n", user.Name) - return nil -} diff --git a/cmd/cert.go b/cmd/cert.go index f9e3a16f3e..bf83af389f 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -6,7 +6,6 @@ package cmd import ( - "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" @@ -21,49 +20,47 @@ import ( "strings" "time" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // CmdCert represents the available cert sub-command. -func cmdCert() *cli.Command { - return &cli.Command{ - Name: "cert", - Usage: "Generate self-signed certificate", - Description: `Generate a self-signed X.509 certificate for a TLS server. +var CmdCert = &cli.Command{ + Name: "cert", + Usage: "Generate self-signed certificate", + Description: `Generate a self-signed X.509 certificate for a TLS server. Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`, - Action: runCert, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "host", - Value: "", - Usage: "Comma-separated hostnames and IPs to generate a certificate for", - }, - &cli.StringFlag{ - Name: "ecdsa-curve", - Value: "", - Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", - }, - &cli.IntFlag{ - Name: "rsa-bits", - Value: 3072, - Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set", - }, - &cli.StringFlag{ - Name: "start-date", - Value: "", - Usage: "Creation date formatted as Jan 1 15:04:05 2011", - }, - &cli.DurationFlag{ - Name: "duration", - Value: 365 * 24 * time.Hour, - Usage: "Duration that certificate is valid for", - }, - &cli.BoolFlag{ - Name: "ca", - Usage: "whether this cert should be its own Certificate Authority", - }, + Action: runCert, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "host", + Value: "", + Usage: "Comma-separated hostnames and IPs to generate a certificate for", }, - } + &cli.StringFlag{ + Name: "ecdsa-curve", + Value: "", + Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", + }, + &cli.IntFlag{ + Name: "rsa-bits", + Value: 3072, + Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set", + }, + &cli.StringFlag{ + Name: "start-date", + Value: "", + Usage: "Creation date formatted as Jan 1 15:04:05 2011", + }, + &cli.DurationFlag{ + Name: "duration", + Value: 365 * 24 * time.Hour, + Usage: "Duration that certificate is valid for", + }, + &cli.BoolFlag{ + Name: "ca", + Usage: "whether this cert should be its own Certificate Authority", + }, + }, } func publicKey(priv any) any { @@ -92,7 +89,7 @@ func pemBlockForKey(priv any) *pem.Block { } } -func runCert(ctx context.Context, c *cli.Command) error { +func runCert(c *cli.Context) error { if err := argsSet(c, "host"); err != nil { return err } diff --git a/cmd/cmd.go b/cmd/cmd.go index 85a482b78c..423dce2674 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -15,26 +15,24 @@ import ( "strings" "syscall" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // argsSet checks that all the required arguments are set. args is a list of // arguments that must be set in the passed Context. -func argsSet(c *cli.Command, args ...string) error { +func argsSet(c *cli.Context, args ...string) error { for _, a := range args { if !c.IsSet(a) { return errors.New(a + " is not set") } - if s, ok := c.Value(a).(string); ok { - if util.IsEmptyString(s) { - return errors.New(a + " is required") - } + if util.IsEmptyString(c.String(a)) { + return errors.New(a + " is required") } } return nil @@ -75,8 +73,8 @@ If this is the intended configuration file complete the [database] section.`, se return nil } -func installSignals(ctx context.Context) (context.Context, context.CancelFunc) { - ctx, cancel := context.WithCancel(ctx) +func installSignals() (context.Context, context.CancelFunc) { + ctx, cancel := context.WithCancel(context.Background()) go func() { // install notify signalChannel := make(chan os.Signal, 1) @@ -111,7 +109,7 @@ func setupConsoleLogger(level log.Level, colorize bool, out io.Writer) { log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer) } -func globalBool(c *cli.Command, name string) bool { +func globalBool(c *cli.Context, name string) bool { for _, ctx := range c.Lineage() { if ctx.Bool(name) { return true @@ -122,16 +120,16 @@ func globalBool(c *cli.Command, name string) bool { // PrepareConsoleLoggerLevel by default, use INFO level for console logger, but some sub-commands (for git/ssh protocol) shouldn't output any log to stdout. // Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever. -func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(ctx context.Context, cli *cli.Command) (context.Context, error) { - return func(ctx context.Context, cli *cli.Command) (context.Context, error) { +func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(*cli.Context) error { + return func(c *cli.Context) error { level := defaultLevel - if globalBool(cli, "quiet") { + if globalBool(c, "quiet") { level = log.FATAL } - if globalBool(cli, "debug") || globalBool(cli, "verbose") { + if globalBool(c, "debug") || globalBool(c, "verbose") { level = log.TRACE } log.SetConsoleLogger(log.DEFAULT, "console-default", level) - return ctx, nil + return nil } } diff --git a/cmd/docs.go b/cmd/docs.go new file mode 100644 index 0000000000..1dc0980c00 --- /dev/null +++ b/cmd/docs.go @@ -0,0 +1,65 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "fmt" + "os" + "strings" + + "github.com/urfave/cli/v2" +) + +// CmdDocs represents the available docs sub-command. +var CmdDocs = &cli.Command{ + Name: "docs", + Usage: "Output CLI documentation", + Description: "A command to output Forgejo's CLI documentation, optionally to a file.", + Action: runDocs, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "man", + Usage: "Output man pages instead", + }, + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "Path to output to instead of stdout (will overwrite if exists)", + }, + }, +} + +func runDocs(ctx *cli.Context) error { + docs, err := ctx.App.ToMarkdown() + if ctx.Bool("man") { + docs, err = ctx.App.ToMan() + } + if err != nil { + return err + } + + if !ctx.Bool("man") { + // Clean up markdown. The following bug was fixed in v2, but is present in v1. + // It affects markdown output (even though the issue is referring to man pages) + // https://github.com/urfave/cli/issues/1040 + firstHashtagIndex := strings.Index(docs, "#") + + if firstHashtagIndex > 0 { + docs = docs[firstHashtagIndex:] + } + } + + out := os.Stdout + if ctx.String("output") != "" { + fi, err := os.Create(ctx.String("output")) + if err != nil { + return err + } + defer fi.Close() + out = fi + } + + _, err = fmt.Fprintln(out, docs) + return err +} diff --git a/cmd/doctor.go b/cmd/doctor.go index 681794f094..9957053365 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -4,7 +4,6 @@ package cmd import ( - "context" "fmt" golog "log" "os" @@ -12,94 +11,89 @@ import ( "strings" "text/tabwriter" - "forgejo.org/models/db" - "forgejo.org/models/migrations" - migrate_base "forgejo.org/models/migrations/base" - "forgejo.org/modules/container" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/services/doctor" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/migrations" + migrate_base "code.gitea.io/gitea/models/migrations/base" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/doctor" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" + "xorm.io/xorm" ) // CmdDoctor represents the available doctor sub-command. -func cmdDoctor() *cli.Command { - return &cli.Command{ - Name: "doctor", - Usage: "Diagnose and optionally fix problems, convert or re-create database tables", - Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", +var CmdDoctor = &cli.Command{ + Name: "doctor", + Usage: "Diagnose and optionally fix problems, convert or re-create database tables", + Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", - Commands: []*cli.Command{ - cmdDoctorCheck(), - cmdRecreateTable(), - cmdDoctorConvert(), - }, - } + Subcommands: []*cli.Command{ + cmdDoctorCheck, + cmdRecreateTable, + cmdDoctorConvert, + }, } -func cmdDoctorCheck() *cli.Command { - return &cli.Command{ - Name: "check", - Usage: "Diagnose and optionally fix problems", - Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", - Action: runDoctorCheck, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "list", - Usage: "List the available checks", - }, - &cli.BoolFlag{ - Name: "default", - Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)", - }, - &cli.StringSliceFlag{ - Name: "run", - Usage: "Run the provided checks - (if --default is set, the default checks will also run)", - }, - &cli.BoolFlag{ - Name: "all", - Usage: "Run all the available checks", - }, - &cli.BoolFlag{ - Name: "fix", - Usage: "Automatically fix what we can", - }, - &cli.StringFlag{ - Name: "log-file", - Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`, - }, - &cli.BoolFlag{ - Name: "color", - Aliases: []string{"H"}, - Usage: "Use color for outputted information", - }, +var cmdDoctorCheck = &cli.Command{ + Name: "check", + Usage: "Diagnose and optionally fix problems", + Description: "A command to diagnose problems with the current Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", + Action: runDoctorCheck, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "list", + Usage: "List the available checks", }, - } + &cli.BoolFlag{ + Name: "default", + Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)", + }, + &cli.StringSliceFlag{ + Name: "run", + Usage: "Run the provided checks - (if --default is set, the default checks will also run)", + }, + &cli.BoolFlag{ + Name: "all", + Usage: "Run all the available checks", + }, + &cli.BoolFlag{ + Name: "fix", + Usage: "Automatically fix what we can", + }, + &cli.StringFlag{ + Name: "log-file", + Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`, + }, + &cli.BoolFlag{ + Name: "color", + Aliases: []string{"H"}, + Usage: "Use color for outputted information", + }, + }, } -func cmdRecreateTable() *cli.Command { - return &cli.Command{ - Name: "recreate-table", - Usage: "Recreate tables from XORM definitions and copy the data.", - ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "debug", - Usage: "Print SQL commands sent", - }, +var cmdRecreateTable = &cli.Command{ + Name: "recreate-table", + Usage: "Recreate tables from XORM definitions and copy the data.", + ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "debug", + Usage: "Print SQL commands sent", }, - Description: `The database definitions Forgejo uses change across versions, sometimes changing default values and leaving old unused columns. + }, + Description: `The database definitions Forgejo uses change across versions, sometimes changing default values and leaving old unused columns. This command will cause Xorm to recreate tables, copying over the data and deleting the old table. You should back-up your database before doing this and ensure that your database is up-to-date first.`, - Action: runRecreateTable, - } + Action: runRecreateTable, } -func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error { - stdCtx, cancel := installSignals(stdCtx) +func runRecreateTable(ctx *cli.Context) error { + stdCtx, cancel := installSignals() defer cancel() // Redirect the default golog to here @@ -126,7 +120,7 @@ func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error { args := ctx.Args() names := make([]string, 0, ctx.NArg()) - for i := range ctx.NArg() { + for i := 0; i < ctx.NArg(); i++ { names = append(names, args.Get(i)) } @@ -136,31 +130,24 @@ func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error { } recreateTables := migrate_base.RecreateTables(beans...) - return db.InitEngineWithMigration(stdCtx, func(x db.Engine) error { - engine, err := db.GetMasterEngine(x) - if err != nil { + return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error { + if err := migrations.EnsureUpToDate(x); err != nil { return err } - - if err := migrations.EnsureUpToDate(engine); err != nil { - return err - } - - return recreateTables(engine) + return recreateTables(x) }) } -func setupDoctorDefaultLogger(ctx *cli.Command, colorize bool) { +func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) { // Silence the default loggers setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr) logFile := ctx.String("log-file") - switch logFile { - case "": + if logFile == "" { return // if no doctor log-file is set, do not show any log from default logger - case "-": + } else if logFile == "-" { setupConsoleLogger(log.TRACE, colorize, os.Stdout) - default: + } else { logFile, _ = filepath.Abs(logFile) writeMode := log.WriterMode{Level: log.TRACE, WriterOption: log.WriterFileOption{FileName: logFile}} writer, err := log.NewEventWriter("console-to-file", "file", writeMode) @@ -172,8 +159,8 @@ func setupDoctorDefaultLogger(ctx *cli.Command, colorize bool) { } } -func runDoctorCheck(stdCtx context.Context, ctx *cli.Command) error { - stdCtx, cancel := installSignals(stdCtx) +func runDoctorCheck(ctx *cli.Context) error { + stdCtx, cancel := installSignals() defer cancel() colorize := log.CanColorStdout diff --git a/cmd/doctor_convert.go b/cmd/doctor_convert.go index 44bebae154..190b2fc2ef 100644 --- a/cmd/doctor_convert.go +++ b/cmd/doctor_convert.go @@ -4,28 +4,25 @@ package cmd import ( - "context" "fmt" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // cmdDoctorConvert represents the available convert sub-command. -func cmdDoctorConvert() *cli.Command { - return &cli.Command{ - Name: "convert", - Usage: "Convert the database", - Description: "A command to convert an existing MySQL database from utf8 to utf8mb4", - Action: runDoctorConvert, - } +var cmdDoctorConvert = &cli.Command{ + Name: "convert", + Usage: "Convert the database", + Description: "A command to convert an existing MySQL database from utf8 to utf8mb4", + Action: runDoctorConvert, } -func runDoctorConvert(stdCtx context.Context, ctx *cli.Command) error { - stdCtx, cancel := installSignals(stdCtx) +func runDoctorConvert(ctx *cli.Context) error { + stdCtx, cancel := installSignals() defer cancel() if err := initDB(stdCtx); err != nil { diff --git a/cmd/doctor_test.go b/cmd/doctor_test.go index c3eda8315b..3e1ff299c5 100644 --- a/cmd/doctor_test.go +++ b/cmd/doctor_test.go @@ -7,11 +7,11 @@ import ( "context" "testing" - "forgejo.org/modules/log" - "forgejo.org/services/doctor" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/doctor" - "github.com/stretchr/testify/require" - "github.com/urfave/cli/v3" + "github.com/stretchr/testify/assert" + "github.com/urfave/cli/v2" ) func TestDoctorRun(t *testing.T) { @@ -22,12 +22,12 @@ func TestDoctorRun(t *testing.T) { SkipDatabaseInitialization: true, }) - app := cli.Command{} - app.Commands = []*cli.Command{cmdDoctorCheck()} - err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"}) - require.NoError(t, err) - err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "no-such"}) - require.ErrorContains(t, err, `unknown checks: "no-such"`) - err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check,no-such"}) - require.ErrorContains(t, err, `unknown checks: "no-such"`) + app := cli.NewApp() + app.Commands = []*cli.Command{cmdDoctorCheck} + err := app.Run([]string{"./gitea", "check", "--run", "test-check"}) + assert.NoError(t, err) + err = app.Run([]string{"./gitea", "check", "--run", "no-such"}) + assert.ErrorContains(t, err, `unknown checks: "no-such"`) + err = app.Run([]string{"./gitea", "check", "--run", "test-check,no-such"}) + assert.ErrorContains(t, err, `unknown checks: "no-such"`) } diff --git a/cmd/dump.go b/cmd/dump.go index cb01e74196..0a18adb27d 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -5,8 +5,6 @@ package cmd import ( - "context" - "errors" "fmt" "io" "os" @@ -15,16 +13,16 @@ import ( "strings" "time" - "forgejo.org/models/db" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/storage" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" - "code.forgejo.org/go-chi/session" + "gitea.com/go-chi/session" "github.com/mholt/archiver/v3" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error { @@ -85,10 +83,6 @@ func (o *outputType) Set(value string) error { return fmt.Errorf("allowed values are %s", o.Join()) } -func (o *outputType) Get() any { - return o.String() -} - func (o outputType) String() string { if o.selected == "" { return o.Default @@ -102,81 +96,76 @@ var outputTypeEnum = &outputType{ } // CmdDump represents the available dump sub-command. -func cmdDump() *cli.Command { - return &cli.Command{ - Name: "dump", - Usage: "Dump Forgejo files and database", - Description: `Dump compresses all related files and database into zip file. +var CmdDump = &cli.Command{ + Name: "dump", + Usage: "Dump Forgejo files and database", + Description: `Dump compresses all related files and database into zip file. It can be used for backup and capture Forgejo server image to send to maintainer`, - Action: runDump, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "file", - Aliases: []string{"f"}, - Value: fmt.Sprintf("forgejo-dump-%d.zip", time.Now().Unix()), - Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", - }, - &cli.BoolFlag{ - Name: "verbose", - Aliases: []string{"V"}, - Usage: "Show process details", - }, - &cli.BoolFlag{ - Name: "quiet", - Aliases: []string{"q"}, - Usage: "Only display warnings and errors", - }, - &cli.StringFlag{ - Name: "tempdir", - Aliases: []string{"t"}, - Usage: "Temporary dir path", - }, - &cli.StringFlag{ - Name: "database", - Aliases: []string{"d"}, - Usage: "Specify the database SQL syntax: sqlite3, mysql, postgres", - }, - &cli.BoolFlag{ - Name: "skip-repository", - Aliases: []string{"R"}, - Usage: "Skip repositories", - }, - &cli.BoolFlag{ - Name: "skip-log", - Aliases: []string{"L"}, - Usage: "Skip logs", - }, - &cli.BoolFlag{ - Name: "skip-custom-dir", - Usage: "Skip custom directory", - }, - &cli.BoolFlag{ - Name: "skip-lfs-data", - Usage: "Skip LFS data", - }, - &cli.BoolFlag{ - Name: "skip-attachment-data", - Usage: "Skip attachment data", - }, - &cli.BoolFlag{ - Name: "skip-package-data", - Usage: "Skip package data", - }, - &cli.BoolFlag{ - Name: "skip-index", - Usage: "Skip bleve index data", - }, - &cli.BoolFlag{ - Name: "skip-repo-archives", - Usage: "Skip repository archives", - }, - &cli.GenericFlag{ - Name: "type", - Value: outputTypeEnum, - Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), - }, + Action: runDump, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "file", + Aliases: []string{"f"}, + Value: fmt.Sprintf("forgejo-dump-%d.zip", time.Now().Unix()), + Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", }, - } + &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"V"}, + Usage: "Show process details", + }, + &cli.BoolFlag{ + Name: "quiet", + Aliases: []string{"q"}, + Usage: "Only display warnings and errors", + }, + &cli.StringFlag{ + Name: "tempdir", + Aliases: []string{"t"}, + Value: os.TempDir(), + Usage: "Temporary dir path", + }, + &cli.StringFlag{ + Name: "database", + Aliases: []string{"d"}, + Usage: "Specify the database SQL syntax: sqlite3, mysql, postgres", + }, + &cli.BoolFlag{ + Name: "skip-repository", + Aliases: []string{"R"}, + Usage: "Skip the repository dumping", + }, + &cli.BoolFlag{ + Name: "skip-log", + Aliases: []string{"L"}, + Usage: "Skip the log dumping", + }, + &cli.BoolFlag{ + Name: "skip-custom-dir", + Usage: "Skip custom directory", + }, + &cli.BoolFlag{ + Name: "skip-lfs-data", + Usage: "Skip LFS data", + }, + &cli.BoolFlag{ + Name: "skip-attachment-data", + Usage: "Skip attachment data", + }, + &cli.BoolFlag{ + Name: "skip-package-data", + Usage: "Skip package data", + }, + &cli.BoolFlag{ + Name: "skip-index", + Usage: "Skip bleve index data", + }, + &cli.GenericFlag{ + Name: "type", + Value: outputTypeEnum, + Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), + }, + }, } func fatal(format string, args ...any) { @@ -184,7 +173,7 @@ func fatal(format string, args ...any) { log.Fatal(format, args...) } -func runDump(stdCtx context.Context, ctx *cli.Command) error { +func runDump(ctx *cli.Context) error { var file *os.File fileName := ctx.String("file") outType := ctx.String("type") @@ -220,16 +209,16 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { if !setting.InstallLock { log.Error("Is '%s' really the right config path?\n", setting.CustomConf) - return errors.New("forgejo is not initialized") + return fmt.Errorf("forgejo is not initialized") } setting.LoadSettings() // cannot access session settings otherwise verbose := ctx.Bool("verbose") if verbose && ctx.Bool("quiet") { - return errors.New("--quiet and --verbose cannot both be set") + return fmt.Errorf("--quiet and --verbose cannot both be set") } - stdCtx, cancel := installSignals(stdCtx) + stdCtx, cancel := installSignals() defer cancel() err := db.InitEngine(stdCtx) @@ -244,7 +233,7 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { if file == nil { file, err = os.Create(fileName) if err != nil { - fatal("Failed to open %s: %v", fileName, err) + fatal("Unable to open %s: %v", fileName, err) } } defer file.Close() @@ -261,7 +250,7 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { iface, err = archiver.ByExtension(fileName) } if err != nil { - fatal("Failed to get archiver for extension: %v", err) + fatal("Unable to get archiver for extension: %v", err) } w, _ := iface.(archiver.Writer) @@ -271,7 +260,7 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { defer w.Close() if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") { - log.Info("Skipping local repositories") + log.Info("Skip dumping local repositories") } else { log.Info("Dumping local repositories... %s", setting.RepoRootPath) if err := addRecursiveExclude(w, "repos", setting.RepoRootPath, []string{absFileName}, verbose); err != nil { @@ -279,9 +268,9 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { } if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") { - log.Info("Skipping LFS data") + log.Info("Skip dumping LFS data") } else if !setting.LFS.StartServer { - log.Info("LFS not enabled - skipping") + log.Info("LFS isn't enabled. Skip dumping LFS data") } else if err := storage.LFS.IterateObjects("", func(objPath string, object storage.Object) error { info, err := object.Stat() if err != nil { @@ -295,31 +284,18 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { } tmpDir := ctx.String("tempdir") - if tmpDir == "" { - tmpDir, err = os.MkdirTemp("", "forgejo-dump-*") - if err != nil { - fatal("Failed to create temporary directory: %v", err) - } - - defer func() { - if err := util.Remove(tmpDir); err != nil { - log.Warn("Failed to remove temporary directory: %s: Error: %v", tmpDir, err) - } - }() - } - if _, err := os.Stat(tmpDir); os.IsNotExist(err) { fatal("Path does not exist: %s", tmpDir) } dbDump, err := os.CreateTemp(tmpDir, "forgejo-db.sql") if err != nil { - fatal("Failed to create temporary file: %v", err) + fatal("Failed to create tmp file: %v", err) } defer func() { _ = dbDump.Close() if err := util.Remove(dbDump.Name()); err != nil { - log.Warn("Failed to remove temporary database file: %s: Error: %v", dbDump.Name(), err) + log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err) } }() @@ -355,16 +331,16 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { fatal("Failed to include custom: %v", err) } } else { - log.Info("Custom dir %s is inside data dir %s, skipping", setting.CustomPath, setting.AppDataPath) + log.Info("Custom dir %s is inside data dir %s, skipped", setting.CustomPath, setting.AppDataPath) } } else { - log.Info("Custom dir %s does not exist, skipping", setting.CustomPath) + log.Info("Custom dir %s doesn't exist, skipped", setting.CustomPath) } } isExist, err := util.IsExist(setting.AppDataPath) if err != nil { - log.Error("Failed to check if %s exists: %v", setting.AppDataPath, err) + log.Error("Unable to check if %s exists. Error: %v", setting.AppDataPath, err) } if isExist { log.Info("Packing data directory...%s", setting.AppDataPath) @@ -379,16 +355,10 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { } if ctx.IsSet("skip-index") && ctx.Bool("skip-index") { - log.Info("Skipping bleve index data") excludes = append(excludes, setting.Indexer.RepoPath) excludes = append(excludes, setting.Indexer.IssuePath) } - if ctx.IsSet("skip-repo-archives") && ctx.Bool("skip-repo-archives") { - log.Info("Skipping repository archives data") - excludes = append(excludes, setting.RepoArchive.Storage.Path) - } - excludes = append(excludes, setting.RepoRootPath) excludes = append(excludes, setting.LFS.Storage.Path) excludes = append(excludes, setting.Attachment.Storage.Path) @@ -401,7 +371,7 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { } if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") { - log.Info("Skipping attachment data") + log.Info("Skip dumping attachment data") } else if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error { info, err := object.Stat() if err != nil { @@ -414,9 +384,9 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { } if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") { - log.Info("Skipping package data") + log.Info("Skip dumping package data") } else if !setting.Packages.Enabled { - log.Info("Package registry not enabled - skipping") + log.Info("Packages isn't enabled. Skip dumping package data") } else if err := storage.Packages.IterateObjects("", func(objPath string, object storage.Object) error { info, err := object.Stat() if err != nil { @@ -432,11 +402,11 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { // ensuring that it's clear the dump is skipped whether the directory's initialized // yet or not. if ctx.IsSet("skip-log") && ctx.Bool("skip-log") { - log.Info("Skipping log files") + log.Info("Skip dumping log files") } else { isExist, err := util.IsExist(setting.Log.RootPath) if err != nil { - log.Error("Failed to check if %s exists: %v", setting.Log.RootPath, err) + log.Error("Unable to check if %s exists. Error: %v", setting.Log.RootPath, err) } if isExist { if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil { @@ -486,7 +456,7 @@ func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeA currentInsidePath := path.Join(insidePath, file.Name()) if util.SliceContainsString(excludeAbsPath, currentAbsPath) { - log.Debug("Skipping %q (matched an excluded path)", currentAbsPath) + log.Debug("Skipping %q because matched an excluded path.", currentAbsPath) continue } diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index eb89273e7f..3a24cf6c5f 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -10,79 +10,77 @@ import ( "os" "strings" - "forgejo.org/modules/git" - "forgejo.org/modules/log" - base "forgejo.org/modules/migration" - "forgejo.org/modules/setting" - "forgejo.org/modules/structs" - "forgejo.org/modules/util" - "forgejo.org/services/convert" - "forgejo.org/services/migrations" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + base "code.gitea.io/gitea/modules/migration" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/convert" + "code.gitea.io/gitea/services/migrations" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // CmdDumpRepository represents the available dump repository sub-command. -func cmdDumpRepository() *cli.Command { - return &cli.Command{ - Name: "dump-repo", - Usage: "Dump the repository from git/github/gitea/gitlab", - Description: "This is a command for dumping the repository data.", - Action: runDumpRepository, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "git_service", - Value: "", - Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.", - }, - &cli.StringFlag{ - Name: "repo_dir", - Aliases: []string{"r"}, - Value: "./data", - Usage: "Repository dir path to store the data", - }, - &cli.StringFlag{ - Name: "clone_addr", - Value: "", - Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL", - }, - &cli.StringFlag{ - Name: "auth_username", - Value: "", - Usage: "The username to visit the clone_addr", - }, - &cli.StringFlag{ - Name: "auth_password", - Value: "", - Usage: "The password to visit the clone_addr", - }, - &cli.StringFlag{ - Name: "auth_token", - Value: "", - Usage: "The personal token to visit the clone_addr", - }, - &cli.StringFlag{ - Name: "owner_name", - Value: "", - Usage: "The data will be stored on a directory with owner name if not empty", - }, - &cli.StringFlag{ - Name: "repo_name", - Value: "", - Usage: "The data will be stored on a directory with repository name if not empty", - }, - &cli.StringFlag{ - Name: "units", - Value: "", - Usage: `Which items will be migrated, one or more units should be separated as comma. -wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, - }, +var CmdDumpRepository = &cli.Command{ + Name: "dump-repo", + Usage: "Dump the repository from git/github/gitea/gitlab", + Description: "This is a command for dumping the repository data.", + Action: runDumpRepository, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "git_service", + Value: "", + Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.", }, - } + &cli.StringFlag{ + Name: "repo_dir", + Aliases: []string{"r"}, + Value: "./data", + Usage: "Repository dir path to store the data", + }, + &cli.StringFlag{ + Name: "clone_addr", + Value: "", + Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL", + }, + &cli.StringFlag{ + Name: "auth_username", + Value: "", + Usage: "The username to visit the clone_addr", + }, + &cli.StringFlag{ + Name: "auth_password", + Value: "", + Usage: "The password to visit the clone_addr", + }, + &cli.StringFlag{ + Name: "auth_token", + Value: "", + Usage: "The personal token to visit the clone_addr", + }, + &cli.StringFlag{ + Name: "owner_name", + Value: "", + Usage: "The data will be stored on a directory with owner name if not empty", + }, + &cli.StringFlag{ + Name: "repo_name", + Value: "", + Usage: "The data will be stored on a directory with repository name if not empty", + }, + &cli.StringFlag{ + Name: "units", + Value: "", + Usage: `Which items will be migrated, one or more units should be separated as comma. +wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, + }, + }, } -func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error { - stdCtx, cancel := installSignals(stdCtx) +func runDumpRepository(ctx *cli.Context) error { + stdCtx, cancel := installSignals() defer cancel() if err := initDB(stdCtx); err != nil { diff --git a/cmd/dump_test.go b/cmd/dump_test.go index 459386318f..d33619bab8 100644 --- a/cmd/dump_test.go +++ b/cmd/dump_test.go @@ -10,7 +10,6 @@ import ( "github.com/mholt/archiver/v3" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) type mockArchiver struct { @@ -36,20 +35,20 @@ func TestAddRecursiveExclude(t *testing.T) { archiver := &mockArchiver{} err := addRecursiveExclude(archiver, "", dir, []string{}, false) - require.NoError(t, err) + assert.NoError(t, err) assert.Empty(t, archiver.addedFiles) }) t.Run("Single file", func(t *testing.T) { dir := t.TempDir() err := os.WriteFile(dir+"/example", nil, 0o666) - require.NoError(t, err) + assert.NoError(t, err) t.Run("No exclude", func(t *testing.T) { archiver := &mockArchiver{} err = addRecursiveExclude(archiver, "", dir, nil, false) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, archiver.addedFiles, 1) assert.Contains(t, archiver.addedFiles, "example") }) @@ -58,7 +57,7 @@ func TestAddRecursiveExclude(t *testing.T) { archiver := &mockArchiver{} err = addRecursiveExclude(archiver, "", dir, []string{dir + "/example"}, false) - require.NoError(t, err) + assert.NoError(t, err) assert.Empty(t, archiver.addedFiles) }) }) @@ -66,17 +65,17 @@ func TestAddRecursiveExclude(t *testing.T) { t.Run("File inside directory", func(t *testing.T) { dir := t.TempDir() err := os.MkdirAll(dir+"/deep/nested/folder", 0o750) - require.NoError(t, err) + assert.NoError(t, err) err = os.WriteFile(dir+"/deep/nested/folder/example", nil, 0o666) - require.NoError(t, err) + assert.NoError(t, err) err = os.WriteFile(dir+"/deep/nested/folder/another-file", nil, 0o666) - require.NoError(t, err) + assert.NoError(t, err) t.Run("No exclude", func(t *testing.T) { archiver := &mockArchiver{} err = addRecursiveExclude(archiver, "", dir, nil, false) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, archiver.addedFiles, 5) assert.Contains(t, archiver.addedFiles, "deep") assert.Contains(t, archiver.addedFiles, "deep/nested") @@ -89,7 +88,7 @@ func TestAddRecursiveExclude(t *testing.T) { archiver := &mockArchiver{} err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep"}, false) - require.NoError(t, err) + assert.NoError(t, err) assert.Empty(t, archiver.addedFiles) }) @@ -97,7 +96,7 @@ func TestAddRecursiveExclude(t *testing.T) { archiver := &mockArchiver{} err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep/nested/folder"}, false) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, archiver.addedFiles, 2) assert.Contains(t, archiver.addedFiles, "deep") assert.Contains(t, archiver.addedFiles, "deep/nested") @@ -107,7 +106,7 @@ func TestAddRecursiveExclude(t *testing.T) { archiver := &mockArchiver{} err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep/nested/folder/example"}, false) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, archiver.addedFiles, 4) assert.Contains(t, archiver.addedFiles, "deep") assert.Contains(t, archiver.addedFiles, "deep/nested") diff --git a/cmd/embedded.go b/cmd/embedded.go index 8fa76ccef1..9f03f7be7c 100644 --- a/cmd/embedded.go +++ b/cmd/embedded.go @@ -4,41 +4,38 @@ package cmd import ( - "context" "errors" "fmt" "os" "path/filepath" "strings" - "forgejo.org/modules/assetfs" - "forgejo.org/modules/log" - "forgejo.org/modules/options" - "forgejo.org/modules/public" - "forgejo.org/modules/setting" - "forgejo.org/modules/templates" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/public" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/util" "github.com/gobwas/glob" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // CmdEmbedded represents the available extract sub-command. -func cmdEmbedded() *cli.Command { - return &cli.Command{ +var ( + CmdEmbedded = &cli.Command{ Name: "embedded", Usage: "Extract embedded resources", Description: "A command for extracting embedded resources, like templates and images", - Commands: []*cli.Command{ - subcmdList(), - subcmdView(), - subcmdExtract(), + Subcommands: []*cli.Command{ + subcmdList, + subcmdView, + subcmdExtract, }, } -} -func subcmdList() *cli.Command { - return &cli.Command{ + subcmdList = &cli.Command{ Name: "list", Usage: "List files matching the given pattern", Action: runList, @@ -50,10 +47,8 @@ func subcmdList() *cli.Command { }, }, } -} -func subcmdView() *cli.Command { - return &cli.Command{ + subcmdView = &cli.Command{ Name: "view", Usage: "View a file matching the given pattern", Action: runView, @@ -65,10 +60,8 @@ func subcmdView() *cli.Command { }, }, } -} -func subcmdExtract() *cli.Command { - return &cli.Command{ + subcmdExtract = &cli.Command{ Name: "extract", Usage: "Extract resources", Action: runExtract, @@ -97,9 +90,9 @@ func subcmdExtract() *cli.Command { }, }, } -} -var matchedAssetFiles []assetFile + matchedAssetFiles []assetFile +) type assetFile struct { fs *assetfs.LayeredFS @@ -107,7 +100,7 @@ type assetFile struct { path string } -func initEmbeddedExtractor(_ context.Context, c *cli.Command) error { +func initEmbeddedExtractor(c *cli.Context) error { setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr) patterns, err := compileCollectPatterns(c.Args().Slice()) @@ -122,32 +115,32 @@ func initEmbeddedExtractor(_ context.Context, c *cli.Command) error { return nil } -func runList(ctx context.Context, c *cli.Command) error { - if err := runListDo(ctx, c); err != nil { +func runList(c *cli.Context) error { + if err := runListDo(c); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return err } return nil } -func runView(ctx context.Context, c *cli.Command) error { - if err := runViewDo(ctx, c); err != nil { +func runView(c *cli.Context) error { + if err := runViewDo(c); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return err } return nil } -func runExtract(ctx context.Context, c *cli.Command) error { - if err := runExtractDo(ctx, c); err != nil { +func runExtract(c *cli.Context) error { + if err := runExtractDo(c); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return err } return nil } -func runListDo(ctx context.Context, c *cli.Command) error { - if err := initEmbeddedExtractor(ctx, c); err != nil { +func runListDo(c *cli.Context) error { + if err := initEmbeddedExtractor(c); err != nil { return err } @@ -158,8 +151,8 @@ func runListDo(ctx context.Context, c *cli.Command) error { return nil } -func runViewDo(ctx context.Context, c *cli.Command) error { - if err := initEmbeddedExtractor(ctx, c); err != nil { +func runViewDo(c *cli.Context) error { + if err := initEmbeddedExtractor(c); err != nil { return err } @@ -181,8 +174,8 @@ func runViewDo(ctx context.Context, c *cli.Command) error { return nil } -func runExtractDo(ctx context.Context, c *cli.Command) error { - if err := initEmbeddedExtractor(ctx, c); err != nil { +func runExtractDo(c *cli.Context) error { + if err := initEmbeddedExtractor(c); err != nil { return err } @@ -278,7 +271,7 @@ func extractAsset(d string, a assetFile, overwrite, rename bool) error { return nil } -func collectAssetFilesByPattern(c *cli.Command, globs []glob.Glob, path string, layer *assetfs.Layer) { +func collectAssetFilesByPattern(c *cli.Context, globs []glob.Glob, path string, layer *assetfs.Layer) { fs := assetfs.Layered(layer) files, err := fs.ListAllFiles(".", true) if err != nil { diff --git a/cmd/forgejo/actions.go b/cmd/forgejo/actions.go index c445d1aa38..70f9452cb8 100644 --- a/cmd/forgejo/actions.go +++ b/cmd/forgejo/actions.go @@ -6,25 +6,24 @@ package forgejo import ( "context" "encoding/hex" - "errors" "fmt" "io" "os" "strings" - actions_model "forgejo.org/models/actions" - "forgejo.org/modules/private" - "forgejo.org/modules/setting" - private_routers "forgejo.org/routers/private" + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" + private_routers "code.gitea.io/gitea/routers/private" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) func CmdActions(ctx context.Context) *cli.Command { return &cli.Command{ Name: "actions", Usage: "Commands for managing Forgejo Actions", - Commands: []*cli.Command{ + Subcommands: []*cli.Command{ SubcmdActionsGenerateRunnerToken(ctx), SubcmdActionsGenerateRunnerSecret(ctx), SubcmdActionsRegister(ctx), @@ -37,7 +36,7 @@ func SubcmdActionsGenerateRunnerToken(ctx context.Context) *cli.Command { Name: "generate-runner-token", Usage: "Generate a new token for a runner to use to register with the server", Before: prepareWorkPathAndCustomConf(ctx), - Action: RunGenerateActionsRunnerToken, + Action: func(cliCtx *cli.Context) error { return RunGenerateActionsRunnerToken(ctx, cliCtx) }, Flags: []cli.Flag{ &cli.StringFlag{ Name: "scope", @@ -53,7 +52,7 @@ func SubcmdActionsGenerateRunnerSecret(ctx context.Context) *cli.Command { return &cli.Command{ Name: "generate-secret", Usage: "Generate a secret suitable for input to the register subcommand", - Action: RunGenerateSecret, + Action: func(cliCtx *cli.Context) error { return RunGenerateSecret(ctx, cliCtx) }, } } @@ -62,7 +61,7 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command { Name: "register", Usage: "Idempotent registration of a runner using a shared secret", Before: prepareWorkPathAndCustomConf(ctx), - Action: RunRegister, + Action: func(cliCtx *cli.Context) error { return RunRegister(ctx, cliCtx) }, Flags: []cli.Flag{ &cli.StringFlag{ Name: "secret", @@ -87,11 +86,6 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command { Value: "", Usage: "comma separated list of labels supported by the runner (e.g. docker,ubuntu-latest,self-hosted) (not required since v1.21)", }, - &cli.BoolFlag{ - Name: "keep-labels", - Value: false, - Usage: "do not affect the labels when updating an existing runner", - }, &cli.StringFlag{ Name: "name", Value: "runner", @@ -106,26 +100,26 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command { } } -func readSecret(ctx context.Context, cli *cli.Command) (string, error) { - if cli.IsSet("secret") { - return cli.String("secret"), nil +func readSecret(ctx context.Context, cliCtx *cli.Context) (string, error) { + if cliCtx.IsSet("secret") { + return cliCtx.String("secret"), nil } - if cli.IsSet("secret-stdin") { + if cliCtx.IsSet("secret-stdin") { buf, err := io.ReadAll(ContextGetStdin(ctx)) if err != nil { return "", err } return string(buf), nil } - if cli.IsSet("secret-file") { - path := cli.String("secret-file") + if cliCtx.IsSet("secret-file") { + path := cliCtx.String("secret-file") buf, err := os.ReadFile(path) if err != nil { return "", err } return string(buf), nil } - return "", errors.New("at least one of the --secret, --secret-stdin, --secret-file options is required") + return "", fmt.Errorf("at least one of the --secret, --secret-stdin, --secret-file options is required") } func validateSecret(secret string) error { @@ -139,18 +133,7 @@ func validateSecret(secret string) error { return nil } -func getLabels(cli *cli.Command) (*[]string, error) { - if !cli.Bool("keep-labels") { - lblValue := strings.Split(cli.String("labels"), ",") - return &lblValue, nil - } - if cli.String("labels") != "" { - return nil, errors.New("--labels and --keep-labels should not be used together") - } - return nil, nil -} - -func RunRegister(ctx context.Context, cli *cli.Command) error { +func RunRegister(ctx context.Context, cliCtx *cli.Context) error { var cancel context.CancelFunc if !ContextGetNoInit(ctx) { ctx, cancel = installSignals(ctx) @@ -162,20 +145,17 @@ func RunRegister(ctx context.Context, cli *cli.Command) error { } setting.MustInstalled() - secret, err := readSecret(ctx, cli) + secret, err := readSecret(ctx, cliCtx) if err != nil { return err } if err := validateSecret(secret); err != nil { return err } - scope := cli.String("scope") - name := cli.String("name") - version := cli.String("version") - labels, err := getLabels(cli) - if err != nil { - return err - } + scope := cliCtx.String("scope") + labels := cliCtx.String("labels") + name := cliCtx.String("name") + version := cliCtx.String("version") // // There are two kinds of tokens @@ -199,7 +179,7 @@ func RunRegister(ctx context.Context, cli *cli.Command) error { return err } - runner, err := actions_model.RegisterRunner(ctx, owner, repo, secret, labels, name, version) + runner, err := actions_model.RegisterRunner(ctx, owner, repo, secret, strings.Split(labels, ","), name, version) if err != nil { return fmt.Errorf("error while registering runner: %v", err) } @@ -210,7 +190,7 @@ func RunRegister(ctx context.Context, cli *cli.Command) error { return nil } -func RunGenerateSecret(ctx context.Context, cli *cli.Command) error { +func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error { runner := actions_model.ActionRunner{} if err := runner.GenerateToken(); err != nil { return err @@ -221,7 +201,7 @@ func RunGenerateSecret(ctx context.Context, cli *cli.Command) error { return nil } -func RunGenerateActionsRunnerToken(ctx context.Context, cli *cli.Command) error { +func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) error { if !ContextGetNoInit(ctx) { var cancel context.CancelFunc ctx, cancel = installSignals(ctx) @@ -230,7 +210,7 @@ func RunGenerateActionsRunnerToken(ctx context.Context, cli *cli.Command) error setting.MustInstalled() - scope := cli.String("scope") + scope := cliCtx.String("scope") respText, extra := private.GenerateActionsRunnerToken(ctx, scope) if extra.HasError() { diff --git a/cmd/forgejo/actions_test.go b/cmd/forgejo/actions_test.go deleted file mode 100644 index 11315239f7..0000000000 --- a/cmd/forgejo/actions_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright The Forgejo Authors. -// SPDX-License-Identifier: MIT - -package forgejo - -import ( - "context" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/urfave/cli/v3" -) - -func TestActions_getLabels(t *testing.T) { - type testCase struct { - args []string - hasLabels bool - hasError bool - labels []string - } - type resultType struct { - labels *[]string - err error - } - - cases := []testCase{ - { - args: []string{"x"}, - hasLabels: true, - hasError: false, - labels: []string{""}, - }, { - args: []string{"x", "--labels", "a,b"}, - hasLabels: true, - hasError: false, - labels: []string{"a", "b"}, - }, { - args: []string{"x", "--keep-labels"}, - hasLabels: false, - hasError: false, - }, { - args: []string{"x", "--keep-labels", "--labels", "a,b"}, - hasLabels: false, - hasError: true, - }, { - // this edge-case exists because that's what actually happens - // when no '--labels ...' options are present - args: []string{"x", "--keep-labels", "--labels", ""}, - hasLabels: false, - hasError: false, - }, - } - - flags := SubcmdActionsRegister(t.Context()).Flags - for _, c := range cases { - t.Run(fmt.Sprintf("args: %v", c.args), func(t *testing.T) { - // Create a copy of command to test - var result *resultType - app := cli.Command{} - app.Flags = flags - app.Action = func(_ context.Context, ctx *cli.Command) error { - labels, err := getLabels(ctx) - result = &resultType{labels, err} - return nil - } - - // Run it - _ = app.Run(t.Context(), c.args) - - // Test the results - require.NotNil(t, result) - if c.hasLabels { - assert.NotNil(t, result.labels) - assert.Equal(t, c.labels, *result.labels) - } else { - assert.Nil(t, result.labels) - } - if c.hasError { - require.Error(t, result.err) - } else { - assert.NoError(t, result.err) - } - }) - } -} diff --git a/cmd/forgejo/f3.go b/cmd/forgejo/f3.go index c4aafeac58..5a0d0ac036 100644 --- a/cmd/forgejo/f3.go +++ b/cmd/forgejo/f3.go @@ -8,19 +8,19 @@ import ( "context" "errors" - "forgejo.org/models" - "forgejo.org/modules/git" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/storage" - "forgejo.org/services/f3/util" + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/services/f3/util" - _ "forgejo.org/services/f3/driver" // register the driver + _ "code.gitea.io/gitea/services/f3/driver" // register the driver f3_cmd "code.forgejo.org/f3/gof3/v3/cmd" f3_logger "code.forgejo.org/f3/gof3/v3/logger" f3_util "code.forgejo.org/f3/gof3/v3/util" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) func CmdF3(ctx context.Context) *cli.Command { @@ -28,21 +28,21 @@ func CmdF3(ctx context.Context) *cli.Command { return &cli.Command{ Name: "f3", Usage: "F3", - Commands: []*cli.Command{ + Subcommands: []*cli.Command{ SubcmdF3Mirror(ctx), }, } } func SubcmdF3Mirror(ctx context.Context) *cli.Command { - mirrorCmd := f3_cmd.CreateCmdMirror() + mirrorCmd := f3_cmd.CreateCmdMirror(ctx) mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx) f3Action := mirrorCmd.Action - mirrorCmd.Action = func(ctx context.Context, cli *cli.Command) error { return runMirror(ctx, cli, f3Action) } + mirrorCmd.Action = func(c *cli.Context) error { return runMirror(ctx, c, f3Action) } return mirrorCmd } -func runMirror(ctx context.Context, c *cli.Command, action cli.ActionFunc) error { +func runMirror(ctx context.Context, c *cli.Context, action cli.ActionFunc) error { setting.LoadF3Setting() if !setting.F3.Enabled { return errors.New("F3 is disabled, it is not ready to be used and is only present for development purposes") @@ -69,7 +69,7 @@ func runMirror(ctx context.Context, c *cli.Command, action cli.ActionFunc) error } } - err := action(ctx, c) + err := action(c) if panicError, ok := err.(f3_util.PanicError); ok { log.Debug("F3 Stack trace\n%s", panicError.Stack()) } diff --git a/cmd/forgejo/forgejo.go b/cmd/forgejo/forgejo.go index 171ef1a71d..1b7e16ca8f 100644 --- a/cmd/forgejo/forgejo.go +++ b/cmd/forgejo/forgejo.go @@ -11,12 +11,12 @@ import ( "os/signal" "syscall" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/private" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) type key int @@ -34,7 +34,7 @@ func CmdForgejo(ctx context.Context) *cli.Command { Name: "forgejo-cli", Usage: "Forgejo CLI", Flags: []cli.Flag{}, - Commands: []*cli.Command{ + Subcommands: []*cli.Command{ CmdActions(ctx), CmdF3(ctx), }, @@ -147,12 +147,12 @@ func handleCliResponseExtra(ctx context.Context, extra private.ResponseExtra) er return cli.Exit(extra.Error, 1) } -func prepareWorkPathAndCustomConf(ctx context.Context) func(ctx context.Context, cli *cli.Command) (context.Context, error) { - return func(ctx context.Context, cli *cli.Command) (context.Context, error) { +func prepareWorkPathAndCustomConf(ctx context.Context) func(c *cli.Context) error { + return func(c *cli.Context) error { if !ContextGetNoInit(ctx) { var args setting.ArgWorkPathAndCustomConf // from children to parent, check the global flags - for _, curCtx := range cli.Lineage() { + for _, curCtx := range c.Lineage() { if curCtx.IsSet("work-path") && args.WorkPath == "" { args.WorkPath = curCtx.String("work-path") } @@ -165,6 +165,6 @@ func prepareWorkPathAndCustomConf(ctx context.Context) func(ctx context.Context, } setting.InitWorkPathAndCommonConfig(os.Getenv, args) } - return ctx, nil + return nil } } diff --git a/cmd/generate.go b/cmd/generate.go index 7076ae541f..806946244b 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -5,65 +5,56 @@ package cmd import ( - "context" "fmt" "os" - "forgejo.org/modules/generate" + "code.gitea.io/gitea/modules/generate" "github.com/mattn/go-isatty" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -// CmdGenerate represents the available generate sub-command. -func cmdGenerate() *cli.Command { - return &cli.Command{ +var ( + // CmdGenerate represents the available generate sub-command. + CmdGenerate = &cli.Command{ Name: "generate", Usage: "Generate Gitea's secrets/keys/tokens", - Commands: []*cli.Command{ - subcmdSecret(), + Subcommands: []*cli.Command{ + subcmdSecret, }, } -} -func subcmdSecret() *cli.Command { - return &cli.Command{ + subcmdSecret = &cli.Command{ Name: "secret", Usage: "Generate a secret token", - Commands: []*cli.Command{ - microcmdGenerateInternalToken(), - microcmdGenerateLfsJwtSecret(), - microcmdGenerateSecretKey(), + Subcommands: []*cli.Command{ + microcmdGenerateInternalToken, + microcmdGenerateLfsJwtSecret, + microcmdGenerateSecretKey, }, } -} -func microcmdGenerateInternalToken() *cli.Command { - return &cli.Command{ + microcmdGenerateInternalToken = &cli.Command{ Name: "INTERNAL_TOKEN", Usage: "Generate a new INTERNAL_TOKEN", Action: runGenerateInternalToken, } -} -func microcmdGenerateLfsJwtSecret() *cli.Command { - return &cli.Command{ + microcmdGenerateLfsJwtSecret = &cli.Command{ Name: "JWT_SECRET", Aliases: []string{"LFS_JWT_SECRET"}, Usage: "Generate a new JWT_SECRET", Action: runGenerateLfsJwtSecret, } -} -func microcmdGenerateSecretKey() *cli.Command { - return &cli.Command{ + microcmdGenerateSecretKey = &cli.Command{ Name: "SECRET_KEY", Usage: "Generate a new SECRET_KEY", Action: runGenerateSecretKey, } -} +) -func runGenerateInternalToken(ctx context.Context, c *cli.Command) error { +func runGenerateInternalToken(c *cli.Context) error { internalToken, err := generate.NewInternalToken() if err != nil { return err @@ -72,25 +63,28 @@ func runGenerateInternalToken(ctx context.Context, c *cli.Command) error { fmt.Printf("%s", internalToken) if isatty.IsTerminal(os.Stdout.Fd()) { - fmt.Println() + fmt.Printf("\n") } return nil } -func runGenerateLfsJwtSecret(ctx context.Context, c *cli.Command) error { - _, jwtSecretBase64 := generate.NewJwtSecret() +func runGenerateLfsJwtSecret(c *cli.Context) error { + _, jwtSecretBase64, err := generate.NewJwtSecret() + if err != nil { + return err + } fmt.Printf("%s", jwtSecretBase64) if isatty.IsTerminal(os.Stdout.Fd()) { - fmt.Print("\n") + fmt.Printf("\n") } return nil } -func runGenerateSecretKey(ctx context.Context, c *cli.Command) error { +func runGenerateSecretKey(c *cli.Context) error { secretKey, err := generate.NewSecretKey() if err != nil { return err @@ -99,7 +93,7 @@ func runGenerateSecretKey(ctx context.Context, c *cli.Command) error { fmt.Printf("%s", secretKey) if isatty.IsTerminal(os.Stdout.Fd()) { - fmt.Print("\n") + fmt.Printf("\n") } return nil diff --git a/cmd/hook.go b/cmd/hook.go index 909cdfdf84..eec93aece7 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -14,38 +14,36 @@ import ( "strings" "time" - "forgejo.org/modules/git" - "forgejo.org/modules/git/pushoptions" - "forgejo.org/modules/log" - "forgejo.org/modules/private" - repo_module "forgejo.org/modules/repository" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/git/pushoptions" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) const ( hookBatchSize = 30 ) -// CmdHook represents the available hooks sub-command. -func cmdHook() *cli.Command { - return &cli.Command{ +var ( + // CmdHook represents the available hooks sub-command. + CmdHook = &cli.Command{ Name: "hook", Usage: "(internal) Should only be called by Git", Description: "Delegate commands to corresponding Git hooks", Before: PrepareConsoleLoggerLevel(log.FATAL), - Commands: []*cli.Command{ - subcmdHookPreReceive(), - subcmdHookUpdate(), - subcmdHookPostReceive(), - subcmdHookProcReceive(), + Subcommands: []*cli.Command{ + subcmdHookPreReceive, + subcmdHookUpdate, + subcmdHookPostReceive, + subcmdHookProcReceive, }, } -} -func subcmdHookPreReceive() *cli.Command { - return &cli.Command{ + subcmdHookPreReceive = &cli.Command{ Name: "pre-receive", Usage: "Delegate pre-receive Git hook", Description: "This command should only be called by Git", @@ -56,10 +54,7 @@ func subcmdHookPreReceive() *cli.Command { }, }, } -} - -func subcmdHookUpdate() *cli.Command { - return &cli.Command{ + subcmdHookUpdate = &cli.Command{ Name: "update", Usage: "Delegate update Git hook", Description: "This command should only be called by Git", @@ -70,10 +65,7 @@ func subcmdHookUpdate() *cli.Command { }, }, } -} - -func subcmdHookPostReceive() *cli.Command { - return &cli.Command{ + subcmdHookPostReceive = &cli.Command{ Name: "post-receive", Usage: "Delegate post-receive Git hook", Description: "This command should only be called by Git", @@ -84,11 +76,8 @@ func subcmdHookPostReceive() *cli.Command { }, }, } -} - -// Note: new hook since git 2.29 -func subcmdHookProcReceive() *cli.Command { - return &cli.Command{ + // Note: new hook since git 2.29 + subcmdHookProcReceive = &cli.Command{ Name: "proc-receive", Usage: "Delegate proc-receive Git hook", Description: "This command should only be called by Git", @@ -99,7 +88,7 @@ func subcmdHookProcReceive() *cli.Command { }, }, } -} +) type delayWriter struct { internal io.Writer @@ -172,14 +161,14 @@ func (n *nilWriter) WriteString(s string) (int, error) { return len(s), nil } -func runHookPreReceive(ctx context.Context, c *cli.Command) error { +func runHookPreReceive(c *cli.Context) error { if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal { return nil } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), true) + setup(ctx, c.Bool("debug")) if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if setting.OnlyAllowPushIfGiteaEnvironmentSet { @@ -231,7 +220,10 @@ Forgejo or set your environment appropriately.`, "") } } - supportProcReceive := git.CheckGitVersionAtLeast("2.29") == nil + supportProcReceive := false + if git.CheckGitVersionAtLeast("2.29") == nil { + supportProcReceive = true + } for scanner.Scan() { // TODO: support news feeds for wiki @@ -258,7 +250,7 @@ Forgejo or set your environment appropriately.`, "") newCommitIDs[count] = newCommitID refFullNames[count] = refFullName count++ - fmt.Fprint(out, "*") + fmt.Fprintf(out, "*") if count >= hookBatchSize { fmt.Fprintf(out, " Checking %d references\n", count) @@ -274,10 +266,10 @@ Forgejo or set your environment appropriately.`, "") lastline = 0 } } else { - fmt.Fprint(out, ".") + fmt.Fprintf(out, ".") } if lastline >= hookBatchSize { - fmt.Fprint(out, "\n") + fmt.Fprintf(out, "\n") lastline = 0 } } @@ -294,7 +286,7 @@ Forgejo or set your environment appropriately.`, "") return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error) } } else if lastline > 0 { - fmt.Fprint(out, "\n") + fmt.Fprintf(out, "\n") } fmt.Fprintf(out, "Checked %d references in total\n", total) @@ -302,13 +294,13 @@ Forgejo or set your environment appropriately.`, "") } // runHookUpdate process the update hook: https://git-scm.com/docs/githooks#update -func runHookUpdate(ctx context.Context, c *cli.Command) error { +func runHookUpdate(c *cli.Context) error { // Now if we're an internal don't do anything else if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal { return nil } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() if c.NArg() != 3 { @@ -330,15 +322,14 @@ func runHookUpdate(ctx context.Context, c *cli.Command) error { return fail(ctx, fmt.Sprintf("The deletion of %s is skipped as it's an internal reference.", refFullName), "") } - // If the new comment isn't empty it means modification. - return fail(ctx, fmt.Sprintf("The modification of %s is skipped as it's an internal reference.", refFullName), "") + return nil } -func runHookPostReceive(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runHookPostReceive(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), true) + setup(ctx, c.Bool("debug")) // First of all run update-server-info no matter what if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil { @@ -410,7 +401,7 @@ Forgejo or set your environment appropriately.`, "") continue } - fmt.Fprint(out, ".") + fmt.Fprintf(out, ".") oldCommitIDs[count] = string(fields[0]) newCommitIDs[count] = string(fields[1]) refFullNames[count] = git.RefName(fields[2]) @@ -498,11 +489,11 @@ func hookPrintResults(results []private.HookPostReceiveBranchResult) { } } -func runHookProcReceive(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runHookProcReceive(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), true) + setup(ctx, c.Bool("debug")) if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if setting.OnlyAllowPushIfGiteaEnvironmentSet { @@ -544,14 +535,14 @@ Forgejo or set your environment appropriately.`, "") index := bytes.IndexByte(rs.Data, byte(0)) if index >= len(rs.Data) { - return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data) + return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data)) } if index < 0 { if len(rs.Data) == 10 && rs.Data[9] == '\n' { index = 9 } else { - return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data) + return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data)) } } diff --git a/cmd/hook_test.go b/cmd/hook_test.go index 82ed392fb8..36149eb91f 100644 --- a/cmd/hook_test.go +++ b/cmd/hook_test.go @@ -6,6 +6,7 @@ package cmd import ( "bufio" "bytes" + "context" "io" "net/http" "net/http/httptest" @@ -14,12 +15,12 @@ import ( "testing" "time" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // Capture what's being written into a standard file descriptor. @@ -41,72 +42,72 @@ func captureOutput(t *testing.T, stdFD *os.File) (finish func() (output string)) } func TestPktLine(t *testing.T) { - ctx := t.Context() + ctx := context.Background() t.Run("Read", func(t *testing.T) { s := strings.NewReader("0000") r := bufio.NewReader(s) result, err := readPktLine(ctx, r, pktLineTypeFlush) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, pktLineTypeFlush, result.Type) s = strings.NewReader("0006a\n") r = bufio.NewReader(s) result, err = readPktLine(ctx, r, pktLineTypeData) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, pktLineTypeData, result.Type) assert.Equal(t, []byte("a\n"), result.Data) s = strings.NewReader("0004") r = bufio.NewReader(s) result, err = readPktLine(ctx, r, pktLineTypeData) - require.Error(t, err) + assert.Error(t, err) assert.Nil(t, result) data := strings.Repeat("x", 65516) r = bufio.NewReader(strings.NewReader("fff0" + data)) result, err = readPktLine(ctx, r, pktLineTypeData) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, pktLineTypeData, result.Type) assert.Equal(t, []byte(data), result.Data) r = bufio.NewReader(strings.NewReader("fff1a")) result, err = readPktLine(ctx, r, pktLineTypeData) - require.Error(t, err) + assert.Error(t, err) assert.Nil(t, result) }) t.Run("Write", func(t *testing.T) { w := bytes.NewBuffer([]byte{}) err := writeFlushPktLine(ctx, w) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, []byte("0000"), w.Bytes()) w.Reset() err = writeDataPktLine(ctx, w, []byte("a\nb")) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, []byte("0007a\nb"), w.Bytes()) w.Reset() data := bytes.Repeat([]byte{0x05}, 288) err = writeDataPktLine(ctx, w, data) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, append([]byte("0124"), data...), w.Bytes()) w.Reset() err = writeDataPktLine(ctx, w, nil) - require.Error(t, err) + assert.Error(t, err) assert.Empty(t, w.Bytes()) w.Reset() data = bytes.Repeat([]byte{0x64}, 65516) err = writeDataPktLine(ctx, w, data) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, append([]byte("fff0"), data...), w.Bytes()) w.Reset() err = writeDataPktLine(ctx, w, bytes.Repeat([]byte{0x64}, 65516+1)) - require.Error(t, err) + assert.Error(t, err) assert.Empty(t, w.Bytes()) }) } @@ -116,7 +117,7 @@ func TestDelayWriter(t *testing.T) { defer test.MockVariableValue(&setting.InternalToken, "Random")() defer test.MockVariableValue(&setting.InstallLock, true)() defer test.MockVariableValue(&setting.Git.VerbosePush, true)() - t.Setenv("SSH_ORIGINAL_COMMAND", "true") + require.NoError(t, os.Setenv("SSH_ORIGINAL_COMMAND", "true")) // Setup the Stdin. f, err := os.OpenFile(t.TempDir()+"/stdin", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666) @@ -134,14 +135,14 @@ func TestDelayWriter(t *testing.T) { defer ts.Close() defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")() - app := cli.Command{} - app.Commands = []*cli.Command{subcmdHookPreReceive()} + app := cli.NewApp() + app.Commands = []*cli.Command{subcmdHookPreReceive} t.Run("Should delay", func(t *testing.T) { defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)() finish := captureOutput(t, os.Stdout) - err = app.Run(t.Context(), []string{"./forgejo", "pre-receive"}) + err = app.Run([]string{"./forgejo", "pre-receive"}) require.NoError(t, err) out := finish() @@ -153,7 +154,7 @@ func TestDelayWriter(t *testing.T) { defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)() finish := captureOutput(t, os.Stdout) - err = app.Run(t.Context(), []string{"./forgejo", "pre-receive"}) + err = app.Run([]string{"./forgejo", "pre-receive"}) require.NoError(t, err) out := finish() @@ -163,40 +164,33 @@ func TestDelayWriter(t *testing.T) { } func TestRunHookUpdate(t *testing.T) { - app := cli.Command{} - app.Commands = []*cli.Command{subcmdHookUpdate()} + app := cli.NewApp() + app.Commands = []*cli.Command{subcmdHookUpdate} t.Run("Removal of internal reference", func(t *testing.T) { defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() defer test.MockVariableValue(&setting.IsProd, false)() finish := captureOutput(t, os.Stderr) - err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"}) + err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"}) out := finish() - require.Error(t, err) + assert.Error(t, err) assert.Contains(t, out, "The deletion of refs/pull/1/head is skipped as it's an internal reference.") }) t.Run("Update of internal reference", func(t *testing.T) { - defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() - defer test.MockVariableValue(&setting.IsProd, false)() - finish := captureOutput(t, os.Stderr) - - err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"}) - out := finish() - require.Error(t, err) - - assert.Contains(t, out, "The modification of refs/pull/1/head is skipped as it's an internal reference.") + err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"}) + assert.NoError(t, err) }) t.Run("Removal of branch", func(t *testing.T) { - err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"}) - require.NoError(t, err) + err := app.Run([]string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"}) + assert.NoError(t, err) }) t.Run("Not enough arguments", func(t *testing.T) { - err := app.Run(t.Context(), []string{"./forgejo", "update"}) - require.NoError(t, err) + err := app.Run([]string{"./forgejo", "update"}) + assert.NoError(t, err) }) } diff --git a/cmd/keys.go b/cmd/keys.go index 00901903f4..81425a5722 100644 --- a/cmd/keys.go +++ b/cmd/keys.go @@ -4,55 +4,52 @@ package cmd import ( - "context" "errors" "fmt" "strings" - "forgejo.org/modules/log" - "forgejo.org/modules/private" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // CmdKeys represents the available keys sub-command -func cmdKeys() *cli.Command { - return &cli.Command{ - Name: "keys", - Usage: "(internal) Should only be called by SSH server", - Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint", - Before: PrepareConsoleLoggerLevel(log.FATAL), - Action: runKeys, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "expected", - Aliases: []string{"e"}, - Value: "git", - Usage: "Expected user for whom provide key commands", - }, - &cli.StringFlag{ - Name: "username", - Aliases: []string{"u"}, - Value: "", - Usage: "Username trying to log in by SSH", - }, - &cli.StringFlag{ - Name: "type", - Aliases: []string{"t"}, - Value: "", - Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)", - }, - &cli.StringFlag{ - Name: "content", - Aliases: []string{"k"}, - Value: "", - Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)", - }, +var CmdKeys = &cli.Command{ + Name: "keys", + Usage: "(internal) Should only be called by SSH server", + Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint", + Before: PrepareConsoleLoggerLevel(log.FATAL), + Action: runKeys, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "expected", + Aliases: []string{"e"}, + Value: "git", + Usage: "Expected user for whom provide key commands", }, - } + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Value: "", + Usage: "Username trying to log in by SSH", + }, + &cli.StringFlag{ + Name: "type", + Aliases: []string{"t"}, + Value: "", + Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)", + }, + &cli.StringFlag{ + Name: "content", + Aliases: []string{"k"}, + Value: "", + Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)", + }, + }, } -func runKeys(ctx context.Context, c *cli.Command) error { +func runKeys(c *cli.Context) error { if !c.IsSet("username") { return errors.New("No username provided") } @@ -71,16 +68,16 @@ func runKeys(ctx context.Context, c *cli.Command) error { return errors.New("No key type and content provided") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), true) + setup(ctx, c.Bool("debug")) authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content) // do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys if extra.Error != nil { return extra.Error } - _, _ = fmt.Fprintln(c.Root().Writer, strings.TrimSpace(authorizedString.Text)) + _, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString.Text)) return nil } diff --git a/cmd/mailer.go b/cmd/mailer.go index d05d6c849b..0c5f2c8c8d 100644 --- a/cmd/mailer.go +++ b/cmd/mailer.go @@ -4,17 +4,16 @@ package cmd import ( - "context" "fmt" - "forgejo.org/modules/private" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func runSendMail(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runSendMail(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() setting.MustInstalled() diff --git a/cmd/main.go b/cmd/main.go index 65cde47884..b48a6143d7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -10,11 +10,11 @@ import ( "path/filepath" "strings" - "forgejo.org/cmd/forgejo" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/cmd/forgejo" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // cmdHelp is our own help subcommand with more information @@ -25,18 +25,18 @@ func cmdHelp() *cli.Command { Aliases: []string{"h"}, Usage: "Shows a list of commands or help for one command", ArgsUsage: "[command]", - Action: func(ctx context.Context, c *cli.Command) (err error) { - lineage := c.Lineage() // The order is from child to parent: help, doctor, Forgejo + Action: func(c *cli.Context) (err error) { + lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea, {Command:nil} targetCmdIdx := 0 - if c.Name == "help" { + if c.Command.Name == "help" { targetCmdIdx = 1 } - if targetCmdIdx+1 < len(lineage) { - err = cli.ShowCommandHelp(ctx, lineage[targetCmdIdx+1], lineage[targetCmdIdx].Name) + if lineage[targetCmdIdx+1].Command != nil { + err = cli.ShowCommandHelp(lineage[targetCmdIdx+1], lineage[targetCmdIdx].Command.Name) } else { err = cli.ShowAppHelp(c) } - _, _ = fmt.Fprintf(c.Root().Writer, ` + _, _ = fmt.Fprintf(c.App.Writer, ` DEFAULT CONFIGURATION: AppPath: %s WorkPath: %s @@ -77,25 +77,25 @@ func appGlobalFlags() []cli.Flag { } } -func prepareSubcommandWithConfig(command *cli.Command, globalFlags func() []cli.Flag) { - command.Flags = append(globalFlags(), command.Flags...) +func prepareSubcommandWithConfig(command *cli.Command, globalFlags []cli.Flag) { + command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...) command.Action = prepareWorkPathAndCustomConf(command.Action) command.HideHelp = true if command.Name != "help" { - command.Commands = append(command.Commands, cmdHelp()) + command.Subcommands = append(command.Subcommands, cmdHelp()) } - for i := range command.Commands { - prepareSubcommandWithConfig(command.Commands[i], globalFlags) + for i := range command.Subcommands { + prepareSubcommandWithConfig(command.Subcommands[i], globalFlags) } } // prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config // It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times -func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(_ context.Context, _ *cli.Command) error { - return func(ctx context.Context, cli *cli.Command) error { +func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) error { + return func(ctx *cli.Context) error { var args setting.ArgWorkPathAndCustomConf // from children to parent, check the global flags - for _, curCtx := range cli.Lineage() { + for _, curCtx := range ctx.Lineage() { if curCtx.IsSet("work-path") && args.WorkPath == "" { args.WorkPath = curCtx.String("work-path") } @@ -107,24 +107,24 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(_ context.Context, } } setting.InitWorkPathAndCommonConfig(os.Getenv, args) - if cli.Bool("help") || action == nil { + if ctx.Bool("help") || action == nil { // the default behavior of "urfave/cli": "nil action" means "show help" - return cmdHelp().Action(ctx, cli) + return cmdHelp().Action(ctx) } - return action(ctx, cli) + return action(ctx) } } -func NewMainApp(version, versionExtra string) *cli.Command { +func NewMainApp(version, versionExtra string) *cli.App { path, err := os.Executable() if err != nil { panic(err) } executable := filepath.Base(path) - subCmdsStandalone := make([]*cli.Command, 0, 10) - subCmdWithConfig := make([]*cli.Command, 0, 10) - globalFlags := func() []cli.Flag { return []cli.Flag{} } + var subCmdsStandalone []*cli.Command = make([]*cli.Command, 0, 10) + var subCmdWithConfig []*cli.Command = make([]*cli.Command, 0, 10) + var globalFlags []cli.Flag = make([]cli.Flag, 0, 10) // // If the executable is forgejo-cli, provide a Forgejo specific CLI @@ -133,16 +133,14 @@ func NewMainApp(version, versionExtra string) *cli.Command { if executable == "forgejo-cli" { subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdActions(context.Background())) subCmdWithConfig = append(subCmdWithConfig, forgejo.CmdF3(context.Background())) - globalFlags = func() []cli.Flag { - return []cli.Flag{ - &cli.BoolFlag{ - Name: "quiet", - }, - &cli.BoolFlag{ - Name: "verbose", - }, - } - } + globalFlags = append(globalFlags, []cli.Flag{ + &cli.BoolFlag{ + Name: "quiet", + }, + &cli.BoolFlag{ + Name: "verbose", + }, + }...) } else { // // Otherwise provide a Gitea compatible CLI which includes Forgejo @@ -151,54 +149,55 @@ func NewMainApp(version, versionExtra string) *cli.Command { // binary and rename it to forgejo if they want. // subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdForgejo(context.Background())) - subCmdWithConfig = append(subCmdWithConfig, cmdActions()) + subCmdWithConfig = append(subCmdWithConfig, CmdActions) } return innerNewMainApp(version, versionExtra, subCmdsStandalone, subCmdWithConfig, globalFlags) } -func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs func() []cli.Flag) *cli.Command { - app := &cli.Command{} - app.Name = "forgejo" +func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs []cli.Flag) *cli.App { + app := cli.NewApp() + app.HelpName = "forgejo" + app.Name = "Forgejo" app.Usage = "Beyond coding. We forge." app.Description = `By default, forgejo will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".` app.Version = version + versionExtra - app.EnableShellCompletion = true + app.EnableBashCompletion = true // these sub-commands need to use config file subCmdWithConfig := []*cli.Command{ cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config" - cmdWeb(), - cmdServ(), - cmdHook(), - cmdKeys(), - cmdDump(), - cmdAdmin(), - cmdMigrate(), - cmdDoctor(), - cmdManager(), - cmdEmbedded(), - cmdMigrateStorage(), - cmdDumpRepository(), - cmdRestoreRepository(), + CmdWeb, + CmdServ, + CmdHook, + CmdKeys, + CmdDump, + CmdAdmin, + CmdMigrate, + CmdDoctor, + CmdManager, + CmdEmbedded, + CmdMigrateStorage, + CmdDumpRepository, + CmdRestoreRepository, } subCmdWithConfig = append(subCmdWithConfig, subCmdWithConfigArgs...) // these sub-commands do not need the config file, and they do not depend on any path or environment variable. subCmdStandalone := []*cli.Command{ - cmdCert(), - cmdGenerate(), + CmdCert, + CmdGenerate, + CmdDocs, } subCmdStandalone = append(subCmdStandalone, subCmdsStandaloneArgs...) - app.DefaultCommand = cmdWeb().Name + app.DefaultCommand = CmdWeb.Name - globalFlags := func() []cli.Flag { - return append(appGlobalFlags(), globalFlagsArgs()...) - } + globalFlags := appGlobalFlags() + globalFlags = append(globalFlags, globalFlagsArgs...) app.Flags = append(app.Flags, cli.VersionFlag) - app.Flags = append(app.Flags, globalFlags()...) + app.Flags = append(app.Flags, globalFlags...) app.HideHelp = true // use our own help action to show helps (with more information like default config) app.Before = PrepareConsoleLoggerLevel(log.INFO) for i := range subCmdWithConfig { @@ -207,12 +206,11 @@ func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmd app.Commands = append(app.Commands, subCmdWithConfig...) app.Commands = append(app.Commands, subCmdStandalone...) - setting.InitGiteaEnvVars() return app } -func RunMainApp(app *cli.Command, args ...string) error { - err := app.Run(context.Background(), args) +func RunMainApp(app *cli.App, args ...string) error { + err := app.Run(args) if err == nil { return nil } @@ -221,7 +219,7 @@ func RunMainApp(app *cli.Command, args ...string) error { cli.OsExiter(1) return err } - _, _ = fmt.Fprintf(app.Root().ErrWriter, "Command error: %v\n", err) + _, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err) cli.OsExiter(1) return err } diff --git a/cmd/main_test.go b/cmd/main_test.go index 737150c62f..a916c61f85 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -4,21 +4,19 @@ package cmd import ( - "context" - "errors" "fmt" "io" + "os" "path/filepath" "strings" "testing" - "forgejo.org/models/unittest" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) func TestMain(m *testing.M) { @@ -29,10 +27,10 @@ func makePathOutput(workPath, customPath, customConf string) string { return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf) } -func newTestApp(testCmdAction func(_ context.Context, ctx *cli.Command) error) *cli.Command { +func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App { app := NewMainApp("version", "version-extra") testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction} - prepareSubcommandWithConfig(testCmd, appGlobalFlags) + prepareSubcommandWithConfig(testCmd, appGlobalFlags()) app.Commands = append(app.Commands, testCmd) app.DefaultCommand = testCmd.Name return app @@ -44,7 +42,7 @@ type runResult struct { ExitCode int } -func runTestApp(app *cli.Command, args ...string) (runResult, error) { +func runTestApp(app *cli.App, args ...string) (runResult, error) { outBuf := new(strings.Builder) errBuf := new(strings.Builder) app.Writer = outBuf @@ -67,6 +65,7 @@ func TestCliCmd(t *testing.T) { defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini") cli.CommandHelpTemplate = "(command help template)" + cli.AppHelpTemplate = "(app help template)" cli.SubcommandHelpTemplate = "(subcommand help template)" cases := []struct { @@ -110,55 +109,70 @@ func TestCliCmd(t *testing.T) { }, } - for _, c := range cases { - t.Run(c.cmd, func(t *testing.T) { - defer test.MockProtect(&setting.AppWorkPath)() - defer test.MockProtect(&setting.CustomPath)() - defer test.MockProtect(&setting.CustomConf)() - - app := newTestApp(func(_ context.Context, ctx *cli.Command) error { - _, _ = fmt.Fprint(ctx.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) - return nil - }) - - for k, v := range c.env { - t.Setenv(k, v) + app := newTestApp(func(ctx *cli.Context) error { + _, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) + return nil + }) + var envBackup []string + for _, s := range os.Environ() { + if strings.HasPrefix(s, "GITEA_") && strings.Contains(s, "=") { + envBackup = append(envBackup, s) + } + } + clearGiteaEnv := func() { + for _, s := range os.Environ() { + if strings.HasPrefix(s, "GITEA_") { + _ = os.Unsetenv(s) } - args := strings.Split(c.cmd, " ") // for test only, "split" is good enough - r, err := runTestApp(app, args...) - require.NoError(t, err, c.cmd) - assert.NotEmpty(t, c.exp, c.cmd) - assert.Contains(t, r.Stdout, c.exp, c.cmd+"\n"+r.Stdout) - }) + } + } + defer func() { + clearGiteaEnv() + for _, s := range envBackup { + k, v, _ := strings.Cut(s, "=") + _ = os.Setenv(k, v) + } + }() + + for _, c := range cases { + clearGiteaEnv() + for k, v := range c.env { + _ = os.Setenv(k, v) + } + args := strings.Split(c.cmd, " ") // for test only, "split" is good enough + r, err := runTestApp(app, args...) + assert.NoError(t, err, c.cmd) + assert.NotEmpty(t, c.exp, c.cmd) + assert.Contains(t, r.Stdout, c.exp, c.cmd) } } func TestCliCmdError(t *testing.T) { - app := newTestApp(func(_ context.Context, ctx *cli.Command) error { return errors.New("normal error") }) + app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") }) r, err := runTestApp(app, "./gitea", "test-cmd") - require.Error(t, err) + assert.Error(t, err) assert.Equal(t, 1, r.ExitCode) - assert.Empty(t, r.Stdout) + assert.Equal(t, "", r.Stdout) assert.Equal(t, "Command error: normal error\n", r.Stderr) - app = newTestApp(func(_ context.Context, ctx *cli.Command) error { return cli.Exit("exit error", 2) }) + app = newTestApp(func(ctx *cli.Context) error { return cli.Exit("exit error", 2) }) r, err = runTestApp(app, "./gitea", "test-cmd") - require.Error(t, err) + assert.Error(t, err) assert.Equal(t, 2, r.ExitCode) - assert.Empty(t, r.Stdout) + assert.Equal(t, "", r.Stdout) assert.Equal(t, "exit error\n", r.Stderr) - app = newTestApp(func(_ context.Context, ctx *cli.Command) error { return nil }) + app = newTestApp(func(ctx *cli.Context) error { return nil }) r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such") - require.Error(t, err) + assert.Error(t, err) assert.Equal(t, 1, r.ExitCode) - assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr) - assert.Empty(t, r.Stdout) + assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout) + assert.Equal(t, "", r.Stderr) // the cli package's strange behavior, the error message is not in stderr .... - app = newTestApp(func(_ context.Context, ctx *cli.Command) error { return nil }) + app = newTestApp(func(ctx *cli.Context) error { return nil }) r, err = runTestApp(app, "./gitea", "test-cmd") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called - assert.Empty(t, r.Stdout) - assert.Empty(t, r.Stderr) + assert.Equal(t, "", r.Stdout) + assert.Equal(t, "", r.Stderr) } diff --git a/cmd/manager.go b/cmd/manager.go index 029329b44e..b74771e53d 100644 --- a/cmd/manager.go +++ b/cmd/manager.go @@ -4,34 +4,30 @@ package cmd import ( - "context" "os" "time" - "forgejo.org/modules/private" + "code.gitea.io/gitea/modules/private" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -// CmdManager represents the manager command -func cmdManager() *cli.Command { - return &cli.Command{ +var ( + // CmdManager represents the manager command + CmdManager = &cli.Command{ Name: "manager", Usage: "Manage the running forgejo process", Description: "This is a command for managing the running forgejo process", - Commands: []*cli.Command{ - subcmdShutdown(), - subcmdRestart(), - subcmdReloadTemplates(), - subcmdFlushQueues(), - subcmdLogging(), - subCmdProcesses(), + Subcommands: []*cli.Command{ + subcmdShutdown, + subcmdRestart, + subcmdReloadTemplates, + subcmdFlushQueues, + subcmdLogging, + subCmdProcesses, }, } -} - -func subcmdShutdown() *cli.Command { - return &cli.Command{ + subcmdShutdown = &cli.Command{ Name: "shutdown", Usage: "Gracefully shutdown the running process", Flags: []cli.Flag{ @@ -41,10 +37,7 @@ func subcmdShutdown() *cli.Command { }, Action: runShutdown, } -} - -func subcmdRestart() *cli.Command { - return &cli.Command{ + subcmdRestart = &cli.Command{ Name: "restart", Usage: "Gracefully restart the running process - (not implemented for windows servers)", Flags: []cli.Flag{ @@ -54,10 +47,7 @@ func subcmdRestart() *cli.Command { }, Action: runRestart, } -} - -func subcmdReloadTemplates() *cli.Command { - return &cli.Command{ + subcmdReloadTemplates = &cli.Command{ Name: "reload-templates", Usage: "Reload template files in the running process", Flags: []cli.Flag{ @@ -67,10 +57,7 @@ func subcmdReloadTemplates() *cli.Command { }, Action: runReloadTemplates, } -} - -func subcmdFlushQueues() *cli.Command { - return &cli.Command{ + subcmdFlushQueues = &cli.Command{ Name: "flush-queues", Usage: "Flush queues in the running process", Action: runFlushQueues, @@ -89,10 +76,7 @@ func subcmdFlushQueues() *cli.Command { }, }, } -} - -func subCmdProcesses() *cli.Command { - return &cli.Command{ + subCmdProcesses = &cli.Command{ Name: "processes", Usage: "Display running processes within the current process", Action: runProcesses, @@ -122,49 +106,49 @@ func subCmdProcesses() *cli.Command { }, }, } -} +) -func runShutdown(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runShutdown(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) extra := private.Shutdown(ctx) return handleCliResponseExtra(extra) } -func runRestart(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runRestart(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) extra := private.Restart(ctx) return handleCliResponseExtra(extra) } -func runReloadTemplates(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runReloadTemplates(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) extra := private.ReloadTemplates(ctx) return handleCliResponseExtra(extra) } -func runFlushQueues(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runFlushQueues(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking")) return handleCliResponseExtra(extra) } -func runProcesses(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runProcesses(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) extra := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel")) return handleCliResponseExtra(extra) } diff --git a/cmd/manager_logging.go b/cmd/manager_logging.go index c543afe872..6049b00d5e 100644 --- a/cmd/manager_logging.go +++ b/cmd/manager_logging.go @@ -4,19 +4,18 @@ package cmd import ( - "context" "errors" "fmt" "os" - "forgejo.org/modules/log" - "forgejo.org/modules/private" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) -func defaultLoggingFlags() []cli.Flag { - return []cli.Flag{ +var ( + defaultLoggingFlags = []cli.Flag{ &cli.StringFlag{ Name: "logger", Usage: `Logger name - will default to "default"`, @@ -57,13 +56,11 @@ func defaultLoggingFlags() []cli.Flag { Name: "debug", }, } -} -func subcmdLogging() *cli.Command { - return &cli.Command{ + subcmdLogging = &cli.Command{ Name: "logging", Usage: "Adjust logging commands", - Commands: []*cli.Command{ + Subcommands: []*cli.Command{ { Name: "pause", Usage: "Pause logging (Forgejo will buffer logs up to a certain point and will drop them after that point)", @@ -107,11 +104,11 @@ func subcmdLogging() *cli.Command { }, { Name: "add", Usage: "Add a logger", - Commands: []*cli.Command{ + Subcommands: []*cli.Command{ { Name: "file", Usage: "Add a file logger", - Flags: append(defaultLoggingFlags(), []cli.Flag{ + Flags: append(defaultLoggingFlags, []cli.Flag{ &cli.StringFlag{ Name: "filename", Aliases: []string{"f"}, @@ -155,7 +152,7 @@ func subcmdLogging() *cli.Command { }, { Name: "conn", Usage: "Add a net conn logger", - Flags: append(defaultLoggingFlags(), []cli.Flag{ + Flags: append(defaultLoggingFlags, []cli.Flag{ &cli.BoolFlag{ Name: "reconnect-on-message", Aliases: []string{"R"}, @@ -196,13 +193,13 @@ func subcmdLogging() *cli.Command { }, }, } -} +) -func runRemoveLogger(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runRemoveLogger(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) logger := c.String("logger") if len(logger) == 0 { logger = log.DEFAULT @@ -213,11 +210,11 @@ func runRemoveLogger(ctx context.Context, c *cli.Command) error { return handleCliResponseExtra(extra) } -func runAddConnLogger(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runAddConnLogger(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) vals := map[string]any{} mode := "conn" vals["net"] = "tcp" @@ -240,14 +237,14 @@ func runAddConnLogger(ctx context.Context, c *cli.Command) error { if c.IsSet("reconnect-on-message") { vals["reconnectOnMsg"] = c.Bool("reconnect-on-message") } - return commonAddLogger(ctx, c, mode, vals) + return commonAddLogger(c, mode, vals) } -func runAddFileLogger(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runAddFileLogger(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) vals := map[string]any{} mode := "file" if c.IsSet("filename") { @@ -273,10 +270,10 @@ func runAddFileLogger(ctx context.Context, c *cli.Command) error { if c.IsSet("compression-level") { vals["compressionLevel"] = c.Int("compression-level") } - return commonAddLogger(ctx, c, mode, vals) + return commonAddLogger(c, mode, vals) } -func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[string]any) error { +func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error { if len(c.String("level")) > 0 { vals["level"] = log.LevelFromString(c.String("level")).String() } @@ -303,47 +300,47 @@ func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[ if c.IsSet("writer") { writer = c.String("writer") } - ctx, cancel := installSignals(ctx) + ctx, cancel := installSignals() defer cancel() extra := private.AddLogger(ctx, logger, writer, mode, vals) return handleCliResponseExtra(extra) } -func runPauseLogging(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runPauseLogging(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) userMsg := private.PauseLogging(ctx) _, _ = fmt.Fprintln(os.Stdout, userMsg) return nil } -func runResumeLogging(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runResumeLogging(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) userMsg := private.ResumeLogging(ctx) _, _ = fmt.Fprintln(os.Stdout, userMsg) return nil } -func runReleaseReopenLogging(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runReleaseReopenLogging(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) userMsg := private.ReleaseReopenLogging(ctx) _, _ = fmt.Fprintln(os.Stdout, userMsg) return nil } -func runSetLogSQL(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runSetLogSQL(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() - setup(ctx, c.Bool("debug"), false) + setup(ctx, c.Bool("debug")) extra := private.SetLogSQL(ctx, !c.Bool("off")) return handleCliResponseExtra(extra) diff --git a/cmd/migrate.go b/cmd/migrate.go index 5a485d17f9..4e4dd45af3 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -6,26 +6,24 @@ package cmd import ( "context" - "forgejo.org/models/db" - "forgejo.org/models/migrations" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/migrations" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // CmdMigrate represents the available migrate sub-command. -func cmdMigrate() *cli.Command { - return &cli.Command{ - Name: "migrate", - Usage: "Migrate the database", - Description: "This is a command for migrating the database, so that you can run 'forgejo admin user create' before starting the server.", - Action: runMigrate, - } +var CmdMigrate = &cli.Command{ + Name: "migrate", + Usage: "Migrate the database", + Description: "This is a command for migrating the database, so that you can run gitea admin create-user before starting the server.", + Action: runMigrate, } -func runMigrate(stdCtx context.Context, ctx *cli.Command) error { - stdCtx, cancel := installSignals(stdCtx) +func runMigrate(ctx *cli.Context) error { + stdCtx, cancel := installSignals() defer cancel() if err := initDB(stdCtx); err != nil { @@ -38,13 +36,7 @@ func runMigrate(stdCtx context.Context, ctx *cli.Command) error { log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) - if err := db.InitEngineWithMigration(context.Background(), func(dbEngine db.Engine) error { - masterEngine, err := db.GetMasterEngine(dbEngine) - if err != nil { - return err - } - return migrations.Migrate(masterEngine) - }); err != nil { + if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { log.Fatal("Failed to initialize ORM engine: %v", err) return err } diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index d741a883e3..3a69b555e0 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -10,93 +10,90 @@ import ( "io/fs" "strings" - actions_model "forgejo.org/models/actions" - "forgejo.org/models/db" - git_model "forgejo.org/models/git" - "forgejo.org/models/migrations" - packages_model "forgejo.org/models/packages" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/log" - packages_module "forgejo.org/modules/packages" - "forgejo.org/modules/setting" - "forgejo.org/modules/storage" + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + "code.gitea.io/gitea/models/migrations" + packages_model "code.gitea.io/gitea/models/packages" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + packages_module "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" - "github.com/urfave/cli/v3" - "xorm.io/xorm" + "github.com/urfave/cli/v2" ) // CmdMigrateStorage represents the available migrate storage sub-command. -func cmdMigrateStorage() *cli.Command { - return &cli.Command{ - Name: "migrate-storage", - Usage: "Migrate the storage", - Description: "Copies stored files from storage configured in app.ini to parameter-configured storage", - Action: runMigrateStorage, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "type", - Aliases: []string{"t"}, - Value: "", - Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'", - }, - &cli.StringFlag{ - Name: "storage", - Aliases: []string{"s"}, - Value: "", - Usage: "New storage type: local (default) or minio", - }, - &cli.StringFlag{ - Name: "path", - Aliases: []string{"p"}, - Value: "", - Usage: "New storage placement if store is local (leave blank for default)", - }, - &cli.StringFlag{ - Name: "minio-endpoint", - Value: "", - Usage: "Minio storage endpoint", - }, - &cli.StringFlag{ - Name: "minio-access-key-id", - Value: "", - Usage: "Minio storage accessKeyID", - }, - &cli.StringFlag{ - Name: "minio-secret-access-key", - Value: "", - Usage: "Minio storage secretAccessKey", - }, - &cli.StringFlag{ - Name: "minio-bucket", - Value: "", - Usage: "Minio storage bucket", - }, - &cli.StringFlag{ - Name: "minio-location", - Value: "", - Usage: "Minio storage location to create bucket", - }, - &cli.StringFlag{ - Name: "minio-base-path", - Value: "", - Usage: "Minio storage base path on the bucket", - }, - &cli.BoolFlag{ - Name: "minio-use-ssl", - Usage: "Enable SSL for minio", - }, - &cli.BoolFlag{ - Name: "minio-insecure-skip-verify", - Usage: "Skip SSL verification", - }, - &cli.StringFlag{ - Name: "minio-checksum-algorithm", - Value: "", - Usage: "Minio checksum algorithm (default/md5)", - }, +var CmdMigrateStorage = &cli.Command{ + Name: "migrate-storage", + Usage: "Migrate the storage", + Description: "Copies stored files from storage configured in app.ini to parameter-configured storage", + Action: runMigrateStorage, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "type", + Aliases: []string{"t"}, + Value: "", + Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'", }, - } + &cli.StringFlag{ + Name: "storage", + Aliases: []string{"s"}, + Value: "", + Usage: "New storage type: local (default) or minio", + }, + &cli.StringFlag{ + Name: "path", + Aliases: []string{"p"}, + Value: "", + Usage: "New storage placement if store is local (leave blank for default)", + }, + &cli.StringFlag{ + Name: "minio-endpoint", + Value: "", + Usage: "Minio storage endpoint", + }, + &cli.StringFlag{ + Name: "minio-access-key-id", + Value: "", + Usage: "Minio storage accessKeyID", + }, + &cli.StringFlag{ + Name: "minio-secret-access-key", + Value: "", + Usage: "Minio storage secretAccessKey", + }, + &cli.StringFlag{ + Name: "minio-bucket", + Value: "", + Usage: "Minio storage bucket", + }, + &cli.StringFlag{ + Name: "minio-location", + Value: "", + Usage: "Minio storage location to create bucket", + }, + &cli.StringFlag{ + Name: "minio-base-path", + Value: "", + Usage: "Minio storage base path on the bucket", + }, + &cli.BoolFlag{ + Name: "minio-use-ssl", + Usage: "Enable SSL for minio", + }, + &cli.BoolFlag{ + Name: "minio-insecure-skip-verify", + Usage: "Skip SSL verification", + }, + &cli.StringFlag{ + Name: "minio-checksum-algorithm", + Value: "", + Usage: "Minio checksum algorithm (default/md5)", + }, + }, } func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error { @@ -184,8 +181,8 @@ func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStora }) } -func runMigrateStorage(stdCtx context.Context, ctx *cli.Command) error { - stdCtx, cancel := installSignals(stdCtx) +func runMigrateStorage(ctx *cli.Context) error { + stdCtx, cancel := installSignals() defer cancel() if err := initDB(stdCtx); err != nil { @@ -198,9 +195,7 @@ func runMigrateStorage(stdCtx context.Context, ctx *cli.Command) error { log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) - if err := db.InitEngineWithMigration(context.Background(), func(e db.Engine) error { - return migrations.Migrate(e.(*xorm.Engine)) - }); err != nil { + if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { log.Fatal("Failed to initialize ORM engine: %v", err) return err } diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go index b75eb3cfa0..fa7067f97b 100644 --- a/cmd/migrate_storage_test.go +++ b/cmd/migrate_storage_test.go @@ -4,21 +4,22 @@ package cmd import ( + "context" "io" "os" "strings" "testing" - "forgejo.org/models/actions" - "forgejo.org/models/db" - "forgejo.org/models/packages" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - packages_module "forgejo.org/modules/packages" - "forgejo.org/modules/setting" - "forgejo.org/modules/storage" - "forgejo.org/modules/test" - packages_service "forgejo.org/services/packages" + "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/packages" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + packages_module "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/test" + packages_service "code.gitea.io/gitea/services/packages" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -30,7 +31,7 @@ func createLocalStorage(t *testing.T) (storage.ObjectStorage, string) { p := t.TempDir() storage, err := storage.NewLocalStorage( - t.Context(), + context.Background(), &setting.Storage{ Path: p, }) @@ -40,13 +41,13 @@ func createLocalStorage(t *testing.T) (storage.ObjectStorage, string) { } func TestMigratePackages(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) creator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) content := "package main\n\nfunc main() {\nfmt.Println(\"hi\")\n}\n" buf, err := packages_module.CreateHashedBufferFromReaderWithSize(strings.NewReader(content), 1024) - require.NoError(t, err) + assert.NoError(t, err) defer buf.Close() v, f, err := packages_service.CreatePackageAndAddFile(db.DefaultContext, &packages_service.PackageCreationInfo{ @@ -67,30 +68,30 @@ func TestMigratePackages(t *testing.T) { Data: buf, IsLead: true, }) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, v) assert.NotNil(t, f) - ctx := t.Context() + ctx := context.Background() dstStorage, p := createLocalStorage(t) err = migratePackages(ctx, dstStorage) - require.NoError(t, err) + assert.NoError(t, err) entries, err := os.ReadDir(p) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, entries, 2) - assert.Equal(t, "01", entries[0].Name()) - assert.Equal(t, "tmp", entries[1].Name()) + assert.EqualValues(t, "01", entries[0].Name()) + assert.EqualValues(t, "tmp", entries[1].Name()) } func TestMigrateActionsArtifacts(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) srcStorage, _ := createLocalStorage(t) defer test.MockVariableValue(&storage.ActionsArtifacts, srcStorage)() - id := int64(42) + id := int64(0) addArtifact := func(storagePath string, status actions.ArtifactStatus) { id++ @@ -117,17 +118,17 @@ func TestMigrateActionsArtifacts(t *testing.T) { dstStorage, _ := createLocalStorage(t) - require.NoError(t, migrateActionsArtifacts(db.DefaultContext, dstStorage)) + assert.NoError(t, migrateActionsArtifacts(db.DefaultContext, dstStorage)) object, err := dstStorage.Open(exists) - require.NoError(t, err) + assert.NoError(t, err) buf, err := io.ReadAll(object) require.NoError(t, err) assert.Equal(t, exists, string(buf)) _, err = dstStorage.Stat(expired) - require.Error(t, err) + assert.Error(t, err) _, err = dstStorage.Stat(notFound) - require.Error(t, err) + assert.Error(t, err) } diff --git a/cmd/restore_repo.go b/cmd/restore_repo.go index 0e9f0bb50a..37b32aa304 100644 --- a/cmd/restore_repo.go +++ b/cmd/restore_repo.go @@ -4,55 +4,52 @@ package cmd import ( - "context" "strings" - "forgejo.org/modules/private" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // CmdRestoreRepository represents the available restore a repository sub-command. -func cmdRestoreRepository() *cli.Command { - return &cli.Command{ - Name: "restore-repo", - Usage: "Restore the repository from disk", - Description: "This is a command for restoring the repository data.", - Action: runRestoreRepository, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "repo_dir", - Aliases: []string{"r"}, - Value: "./data", - Usage: "Repository dir path to restore from", - }, - &cli.StringFlag{ - Name: "owner_name", - Value: "", - Usage: "Restore destination owner name", - }, - &cli.StringFlag{ - Name: "repo_name", - Value: "", - Usage: "Restore destination repository name", - }, - &cli.StringFlag{ - Name: "units", - Value: "", - Usage: `Which items will be restored, one or more units should be separated as comma. -wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, - }, - &cli.BoolFlag{ - Name: "validation", - Usage: "Sanity check the content of the files before trying to load them", - }, +var CmdRestoreRepository = &cli.Command{ + Name: "restore-repo", + Usage: "Restore the repository from disk", + Description: "This is a command for restoring the repository data.", + Action: runRestoreRepository, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo_dir", + Aliases: []string{"r"}, + Value: "./data", + Usage: "Repository dir path to restore from", }, - } + &cli.StringFlag{ + Name: "owner_name", + Value: "", + Usage: "Restore destination owner name", + }, + &cli.StringFlag{ + Name: "repo_name", + Value: "", + Usage: "Restore destination repository name", + }, + &cli.StringFlag{ + Name: "units", + Value: "", + Usage: `Which items will be restored, one or more units should be separated as comma. +wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, + }, + &cli.BoolFlag{ + Name: "validation", + Usage: "Sanity check the content of the files before trying to load them", + }, + }, } -func runRestoreRepository(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runRestoreRepository(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() setting.MustInstalled() diff --git a/cmd/serv.go b/cmd/serv.go index 2e34f2e24c..2aa720bebc 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -18,22 +18,22 @@ import ( "time" "unicode" - asymkey_model "forgejo.org/models/asymkey" - git_model "forgejo.org/models/git" - "forgejo.org/models/perm" - "forgejo.org/modules/git" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/pprof" - "forgejo.org/modules/private" - "forgejo.org/modules/process" - repo_module "forgejo.org/modules/repository" - "forgejo.org/modules/setting" - "forgejo.org/services/lfs" + asymkey_model "code.gitea.io/gitea/models/asymkey" + git_model "code.gitea.io/gitea/models/git" + "code.gitea.io/gitea/models/perm" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/pprof" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/process" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/lfs" "github.com/golang-jwt/jwt/v5" "github.com/kballard/go-shellquote" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) const ( @@ -42,40 +42,35 @@ const ( ) // CmdServ represents the available serv sub-command. -func cmdServ() *cli.Command { - return &cli.Command{ - Name: "serv", - Usage: "(internal) Should only be called by SSH shell", - Description: "Serv provides access auth for repositories", - Before: PrepareConsoleLoggerLevel(log.FATAL), - Action: runServ, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "enable-pprof", - }, - &cli.BoolFlag{ - Name: "debug", - }, +var CmdServ = &cli.Command{ + Name: "serv", + Usage: "(internal) Should only be called by SSH shell", + Description: "Serv provides access auth for repositories", + Before: PrepareConsoleLoggerLevel(log.FATAL), + Action: runServ, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "enable-pprof", }, - } + &cli.BoolFlag{ + Name: "debug", + }, + }, } -func setup(ctx context.Context, debug, gitNeeded bool) { +func setup(ctx context.Context, debug bool) { if debug { setupConsoleLogger(log.TRACE, false, os.Stderr) } else { setupConsoleLogger(log.FATAL, false, os.Stderr) } setting.MustInstalled() - // Sanity check to ensure path is not relative, see: https://github.com/go-gitea/gitea/pull/19317 if _, err := os.Stat(setting.RepoRootPath); err != nil { _ = fail(ctx, "Unable to access repository path", "Unable to access repository path %q, err: %v", setting.RepoRootPath, err) return } - if gitNeeded { - if err := git.InitSimple(context.Background()); err != nil { - _ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err) - } + if err := git.InitSimple(context.Background()); err != nil { + _ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err) } } @@ -85,7 +80,7 @@ var ( "git-upload-archive": perm.AccessModeRead, "git-receive-pack": perm.AccessModeWrite, lfsAuthenticateVerb: perm.AccessModeNone, - gitAnnexShellVerb: perm.AccessModeRead, // annex permissions are enforced by GIT_ANNEX_SHELL_READONLY, rather than the Gitea API, but read permissions are required at a minimum + gitAnnexShellVerb: perm.AccessModeNone, // annex permissions are enforced by GIT_ANNEX_SHELL_READONLY, rather than the Gitea API } alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) ) @@ -135,12 +130,12 @@ func handleCliResponseExtra(extra private.ResponseExtra) error { return nil } -func runServ(ctx context.Context, c *cli.Command) error { - ctx, cancel := installSignals(ctx) +func runServ(c *cli.Context) error { + ctx, cancel := installSignals() defer cancel() // FIXME: This needs to internationalised - setup(ctx, c.Bool("debug"), true) + setup(ctx, c.Bool("debug")) if setting.SSH.Disabled { fmt.Println("Forgejo: SSH has been disabled") @@ -154,12 +149,6 @@ func runServ(ctx context.Context, c *cli.Command) error { return nil } - defer func() { - if err := recover(); err != nil { - _ = fail(ctx, "Internal Server Error", "Panic: %v\n%s", err, log.Stack(2)) - } - }() - keys := strings.Split(c.Args().First(), "-") if len(keys) != 2 || keys[0] != "key" { return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args().First()) @@ -198,7 +187,7 @@ func runServ(ctx context.Context, c *cli.Command) error { if git.CheckGitVersionAtLeast("2.29") == nil { // for AGit Flow if cmd == "ssh_info" { - fmt.Print(`{"type":"agit","version":1}`) + fmt.Print(`{"type":"gitea","version":1}`) return nil } } @@ -206,7 +195,11 @@ func runServ(ctx context.Context, c *cli.Command) error { } verb := words[0] - repoPath := strings.TrimPrefix(words[1], "/") + repoPath := words[1] + + if repoPath[0] == '/' { + repoPath = repoPath[1:] + } var lfsVerb string if verb == lfsAuthenticateVerb { @@ -294,12 +287,11 @@ func runServ(ctx context.Context, c *cli.Command) error { } if verb == lfsAuthenticateVerb { - switch lfsVerb { - case "upload": + if lfsVerb == "upload" { requestedMode = perm.AccessModeWrite - case "download": + } else if lfsVerb == "download" { requestedMode = perm.AccessModeRead - default: + } else { return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb) } } @@ -345,8 +337,9 @@ func runServ(ctx context.Context, c *cli.Command) error { return nil } - gitBinVerb, err := exec.LookPath(verb) - if err != nil { + gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin + gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack + if _, err := os.Stat(gitBinVerb); err != nil { // if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git // ps: Windows only has "git.exe" in the bin path, so Windows always uses this way // ps: git-annex-shell and other extensions may not necessarily be in gitBinPath, diff --git a/cmd/web.go b/cmd/web.go index 27a70008f0..661e6d158e 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -13,64 +13,61 @@ import ( "path/filepath" "strconv" "strings" - "time" _ "net/http/pprof" // Used for debugging if enabled and a web server is running - "forgejo.org/modules/container" - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/process" - "forgejo.org/modules/public" - "forgejo.org/modules/setting" - "forgejo.org/routers" - "forgejo.org/routers/install" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/public" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/routers" + "code.gitea.io/gitea/routers/install" "github.com/felixge/fgprof" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // PIDFile could be set from build tag var PIDFile = "/run/gitea.pid" // CmdWeb represents the available web sub-command. -func cmdWeb() *cli.Command { - return &cli.Command{ - Name: "web", - Usage: "Start the Forgejo web server", - Description: `The Forgejo web server is the only thing you need to run, +var CmdWeb = &cli.Command{ + Name: "web", + Usage: "Start the Forgejo web server", + Description: `The Forgejo web server is the only thing you need to run, and it takes care of all the other things for you`, - Before: PrepareConsoleLoggerLevel(log.INFO), - Action: runWeb, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "port", - Aliases: []string{"p"}, - Value: "3000", - Usage: "Temporary port number to prevent conflict", - }, - &cli.StringFlag{ - Name: "install-port", - Value: "3000", - Usage: "Temporary port number to run the install page on to prevent conflict", - }, - &cli.StringFlag{ - Name: "pid", - Aliases: []string{"P"}, - Value: PIDFile, - Usage: "Custom pid file path", - }, - &cli.BoolFlag{ - Name: "quiet", - Aliases: []string{"q"}, - Usage: "Only display Fatal logging errors until logging is set-up", - }, - &cli.BoolFlag{ - Name: "verbose", - Usage: "Set initial logging to TRACE level until logging is properly set-up", - }, + Before: PrepareConsoleLoggerLevel(log.INFO), + Action: runWeb, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "port", + Aliases: []string{"p"}, + Value: "3000", + Usage: "Temporary port number to prevent conflict", }, - } + &cli.StringFlag{ + Name: "install-port", + Value: "3000", + Usage: "Temporary port number to run the install page on to prevent conflict", + }, + &cli.StringFlag{ + Name: "pid", + Aliases: []string{"P"}, + Value: PIDFile, + Usage: "Custom pid file path", + }, + &cli.BoolFlag{ + Name: "quiet", + Aliases: []string{"q"}, + Usage: "Only display Fatal logging errors until logging is set-up", + }, + &cli.BoolFlag{ + Name: "verbose", + Usage: "Set initial logging to TRACE level until logging is properly set-up", + }, + }, } func runHTTPRedirector() { @@ -119,19 +116,9 @@ func showWebStartupMessage(msg string) { log.Info("* CustomPath: %s", setting.CustomPath) log.Info("* ConfigFile: %s", setting.CustomConf) log.Info("%s", msg) // show startup message - - if setting.CORSConfig.Enabled { - log.Info("CORS Service Enabled") - } - if setting.DefaultUILocation != time.Local { - log.Info("Default UI Location is %v", setting.DefaultUILocation.String()) - } - if setting.MailService != nil { - log.Info("Mail Service Enabled: RegisterEmailConfirm=%v, Service.EnableNotifyMail=%v", setting.Service.RegisterEmailConfirm, setting.Service.EnableNotifyMail) - } } -func serveInstall(_ context.Context, ctx *cli.Command) error { +func serveInstall(ctx *cli.Context) error { showWebStartupMessage("Prepare to run install page") routers.InitWebInstallPage(graceful.GetManager().HammerContext()) @@ -164,7 +151,7 @@ func serveInstall(_ context.Context, ctx *cli.Command) error { return nil } -func serveInstalled(_ context.Context, ctx *cli.Command) error { +func serveInstalled(ctx *cli.Context) error { setting.InitCfgProvider(setting.CustomConf) setting.LoadCommonSettings() setting.MustInstalled() @@ -198,9 +185,12 @@ func serveInstalled(_ context.Context, ctx *cli.Command) error { publicFilesSet.Remove(".well-known") publicFilesSet.Remove("assets") publicFilesSet.Remove("robots.txt") - for fn := range publicFilesSet.Seq() { + for _, fn := range publicFilesSet.Values() { log.Error("Found legacy public asset %q in CustomPath. Please move it to %s/public/assets/%s", fn, setting.CustomPath, fn) } + if _, err := os.Stat(filepath.Join(setting.CustomPath, "robots.txt")); err == nil { + log.Error(`Found legacy public asset "robots.txt" in CustomPath. Please move it to %s/public/robots.txt`, setting.CustomPath) + } routers.InitWebInstalled(graceful.GetManager().HammerContext()) @@ -236,7 +226,7 @@ func servePprof() { finished() } -func runWeb(ctx context.Context, cli *cli.Command) error { +func runWeb(ctx *cli.Context) error { defer func() { if panicked := recover(); panicked != nil { log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2)) @@ -254,8 +244,8 @@ func runWeb(ctx context.Context, cli *cli.Command) error { } // Set pid file setting - if cli.IsSet("pid") { - createPIDFile(cli.String("pid")) + if ctx.IsSet("pid") { + createPIDFile(ctx.String("pid")) } if setting.Annex.Enabled { @@ -265,7 +255,7 @@ func runWeb(ctx context.Context, cli *cli.Command) error { } if !setting.InstallLock { - if err := serveInstall(ctx, cli); err != nil { + if err := serveInstall(ctx); err != nil { return err } } else { @@ -276,7 +266,7 @@ func runWeb(ctx context.Context, cli *cli.Command) error { go servePprof() } - return serveInstalled(ctx, cli) + return serveInstalled(ctx) } func setPort(port string) error { diff --git a/cmd/web_acme.go b/cmd/web_acme.go index be6314addb..90e4a02764 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -12,11 +12,10 @@ import ( "strconv" "strings" - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/process" - "forgejo.org/modules/proxy" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" "github.com/caddyserver/certmagic" ) @@ -55,8 +54,8 @@ func runACME(listenAddr string, m http.Handler) error { altTLSALPNPort = p } - certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory} - + magic := certmagic.NewDefault() + magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory} // Try to use private CA root if provided, otherwise defaults to system's trust var certPool *x509.CertPool if setting.AcmeCARoot != "" { @@ -66,8 +65,7 @@ func runACME(listenAddr string, m http.Handler) error { log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) } } - - certmagic.DefaultACME = certmagic.ACMEIssuer{ + myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{ CA: setting.AcmeURL, TrustedRoots: certPool, Email: setting.AcmeEmail, @@ -77,17 +75,7 @@ func runACME(listenAddr string, m http.Handler) error { ListenHost: setting.HTTPAddr, AltTLSALPNPort: altTLSALPNPort, AltHTTPPort: altHTTPPort, - HTTPProxy: proxy.Proxy(), - } - - // Preserve behavior to use Let's encrypt test CA when Let's encrypt is CA. - if certmagic.DefaultACME.CA == certmagic.LetsEncryptProductionCA { - certmagic.DefaultACME.TestCA = certmagic.LetsEncryptStagingCA - } - - magic := certmagic.NewDefault() - - myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME) + }) magic.Issuers = []certmagic.Issuer{myACME} diff --git a/cmd/web_graceful.go b/cmd/web_graceful.go index b0145d4fc7..996537be3b 100644 --- a/cmd/web_graceful.go +++ b/cmd/web_graceful.go @@ -9,9 +9,9 @@ import ( "net/http/fcgi" "strings" - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) func runHTTP(network, listenAddr, name string, m http.Handler, useProxyProtocol bool) error { diff --git a/cmd/web_https.go b/cmd/web_https.go index bebc5f7c8f..70d35cd40d 100644 --- a/cmd/web_https.go +++ b/cmd/web_https.go @@ -9,9 +9,9 @@ import ( "os" "strings" - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "github.com/klauspost/cpuid/v2" ) diff --git a/contrib/autocompletion/bash_autocomplete b/contrib/autocompletion/bash_autocomplete index 58844938a6..5cb62f26a7 100755 --- a/contrib/autocompletion/bash_autocomplete +++ b/contrib/autocompletion/bash_autocomplete @@ -1,3 +1,4 @@ +#! /bin/bash # Heavily inspired by https://github.com/urfave/cli _cli_bash_autocomplete() { @@ -6,9 +7,9 @@ _cli_bash_autocomplete() { COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" if [[ "$cur" == "-"* ]]; then - opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-shell-completion ) + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion ) else - opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-shell-completion ) + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) fi COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 diff --git a/contrib/autocompletion/zsh_autocomplete b/contrib/autocompletion/zsh_autocomplete index 0fd1a0b175..b3b40df503 100644 --- a/contrib/autocompletion/zsh_autocomplete +++ b/contrib/autocompletion/zsh_autocomplete @@ -9,9 +9,9 @@ _cli_zsh_autocomplete() { local cur cur=${words[-1]} if [[ "$cur" == "-"* ]]; then - opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-shell-completion)}") + opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") else - opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-shell-completion)}") + opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}") fi if [[ "${opts[1]}" != "" ]]; then diff --git a/contrib/backport/README b/contrib/backport/README new file mode 100644 index 0000000000..466b79c6d4 --- /dev/null +++ b/contrib/backport/README @@ -0,0 +1,41 @@ +`backport` +========== + +`backport` is a command to help create backports of PRs. It backports a +provided PR from main on to a released version. + +It will create a backport branch, cherry-pick the PR's merge commit, adjust +the commit message and then push this back up to your fork's remote. + +The default version will read from `docs/config.yml`. You can override this +using the option `--version`. + +The upstream branches will be fetched, using the remote `origin`. This can +be overridden using `--upstream`, and fetching can be avoided using +`--no-fetch`. + +By default the branch created will be called `backport-$PR-$VERSION`. You +can override this using the option `--backport-branch`. This branch will +be created from `--release-branch` which is `release/$(VERSION)` +by default and will be pulled from `$(UPSTREAM)`. + +The merge-commit as determined by the github API will be used as the SHA to +cherry-pick. You can override this using `--cherry-pick`. + +The commit message will be amended to add the `Backport` header. +`--no-amend-message` can be set to stop this from happening. + +If cherry-pick is successful the backported branch will be pushed up to your +fork using your remote. These will be determined using `git remote -v`. You +can set your fork name using `--fork-user` and your remote name using +`--remote`. You can avoid pushing using `--no-push`. + +If the push is successful, `xdg-open` will be called to open a backport url. +You can stop this using `--no-xdg-open`. + +Installation +============ + +```bash +go install contrib/backport/backport.go +``` diff --git a/contrib/backport/backport.go b/contrib/backport/backport.go new file mode 100644 index 0000000000..820c0702b7 --- /dev/null +++ b/contrib/backport/backport.go @@ -0,0 +1,474 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//nolint:forbidigo +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "os/exec" + "os/signal" + "path" + "strconv" + "strings" + "syscall" + + "github.com/google/go-github/v57/github" + "github.com/urfave/cli/v2" + "gopkg.in/yaml.v3" +) + +const defaultVersion = "v1.18" // to backport to + +func main() { + app := cli.NewApp() + app.Name = "backport" + app.Usage = "Backport provided PR-number on to the current or previous released version" + app.Description = `Backport will look-up the PR in Gitea's git log and attempt to cherry-pick it on the current version` + app.ArgsUsage = "" + + app.Flags = []cli.Flag{ + &cli.StringFlag{ + Name: "version", + Usage: "Version branch to backport on to", + }, + &cli.StringFlag{ + Name: "upstream", + Value: "origin", + Usage: "Upstream remote for the Gitea upstream", + }, + &cli.StringFlag{ + Name: "release-branch", + Value: "", + Usage: "Release branch to backport on. Will default to release/", + }, + &cli.StringFlag{ + Name: "cherry-pick", + Usage: "SHA to cherry-pick as backport", + }, + &cli.StringFlag{ + Name: "backport-branch", + Usage: "Backport branch to backport on to (default: backport--", + }, + &cli.StringFlag{ + Name: "remote", + Value: "", + Usage: "Remote for your fork of the Gitea upstream", + }, + &cli.StringFlag{ + Name: "fork-user", + Value: "", + Usage: "Forked user name on Github", + }, + &cli.BoolFlag{ + Name: "no-fetch", + Usage: "Set this flag to prevent fetch of remote branches", + }, + &cli.BoolFlag{ + Name: "no-amend-message", + Usage: "Set this flag to prevent automatic amendment of the commit message", + }, + &cli.BoolFlag{ + Name: "no-push", + Usage: "Set this flag to prevent pushing the backport up to your fork", + }, + &cli.BoolFlag{ + Name: "no-xdg-open", + Usage: "Set this flag to not use xdg-open to open the PR URL", + }, + &cli.BoolFlag{ + Name: "continue", + Usage: "Set this flag to continue from a git cherry-pick that has broken", + }, + } + cli.AppHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} +USAGE: + {{.HelpName}} {{if .VisibleFlags}}[options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} + {{if len .Authors}} +AUTHOR: + {{range .Authors}}{{ . }}{{end}} + {{end}}{{if .Commands}} +OPTIONS: + {{range .VisibleFlags}}{{.}} + {{end}}{{end}} +` + + app.Action = runBackport + + if err := app.Run(os.Args); err != nil { + fmt.Fprintf(os.Stderr, "Unable to backport: %v\n", err) + } +} + +func runBackport(c *cli.Context) error { + ctx, cancel := installSignals() + defer cancel() + + continuing := c.Bool("continue") + + var pr string + + version := c.String("version") + if version == "" && continuing { + // determine version from current branch name + var err error + pr, version, err = readCurrentBranch(ctx) + if err != nil { + return err + } + } + if version == "" { + version = readVersion() + } + if version == "" { + version = defaultVersion + } + + upstream := c.String("upstream") + if upstream == "" { + upstream = "origin" + } + + forkUser := c.String("fork-user") + remote := c.String("remote") + if remote == "" && !c.Bool("--no-push") { + var err error + remote, forkUser, err = determineRemote(ctx, forkUser) + if err != nil { + return err + } + } + + upstreamReleaseBranch := c.String("release-branch") + if upstreamReleaseBranch == "" { + upstreamReleaseBranch = path.Join("release", version) + } + + localReleaseBranch := path.Join(upstream, upstreamReleaseBranch) + + args := c.Args().Slice() + if len(args) == 0 && pr == "" { + return fmt.Errorf("no PR number provided\nProvide a PR number to backport") + } else if len(args) != 1 && pr == "" { + return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args) + } + if pr == "" { + pr = args[0] + } + + backportBranch := c.String("backport-branch") + if backportBranch == "" { + backportBranch = "backport-" + pr + "-" + version + } + + fmt.Printf("* Backporting %s to %s as %s\n", pr, localReleaseBranch, backportBranch) + + sha := c.String("cherry-pick") + if sha == "" { + var err error + sha, err = determineSHAforPR(ctx, pr) + if err != nil { + return err + } + } + if sha == "" { + return fmt.Errorf("unable to determine sha for cherry-pick of %s", pr) + } + + if !c.Bool("no-fetch") { + if err := fetchRemoteAndMain(ctx, upstream, upstreamReleaseBranch); err != nil { + return err + } + } + + if !continuing { + if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil { + return err + } + } + + if err := cherrypick(ctx, sha); err != nil { + return err + } + + if !c.Bool("no-amend-message") { + if err := amendCommit(ctx, pr); err != nil { + return err + } + } + + if !c.Bool("no-push") { + url := "https://github.com/go-gitea/gitea/compare/" + upstreamReleaseBranch + "..." + forkUser + ":" + backportBranch + + if err := gitPushUp(ctx, remote, backportBranch); err != nil { + return err + } + + if !c.Bool("no-xdg-open") { + if err := xdgOpen(ctx, url); err != nil { + return err + } + } else { + fmt.Printf("* Navigate to %s to open PR\n", url) + } + } + return nil +} + +func xdgOpen(ctx context.Context, url string) error { + fmt.Printf("* `xdg-open %s`\n", url) + out, err := exec.CommandContext(ctx, "xdg-open", url).Output() + if err != nil { + fmt.Fprintf(os.Stderr, "%s", string(out)) + return fmt.Errorf("unable to xdg-open to %s: %w", url, err) + } + return nil +} + +func gitPushUp(ctx context.Context, remote, backportBranch string) error { + fmt.Printf("* `git push -u %s %s`\n", remote, backportBranch) + out, err := exec.CommandContext(ctx, "git", "push", "-u", remote, backportBranch).Output() + if err != nil { + fmt.Fprintf(os.Stderr, "%s", string(out)) + return fmt.Errorf("unable to push up to %s: %w", remote, err) + } + return nil +} + +func amendCommit(ctx context.Context, pr string) error { + fmt.Printf("* Amending commit to prepend `Backport #%s` to body\n", pr) + out, err := exec.CommandContext(ctx, "git", "log", "-1", "--pretty=format:%B").Output() + if err != nil { + fmt.Fprintf(os.Stderr, "%s", string(out)) + return fmt.Errorf("unable to get last log message: %w", err) + } + + parts := strings.SplitN(string(out), "\n", 2) + + if len(parts) != 2 { + return fmt.Errorf("unable to interpret log message:\n%s", string(out)) + } + subject, body := parts[0], parts[1] + if !strings.HasSuffix(subject, " (#"+pr+")") { + subject = subject + " (#" + pr + ")" + } + + out, err = exec.CommandContext(ctx, "git", "commit", "--amend", "-m", subject+"\n\nBackport #"+pr+"\n"+body).Output() + if err != nil { + fmt.Fprintf(os.Stderr, "%s", string(out)) + return fmt.Errorf("unable to amend last log message: %w", err) + } + return nil +} + +func cherrypick(ctx context.Context, sha string) error { + // Check if a CHERRY_PICK_HEAD exists + if _, err := os.Stat(".git/CHERRY_PICK_HEAD"); err == nil { + // Assume that we are in the middle of cherry-pick - continue it + fmt.Println("* Attempting git cherry-pick --continue") + out, err := exec.CommandContext(ctx, "git", "cherry-pick", "--continue").Output() + if err != nil { + fmt.Fprintf(os.Stderr, "git cherry-pick --continue failed:\n%s\n", string(out)) + return fmt.Errorf("unable to continue cherry-pick: %w", err) + } + return nil + } + + fmt.Printf("* Attempting git cherry-pick %s\n", sha) + out, err := exec.CommandContext(ctx, "git", "cherry-pick", sha).Output() + if err != nil { + fmt.Fprintf(os.Stderr, "git cherry-pick %s failed:\n%s\n", sha, string(out)) + return fmt.Errorf("git cherry-pick %s failed: %w", sha, err) + } + return nil +} + +func checkoutBackportBranch(ctx context.Context, backportBranch, releaseBranch string) error { + out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output() + if err != nil { + return fmt.Errorf("unable to check current branch %w", err) + } + + currentBranch := strings.TrimSpace(string(out)) + fmt.Printf("* Current branch is %s\n", currentBranch) + if currentBranch == backportBranch { + fmt.Printf("* Current branch is %s - not checking out\n", currentBranch) + return nil + } + + if _, err := exec.CommandContext(ctx, "git", "rev-list", "-1", backportBranch).Output(); err == nil { + fmt.Printf("* Branch %s already exists. Checking it out...\n", backportBranch) + return exec.CommandContext(ctx, "git", "checkout", "-f", backportBranch).Run() + } + + fmt.Printf("* `git checkout -b %s %s`\n", backportBranch, releaseBranch) + return exec.CommandContext(ctx, "git", "checkout", "-b", backportBranch, releaseBranch).Run() +} + +func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error { + fmt.Printf("* `git fetch %s main`\n", remote) + out, err := exec.CommandContext(ctx, "git", "fetch", remote, "main").Output() + if err != nil { + fmt.Println(string(out)) + return fmt.Errorf("unable to fetch %s from %s: %w", "main", remote, err) + } + fmt.Println(string(out)) + + fmt.Printf("* `git fetch %s %s`\n", remote, releaseBranch) + out, err = exec.CommandContext(ctx, "git", "fetch", remote, releaseBranch).Output() + if err != nil { + fmt.Println(string(out)) + return fmt.Errorf("unable to fetch %s from %s: %w", releaseBranch, remote, err) + } + fmt.Println(string(out)) + + return nil +} + +func determineRemote(ctx context.Context, forkUser string) (string, string, error) { + out, err := exec.CommandContext(ctx, "git", "remote", "-v").Output() + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to list git remotes:\n%s\n", string(out)) + return "", "", fmt.Errorf("unable to determine forked remote: %w", err) + } + lines := strings.Split(string(out), "\n") + for _, line := range lines { + fields := strings.Split(line, "\t") + name, remote := fields[0], fields[1] + // only look at pushers + if !strings.HasSuffix(remote, " (push)") { + continue + } + // only look at github.com pushes + if !strings.Contains(remote, "github.com") { + continue + } + // ignore go-gitea/gitea + if strings.Contains(remote, "go-gitea/gitea") { + continue + } + if !strings.Contains(remote, forkUser) { + continue + } + if strings.HasPrefix(remote, "git@github.com:") { + forkUser = strings.TrimPrefix(remote, "git@github.com:") + } else if strings.HasPrefix(remote, "https://github.com/") { + forkUser = strings.TrimPrefix(remote, "https://github.com/") + } else if strings.HasPrefix(remote, "https://www.github.com/") { + forkUser = strings.TrimPrefix(remote, "https://www.github.com/") + } else if forkUser == "" { + return "", "", fmt.Errorf("unable to extract forkUser from remote %s: %s", name, remote) + } + idx := strings.Index(forkUser, "/") + if idx >= 0 { + forkUser = forkUser[:idx] + } + return name, forkUser, nil + } + return "", "", fmt.Errorf("unable to find appropriate remote in:\n%s", string(out)) +} + +func readCurrentBranch(ctx context.Context) (pr, version string, err error) { + out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output() + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to read current git branch:\n%s\n", string(out)) + return "", "", fmt.Errorf("unable to read current git branch: %w", err) + } + parts := strings.Split(strings.TrimSpace(string(out)), "-") + + if len(parts) != 3 || parts[0] != "backport" { + fmt.Fprintf(os.Stderr, "Unable to continue from git branch:\n%s\n", string(out)) + return "", "", fmt.Errorf("unable to continue from git branch:\n%s", string(out)) + } + + return parts[1], parts[2], nil +} + +func readVersion() string { + bs, err := os.ReadFile("docs/config.yaml") + if err != nil { + if err == os.ErrNotExist { + log.Println("`docs/config.yaml` not present") + return "" + } + fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err) + return "" + } + + type params struct { + Version string + } + type docConfig struct { + Params params + } + dc := &docConfig{} + if err := yaml.Unmarshal(bs, dc); err != nil { + fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err) + return "" + } + + if dc.Params.Version == "" { + fmt.Fprintf(os.Stderr, "No version in `docs/config.yaml`") + return "" + } + + version := dc.Params.Version + if version[0] != 'v' { + version = "v" + version + } + + split := strings.SplitN(version, ".", 3) + + return strings.Join(split[:2], ".") +} + +func determineSHAforPR(ctx context.Context, prStr string) (string, error) { + prNum, err := strconv.Atoi(prStr) + if err != nil { + return "", err + } + + client := github.NewClient(http.DefaultClient) + + pr, _, err := client.PullRequests.Get(ctx, "go-gitea", "gitea", prNum) + if err != nil { + return "", err + } + + if pr.Merged == nil || !*pr.Merged { + return "", fmt.Errorf("PR #%d is not yet merged - cannot determine sha to backport", prNum) + } + + if pr.MergeCommitSHA != nil { + return *pr.MergeCommitSHA, nil + } + + return "", nil +} + +func installSignals() (context.Context, context.CancelFunc) { + ctx, cancel := context.WithCancel(context.Background()) + go func() { + // install notify + signalChannel := make(chan os.Signal, 1) + + signal.Notify( + signalChannel, + syscall.SIGINT, + syscall.SIGTERM, + ) + select { + case <-signalChannel: + case <-ctx.Done(): + } + cancel() + signal.Reset() + }() + + return ctx, cancel +} diff --git a/contrib/environment-to-ini/README b/contrib/environment-to-ini/README index e4caf25666..f1d3f2ae83 100644 --- a/contrib/environment-to-ini/README +++ b/contrib/environment-to-ini/README @@ -1,46 +1,45 @@ Environment To Ini ================== -This tool allows defining Forgejo's entire configuration via environment -variables, mostly geared towards usage in Docker. +Multiple docker users have requested that the Gitea docker is changed +to permit arbitrary configuration via environment variables. -Forgejo needs to use an INI file for configuration because the running -environment that starts the container may not be the same as the one used -by the hooks. An INI file also gives a good default and means that -users do not have to provide the entire set of environment variables. +Gitea needs to use an ini file for configuration because the running +environment that starts the docker may not be the same as that used +by the hooks. An ini file also gives a good default and means that +users do not have to completely provide a full environment. With those caveats above, this command provides a generic way of converting suitably structured environment variables into any ini value. -When run, `environment-to-ini` will write the config files based on the -environment variables provided. -Check with the `-h` flag for several options to alter this behaviour. +To use the command is very simple just run it and the default gitea +app.ini will be rewritten to take account of the variables provided, +however there are various options to give slightly different +behavior and these can be interrogated with the `-h` option. -Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME" -will be mapped to the ini section "[section_name]" and the key -"KEY_NAME" with the value as provided. +The environment variables should be of the form: -Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME__FILE" -will be mapped to the ini section "[section_name]" and the key -"KEY_NAME" with the value loaded from the specified file. + GITEA__SECTION_NAME__KEY_NAME + +Note, SECTION_NAME in the notation above is case-insensitive. Environment variables are usually restricted to a reduced character set "0-9A-Z_" - in order to allow the setting of sections with characters outside of that set, they should be escaped as following: -"_0X2E_" for ".". The entire section and key names can be escaped as -a UTF8 byte string if necessary. E.g. to configure: +"_0X2E_" for "." and "_0X2D_" for "-". The entire section and key names +can be escaped as a UTF8 byte string if necessary. E.g. to configure: - """ - ... - [log.console] - COLORIZE=false - STDERR=true - ... - """ + """ + ... + [log.console] + COLORIZE=false + STDERR=true + ... + """ -You would set the environment variables: "FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false" -and "FORGEJO__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found +You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false" +and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found on the configuration cheat sheet. To build locally, run: diff --git a/contrib/environment-to-ini/environment-to-ini.go b/contrib/environment-to-ini/environment-to-ini.go index e8e799b5f3..f8593e49c3 100644 --- a/contrib/environment-to-ini/environment-to-ini.go +++ b/contrib/environment-to-ini/environment-to-ini.go @@ -4,17 +4,16 @@ package main import ( - "context" "os" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) func main() { - app := cli.Command{} + app := cli.NewApp() app.Name = "environment-to-ini" app.Usage = "Use provided environment to update configuration ini" app.Description = `As a helper to allow docker users to update the forgejo configuration @@ -73,13 +72,13 @@ func main() { }, } app.Action = runEnvironmentToIni - err := app.Run(context.Background(), os.Args) + err := app.Run(os.Args) if err != nil { log.Fatal("Failed to run app with %s: %v", os.Args, err) } } -func runEnvironmentToIni(ctx context.Context, c *cli.Command) error { +func runEnvironmentToIni(c *cli.Context) error { // the config system may change the environment variables, so get a copy first, to be used later env := append([]string{}, os.Environ()...) setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{ diff --git a/contrib/fixtures/fixture_generation.go b/contrib/fixtures/fixture_generation.go new file mode 100644 index 0000000000..31797cc800 --- /dev/null +++ b/contrib/fixtures/fixture_generation.go @@ -0,0 +1,80 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//nolint:forbidigo +package main + +import ( + "context" + "fmt" + "os" + "path/filepath" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/unittest" +) + +// To generate derivative fixtures, execute the following from Gitea's repository base dir: +// go run -tags 'sqlite sqlite_unlock_notify' contrib/fixtures/fixture_generation.go [fixture...] + +var ( + generators = []struct { + gen func(ctx context.Context) (string, error) + name string + }{ + { + models.GetYamlFixturesAccess, "access", + }, + } + fixturesDir string +) + +func main() { + pathToGiteaRoot := "." + fixturesDir = filepath.Join(pathToGiteaRoot, "models", "fixtures") + if err := unittest.CreateTestEngine(unittest.FixturesOptions{ + Dir: fixturesDir, + }); err != nil { + fmt.Printf("CreateTestEngine: %+v", err) + os.Exit(1) + } + if err := unittest.PrepareTestDatabase(); err != nil { + fmt.Printf("PrepareTestDatabase: %+v\n", err) + os.Exit(1) + } + ctx := context.Background() + if len(os.Args) == 0 { + for _, r := range os.Args { + if err := generate(ctx, r); err != nil { + fmt.Printf("generate '%s': %+v\n", r, err) + os.Exit(1) + } + } + } else { + for _, g := range generators { + if err := generate(ctx, g.name); err != nil { + fmt.Printf("generate '%s': %+v\n", g.name, err) + os.Exit(1) + } + } + } +} + +func generate(ctx context.Context, name string) error { + for _, g := range generators { + if g.name == name { + data, err := g.gen(ctx) + if err != nil { + return err + } + path := filepath.Join(fixturesDir, name+".yml") + if err := os.WriteFile(path, []byte(data), 0o644); err != nil { + return fmt.Errorf("%s: %+v", path, err) + } + fmt.Printf("%s created.\n", path) + return nil + } + } + + return fmt.Errorf("generator not found") +} diff --git a/contrib/gitea-monitoring-mixin/dashboards/overview.libsonnet b/contrib/gitea-monitoring-mixin/dashboards/overview.libsonnet index 108cab0eb1..31b7d4f9b2 100644 --- a/contrib/gitea-monitoring-mixin/dashboards/overview.libsonnet +++ b/contrib/gitea-monitoring-mixin/dashboards/overview.libsonnet @@ -408,7 +408,7 @@ local addIssueLabelsOverrides(labels) = regex: '', type: 'query', multi: true, - allValue: '.+', + allValue: '.+' }, ) .addTemplate( @@ -423,7 +423,7 @@ local addIssueLabelsOverrides(labels) = regex: '', type: 'query', multi: true, - allValue: '.+', + allValue: '.+' }, ) .addTemplate( diff --git a/contrib/ide/vscode/settings.json b/contrib/ide/vscode/settings.json index 7f7de43622..2ec666f3c1 100644 --- a/contrib/ide/vscode/settings.json +++ b/contrib/ide/vscode/settings.json @@ -1,6 +1,4 @@ { - "go.buildTags": "sqlite,sqlite_unlock_notify", - "go.testFlags": ["-v"], - "go.lintTool": "golangci-lint", - "go.lintFlags": ["--fast"] + "go.buildTags": "sqlite,sqlite_unlock_notify", + "go.testFlags": ["-v"] } diff --git a/contrib/legal/privacy.html.sample b/contrib/legal/privacy.html.sample index 34a9a5142f..adb3ea7ad4 100644 --- a/contrib/legal/privacy.html.sample +++ b/contrib/legal/privacy.html.sample @@ -7,11 +7,11 @@

Privacy Policy

-

Last updated: December 19, 2024

+

Last updated: January 29, 2020

Who We Are?

-

Your Forgejo Instance

+

Your Gitea Instance

What Personal Data We Collect?

@@ -37,19 +37,19 @@

With your Consent

-

We share your User Personal Information, if you consent, after letting you know what information will be shared, with whom, and why. For example, if you allow third party applications to access your Account using OAuth2 providers, we share all information associated with your Account, including private repos and organizations. You may also direct us through your action on Your Forgejo Instance to share your User Personal Information, such as when joining an Organization.

+

We share your User Personal Information, if you consent, after letting you know what information will be shared, with whom, and why. For example, if you allow third party applications to access your Account using OAuth2 providers, we share all information associated with your Account, including private repos and organizations. You may also direct us through your action on Your Gitea Instance to share your User Personal Information, such as when joining an Organization.

With Service Providers

-

We share User Personal Information with a limited number of service providers who process it on our behalf to provide or improve our Service, and who have agreed to privacy restrictions similar to the ones in our Privacy Statement by signing data protection agreements or making similar commitments. Our service providers perform payment processing, customer support ticketing, network data transmission, security, and other similar services. While Your Forgejo Instance processes all User Personal Information in the (country/state where Forgejo is deployed), our service providers may process data outside of (country/state where Forgejo is deployed), the United States or the European Union.

+

We share User Personal Information with a limited number of service providers who process it on our behalf to provide or improve our Service, and who have agreed to privacy restrictions similar to the ones in our Privacy Statement by signing data protection agreements or making similar commitments. Our service providers perform payment processing, customer support ticketing, network data transmission, security, and other similar services. While Your Gitea Instance processes all User Personal Information in the (country/state where Gitea is deployed), our service providers may process data outside of (country/state where Gitea is deployed), the United States or the European Union.

For Security Purposes

-

If you are a member of an Organization, Your Forgejo Instance may share your username, Usage Information, and Device Information associated with that Organization with an owner and/or administrator of the Organization who has agreed to the Corporate Terms of Service or applicable customer agreements, to the extent that such information is provided only to investigate or respond to a security incident that affects or compromises the security of that particular Organization.

+

If you are a member of an Organization, Your Gitea Instance may share your username, Usage Information, and Device Information associated with that Organization with an owner and/or administrator of the Organization who has agreed to the Corporate Terms of Service or applicable customer agreements, to the extent that such information is provided only to investigate or respond to a security incident that affects or compromises the security of that particular Organization.

For Legal Disclosure

-

Your Forgejo Instance strives for transparency in complying with legal process and legal obligations. Unless prevented from doing so by law or court order, or in rare, exigent circumstances, we make a reasonable effort to notify users of any legally compelled or required disclosure of their information. Your Forgejo Instance may disclose User Personal Information or other information we collect about you to law enforcement if required in response to a valid subpoena, court order, search warrant, a similar government order, or when we believe in good faith that disclosure is necessary to comply with our legal obligations, to protect our property or rights, or those of third parties or the public at large.

+

Your Gitea Instance strives for transparency in complying with legal process and legal obligations. Unless prevented from doing so by law or court order, or in rare, exigent circumstances, we make a reasonable effort to notify users of any legally compelled or required disclosure of their information. Your Gitea Instance may disclose User Personal Information or other information we collect about you to law enforcement if required in response to a valid subpoena, court order, search warrant, a similar government order, or when we believe in good faith that disclosure is necessary to comply with our legal obligations, to protect our property or rights, or those of third parties or the public at large.

Change in Control or Sale

@@ -57,7 +57,7 @@

Aggregate, Non-Personally Identifying Information

-

We share certain aggregated, non-personally identifying information with others about how our users, collectively, use Your Forgejo Instance, or how our users respond to our other offerings, such as our conferences or events. For example, we may compile statistics on the open source activity across Your Forgejo Instance.

+

We share certain aggregated, non-personally identifying information with others about how our users, collectively, use Your Gitea Instance, or how our users respond to our other offerings, such as our conferences or events. For example, we may compile statistics on the open source activity across Your Gitea Instance.

We don't sell your User Personal Information for monetary or other consideration.

@@ -67,34 +67,34 @@
  1. We use your Registration Information to create your account, and to provide you the Service.
  2. -
  3. We use your User Personal Information, specifically your username, to identify you on Your Forgejo Instance.
  4. +
  5. We use your User Personal Information, specifically your username, to identify you on Your Gitea Instance.
  6. We use your Profile Information to fill out your Account profile and to share that profile with other users if you ask us to.
  7. We use your email address to communicate with you, if you've said that's okay, and only for the reasons you’ve said that’s okay.
  8. -
  9. We use User Personal Information and other data to make recommendations for you, such as to suggest projects you may want to follow or contribute to. We learn from your public behavior on Your Forgejo Instance—such as the projects you star—to determine your coding interests, and we recommend similar projects. These recommendations are automated decisions, but they have no legal impact on your rights.
  10. -
  11. We use Usage Information and Device Information to better understand how our Users use Your Forgejo Instance and to improve our Website and Service.
  12. -
  13. We may use your User Personal Information if it is necessary for security purposes or to investigate possible fraud or attempts to harm Your Forgejo Instance or our Users.
  14. +
  15. We use User Personal Information and other data to make recommendations for you, such as to suggest projects you may want to follow or contribute to. We learn from your public behavior on Your Gitea Instance—such as the projects you star—to determine your coding interests, and we recommend similar projects. These recommendations are automated decisions, but they have no legal impact on your rights.
  16. +
  17. We use Usage Information and Device Information to better understand how our Users use Your Gitea Instance and to improve our Website and Service.
  18. +
  19. We may use your User Personal Information if it is necessary for security purposes or to investigate possible fraud or attempts to harm Your Gitea Instance or our Users.
  20. We may use your User Personal Information to comply with our legal obligations, protect our intellectual property, and enforce our Terms of Service.
  21. We limit our use of your User Personal Information to the purposes listed in this Privacy Statement. If we need to use your User Personal Information for other purposes, we will ask your permission first. You can always see what information we have, how we're using it, and what permissions you have given us in your user profile.
-

How Your Forgejo Instance Secures Your Information?

+

How Your Gitea Instance Secures Your Information?

-

Your Forgejo Instance takes all measures reasonably necessary to protect User Personal Information from unauthorized access, alteration, or destruction; maintain data accuracy; and help ensure the appropriate use of User Personal Information.

+

Your Gitea Instance takes all measures reasonably necessary to protect User Personal Information from unauthorized access, alteration, or destruction; maintain data accuracy; and help ensure the appropriate use of User Personal Information.

To the extent above, we enforce a written security information program, which:

  • aligns with industry recognized frameworks;
  • includes security safeguards reasonably designed to protect the confidentiality, integrity, availability, and resilience of our Users' data;
  • -
  • is appropriate to the nature, size, and complexity of Your Forgejo Instance’s business operations;
  • +
  • is appropriate to the nature, size, and complexity of Your Gitea Instance’s business operations;
  • includes incident response and data breach notification processes; and
  • -
  • complies with applicable information security-related laws and regulations in the geographic regions where Your Forgejo Instance does business.
  • +
  • complies with applicable information security-related laws and regulations in the geographic regions where Your Gitea Instance does business.

In the event of a data breach that affects your User Personal Information, we will act promptly to mitigate the impact of a breach and notify any affected Users without undue delay.

-

Transmission of data on Your Forgejo Instance is encrypted using SSH, HTTPS (TLS), and git repository content is encrypted at rest. We host Your Forgejo Instance at our hosting partner, which they provide data centers with high level of physical and network security.

+

Transmission of data on Your Gitea Instance is encrypted using SSH, HTTPS (TLS), and git repository content is encrypted at rest. We host Your Gitea Instance at our hosting partner, which they provide data centers with high level of physical and network security.

Disclaimer: No method of transmission, or method of electronic storage, is 100% secure, therefore, we cannot guarantee absolute security.

@@ -102,13 +102,13 @@

Cookies

-

We uses cookies to make interactions with our service easy and meaningful. Cookies are small text files that websites often store on computer hard drives or mobile devices of visitors. We use cookies (and similar technologies, like HTML5 localStorage) to keep you logged in, remember your preferences, and provide information for future development of Your Forgejo Instance. For security purposes, we use cookies to identify a device. By using our Website, you agree that we can place these types of cookies on your computer or device. If you disable your browser or device’s ability to accept these cookies, you will not be able to log in or use our services.

+

We uses cookies to make interactions with our service easy and meaningful. Cookies are small text files that websites often store on computer hard drives or mobile devices of visitors. We use cookies (and similar technologies, like HTML5 localStorage) to keep you logged in, remember your preferences, and provide information for future development of Your Gitea Instance. For security purposes, we use cookies to identify a device. By using our Website, you agree that we can place these types of cookies on your computer or device. If you disable your browser or device’s ability to accept these cookies, you will not be able to log in or use our services.

Tracking and Analytics

-

Out of the box, Forgejo doesn't use third-party analytics. In case when we opt in to their usage, we do that to help us evaluate our Users' use of Your Forgejo Instance, compile statistical reports on activity, and improve our content and Website performance. We only use these third-party analytics providers on certain areas of our Website, and all of them have signed data protection agreements with us that limit the type of User Personal Information they can collect and the purpose for which they can process the information. In addition, we may also deploy internal analytics software to provide similar functionality.

+

Out of the box, Gitea doesn't use third-party analytics. In case when we opt in to their usage, we do that to help us evaluate our Users' use of Your Gitea Instance, compile statistical reports on activity, and improve our content and Website performance. We only use these third-party analytics providers on certain areas of our Website, and all of them have signed data protection agreements with us that limit the type of User Personal Information they can collect and the purpose for which they can process the information. In addition, we may also deploy internal analytics software to provide similar functionality.

-

Some browsers have incorporated "Do Not Track" (DNT) features that can send a signal to the websites you visit indicating you do not wish to be tracked. Your Forgejo Instance responds to browser DNT signals and follows the W3C standard for responding to DNT signals. If you have not enabled DNT on a browser that supports it, cookies on some parts of our Website will track your online browsing activity on other online services over time, though we do not permit third parties other than our analytics and service providers to track Your Forgejo Instance Users' activity over time on Your Forgejo Instance.

+

Some browsers have incorporated "Do Not Track" (DNT) features that can send a signal to the websites you visit indicating you do not wish to be tracked. Your Gitea Instance responds to browser DNT signals and follows the W3C standard for responding to DNT signals. If you have not enabled DNT on a browser that supports it, cookies on some parts of our Website will track your online browsing activity on other online services over time, though we do not permit third parties other than our analytics and service providers to track Your Gitea Instance Users' activity over time on Your Gitea Instance.

Repository Contents

@@ -118,19 +118,19 @@

Public Information

-

Many of our services and feature are public-facing. If your content is public-facing, third parties may access and use it in compliance with our Terms of Service, such as by viewing your profile or repositories or pulling data via our API. We do not sell that content; it is yours. However, we do allow third parties, such as research organizations or archives, to compile public-facing Your Forgejo Instance information. Other third parties, such as data brokers, have been known to scrape Your Forgejo Instance and compile data as well.

+

Many of our services and feature are public-facing. If your content is public-facing, third parties may access and use it in compliance with our Terms of Service, such as by viewing your profile or repositories or pulling data via our API. We do not sell that content; it is yours. However, we do allow third parties, such as research organizations or archives, to compile public-facing Your Gitea Instance information. Other third parties, such as data brokers, have been known to scrape Your Gitea Instance and compile data as well.

-

Your User Personal Information associated with your content could be gathered by third parties in these compilations of Your Forgejo Instance data. If you do not want your User Personal Information to appear in third parties’ compilations of Your Forgejo Instance data, please do not make your User Personal Information publicly available and be sure to configure your email address to be private in your user profile and in your git commit settings.

+

Your User Personal Information associated with your content could be gathered by third parties in these compilations of Your Gitea Instance data. If you do not want your User Personal Information to appear in third parties’ compilations of Your Gitea Instance data, please do not make your User Personal Information publicly available and be sure to configure your email address to be private in your user profile and in your git commit settings.

-

If you would like to compile Your Forgejo Instance data, you must comply with our Terms of Service regarding scraping and privacy, and you may only use any public-facing User Personal Information you gather for the purpose for which our user authorized it. For example, where a Your Forgejo Instance user has made an email address public-facing for the purpose of identification and attribution, do not use that email address for commercial advertising. We expect you to reasonably secure any User Personal Information you have gathered from Your Forgejo Instance, and to respond promptly to complaints, removal requests, and "do not contact" requests from Your Forgejo Instance or Your Forgejo Instance users.

+

If you would like to compile Your Gitea Instance data, you must comply with our Terms of Service regarding scraping and privacy, and you may only use any public-facing User Personal Information you gather for the purpose for which our user authorized it. For example, where a Your Gitea Instance user has made an email address public-facing for the purpose of identification and attribution, do not use that email address for commercial advertising. We expect you to reasonably secure any User Personal Information you have gathered from Your Gitea Instance, and to respond promptly to complaints, removal requests, and "do not contact" requests from Your Gitea Instance or Your Gitea Instance users.

-

In similar fashion, projects on Your Forgejo Instance may include publicly available User Personal Information collected as part of the collaborative events.

+

In similar fashion, projects on Your Gitea Instance may include publicly available User Personal Information collected as part of the collaborative events.

Organizations

If you collaborate on or become a member of an Organization, then its Account owners may receive your User Personal Information. When you accept an invitation to an Organization, you will be notified of the types of information owners may be able to see. If you accept an invitation to an Organization with a verified domain, then the owners of that Organization will be able to see your full email address(es) within that Organization's verified domain(s).

-

Please note, Your Forgejo Instance may share your username, Usage Information, and Device Information with the owner of the Organization you are a member of, to the extent that your User Personal Information is provided only to investigate or respond to a security incident that affects or compromises the security of that particular Organization.

+

Please note, Your Gitea Instance may share your username, Usage Information, and Device Information with the owner of the Organization you are a member of, to the extent that your User Personal Information is provided only to investigate or respond to a security incident that affects or compromises the security of that particular Organization.

If you collaborate with or become a member of an Account that has agreed to a Data Protection Addendum (DPA) to this Privacy Policy, then that DPA governs in the event of conflicts between this Privacy Policy and DPA with respect to your activity in the Account.

@@ -138,17 +138,17 @@

How You Can Access and Control the Information We Collect?

-

If you're already a Your Forgejo Instance user, you may access, update, alter, or delete your basic user information by editing your user profile. You can control the information we collect about you by limiting what information is in your profile, or by keeping your information current.

+

If you're already a Your Gitea Instance user, you may access, update, alter, or delete your basic user information by editing your user profile. You can control the information we collect about you by limiting what information is in your profile, or by keeping your information current.

-

If Your Forgejo Instance processes information about you, such as information receives from third parties, and you do not have an account, then you may, subject to applicable law, access, update, alter, delete, or object to the processing of your personal information by contacting our support.

+

If Your Gitea Instance processes information about you, such as information receives from third parties, and you do not have an account, then you may, subject to applicable law, access, update, alter, delete, or object to the processing of your personal information by contacting our support.

Data Portability

-

As a Your Forgejo Instance User, you can always take your data with you. You can clone your repositories to your computer, or you can perform migrations using the provided interfaces, for example.

+

As a Your Gitea Instance User, you can always take your data with you. You can clone your repositories to your computer, or you can perform migrations using the provided interfaces, for example.

Data Retention and Deletion of Data

-

In general, Your Forgejo Instance retains User Personal Information for as long as your account is active, or as needed to provide you service.

+

In general, Your Gitea Instance retains User Personal Information for as long as your account is active, or as needed to provide you service.

If you would like to cancel your account or delete your User Personal Information, you may do so in your user profile. We retain and use your information as necessary to comply with our legal obligations, resolve disputes, and enforce our agreements, but barring legal requirements, we will delete your full profile (within reason) within 90 days of your request. Feel free to contact our support to request erasure of the data we process on the basis of consent within 30 days.

@@ -158,14 +158,14 @@

Our Global Privacy Practices

-

We store and process the information that we collect in the (country/state where Forgejo is deployed) in accordance with this Privacy Statement though our service providers may store and process data outside the (country/state where Forgejo is deployed). However, we understand that we have Users from different countries and regions with different privacy expectations, and we try to meet those needs even when the (country/state where Forgejo is deployed) does not have the same privacy framework as other countries.

+

We store and process the information that we collect in the (country/state where Gitea is deployed) in accordance with this Privacy Statement though our service providers may store and process data outside the (country/state where Gitea is deployed). However, we understand that we have Users from different countries and regions with different privacy expectations, and we try to meet those needs even when the (country/state where Gitea is deployed) does not have the same privacy framework as other countries.

We provide a high standard of privacy protection—as described in this Privacy Statement—to all our users around the world, regardless of their country of origin or location, and we are proud of the levels of notice, choice, accountability, security, data integrity, access, and recourse we provide. We work hard to comply with the applicable data privacy laws wherever we do business, working with our Data Protection Officer as part of a cross-functional team that oversees our privacy compliance efforts. Additionally, if our vendors or affiliates have access to User Personal Information, they must sign agreements that require them to comply with our privacy policies and with applicable data privacy laws.

In particular:

    -
  • Your Forgejo Instance provides clear methods of unambiguous, informed, specific, and freely given consent at the time of data collection, when we collect your User Personal Information using consent as a basis.
  • +
  • Your Gitea Instance provides clear methods of unambiguous, informed, specific, and freely given consent at the time of data collection, when we collect your User Personal Information using consent as a basis.
  • We collect only the minimum amount of User Personal Information necessary for our purposes, unless you choose to provide more. We encourage you to only give us the amount of data you are comfortable sharing.
  • We offer you simple methods of accessing, altering, or deleting the User Personal Information we have collected, where legally permitted.
  • We provide our Users notice, choice, accountability, security, and access regarding their User Personal Information, and we limit the purpose for processing it. We also provide our Users a method of recourse and enforcement. These are the Privacy Shield Principles, but they are also just good practices.
  • @@ -173,21 +173,21 @@

    How We Communicate with You?

    -

    We use your email address to communicate with you, if you've said that's okay, and only for the reasons you’ve said that’s okay. For example, if you contact our support with a request, we respond to you via email. You have a lot of control over how your email address is used and shared on and through Your Forgejo instance. You may manage your communication preferences in your user profile.

    +

    We use your email address to communicate with you, if you've said that's okay, and only for the reasons you’ve said that’s okay. For example, if you contact our support with a request, we respond to you via email. You have a lot of control over how your email address is used and shared on and through Your Gitea instance. You may manage your communication preferences in your user profile.

    By design, the Git version control system associates many actions with a User's email address, such as commit messages. We are not able to change many aspects of the Git system. If you would like your email address to remain private, even when you’re commenting on public repositories, you can create a private email address in your user profile. You should also update your local Git configuration to use your private email address. This will not change how we contact you, but it will affect how others see you.

    -

    Depending on your email settings, Your Forgejo instance may occasionally send notification emails about changes in a repository you’re watching, new features, requests for feedback, important policy changes, or to offer customer support. We also send marketing emails, based on your choices and in accordance with applicable laws and regulations. There's an “unsubscribe” link located at the bottom of each of the marketing emails we send you. Note that you can opt out of any communications with us, except the important ones (like from our support and system emails).

    +

    Depending on your email settings, Your Gitea instance may occasionally send notification emails about changes in a repository you’re watching, new features, requests for feedback, important policy changes, or to offer customer support. We also send marketing emails, based on your choices and in accordance with applicable laws and regulations. There's an “unsubscribe” link located at the bottom of each of the marketing emails we send you. Note that you can opt out of any communications with us, except the important ones (like from our support and system emails).

    Our emails may contain a pixel tag, which is a small, clear image that can tell us whether or not you have opened an email and what your IP address is. We use this pixel tag to make our email more effective for you and to make sure we’re not sending you unwanted email.

    Changes to this Privacy Policy

    -

    Although most changes are likely to be minor, Your Forgejo Instance may change our Privacy Statement from time to time. We will provide notification to Users of material changes to this Privacy Statement through our Website at least 30 days prior to the change taking effect by posting a notice on our home page or sending email to the primary email address specified in your account.

    +

    Although most changes are likely to be minor, Your Gitea Instance may change our Privacy Statement from time to time. We will provide notification to Users of material changes to this Privacy Statement through our Website at least 30 days prior to the change taking effect by posting a notice on our home page or sending email to the primary email address specified in your account.

    Contact

    -

    If you have any concerns about privacy, please contact us at privacy@your-forgejo-instance. We will respond promptly, within 45 days.

    +

    If you have any concerns about privacy, please contact us at privacy@your-gitea-instance. We will respond promptly, within 45 days.

    COPYING

    diff --git a/contrib/legal/tos.html.sample b/contrib/legal/tos.html.sample index 73ee0899ef..d39082909f 100644 --- a/contrib/legal/tos.html.sample +++ b/contrib/legal/tos.html.sample @@ -7,26 +7,26 @@

    Terms of Service

    -

    Last updated: December 19, 2024

    +

    Last updated: January 29, 2020

    -

    Thank you for choosing Your Forgejo Instance! Before you use it, please read this Terms of Service agreement carefully, which contains important contract between us and our users.

    +

    Thank you for choosing Your Gitea Instance! Before you use it, please read this Terms of Service agreement carefully, which contains important contract between us and our users.

    Definitions

      -
    1. An "Account" represents your legal relationship with Your Forgejo Instance. A “User Account” represents an individual User’s authorization to log in to and use the Service and serves as a User’s identity on Your Forgejo Instance. “Organizations” are shared workspaces that may be associated with a single entity or with one or more Users where multiple Users can collaborate across many projects at once. A User Account can be a member of any number of Organizations.
    2. +
    3. An "Account" represents your legal relationship with Your Gitea Instance. A “User Account” represents an individual User’s authorization to log in to and use the Service and serves as a User’s identity on Your Gitea Instance. “Organizations” are shared workspaces that may be associated with a single entity or with one or more Users where multiple Users can collaborate across many projects at once. A User Account can be a member of any number of Organizations.
    4. The "Agreement" collectively refers to all terms, conditions, and notices referenced or contained in this document and other operating rules, policies (including Privacy Policy) and procedures that we may publish from time to time on this Website.
    5. “Content” refers to content featured or displayed through the Website, including without limitation code, text, data, articles, images, photographs, graphics, software, applications, packages, designs, features, and other materials that are available on the Website or otherwise available through the Service. "Content" also includes Services. “User-Generated Content” is Content, written or otherwise, created or uploaded by our Users. "Your Content" is Content that you create or own.
    6. -
    7. "Your Forgejo Instance", "We", and "Us" refers to Your Forgejo Instance, as well as our affiliates, directors, subsidiaries, contractors, licensors, officers, agents, and employees.
    8. +
    9. "Your Gitea Instance", "We", and "Us" refers to Your Gitea Instance, as well as our affiliates, directors, subsidiaries, contractors, licensors, officers, agents, and employees.
    10. -
    11. The "Service" refers to applications/software, products, and services provided by Your Forgejo Instance.
    12. +
    13. The "Service" refers to applications/software, products, and services provided by Your Gitea Instance.
    14. The "User", "You", and "Your" refers to individual person or institution (organizations or company) that has visited or using the Service; that have access or use any part of the Account; or that directs to use the Account to perform its function. Please note that additional terms may apply for Accounts related to business or government.
    15. -
    16. The "Website" refers to Your Forgejo Instance's website at your-forgejo-instance, including its subdomains and other websites owned by Your Forgejo Instance.
    17. +
    18. The "Website" refers to Your Gitea Instance's website at your-gitea-instance, including its subdomains and other websites owned by Your Gitea Instance.

    Account Terms

    @@ -48,7 +48,7 @@
    • You must be a human to create an Account. Accounts registered by "bots" or other automated methods are not permitted. We do permit machine accounts:
    • A machine account is an Account set up by an individual human who accepts the Terms on behalf of the Account, provides a valid email address, and is responsible for its actions. A machine account is used exclusively for performing automated tasks. Multiple users may direct the actions of a machine account, but the owner of the Account is ultimately responsible for the machine's actions.
    • -
    • You must be age 13 or older. If we learn of any User under that age, we will immediately terminate that User's Account. Different countries may have different minimum age; in such cases you are responsible for complying with your country's regulation. By using Your Forgejo Instance, you agree to comply with COPPA and/or similar law in your country.
    • +
    • You must be age 13 or older. If we learn of any User under that age, we will immediately terminate that User's Account. Different countries may have different minimum age; in such cases you are responsible for complying with your country's regulation. By using Your Gitea Instance, you agree to comply with COPPA and/or similar law in your country.

    User Account Security

    @@ -57,7 +57,7 @@

    Additional Terms

    -

    In some situations, third parties' terms may apply to your use of Your Forgejo Instance. For example, you may be a member of an organization on Your Forgejo Instance with its own terms or license agreements; you may download an application that integrates with Your Forgejo Instance; or you may use Your Forgejo Instance to authenticate to another service. Please be aware that while these Terms are our full agreement with you, other parties' terms govern their relationships with you.

    +

    In some situations, third parties' terms may apply to your use of Your Gitea Instance. For example, you may be a member of an organization on Your Gitea Instance with its own terms or license agreements; you may download an application that integrates with Your Gitea Instance; or you may use Your Gitea Instance to authenticate to another service. Please be aware that while these Terms are our full agreement with you, other parties' terms govern their relationships with you.

    Acceptable Use

    @@ -73,19 +73,19 @@
  • You retain ownership of and responsibility for Your Content. If you're posting anything you did not create yourself or do not own the rights to, you agree that you are responsible for any Content you post; that you will only submit Content that you have the right to post; and that you will fully comply with any third party licenses relating to Content you post.

    -

    Because of above, we need you to grant us -- and other Your Forgejo Instance users -- certain legal permissions, listed below in this section. If you upload Content that already comes with a license granting Your Forgejo Instance the permissions we need to run our Service, no additional license is required. You understand that you will not receive any payment for any of the rights granted below. The licenses you grant to us will end when you remove Your Content from our servers, unless other Users have forked it.

    +

    Because of above, we need you to grant us -- and other Your Gitea Instance users -- certain legal permissions, listed below in this section. If you upload Content that already comes with a license granting Your Gitea Instance the permissions we need to run our Service, no additional license is required. You understand that you will not receive any payment for any of the rights granted below. The licenses you grant to us will end when you remove Your Content from our servers, unless other Users have forked it.

  • We need the legal right to do things like host Your Content, publish it, and share it. You grant us and our legal successors the right to store, parse, and display Your Content, and make incidental copies as necessary to render the Website and provide the Service. This includes the right to do things like copy it to our database and make backups; show it to you and other users; parse it into a search index or otherwise analyze it on our servers; share it with other users; and perform it, in case Your Content is something like music or video.

    -

    This license, however, doesn't grant Your Forgejo Instance the right to sell Your Content or otherwise distribute or use it outside of our provision of the Service.

    +

    This license, however, doesn't grant Your Gitea Instance the right to sell Your Content or otherwise distribute or use it outside of our provision of the Service.

  • Any User-Generated Content you post publicly, including issues, comments, and contributions to other Users' repositories, may be viewed by others. By setting your repositories to be viewed publicly, you agree to allow others to view and "fork" your repositories (this means that others may make their own copies of Content from your repositories in repositories they control).

    -

    If you set your pages and repositories to be viewed publicly, you grant each User of Your Forgejo Instance a nonexclusive, worldwide license to use, display, and perform Your Content through the Your Forgejo Instance Service and to reproduce Your Content solely on Your Forgejo Instance as permitted through Your Forgejo Instance's functionality (for example, through forking). You may grant further rights if you adopt a license. If you are uploading Content you did not create or own, you are responsible for ensuring that the Content you upload is licensed under terms that grant these permissions to other Your Forgejo Instance Users.

    +

    If you set your pages and repositories to be viewed publicly, you grant each User of Your Gitea Instance a nonexclusive, worldwide license to use, display, and perform Your Content through the Your Gitea Instance Service and to reproduce Your Content solely on Your Gitea Instance as permitted through Your Gitea Instance's functionality (for example, through forking). You may grant further rights if you adopt a license. If you are uploading Content you did not create or own, you are responsible for ensuring that the Content you upload is licensed under terms that grant these permissions to other Your Gitea Instance Users.

  • @@ -97,7 +97,7 @@
  • You retain all moral rights to Your Content that you upload, publish, or submit to any part of the Service, including the rights of integrity and attribution. However, you waive these rights and agree not to assert them against us, to enable us to reasonably exercise the rights granted above, but not otherwise.

    -

    To the extent this agreement is not enforceable by applicable law, you grant Your Forgejo Instance the rights we need to use Your Content without attribution and to make reasonable adaptations of Your Content as necessary to render the Website and provide the Service.

    +

    To the extent this agreement is not enforceable by applicable law, you grant Your Gitea Instance the rights we need to use Your Content without attribution and to make reasonable adaptations of Your Content as necessary to render the Website and provide the Service.

  • @@ -106,27 +106,27 @@
    1. Some Accounts may have private repositories, which allow the User to control access to Content.
    2. -
    3. Your Forgejo Instance considers the contents of private repositories to be confidential to you. Your Forgejo Instance will protect the contents of private repositories from unauthorized use, access, or disclosure in the same manner that we would use to protect our own confidential information of a similar nature and in no event with less than a reasonable degree of care.
    4. +
    5. Your Gitea Instance considers the contents of private repositories to be confidential to you. Your Gitea Instance will protect the contents of private repositories from unauthorized use, access, or disclosure in the same manner that we would use to protect our own confidential information of a similar nature and in no event with less than a reasonable degree of care.
    6. -

      Your Forgejo Instance employees may only access the content of your private repositories in the following situations:

      +

      Your Gitea Instance employees may only access the content of your private repositories in the following situations:

        -
      • With your consent and knowledge, for support reasons. If Your Forgejo Instance accesses a private repository for support reasons, we will only do so with the owner’s consent and knowledge.
      • -
      • When access is required for security reasons, including when access is required to maintain ongoing confidentiality, integrity, availability and resilience of Your Forgejo Instance's systems and Service.
      • +
      • With your consent and knowledge, for support reasons. If Your Gitea Instance accesses a private repository for support reasons, we will only do so with the owner’s consent and knowledge.
      • +
      • When access is required for security reasons, including when access is required to maintain ongoing confidentiality, integrity, availability and resilience of Your Gitea Instance's systems and Service.
    7. -
    8. You may choose to enable additional access to your private repositories. For example: You may enable various Your Forgejo Instance services or features that require additional rights to Your Content in private repositories. These rights may vary depending on the service or feature, but Your Forgejo Instance will continue to treat your private repository Content as confidential. If those services or features require rights in addition to those we need to provide the Your Forgejo Instance Service, we will provide an explanation of those rights.
    9. +
    10. You may choose to enable additional access to your private repositories. For example: You may enable various Your Gitea Instance services or features that require additional rights to Your Content in private repositories. These rights may vary depending on the service or feature, but Your Gitea Instance will continue to treat your private repository Content as confidential. If those services or features require rights in addition to those we need to provide the Your Gitea Instance Service, we will provide an explanation of those rights.

    Copyright Infringement and DMCA Policy

    -

    If you are copyright owner and believe that content on our website violates your copyright, please contact us at copyright@your-forgejo-instance. Please note that before sending a takedown notice, consider legal uses (such as fair use and licensed use); and legal consequences for sending false notices.

    +

    If you are copyright owner and believe that content on our website violates your copyright, please contact us at copyright@your-gitea-instance. Please note that before sending a takedown notice, consider legal uses (such as fair use and licensed use); and legal consequences for sending false notices.

    Intellectual Properties and COPYING

    -

    Your Forgejo Instance and our licensors, vendors, agents, and/or our content providers retain ownership of all intellectual property rights of any kind related to the Website and Service. We reserve all rights that are not expressly granted to you under this Agreement or by law. The look and feel of the Website and Service is copyright © Your Forgejo Instance. All rights reserved.

    +

    Your Gitea Instance and our licensors, vendors, agents, and/or our content providers retain ownership of all intellectual property rights of any kind related to the Website and Service. We reserve all rights that are not expressly granted to you under this Agreement or by law. The look and feel of the Website and Service is copyright © Your Gitea Instance. All rights reserved.

    If you'd like to use our trademarks, you must follow all of our trademark guidelines.

    @@ -134,13 +134,13 @@

    API Terms

    -

    Abuse or excessively frequent requests to Your Forgejo Instance via the API may result in the temporary or permanent suspension of your Account's access to the API. Your Forgejo Instance, in our sole discretion, will determine abuse or excessive usage of the API. We will make a reasonable attempt to warn you via email prior to suspension.

    +

    Abuse or excessively frequent requests to Your Gitea Instance via the API may result in the temporary or permanent suspension of your Account's access to the API. Your Gitea Instance, in our sole discretion, will determine abuse or excessive usage of the API. We will make a reasonable attempt to warn you via email prior to suspension.

    -

    You may not share API tokens to exceed Your Forgejo Instance's rate limitations.

    +

    You may not share API tokens to exceed Your Gitea Instance's rate limitations.

    -

    You may not use the API to download data or Content from Your Forgejo Instance for spamming purposes, including for the purposes of selling Your Forgejo Instance users' personal information, such as to recruiters, headhunters, and job boards.

    +

    You may not use the API to download data or Content from Your Gitea Instance for spamming purposes, including for the purposes of selling Your Gitea Instance users' personal information, such as to recruiters, headhunters, and job boards.

    -

    All use of the Your Forgejo Instance API is subject to these Terms of Service and the Your Forgejo Instance Privacy Statement.

    +

    All use of the Your Gitea Instance API is subject to these Terms of Service and the Your Gitea Instance Privacy Statement.

    However, we may provide subscription-based access to our API for Users who need high-throughput access or reselling our Service.

    @@ -149,7 +149,7 @@

    Account Cancellation

    -

    It is your responsibility to properly cancel your Account with Your Forgejo Instance. You can cancel your Account at any time by going into your Settings in the global navigation bar at the top of the screen. The Account screen provides a simple, no questions asked cancellation link. We are not able to cancel Accounts in response to an email or phone request.

    +

    It is your responsibility to properly cancel your Account with Your Gitea Instance. You can cancel your Account at any time by going into your Settings in the global navigation bar at the top of the screen. The Account screen provides a simple, no questions asked cancellation link. We are not able to cancel Accounts in response to an email or phone request.

    Upon Cancellation

    @@ -161,7 +161,7 @@

    We May Terminate

    -

    Your Forgejo Instance has the right to suspend or terminate your access to all or any part of the Website at any time, with or without cause, with or without notice, effective immediately. Your Forgejo Instance reserves the right to refuse service to anyone for any reason at any time.

    +

    Your Gitea Instance has the right to suspend or terminate your access to all or any part of the Website at any time, with or without cause, with or without notice, effective immediately. Your Gitea Instance reserves the right to refuse service to anyone for any reason at any time.

    Survival

    @@ -175,7 +175,7 @@

    Legal Notices to Us Must Be in Writing

    -

    Communications made through email or Your Forgejo Instance Support's messaging system will not constitute legal notice to Your Forgejo Instance or any of its officers, employees, agents or representatives in any situation where notice to Your Forgejo Instance is required by contract or any law or regulation. Legal notice to Your Forgejo Instance must be in writing and served on Your Forgejo Instance's legal agent.

    +

    Communications made through email or Your Gitea Instance Support's messaging system will not constitute legal notice to Your Gitea Instance or any of its officers, employees, agents or representatives in any situation where notice to Your Gitea Instance is required by contract or any law or regulation. Legal notice to Your Gitea Instance must be in writing and served on Your Gitea Instance's legal agent.

    No Phone Support

    @@ -183,9 +183,9 @@

    Disclaimer of Warranties

    -

    Your Forgejo Instance provides the Website and the Service “as is” and “as available,” without warranty of any kind. Without limiting this, we expressly disclaim all warranties, whether express, implied or statutory, regarding the Website and the Service including without limitation any warranty of merchantability, fitness for a particular purpose, title, security, accuracy and non-infringement.

    +

    Your Gitea Instance provides the Website and the Service “as is” and “as available,” without warranty of any kind. Without limiting this, we expressly disclaim all warranties, whether express, implied or statutory, regarding the Website and the Service including without limitation any warranty of merchantability, fitness for a particular purpose, title, security, accuracy and non-infringement.

    -

    Your Forgejo Instance does not warrant that the Service will meet your requirements; that the Service will be uninterrupted, timely, secure, or error-free; that the information provided through the Service is accurate, reliable or correct; that any defects or errors will be corrected; that the Service will be available at any particular time or location; or that the Service is free of viruses or other harmful components. You assume full responsibility and risk of loss resulting from your downloading and/or use of files, information, content or other material obtained from the Service.

    +

    Your Gitea Instance does not warrant that the Service will meet your requirements; that the Service will be uninterrupted, timely, secure, or error-free; that the information provided through the Service is accurate, reliable or correct; that any defects or errors will be corrected; that the Service will be available at any particular time or location; or that the Service is free of viruses or other harmful components. You assume full responsibility and risk of loss resulting from your downloading and/or use of files, information, content or other material obtained from the Service.

    Limitation of Liability

    @@ -212,9 +212,9 @@

    Release and Indemnification

    -

    If you have a dispute with one or more Users, you agree to release Your Forgejo Instance from any and all claims, demands and damages (actual and consequential) of every kind and nature, known and unknown, arising out of or in any way connected with such disputes.

    +

    If you have a dispute with one or more Users, you agree to release Your Gitea Instance from any and all claims, demands and damages (actual and consequential) of every kind and nature, known and unknown, arising out of or in any way connected with such disputes.

    -

    You agree to indemnify us, defend us, and hold us harmless from and against any and all claims, liabilities, and expenses, including attorneys’ fees, arising out of your use of the Website and the Service, including but not limited to your violation of this Agreement, provided that Your Forgejo Instance (1) promptly gives you written notice of the claim, demand, suit or proceeding; (2) gives you sole control of the defense and settlement of the claim, demand, suit or proceeding (provided that you may not settle any claim, demand, suit or proceeding unless the settlement unconditionally releases Your Forgejo Instance of all liability); and (3) provides to you all reasonable assistance, at your expense.

    +

    You agree to indemnify us, defend us, and hold us harmless from and against any and all claims, liabilities, and expenses, including attorneys’ fees, arising out of your use of the Website and the Service, including but not limited to your violation of this Agreement, provided that Your Gitea Instance (1) promptly gives you written notice of the claim, demand, suit or proceeding; (2) gives you sole control of the defense and settlement of the claim, demand, suit or proceeding (provided that you may not settle any claim, demand, suit or proceeding unless the settlement unconditionally releases Your Gitea Instance of all liability); and (3) provides to you all reasonable assistance, at your expense.

    Changes to These Terms

    @@ -224,22 +224,22 @@

    Governing Law

    -

    Except to the extent applicable law provides otherwise, this Agreement between you and us and any access to or use of the Website or the Service are governed by (national laws of country/state where Forgejo is deployed) and (regional laws of locality where Forgejo is deployed), without regard to conflict of law provisions. You and Your Forgejo Instance agree to submit to the exclusive jurisdiction and venue of the courts located in (locality where Forgejo is deployed).

    +

    Except to the extent applicable law provides otherwise, this Agreement between you and us and any access to or use of the Website or the Service are governed by (national laws of country/state where Gitea is deployed) and (regional laws of locality where Gitea is deployed), without regard to conflict of law provisions. You and Your Gitea Instance agree to submit to the exclusive jurisdiction and venue of the courts located in (locality where Gitea is deployed).

    Non-Assignability

    -

    Your Forgejo Instance may assign or delegate these Terms of Service and/or our Privacy Policy in whole or in part, to any person or entity at any time with or without your consent, including the license granted in User-Generated Content. You may not assign or delegate any rights or obligations under the Terms of Service or Privacy Statement without our prior written consent, and any unauthorized assignment and delegation by you is void.

    +

    Your Gitea Instance may assign or delegate these Terms of Service and/or our Privacy Policy in whole or in part, to any person or entity at any time with or without your consent, including the license granted in User-Generated Content. You may not assign or delegate any rights or obligations under the Terms of Service or Privacy Statement without our prior written consent, and any unauthorized assignment and delegation by you is void.

    Severablity, No Waiver, and Survival

    -

    If any part of this Agreement is held invalid or unenforceable, that portion of the Agreement will be construed to reflect the parties’ original intent. The remaining portions will remain in full force and effect. Any failure on the part of Your Forgejo Instance to enforce any provision of this Agreement will not be considered a waiver of our right to enforce such provision. Our rights under this Agreement will survive any termination of this Agreement.

    +

    If any part of this Agreement is held invalid or unenforceable, that portion of the Agreement will be construed to reflect the parties’ original intent. The remaining portions will remain in full force and effect. Any failure on the part of Your Gitea Instance to enforce any provision of this Agreement will not be considered a waiver of our right to enforce such provision. Our rights under this Agreement will survive any termination of this Agreement.

    Amendments and Complete Agreement

    -

    This Agreement may only be modified by a written amendment signed by an authorized representative of Your Forgejo Instance, or by the posting by Your Forgejo Instance of a revised version in accordance with Changes to These Terms. These Terms of Service, together with the Your Forgejo Instance Privacy Policy, represent the complete and exclusive statement of the agreement between you and us. This Agreement supersedes any proposal or prior agreement oral or written, and any other communications between you and Your Forgejo Instance relating to the subject matter of these terms including any confidentiality or nondisclosure agreements.

    +

    This Agreement may only be modified by a written amendment signed by an authorized representative of Your Gitea Instance, or by the posting by Your Gitea Instance of a revised version in accordance with Changes to These Terms. These Terms of Service, together with the Your Gitea Instance Privacy Policy, represent the complete and exclusive statement of the agreement between you and us. This Agreement supersedes any proposal or prior agreement oral or written, and any other communications between you and Your Gitea Instance relating to the subject matter of these terms including any confidentiality or nondisclosure agreements.

    Contact

    -

    If you have questions about these Terms of Service, you can contact our support.

    +

    If you have questions about these Terms of Service, you can contact our support.

    diff --git a/contrib/systemd/forgejo.service b/contrib/systemd/forgejo.service index ee019e11ea..04ef69adc0 100644 --- a/contrib/systemd/forgejo.service +++ b/contrib/systemd/forgejo.service @@ -61,7 +61,7 @@ WorkingDirectory=/var/lib/forgejo/ #RuntimeDirectory=forgejo ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini Restart=always -Environment=USER=git HOME=/home/git FORGEJO_WORK_DIR=/var/lib/forgejo +Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/forgejo # If you install Git to directory prefix other than default PATH (which happens # for example if you install other versions of Git side-to-side with # distribution version), uncomment below line and add that prefix to PATH diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 37724610a3..cdd0f4d007 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -183,7 +183,7 @@ RUN_USER = ; git ;; ;; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, ;; for system SSH this setting has no effect -;SSH_SERVER_KEY_EXCHANGES = mlkem768x25519-sha256, curve25519-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1 +;SSH_SERVER_KEY_EXCHANGES = curve25519-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1 ;; ;; For the built-in SSH server, choose the MACs to support for SSH connections, ;; for system SSH this setting has no effect @@ -328,10 +328,6 @@ RUN_USER = ; git ;; Maximum number of locks returned per page ;LFS_LOCKS_PAGING_NUM = 50 ;; -;; When clients make lfs batch requests, reject them if there are more pointers than this number -;; zero means 'unlimited' -;LFS_MAX_BATCH_SIZE = 0 -;; ;; Allow graceful restarts using SIGHUP to fork ;ALLOW_GRACEFUL_RESTARTS = true ;; @@ -353,25 +349,16 @@ RUN_USER = ; git ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; Database to use. Either "sqlite3", "mySQL" or "postgres". -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; SQLite Configuration -;; -DB_TYPE = sqlite3 -;PATH= ; defaults to data/forgejo.db -;SQLITE_TIMEOUT = ; Query timeout defaults to: 500 -;SQLITE_JOURNAL_MODE = ; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode +;; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3". ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; MySQL Configuration ;; -;DB_TYPE = mysql -;HOST = 127.0.0.1:3306 ; can use socket e.g. /var/run/mysqld/mysqld.sock -;NAME = gitea -;USER = root +DB_TYPE = mysql +HOST = 127.0.0.1:3306 ; can use socket e.g. /var/run/mysqld/mysqld.sock +NAME = gitea +USER = root ;PASSWD = ;Use PASSWD = `your password` for quoting if you use special characters in the password. ;SSL_MODE = false ; either "false" (default), "true", or "skip-verify" ;CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need. @@ -390,6 +377,26 @@ DB_TYPE = sqlite3 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; SQLite Configuration +;; +;DB_TYPE = sqlite3 +;PATH= ; defaults to data/forgejo.db +;SQLITE_TIMEOUT = ; Query timeout defaults to: 500 +;SQLITE_JOURNAL_MODE = ; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; MSSQL Configuration +;; +;DB_TYPE = mssql +;HOST = 172.17.0.2:1433 +;NAME = gitea +;USER = SA +;PASSWD = MwantsaSecurePassword1 +;CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; Other settings ;; ;; For iterate buffer, default is 50 @@ -522,8 +529,7 @@ INTERNAL_TOKEN = ;; HMAC to encode urls with, it **is required** if camo is enabled. ;HMAC_KEY = ;; Set to true to use camo for https too lese only non https urls are proxyed -;; ALLWAYS is deprecated and will be removed in the future -;ALWAYS = false +;ALLWAYS = false ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -629,7 +635,7 @@ LEVEL = Info ;[log.%(WriterMode)] ;MODE=console/file/conn/... ;LEVEL= -;FLAGS = stdflags or journald +;FLAGS = stdflags ;EXPRESSION = ;PREFIX = ;COLORIZE = false @@ -726,7 +732,6 @@ LEVEL = Info ;CLONE = 300 ;PULL = 300 ;GC = 60 -;GREP = 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Git config options @@ -901,9 +906,6 @@ LEVEL = Info ;; Show Registration button ;SHOW_REGISTRATION_BUTTON = true ;; -;; Whether to allow internal signin -; ENABLE_INTERNAL_SIGNIN = true -;; ;; Show milestones dashboard page - a view of all the user's milestones ;SHOW_MILESTONES_DASHBOARD_PAGE = true ;; @@ -921,24 +923,6 @@ LEVEL = Info ;; Valid site url schemes for user profiles ;VALID_SITE_URL_SCHEMES=http,https -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[service.explore] -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; Only allow signed in users to view the explore pages. -;REQUIRE_SIGNIN_VIEW = false -;; -;; Disable the users explore page. -;DISABLE_USERS_PAGE = false -;; -;; Disable the organizations explore page. -;DISABLE_ORGANIZATIONS_PAGE = false -;; -;; Disable the code explore page. -;DISABLE_CODE_PAGE = false -;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1025,10 +1009,6 @@ LEVEL = Info ;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS. ;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls ;; -;; Comma separated list of default mirror repo units. -;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS. -;DEFAULT_MIRROR_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.wiki,repo.projects,repo.packages -;; ;; Prefix archive files by placing them in a directory named after the repository ;PREFIX_ARCHIVE_FILES = true ;; @@ -1135,6 +1115,9 @@ LEVEL = Info ;; Add co-authored-by and co-committed-by trailers if committer does not match author ;ADD_CO_COMMITTER_TRAILERS = true ;; +;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply +;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false +;; ;; Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo. ;RETARGET_CHILDREN_ON_MERGE = true @@ -1164,13 +1147,9 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; Signing format that Forgejo should use, openpgp uses GPG and ssh uses OpenSSH. -;FORMAT = openpgp -;; ;; GPG key to use to sign commits, Defaults to the default - that is the value of git config --get user.signingkey ;; run in the context of the RUN_USER -;; Switch to none to stop signing completely. -;; If `FORMAT` is set to **ssh** this should be set to an absolute path to an public OpenSSH key. +;; Switch to none to stop signing completely ;SIGNING_KEY = default ;; ;; If a SIGNING_KEY ID is provided and is not set to default, use the provided Name and Email address as the signer. @@ -1576,15 +1555,6 @@ LEVEL = Info ;; - manage_gpg_keys: a user cannot configure gpg keys ;;EXTERNAL_USER_DISABLE_FEATURES = -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[moderation] -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; When true enables moderation capabilities; default is false. -;; If enabled it will be possible for users to report abusive content (new actions are added in the UI and /report_abuse route will be enabled) and a new Moderation section will be added to Admin settings where the reports can be reviewed. -;ENABLED = false - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[openid] @@ -1757,10 +1727,6 @@ LEVEL = Info ;; Sometimes it is helpful to use a different address on the envelope. Set this to use ENVELOPE_FROM as the from on the envelope. Set to `<>` to send an empty address. ;ENVELOPE_FROM = ;; -;; If gitea sends mails on behave of users, it will just use the name also displayed in the WebUI. If you want e.g. `Mister X (by CodeIt) `, -;; set it to `{{ .DisplayName }} (by {{ .AppName }})`. Available Variables: `.DisplayName`, `.AppName` and `.Domain`. -;FROM_DISPLAY_NAME_FORMAT = {{ .DisplayName }} -;; ;; Mailer user name and password, if required by provider. ;USER = ;; @@ -1955,7 +1921,7 @@ LEVEL = Info ;ENABLED = true ;; ;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. -;ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip +;ALLOWED_TYPES = .cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip ;; ;; Max size of each file. Defaults to 2048MB ;MAX_SIZE = 2048 @@ -1993,7 +1959,7 @@ LEVEL = Info ;; Url lookup for the minio bucket only available when STORAGE_TYPE is `minio` ;; Available values: auto, dns, path ;; If empty, it behaves the same as "auto" was set -;MINIO_BUCKET_LOOKUP = +;MINIO_BUCKET_LOOKUP = ;; ;; Minio location to create bucket only available when STORAGE_TYPE is `minio` ;MINIO_LOCATION = us-east-1 @@ -2324,7 +2290,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Delete all old activities from database +;; Delete all old actions from database ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[cron.delete_old_actions] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2421,8 +2387,8 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The first locale will be used as the default if user browser's language doesn't match any locale in the list. -;LANGS = en-US,zh-CN,zh-HK,zh-TW,da,de-DE,nds,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg,it-IT,fi-FI,fil,eo,tr-TR,cs-CZ,sl,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID -;NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Dansk,Deutsch,Plattdüütsch,Français,Nederlands,Latviešu,Русский,Українська,日本語,Español,Português do Brasil,Português de Portugal,Polski,Български,Italiano,Suomi,Filipino,Esperanto,Türkçe,Čeština,Slovenščina,Svenska,한국어,Ελληνικά,فارسی,Magyar nyelv,Bahasa Indonesia +;LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN +;NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,Français,Nederlands,Latviešu,Русский,Українська,日本語,Español,Português do Brasil,Português de Portugal,Polski,Български,Italiano,Suomi,Türkçe,Čeština,Српски,Svenska,한국어,Ελληνικά,فارسی,Magyar nyelv,Bahasa Indonesia,മലയാളം ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2454,7 +2420,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits) -;MERMAID_MAX_SOURCE_CHARACTERS = 50000 +;MERMAID_MAX_SOURCE_CHARACTERS = 5000 ;; Set the maximum number of lines allowed for a filepreview. (Set to -1 to disable limits; set to 0 to disable the feature) ;FILEPREVIEW_MAX_LINES = 50 @@ -2633,8 +2599,6 @@ LEVEL = Info ;LIMIT_SIZE_SWIFT = -1 ;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_VAGRANT = -1 -;; Enable RPM re-signing by default. (It will overwrite the old signature ,using v4 format, not compatible with CentOS 6 or older) -;DEFAULT_RPM_SIGN_ENABLED = false ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2682,16 +2646,6 @@ LEVEL = Info ;; override the minio base path if storage type is minio ;MINIO_BASE_PATH = lfs/ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; settings for Gitea's LFS client (eg: mirroring an upstream lfs endpoint) -;; -;[lfs_client] -;; Limit the number of pointers in each batch request to this number -;BATCH_SIZE = 20 -;; Limit the number of concurrent upload/download operations within a batch -;BATCH_OPERATION_CONCURRENCY = 8 - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[annex] @@ -2700,8 +2654,6 @@ LEVEL = Info ;; ;; Whether git-annex is enabled; defaults to false ;ENABLED = false -;; Whether to disable p2phttp support; default is the same as repository.DISABLE_HTTP_GIT -;DISABLE_P2PHTTP = false ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2737,7 +2689,7 @@ LEVEL = Info ;; Url lookup for the minio bucket only available when STORAGE_TYPE is `minio` ;; Available values: auto, dns, path ;; If empty, it behaves the same as "auto" was set -;MINIO_BUCKET_LOOKUP = +;MINIO_BUCKET_LOOKUP = ;; ;; Minio location to create bucket only available when STORAGE_TYPE is `minio` ;MINIO_LOCATION = us-east-1 @@ -2761,15 +2713,7 @@ LEVEL = Info ;ENABLED = true ;; Default address to get action plugins, e.g. the default value means downloading from "https://code.forgejo.org/actions/checkout" for "uses: actions/checkout@v3" ;DEFAULT_ACTIONS_URL = https://code.forgejo.org -;; Logs retention time in days. Old logs will be deleted after this period. -;LOG_RETENTION_DAYS = 365 -;; Log compression type, `none` for no compression, `zstd` for zstd compression. -;; Other compression types like `gzip` are NOT supported, since seekable stream is required for log view. -;; It's always recommended to use compression when using local disk as log storage if CPU or memory is not a bottleneck. -;; And for object storage services like S3, which is billed for requests, it would cause extra 2 times of get requests for each log view. -;; But it will save storage space and network bandwidth, so it's still recommended to use compression. -;LOG_COMPRESSION = zstd -;; Default artifact retention time in days. Artifacts could have their own retention periods by setting the `retention-days` option in `actions/upload-artifact` step. +;; Default artifact retention time in days, default is 90 days ;ARTIFACT_RETENTION_DAYS = 90 ;; Timeout to stop the task which have running status, but haven't been updated for a long time ;ZOMBIE_TASK_TIMEOUT = 10m diff --git a/docker/root/etc/s6/openssh/setup b/docker/root/etc/s6/openssh/setup index 48e7d4b211..dbb3bafd35 100755 --- a/docker/root/etc/s6/openssh/setup +++ b/docker/root/etc/s6/openssh/setup @@ -31,21 +31,6 @@ if [ -e /data/ssh/ssh_host_ecdsa_cert ]; then SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_cert"} fi -# In case someone wants to sign the `{keyname}.pub` key by `ssh-keygen -s ca -I identity ...` to -# make use of the ssh-key certificate authority feature (see ssh-keygen CERTIFICATES section), -# the generated key file name is `{keyname}-cert.pub` -if [ -e /data/ssh/ssh_host_ed25519_key-cert.pub ]; then - SSH_ED25519_CERT=${SSH_ED25519_CERT:-"/data/ssh/ssh_host_ed25519_key-cert.pub"} -fi - -if [ -e /data/ssh/ssh_host_rsa_key-cert.pub ]; then - SSH_RSA_CERT=${SSH_RSA_CERT:-"/data/ssh/ssh_host_rsa_key-cert.pub"} -fi - -if [ -e /data/ssh/ssh_host_ecdsa_key-cert.pub ]; then - SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_key-cert.pub"} -fi - if [ -d /etc/ssh ]; then SSH_PORT=${SSH_PORT:-"22"} \ SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \ diff --git a/docker/root/usr/bin/entrypoint b/docker/root/usr/bin/entrypoint index 08587fc4f4..d9dbb3ebe0 100755 --- a/docker/root/usr/bin/entrypoint +++ b/docker/root/usr/bin/entrypoint @@ -37,5 +37,5 @@ done if [ $# -gt 0 ]; then exec "$@" else - exec /usr/bin/s6-svscan /etc/s6 + exec /bin/s6-svscan /etc/s6 fi diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 28cfa80089..0000000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,1179 +0,0 @@ -import eslintCommunityEslintPluginEslintComments from '@eslint-community/eslint-plugin-eslint-comments'; -import stylisticEslintPlugin from '@stylistic/eslint-plugin'; -import vitest from '@vitest/eslint-plugin'; -import arrayFunc from 'eslint-plugin-array-func'; -import eslintPluginImportX from 'eslint-plugin-import-x'; -import noJquery from 'eslint-plugin-no-jquery'; -import noUseExtendNative from 'eslint-plugin-no-use-extend-native'; -import regexp from 'eslint-plugin-regexp'; -import sonarjs from 'eslint-plugin-sonarjs'; -import unicorn from 'eslint-plugin-unicorn'; -import playwright from 'eslint-plugin-playwright'; -import vitestGlobals from 'eslint-plugin-vitest-globals'; -import wc from 'eslint-plugin-wc'; -import globals from 'globals'; -import vue from 'eslint-plugin-vue'; -import vueScopedCss from 'eslint-plugin-vue-scoped-css'; -import toml from 'eslint-plugin-toml'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config( - ...tseslint.configs.recommended, - eslintPluginImportX.flatConfigs.typescript, - { - ignores: ['web_src/js/vendor', 'web_src/fomantic', 'public/assets/js', 'tests/e2e/reports/'], - }, - { - plugins: { - '@eslint-community/eslint-comments': eslintCommunityEslintPluginEslintComments, - '@stylistic': stylisticEslintPlugin, - '@vitest': vitest, - 'array-func': arrayFunc, - 'no-jquery': noJquery, - 'no-use-extend-native': noUseExtendNative, - regexp, - sonarjs, - unicorn, - playwright, - toml, - 'vitest-globals': vitestGlobals, - vue, - 'vue-scoped-css': vueScopedCss, - wc, - }, - - linterOptions: { - reportUnusedDisableDirectives: true, - }, - - languageOptions: { - globals: { - ...globals.node, - }, - parserOptions: { - ecmaVersion: 'latest', - }, - - ecmaVersion: 'latest', - sourceType: 'module', - }, - rules: { - '@typescript-eslint/no-unused-vars': 'off', // TODO: enable this rule again - - '@eslint-community/eslint-comments/disable-enable-pair': [2], - '@eslint-community/eslint-comments/no-aggregating-enable': [2], - '@eslint-community/eslint-comments/no-duplicate-disable': [2], - '@eslint-community/eslint-comments/no-restricted-disable': [0], - '@eslint-community/eslint-comments/no-unlimited-disable': [2], - '@eslint-community/eslint-comments/no-unused-disable': [2], - '@eslint-community/eslint-comments/no-unused-enable': [2], - '@eslint-community/eslint-comments/no-use': [0], - '@eslint-community/eslint-comments/require-description': [0], - '@stylistic/array-bracket-newline': [0], - '@stylistic/array-bracket-spacing': [2, 'never'], - '@stylistic/array-element-newline': [0], - '@stylistic/arrow-parens': [2, 'always'], - - '@stylistic/arrow-spacing': [2, { - before: true, - after: true, - }], - - '@stylistic/block-spacing': [0], - - '@stylistic/brace-style': [2, '1tbs', { - allowSingleLine: true, - }], - - '@stylistic/comma-dangle': [2, 'always-multiline'], - - '@stylistic/comma-spacing': [2, { - before: false, - after: true, - }], - - '@stylistic/comma-style': [2, 'last'], - '@stylistic/computed-property-spacing': [2, 'never'], - '@stylistic/dot-location': [2, 'property'], - '@stylistic/eol-last': [2], - '@stylistic/function-call-spacing': [2, 'never'], - '@stylistic/function-call-argument-newline': [0], - '@stylistic/function-paren-newline': [0], - '@stylistic/generator-star-spacing': [0], - '@stylistic/implicit-arrow-linebreak': [0], - - '@stylistic/indent': [2, 2, { - ignoreComments: true, - SwitchCase: 1, - }], - - '@stylistic/key-spacing': [2], - '@stylistic/keyword-spacing': [2], - '@stylistic/linebreak-style': [2, 'unix'], - '@stylistic/lines-around-comment': [0], - '@stylistic/lines-between-class-members': [0], - '@stylistic/max-len': [0], - '@stylistic/max-statements-per-line': [0], - '@stylistic/multiline-ternary': [0], - '@stylistic/new-parens': [2], - '@stylistic/newline-per-chained-call': [0], - '@stylistic/no-confusing-arrow': [0], - '@stylistic/no-extra-parens': [0], - '@stylistic/no-extra-semi': [2], - '@stylistic/no-floating-decimal': [0], - '@stylistic/no-mixed-operators': [0], - '@stylistic/no-mixed-spaces-and-tabs': [2], - - '@stylistic/no-multi-spaces': [2, { - ignoreEOLComments: true, - - exceptions: { - Property: true, - }, - }], - - '@stylistic/no-multiple-empty-lines': [2, { - max: 1, - maxEOF: 0, - maxBOF: 0, - }], - - '@stylistic/no-tabs': [2], - '@stylistic/no-trailing-spaces': [2], - '@stylistic/no-whitespace-before-property': [2], - '@stylistic/nonblock-statement-body-position': [2], - '@stylistic/object-curly-newline': [0], - '@stylistic/object-curly-spacing': [2, 'never'], - '@stylistic/object-property-newline': [0], - '@stylistic/one-var-declaration-per-line': [0], - '@stylistic/operator-linebreak': [2, 'after'], - '@stylistic/padded-blocks': [2, 'never'], - '@stylistic/padding-line-between-statements': [0], - '@stylistic/quote-props': [0], - - '@stylistic/quotes': [2, 'single', { - avoidEscape: true, - allowTemplateLiterals: true, - }], - - '@stylistic/rest-spread-spacing': [2, 'never'], - - '@stylistic/semi': [2, 'always', { - omitLastInOneLineBlock: true, - }], - - '@stylistic/semi-spacing': [2, { - before: false, - after: true, - }], - - '@stylistic/semi-style': [2, 'last'], - '@stylistic/space-before-blocks': [2, 'always'], - - '@stylistic/space-before-function-paren': [2, { - anonymous: 'ignore', - named: 'never', - asyncArrow: 'always', - }], - - '@stylistic/space-in-parens': [2, 'never'], - '@stylistic/space-infix-ops': [2], - '@stylistic/space-unary-ops': [2], - '@stylistic/spaced-comment': [2, 'always'], - '@stylistic/switch-colon-spacing': [2], - '@stylistic/template-curly-spacing': [2, 'never'], - '@stylistic/template-tag-spacing': [2, 'never'], - '@stylistic/wrap-iife': [2, 'inside'], - '@stylistic/wrap-regex': [0], - '@stylistic/yield-star-spacing': [2, 'after'], - 'accessor-pairs': [2], - - 'array-callback-return': [2, { - checkForEach: true, - }], - - 'array-func/avoid-reverse': [2], - 'array-func/from-map': [2], - 'array-func/no-unnecessary-this-arg': [2], - 'array-func/prefer-array-from': [2], - 'array-func/prefer-flat-map': [0], - 'array-func/prefer-flat': [0], - 'arrow-body-style': [0], - 'block-scoped-var': [2], - camelcase: [0], - 'capitalized-comments': [0], - 'class-methods-use-this': [0], - complexity: [0], - 'consistent-return': [0], - 'consistent-this': [0], - 'constructor-super': [2], - curly: [0], - 'default-case-last': [2], - 'default-case': [0], - 'default-param-last': [0], - 'dot-notation': [0], - eqeqeq: [2], - 'for-direction': [2], - 'func-name-matching': [2], - 'func-names': [0], - 'func-style': [0], - 'getter-return': [2], - 'grouped-accessor-pairs': [2], - 'guard-for-in': [0], - 'id-blacklist': [0], - 'id-length': [0], - 'id-match': [0], - 'init-declarations': [0], - 'line-comment-position': [0], - 'logical-assignment-operators': [0], - 'max-classes-per-file': [0], - 'max-depth': [0], - 'max-lines-per-function': [0], - 'max-lines': [0], - 'max-nested-callbacks': [0], - 'max-params': [0], - 'max-statements': [0], - 'multiline-comment-style': [2, 'separate-lines'], - 'new-cap': [0], - 'no-alert': [0], - 'no-array-constructor': [2], - 'no-async-promise-executor': [0], - 'no-await-in-loop': [0], - 'no-bitwise': [0], - 'no-buffer-constructor': [0], - 'no-caller': [2], - 'no-case-declarations': [2], - 'no-class-assign': [2], - 'no-compare-neg-zero': [2], - 'no-cond-assign': [2, 'except-parens'], - - 'no-console': [1, { - allow: ['debug', 'info', 'warn', 'error'], - }], - - 'no-const-assign': [2], - 'no-constant-binary-expression': [2], - 'no-constant-condition': [0], - 'no-constructor-return': [2], - 'no-continue': [0], - 'no-control-regex': [0], - 'no-debugger': [1], - 'no-delete-var': [2], - 'no-div-regex': [0], - 'no-dupe-args': [2], - 'no-dupe-class-members': [2], - 'no-dupe-else-if': [2], - 'no-dupe-keys': [2], - 'no-duplicate-case': [2], - 'no-duplicate-imports': [2], - 'no-else-return': [2], - 'no-empty-character-class': [2], - 'no-empty-function': [0], - 'no-empty-pattern': [2], - 'no-empty-static-block': [2], - - 'no-empty': [2, { - allowEmptyCatch: true, - }], - - 'no-eq-null': [2], - 'no-eval': [2], - 'no-ex-assign': [2], - 'no-extend-native': [2], - 'no-extra-bind': [2], - 'no-extra-boolean-cast': [2], - 'no-extra-label': [0], - 'no-fallthrough': [2], - 'no-func-assign': [2], - 'no-global-assign': [2], - 'no-implicit-coercion': [2], - 'no-implicit-globals': [0], - 'no-implied-eval': [2], - 'no-import-assign': [2], - 'no-inline-comments': [0], - 'no-inner-declarations': [2], - 'no-invalid-regexp': [2], - 'no-invalid-this': [0], - 'no-irregular-whitespace': [2], - 'no-iterator': [2], - 'no-jquery/no-ajax-events': [2], - 'no-jquery/no-ajax': [2], - 'no-jquery/no-and-self': [2], - 'no-jquery/no-animate-toggle': [2], - 'no-jquery/no-animate': [2], - 'no-jquery/no-append-html': [2], - 'no-jquery/no-attr': [2], - 'no-jquery/no-bind': [2], - 'no-jquery/no-box-model': [2], - 'no-jquery/no-browser': [2], - 'no-jquery/no-camel-case': [2], - 'no-jquery/no-class-state': [2], - 'no-jquery/no-class': [0], - 'no-jquery/no-clone': [2], - 'no-jquery/no-closest': [0], - 'no-jquery/no-constructor-attributes': [2], - 'no-jquery/no-contains': [2], - 'no-jquery/no-context-prop': [2], - 'no-jquery/no-css': [2], - 'no-jquery/no-data': [0], - 'no-jquery/no-deferred': [2], - 'no-jquery/no-delegate': [2], - 'no-jquery/no-done-fail': [2], - 'no-jquery/no-each-collection': [0], - 'no-jquery/no-each-util': [2], - 'no-jquery/no-each': [0], - 'no-jquery/no-error-shorthand': [2], - 'no-jquery/no-error': [2], - 'no-jquery/no-escape-selector': [2], - 'no-jquery/no-event-shorthand': [2], - 'no-jquery/no-extend': [2], - 'no-jquery/no-fade': [2], - 'no-jquery/no-filter': [0], - 'no-jquery/no-find-collection': [0], - 'no-jquery/no-find-util': [2], - 'no-jquery/no-find': [0], - 'no-jquery/no-fx': [2], - 'no-jquery/no-fx-interval': [2], - 'no-jquery/no-global-eval': [2], - 'no-jquery/no-global-selector': [0], - 'no-jquery/no-grep': [2], - 'no-jquery/no-has': [2], - 'no-jquery/no-hold-ready': [2], - 'no-jquery/no-html': [0], - 'no-jquery/no-in-array': [2], - 'no-jquery/no-is-array': [2], - 'no-jquery/no-is-empty-object': [2], - 'no-jquery/no-is-function': [2], - 'no-jquery/no-is-numeric': [2], - 'no-jquery/no-is-plain-object': [2], - 'no-jquery/no-is-window': [2], - 'no-jquery/no-is': [2], - 'no-jquery/no-jquery-constructor': [0], - 'no-jquery/no-live': [2], - 'no-jquery/no-load-shorthand': [2], - 'no-jquery/no-load': [2], - 'no-jquery/no-map-collection': [2], - 'no-jquery/no-map-util': [2], - 'no-jquery/no-map': [2], - 'no-jquery/no-merge': [2], - 'no-jquery/no-node-name': [2], - 'no-jquery/no-noop': [2], - 'no-jquery/no-now': [2], - 'no-jquery/no-on-ready': [2], - 'no-jquery/no-other-methods': [0], - 'no-jquery/no-other-utils': [2], - 'no-jquery/no-param': [2], - 'no-jquery/no-parent': [0], - 'no-jquery/no-parents': [2], - 'no-jquery/no-parse-html-literal': [2], - 'no-jquery/no-parse-html': [2], - 'no-jquery/no-parse-json': [2], - 'no-jquery/no-parse-xml': [2], - 'no-jquery/no-prop': [2], - 'no-jquery/no-proxy': [2], - 'no-jquery/no-ready-shorthand': [2], - 'no-jquery/no-ready': [2], - 'no-jquery/no-selector-prop': [2], - 'no-jquery/no-serialize': [2], - 'no-jquery/no-size': [2], - 'no-jquery/no-sizzle': [2], - 'no-jquery/no-slide': [2], - 'no-jquery/no-sub': [2], - 'no-jquery/no-support': [2], - 'no-jquery/no-text': [0], - 'no-jquery/no-trigger': [2], - 'no-jquery/no-trim': [2], - 'no-jquery/no-type': [2], - 'no-jquery/no-unique': [2], - 'no-jquery/no-unload-shorthand': [2], - 'no-jquery/no-val': [0], - 'no-jquery/no-visibility': [2], - 'no-jquery/no-when': [2], - 'no-jquery/no-wrap': [2], - 'no-jquery/variable-pattern': [2], - 'no-label-var': [2], - 'no-labels': [0], - 'no-lone-blocks': [2], - 'no-lonely-if': [0], - 'no-loop-func': [0], - 'no-loss-of-precision': [2], - 'no-magic-numbers': [0], - 'no-misleading-character-class': [2], - 'no-multi-assign': [0], - 'no-multi-str': [2], - 'no-negated-condition': [0], - 'no-nested-ternary': [0], - 'no-new-func': [2], - 'no-new-native-nonconstructor': [2], - 'no-new-object': [2], - 'no-new-symbol': [2], - 'no-new-wrappers': [2], - 'no-new': [0], - 'no-nonoctal-decimal-escape': [2], - 'no-obj-calls': [2], - 'no-octal-escape': [2], - 'no-octal': [2], - 'no-param-reassign': [0], - 'no-plusplus': [0], - 'no-promise-executor-return': [0], - 'no-proto': [2], - 'no-prototype-builtins': [2], - 'no-redeclare': [2], - 'no-regex-spaces': [2], - 'no-restricted-exports': [0], - - 'no-restricted-globals': [ - 2, - 'addEventListener', - 'blur', - 'close', - 'closed', - 'confirm', - 'defaultStatus', - 'defaultstatus', - 'error', - 'event', - 'external', - 'find', - 'focus', - 'frameElement', - 'frames', - 'history', - 'innerHeight', - 'innerWidth', - 'isFinite', - 'isNaN', - 'length', - 'location', - 'locationbar', - 'menubar', - 'moveBy', - 'moveTo', - 'name', - 'onblur', - 'onerror', - 'onfocus', - 'onload', - 'onresize', - 'onunload', - 'open', - 'opener', - 'opera', - 'outerHeight', - 'outerWidth', - 'pageXOffset', - 'pageYOffset', - 'parent', - 'print', - 'removeEventListener', - 'resizeBy', - 'resizeTo', - 'screen', - 'screenLeft', - 'screenTop', - 'screenX', - 'screenY', - 'scroll', - 'scrollbars', - 'scrollBy', - 'scrollTo', - 'scrollX', - 'scrollY', - 'self', - 'status', - 'statusbar', - 'stop', - 'toolbar', - 'top', - '__dirname', - '__filename', - ], - - 'no-restricted-imports': [0], - - 'no-restricted-syntax': [ - 2, - 'WithStatement', - 'ForInStatement', - 'LabeledStatement', - 'SequenceExpression', - { - selector: "CallExpression[callee.name='fetch']", - message: 'use modules/fetch.js instead', - }, - ], - - 'no-return-assign': [0], - 'no-script-url': [2], - - 'no-self-assign': [2, { - props: true, - }], - - 'no-self-compare': [2], - 'no-sequences': [2], - 'no-setter-return': [2], - 'no-shadow-restricted-names': [2], - 'no-shadow': [0], - 'no-sparse-arrays': [2], - 'no-template-curly-in-string': [2], - 'no-ternary': [0], - 'no-this-before-super': [2], - 'no-throw-literal': [2], - 'no-undef-init': [2], - - 'no-undef': [2, { - typeof: true, - }], - - 'no-undefined': [0], - 'no-underscore-dangle': [0], - 'no-unexpected-multiline': [2], - 'no-unmodified-loop-condition': [2], - 'no-unneeded-ternary': [2], - 'no-unreachable-loop': [2], - 'no-unreachable': [2], - 'no-unsafe-finally': [2], - 'no-unsafe-negation': [2], - 'no-unused-expressions': [2], - 'no-unused-labels': [2], - 'no-unused-private-class-members': [2], - - 'no-unused-vars': [2, { - args: 'all', - argsIgnorePattern: '^_', - varsIgnorePattern: '^_', - caughtErrorsIgnorePattern: '^_', - destructuredArrayIgnorePattern: '^_', - ignoreRestSiblings: false, - }], - - 'no-use-before-define': [2, { - functions: false, - classes: true, - variables: true, - allowNamedExports: true, - }], - - 'no-use-extend-native/no-use-extend-native': [2], - 'no-useless-backreference': [2], - 'no-useless-call': [2], - 'no-useless-catch': [2], - 'no-useless-computed-key': [2], - 'no-useless-concat': [2], - 'no-useless-constructor': [2], - 'no-useless-escape': [2], - 'no-useless-rename': [2], - 'no-useless-return': [2], - 'no-var': [2], - 'no-void': [2], - 'no-warning-comments': [0], - 'no-with': [0], - 'object-shorthand': [2, 'always'], - 'one-var-declaration-per-line': [0], - 'one-var': [0], - 'operator-assignment': [2, 'always'], - 'operator-linebreak': [2, 'after'], - - 'prefer-arrow-callback': [2, { - allowNamedFunctions: true, - allowUnboundThis: true, - }], - - 'prefer-const': [2, { - destructuring: 'all', - ignoreReadBeforeAssign: true, - }], - - 'prefer-destructuring': [0], - 'prefer-exponentiation-operator': [2], - 'prefer-named-capture-group': [0], - 'prefer-numeric-literals': [2], - 'prefer-object-has-own': [2], - 'prefer-object-spread': [2], - - 'prefer-promise-reject-errors': [2, { - allowEmptyReject: false, - }], - - 'prefer-regex-literals': [2], - 'prefer-rest-params': [2], - 'prefer-spread': [2], - 'prefer-template': [2], - radix: [2, 'as-needed'], - 'regexp/confusing-quantifier': [2], - 'regexp/control-character-escape': [2], - 'regexp/hexadecimal-escape': [0], - 'regexp/letter-case': [0], - 'regexp/match-any': [2], - 'regexp/negation': [2], - 'regexp/no-contradiction-with-assertion': [0], - 'regexp/no-control-character': [0], - 'regexp/no-dupe-characters-character-class': [2], - 'regexp/no-dupe-disjunctions': [2], - 'regexp/no-empty-alternative': [2], - 'regexp/no-empty-capturing-group': [2], - 'regexp/no-empty-character-class': [0], - 'regexp/no-empty-group': [2], - 'regexp/no-empty-lookarounds-assertion': [2], - 'regexp/no-empty-string-literal': [2], - 'regexp/no-escape-backspace': [2], - 'regexp/no-extra-lookaround-assertions': [0], - 'regexp/no-invalid-regexp': [2], - 'regexp/no-invisible-character': [2], - 'regexp/no-lazy-ends': [2], - 'regexp/no-legacy-features': [2], - 'regexp/no-misleading-capturing-group': [0], - 'regexp/no-misleading-unicode-character': [0], - 'regexp/no-missing-g-flag': [2], - 'regexp/no-non-standard-flag': [2], - 'regexp/no-obscure-range': [2], - 'regexp/no-octal': [2], - 'regexp/no-optional-assertion': [2], - 'regexp/no-potentially-useless-backreference': [2], - 'regexp/no-standalone-backslash': [2], - 'regexp/no-super-linear-backtracking': [0], - 'regexp/no-super-linear-move': [0], - 'regexp/no-trivially-nested-assertion': [2], - 'regexp/no-trivially-nested-quantifier': [2], - 'regexp/no-unused-capturing-group': [0], - 'regexp/no-useless-assertions': [2], - 'regexp/no-useless-backreference': [2], - 'regexp/no-useless-character-class': [2], - 'regexp/no-useless-dollar-replacements': [2], - 'regexp/no-useless-escape': [2], - 'regexp/no-useless-flag': [2], - 'regexp/no-useless-lazy': [2], - 'regexp/no-useless-non-capturing-group': [2], - 'regexp/no-useless-quantifier': [2], - 'regexp/no-useless-range': [2], - 'regexp/no-useless-set-operand': [2], - 'regexp/no-useless-string-literal': [2], - 'regexp/no-useless-two-nums-quantifier': [2], - 'regexp/no-zero-quantifier': [2], - 'regexp/optimal-lookaround-quantifier': [2], - 'regexp/optimal-quantifier-concatenation': [0], - 'regexp/prefer-character-class': [0], - 'regexp/prefer-d': [0], - 'regexp/prefer-escape-replacement-dollar-char': [0], - 'regexp/prefer-lookaround': [0], - 'regexp/prefer-named-backreference': [0], - 'regexp/prefer-named-capture-group': [0], - 'regexp/prefer-named-replacement': [0], - 'regexp/prefer-plus-quantifier': [2], - 'regexp/prefer-predefined-assertion': [2], - 'regexp/prefer-quantifier': [0], - 'regexp/prefer-question-quantifier': [2], - 'regexp/prefer-range': [2], - 'regexp/prefer-regexp-exec': [2], - 'regexp/prefer-regexp-test': [2], - 'regexp/prefer-result-array-groups': [0], - 'regexp/prefer-set-operation': [2], - 'regexp/prefer-star-quantifier': [2], - 'regexp/prefer-unicode-codepoint-escapes': [2], - 'regexp/prefer-w': [0], - 'regexp/require-unicode-regexp': [0], - 'regexp/simplify-set-operations': [2], - 'regexp/sort-alternatives': [0], - 'regexp/sort-character-class-elements': [0], - 'regexp/sort-flags': [0], - 'regexp/strict': [2], - 'regexp/unicode-escape': [0], - 'regexp/use-ignore-case': [0], - 'require-atomic-updates': [0], - 'require-await': [0], - 'require-unicode-regexp': [0], - 'require-yield': [2], - 'sonarjs/cognitive-complexity': [0], - 'sonarjs/elseif-without-else': [0], - 'sonarjs/max-switch-cases': [0], - 'sonarjs/no-all-duplicated-branches': [2], - 'sonarjs/no-collapsible-if': [0], - 'sonarjs/no-collection-size-mischeck': [2], - 'sonarjs/no-duplicate-string': [0], - 'sonarjs/no-duplicated-branches': [0], - 'sonarjs/no-element-overwrite': [2], - 'sonarjs/no-empty-collection': [2], - 'sonarjs/no-extra-arguments': [2], - 'sonarjs/no-gratuitous-expressions': [2], - 'sonarjs/no-identical-conditions': [2], - 'sonarjs/no-identical-expressions': [2], - 'sonarjs/no-identical-functions': [2, 5], - 'sonarjs/no-ignored-return': [2], - 'sonarjs/no-inverted-boolean-check': [2], - 'sonarjs/no-nested-switch': [0], - 'sonarjs/no-nested-template-literals': [0], - 'sonarjs/no-one-iteration-loop': [2], - 'sonarjs/no-redundant-boolean': [2], - 'sonarjs/no-redundant-jump': [2], - 'sonarjs/no-same-line-conditional': [2], - 'sonarjs/no-small-switch': [0], - 'sonarjs/no-unused-collection': [2], - 'sonarjs/no-use-of-empty-return-value': [2], - 'sonarjs/no-useless-catch': [2], - 'sonarjs/non-existent-operator': [2], - 'sonarjs/prefer-immediate-return': [0], - 'sonarjs/prefer-object-literal': [0], - 'sonarjs/prefer-single-boolean-return': [0], - 'sonarjs/prefer-while': [2], - 'sort-imports': [0], - 'sort-keys': [0], - 'sort-vars': [0], - strict: [0], - 'symbol-description': [2], - 'unicode-bom': [2, 'never'], - 'unicorn/better-regex': [0], - 'unicorn/catch-error-name': [0], - 'unicorn/consistent-assert': [0], - 'unicorn/consistent-date-clone': [2], - 'unicorn/consistent-destructuring': [2], - 'unicorn/consistent-empty-array-spread': [2], - 'unicorn/consistent-existence-index-check': [2], - 'unicorn/consistent-function-scoping': [2], - 'unicorn/custom-error-definition': [0], - 'unicorn/empty-brace-spaces': [2], - 'unicorn/error-message': [0], - 'unicorn/escape-case': [0], - 'unicorn/expiring-todo-comments': [0], - 'unicorn/explicit-length-check': [0], - 'unicorn/filename-case': [0], - 'unicorn/import-index': [0], - 'unicorn/import-style': [0], - 'unicorn/new-for-builtins': [2], - 'unicorn/no-accessor-recursion': [2], - 'unicorn/no-abusive-eslint-disable': [0], - 'unicorn/no-anonymous-default-export': [0], - 'unicorn/no-array-callback-reference': [0], - 'unicorn/no-array-for-each': [2], - 'unicorn/no-array-method-this-argument': [2], - 'unicorn/no-array-reduce': [2], - 'unicorn/no-await-expression-member': [0], - 'unicorn/no-await-in-promise-methods': [2], - 'unicorn/no-console-spaces': [0], - 'unicorn/no-document-cookie': [2], - 'unicorn/no-empty-file': [2], - 'unicorn/no-for-loop': [0], - 'unicorn/no-hex-escape': [0], - 'unicorn/no-instanceof-builtins': [0], - 'unicorn/no-invalid-fetch-options': [2], - 'unicorn/no-invalid-remove-event-listener': [2], - 'unicorn/no-keyword-prefix': [0], - 'unicorn/no-lonely-if': [2], - 'unicorn/no-magic-array-flat-depth': [0], - 'unicorn/no-named-default': [2], - 'unicorn/no-negated-condition': [0], - 'unicorn/no-negation-in-equality-check': [2], - 'unicorn/no-nested-ternary': [0], - 'unicorn/no-new-array': [0], - 'unicorn/no-new-buffer': [0], - 'unicorn/no-null': [0], - 'unicorn/no-object-as-default-parameter': [0], - 'unicorn/no-process-exit': [0], - 'unicorn/no-single-promise-in-promise-methods': [2], - 'unicorn/no-static-only-class': [2], - 'unicorn/no-thenable': [2], - 'unicorn/no-this-assignment': [2], - 'unicorn/no-typeof-undefined': [2], - 'unicorn/no-unnecessary-array-flat-depth': [2], - 'unicorn/no-unnecessary-array-splice-count': [2], - 'unicorn/no-unnecessary-await': [2], - 'unicorn/no-unnecessary-polyfills': [2], - 'unicorn/no-unnecessary-slice-end': [2], - 'unicorn/no-unreadable-array-destructuring': [0], - 'unicorn/no-unreadable-iife': [2], - 'unicorn/no-unused-properties': [2], - 'unicorn/no-useless-fallback-in-spread': [2], - 'unicorn/no-useless-length-check': [2], - 'unicorn/no-useless-promise-resolve-reject': [2], - 'unicorn/no-useless-spread': [2], - 'unicorn/no-useless-switch-case': [2], - 'unicorn/no-useless-undefined': [0], - 'unicorn/no-zero-fractions': [2], - 'unicorn/number-literal-case': [0], - 'unicorn/numeric-separators-style': [0], - 'unicorn/prefer-add-event-listener': [2], - 'unicorn/prefer-array-find': [2], - 'unicorn/prefer-array-flat-map': [2], - 'unicorn/prefer-array-flat': [2], - 'unicorn/prefer-array-index-of': [2], - 'unicorn/prefer-array-some': [2], - 'unicorn/prefer-at': [0], - 'unicorn/prefer-blob-reading-methods': [2], - 'unicorn/prefer-code-point': [0], - 'unicorn/prefer-date-now': [2], - 'unicorn/prefer-default-parameters': [0], - 'unicorn/prefer-dom-node-append': [2], - 'unicorn/prefer-dom-node-dataset': [0], - 'unicorn/prefer-dom-node-remove': [2], - 'unicorn/prefer-dom-node-text-content': [2], - 'unicorn/prefer-event-target': [2], - 'unicorn/prefer-export-from': [0], - 'unicorn/prefer-global-this': [0], - 'unicorn/prefer-import-meta-properties': [2], - 'unicorn/prefer-includes': [2], - 'unicorn/prefer-json-parse-buffer': [0], - 'unicorn/prefer-keyboard-event-key': [2], - 'unicorn/prefer-logical-operator-over-ternary': [2], - 'unicorn/prefer-math-min-max': [2], - 'unicorn/prefer-math-trunc': [2], - 'unicorn/prefer-modern-dom-apis': [0], - 'unicorn/prefer-modern-math-apis': [2], - 'unicorn/prefer-module': [2], - 'unicorn/prefer-native-coercion-functions': [2], - 'unicorn/prefer-negative-index': [2], - 'unicorn/prefer-node-protocol': [2], - 'unicorn/prefer-number-properties': [0], - 'unicorn/prefer-object-from-entries': [2], - 'unicorn/prefer-object-has-own': [0], - 'unicorn/prefer-optional-catch-binding': [2], - 'unicorn/prefer-prototype-methods': [0], - 'unicorn/prefer-query-selector': [0], - 'unicorn/prefer-reflect-apply': [0], - 'unicorn/prefer-regexp-test': [2], - 'unicorn/prefer-set-has': [0], - 'unicorn/prefer-set-size': [2], - 'unicorn/prefer-single-call': [2], - 'unicorn/prefer-spread': [0], - 'unicorn/prefer-string-raw': [0], - 'unicorn/prefer-string-replace-all': [0], - 'unicorn/prefer-string-slice': [0], - 'unicorn/prefer-string-starts-ends-with': [2], - 'unicorn/prefer-string-trim-start-end': [2], - 'unicorn/prefer-structured-clone': [2], - 'unicorn/prefer-switch': [0], - 'unicorn/prefer-ternary': [0], - 'unicorn/prefer-top-level-await': [0], - 'unicorn/prefer-type-error': [0], - 'unicorn/prevent-abbreviations': [0], - 'unicorn/relative-url-style': [2], - 'unicorn/require-array-join-separator': [2], - 'unicorn/require-number-to-fixed-digits-argument': [2], - 'unicorn/require-post-message-target-origin': [0], - 'unicorn/string-content': [0], - 'unicorn/switch-case-braces': [0], - 'unicorn/template-indent': [2], - 'unicorn/text-encoding-identifier-case': [0], - 'unicorn/throw-new-error': [2], - 'use-isnan': [2], - - 'valid-typeof': [2, { - requireStringLiterals: true, - }], - - 'vars-on-top': [0], - 'wc/attach-shadow-constructor': [2], - 'wc/define-tag-after-class-definition': [0], - 'wc/expose-class-on-global': [0], - 'wc/file-name-matches-element': [2], - 'wc/guard-define-call': [0], - 'wc/guard-super-call': [2], - 'wc/max-elements-per-file': [0], - 'wc/no-child-traversal-in-attributechangedcallback': [2], - 'wc/no-child-traversal-in-connectedcallback': [2], - 'wc/no-closed-shadow-root': [2], - 'wc/no-constructor-attributes': [2], - 'wc/no-constructor-params': [2], - 'wc/no-constructor': [2], - 'wc/no-customized-built-in-elements': [2], - 'wc/no-exports-with-element': [0], - 'wc/no-invalid-element-name': [2], - 'wc/no-invalid-extends': [2], - 'wc/no-method-prefixed-with-on': [2], - 'wc/no-self-class': [2], - 'wc/no-typos': [2], - 'wc/require-listener-teardown': [2], - 'wc/tag-name-matches-class': [2], - yoda: [2, 'never'], - }, - }, - { - ignores: ['*.vue', '**/*.vue'], - rules: { - 'import-x/consistent-type-specifier-style': [0], - 'import-x/default': [0], - 'import-x/dynamic-import-chunkname': [0], - 'import-x/export': [2], - 'import-x/exports-last': [0], - - 'import-x/extensions': [2, 'always', { - ignorePackages: true, - }], - - 'import-x/first': [2], - 'import-x/group-exports': [0], - 'import-x/max-dependencies': [0], - 'import-x/named': [2], - 'import-x/namespace': [0], - 'import-x/newline-after-import': [0], - 'import-x/no-absolute-path': [0], - 'import-x/no-amd': [2], - 'import-x/no-anonymous-default-export': [0], - 'import-x/no-commonjs': [2], - - 'import-x/no-cycle': [2, { - ignoreExternal: true, - maxDepth: 1, - }], - - 'import-x/no-default-export': [0], - 'import-x/no-deprecated': [0], - 'import-x/no-dynamic-require': [0], - 'import-x/no-empty-named-blocks': [2], - 'import-x/no-extraneous-dependencies': [2], - 'import-x/no-import-module-exports': [0], - 'import-x/no-internal-modules': [0], - 'import-x/no-mutable-exports': [0], - 'import-x/no-named-as-default-member': [0], - 'import-x/no-named-as-default': [2], - 'import-x/no-named-default': [0], - 'import-x/no-named-export': [0], - 'import-x/no-namespace': [0], - 'import-x/no-nodejs-modules': [0], - 'import-x/no-relative-packages': [0], - 'import-x/no-relative-parent-imports': [0], - 'import-x/no-restricted-paths': [0], - 'import-x/no-self-import': [2], - 'import-x/no-unassigned-import': [0], - - 'import-x/no-unresolved': [2, { - commonjs: true, - ignore: ['\\?.+$', '^vitest/'], - }], - - 'import-x/no-useless-path-segments': [2, { - commonjs: true, - }], - - 'import-x/no-webpack-loader-syntax': [2], - 'import-x/order': [0], - 'import-x/prefer-default-export': [0], - 'import-x/unambiguous': [0], - }, - }, - { - files: ['web_src/**/*'], - languageOptions: { - globals: { - __webpack_public_path__: true, - process: false, - }, - }, - }, { - files: ['web_src/**/*', 'docs/**/*'], - - languageOptions: { - globals: { - ...globals.browser, - }, - }, - }, { - files: ['web_src/**/*worker.*'], - - languageOptions: { - globals: { - ...globals.worker, - }, - }, - - rules: { - 'no-restricted-globals': [ - 2, - 'addEventListener', - 'blur', - 'close', - 'closed', - 'confirm', - 'defaultStatus', - 'defaultstatus', - 'error', - 'event', - 'external', - 'find', - 'focus', - 'frameElement', - 'frames', - 'history', - 'innerHeight', - 'innerWidth', - 'isFinite', - 'isNaN', - 'length', - 'locationbar', - 'menubar', - 'moveBy', - 'moveTo', - 'name', - 'onblur', - 'onerror', - 'onfocus', - 'onload', - 'onresize', - 'onunload', - 'open', - 'opener', - 'opera', - 'outerHeight', - 'outerWidth', - 'pageXOffset', - 'pageYOffset', - 'parent', - 'print', - 'removeEventListener', - 'resizeBy', - 'resizeTo', - 'screen', - 'screenLeft', - 'screenTop', - 'screenX', - 'screenY', - 'scroll', - 'scrollbars', - 'scrollBy', - 'scrollTo', - 'scrollX', - 'scrollY', - 'status', - 'statusbar', - 'stop', - 'toolbar', - 'top', - ], - }, - }, { - files: ['**/*.config.*'], - languageOptions: { - ecmaVersion: 'latest', - }, - rules: { - 'import-x/no-unused-modules': [0], - 'import-x/no-unresolved': [0], - 'import-x/no-named-as-default': [0], - }, - }, { - files: ['**/*.test.*', 'web_src/js/test/setup.js'], - languageOptions: { - globals: { - ...vitestGlobals.environments.env.globals, - }, - }, - - rules: { - '@vitest/consistent-test-filename': [0], - '@vitest/consistent-test-it': [0], - '@vitest/expect-expect': [0], - '@vitest/max-expects': [0], - '@vitest/max-nested-describe': [0], - '@vitest/no-alias-methods': [0], - '@vitest/no-commented-out-tests': [0], - '@vitest/no-conditional-expect': [0], - '@vitest/no-conditional-in-test': [0], - '@vitest/no-conditional-tests': [0], - '@vitest/no-disabled-tests': [0], - '@vitest/no-done-callback': [0], - '@vitest/no-duplicate-hooks': [0], - '@vitest/no-focused-tests': [0], - '@vitest/no-hooks': [0], - '@vitest/no-identical-title': [2], - '@vitest/no-interpolation-in-snapshots': [0], - '@vitest/no-large-snapshots': [0], - '@vitest/no-mocks-import': [0], - '@vitest/no-restricted-matchers': [0], - '@vitest/no-restricted-vi-methods': [0], - '@vitest/no-standalone-expect': [0], - '@vitest/no-test-prefixes': [0], - '@vitest/no-test-return-statement': [0], - '@vitest/prefer-called-with': [0], - '@vitest/prefer-comparison-matcher': [0], - '@vitest/prefer-each': [0], - '@vitest/prefer-equality-matcher': [0], - '@vitest/prefer-expect-resolves': [0], - '@vitest/prefer-hooks-in-order': [0], - '@vitest/prefer-hooks-on-top': [2], - '@vitest/prefer-lowercase-title': [0], - '@vitest/prefer-mock-promise-shorthand': [0], - '@vitest/prefer-snapshot-hint': [0], - '@vitest/prefer-spy-on': [0], - '@vitest/prefer-strict-equal': [0], - '@vitest/prefer-to-be': [0], - '@vitest/prefer-to-be-falsy': [0], - '@vitest/prefer-to-be-object': [0], - '@vitest/prefer-to-be-truthy': [0], - '@vitest/prefer-to-contain': [0], - '@vitest/prefer-to-have-length': [0], - '@vitest/prefer-todo': [0], - '@vitest/require-hook': [0], - '@vitest/require-to-throw-message': [0], - '@vitest/require-top-level-describe': [0], - '@vitest/valid-describe-callback': [2], - '@vitest/valid-expect': [2], - '@vitest/valid-title': [2], - }, - }, { - files: ['web_src/js/modules/fetch.js', 'web_src/js/standalone/**/*'], - - rules: { - 'no-restricted-syntax': [ - 2, - 'WithStatement', - 'ForInStatement', - 'LabeledStatement', - 'SequenceExpression', - ], - }, - }, { - files: ['tests/e2e/**/*.ts'], - languageOptions: { - globals: { - ...globals.browser, - }, - - ecmaVersion: 'latest', - sourceType: 'module', - }, - rules: { - ...playwright.configs['flat/recommended'].rules, - 'playwright/no-conditional-in-test': [0], - 'playwright/no-conditional-expect': [0], - // allow grouping helper functions with tests - 'unicorn/consistent-function-scoping': [0], - - 'playwright/no-skipped-test': [ - 2, - { - allowConditional: true, - }, - ], - 'playwright/no-useless-await': [2], - - 'playwright/prefer-comparison-matcher': [2], - 'playwright/prefer-equality-matcher': [2], - 'playwright/prefer-native-locators': [2], - 'playwright/prefer-to-contain': [2], - 'playwright/prefer-to-have-length': [2], - 'playwright/require-to-throw-message': [2], - }, - }, - ...vue.configs['flat/recommended'], - { - files: ['web_src/js/components/*.vue'], - languageOptions: { - globals: { - ...globals.browser, - }, - - ecmaVersion: 'latest', - sourceType: 'module', - }, - rules: { - 'vue/attributes-order': [0], - 'vue/html-closing-bracket-spacing': [2, { - startTag: 'never', - endTag: 'never', - selfClosingTag: 'never', - }], - 'vue/max-attributes-per-line': [0], - 'vue-scoped-css/enforce-style-type': [0], - }, - }, - ...toml.configs['flat/recommended'], -); diff --git a/flake.lock b/flake.lock index dcf7755013..606f8836c1 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1749285348, - "narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=", + "lastModified": 1717974879, + "narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "3e3afe5174c561dee0df6f2c2b2236990146329f", + "rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 01b23258b9..22354663dd 100644 --- a/flake.nix +++ b/flake.nix @@ -4,19 +4,35 @@ flake-utils.url = "github:numtide/flake-utils"; }; outputs = - { - nixpkgs, - flake-utils, - ... - }: + { nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = nixpkgs.legacyPackages.${system}; in { - devShells.default = import ./shell.nix { inherit pkgs; }; - formatter = pkgs.nixfmt-rfc-style; + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + # generic + git + git-lfs + gnumake + gnused + gnutar + gzip + + # frontend + nodejs_20 + + # linting + python312 + poetry + + # backend + go_1_22 + gofumpt + ]; + }; } ); } diff --git a/go.mod b/go.mod index bb2be827eb..32d8b9b4d7 100644 --- a/go.mod +++ b/go.mod @@ -1,251 +1,315 @@ -module forgejo.org +module code.gitea.io/gitea -go 1.24 +go 1.22.0 -toolchain go1.24.4 +toolchain go1.22.5 require ( - code.forgejo.org/f3/gof3/v3 v3.11.0 - code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 - code.forgejo.org/forgejo/go-rpmutils v1.0.0 - code.forgejo.org/forgejo/levelqueue v1.0.0 + code.forgejo.org/f3/gof3/v3 v3.4.0 code.forgejo.org/forgejo/reply v1.0.2 - code.forgejo.org/go-chi/binding v1.0.1 - code.forgejo.org/go-chi/cache v1.0.1 - code.forgejo.org/go-chi/captcha v1.0.2 - code.forgejo.org/go-chi/session v1.0.2 code.gitea.io/actions-proto-go v0.4.0 - code.gitea.io/sdk/gitea v0.21.0 + code.gitea.io/gitea-vet v0.2.3 + code.gitea.io/sdk/gitea v0.17.1 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 - connectrpc.com/connect v1.18.1 - github.com/42wim/httpsig v1.2.3 - github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920 + connectrpc.com/connect v1.16.2 + gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed + gitea.com/go-chi/cache v0.2.0 + gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 + gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96 + gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 + github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 - github.com/ProtonMail/go-crypto v1.3.0 - github.com/PuerkitoBio/goquery v1.10.3 - github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 - github.com/alecthomas/chroma/v2 v2.18.0 + github.com/ProtonMail/go-crypto v1.0.0 + github.com/PuerkitoBio/goquery v1.9.2 + github.com/alecthomas/chroma/v2 v2.14.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb - github.com/blevesearch/bleve/v2 v2.5.2 - github.com/buildkite/terminal-to-html/v3 v3.16.8 - github.com/caddyserver/certmagic v0.23.0 + github.com/blevesearch/bleve/v2 v2.4.0 + github.com/buildkite/terminal-to-html/v3 v3.10.1 + github.com/caddyserver/certmagic v0.21.0 github.com/chi-middleware/proxy v1.1.1 github.com/djherbis/buffer v1.2.0 github.com/djherbis/nio/v3 v3.0.1 - github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 + github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 github.com/dustin/go-humanize v1.0.1 - github.com/editorconfig/editorconfig-core-go/v2 v2.6.3 + github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 github.com/emersion/go-imap v1.2.1 - github.com/felixge/fgprof v0.9.5 - github.com/fsnotify/fsnotify v1.9.0 - github.com/gliderlabs/ssh v0.3.8 + github.com/emirpasic/gods v1.18.1 + github.com/felixge/fgprof v0.9.4 + github.com/fsnotify/fsnotify v1.7.0 + github.com/gliderlabs/ssh v0.3.7 github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 - github.com/go-chi/chi/v5 v5.2.2 + github.com/go-chi/chi/v5 v5.0.14 github.com/go-chi/cors v1.2.1 github.com/go-co-op/gocron v1.37.0 - github.com/go-enry/go-enry/v2 v2.9.2 - github.com/go-git/go-git/v5 v5.13.2 + github.com/go-enry/go-enry/v2 v2.8.8 + github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e + github.com/go-git/go-billy/v5 v5.5.0 + github.com/go-git/go-git/v5 v5.11.0 github.com/go-ldap/ldap/v3 v3.4.6 - github.com/go-openapi/spec v0.21.0 - github.com/go-sql-driver/mysql v1.9.3 - github.com/go-webauthn/webauthn v0.13.0 + github.com/go-sql-driver/mysql v1.8.1 + github.com/go-swagger/go-swagger v0.30.5 + github.com/go-testfixtures/testfixtures/v3 v3.11.0 + github.com/go-webauthn/webauthn v0.10.0 github.com/gobwas/glob v0.2.3 github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 - github.com/golang-jwt/jwt/v5 v5.2.2 - github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/google/go-github/v64 v64.0.0 - github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e + github.com/golang-jwt/jwt/v5 v5.2.0 + github.com/google/go-github/v57 v57.0.0 + github.com/google/pprof v0.0.0-20240528025155-186aa0362fba github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.2.0 - github.com/gorilla/sessions v1.4.0 - github.com/hashicorp/go-version v1.7.0 + github.com/gorilla/sessions v1.2.2 + github.com/h2non/gock v1.2.0 + github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/huandu/xstrings v1.5.0 github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 - github.com/jhillyerd/enmime/v2 v2.1.0 + github.com/jhillyerd/enmime v1.2.0 github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/klauspost/compress v1.18.0 - github.com/klauspost/cpuid/v2 v2.2.10 + github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 + github.com/klauspost/compress v1.17.9 + github.com/klauspost/cpuid/v2 v2.2.7 github.com/lib/pq v1.10.9 github.com/markbates/goth v1.80.0 github.com/mattn/go-isatty v0.0.20 - github.com/mattn/go-sqlite3 v1.14.28 - github.com/meilisearch/meilisearch-go v0.31.0 + github.com/mattn/go-sqlite3 v1.14.22 + github.com/meilisearch/meilisearch-go v0.26.1 github.com/mholt/archiver/v3 v3.5.1 - github.com/microcosm-cc/bluemonday v1.0.27 - github.com/minio/minio-go/v7 v7.0.94 - github.com/msteinert/pam/v2 v2.1.0 + github.com/microcosm-cc/bluemonday v1.0.26 + github.com/minio/minio-go/v7 v7.0.70 + github.com/msteinert/pam v1.2.0 github.com/nektos/act v0.2.52 - github.com/niklasfasching/go-org v1.8.0 + github.com/niklasfasching/go-org v1.7.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 + github.com/opencontainers/image-spec v1.1.0 github.com/pquerna/otp v1.4.0 - github.com/prometheus/client_golang v1.21.1 - github.com/redis/go-redis/v9 v9.8.0 + github.com/prometheus/client_golang v1.18.0 + github.com/quasoft/websspi v1.1.2 + github.com/redis/go-redis/v9 v9.5.2 github.com/robfig/cron/v3 v3.0.1 - github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 - github.com/sergi/go-diff v1.4.0 - github.com/stretchr/testify v1.10.0 + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 + github.com/sassoftware/go-rpmutils v0.2.1-0.20240124161140-277b154961dd + github.com/sergi/go-diff v1.3.1 + github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 + github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.0 - github.com/ulikunitz/xz v0.5.12 - github.com/urfave/cli/v3 v3.3.3 + github.com/ulikunitz/xz v0.5.11 + github.com/urfave/cli/v2 v2.27.2 github.com/valyala/fastjson v1.6.4 + github.com/xanzy/go-gitlab v0.96.0 github.com/yohcop/openid-go v1.0.1 - github.com/yuin/goldmark v1.7.12 + github.com/yuin/goldmark v1.7.4 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc - gitlab.com/gitlab-org/api/client-go v0.130.1 - go.uber.org/mock v0.5.2 - golang.org/x/crypto v0.39.0 - golang.org/x/image v0.27.0 - golang.org/x/net v0.41.0 - golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.15.0 - golang.org/x/sys v0.33.0 - golang.org/x/text v0.26.0 - google.golang.org/protobuf v1.36.4 + github.com/yuin/goldmark-meta v1.1.0 + go.uber.org/mock v0.4.0 + golang.org/x/crypto v0.24.0 + golang.org/x/image v0.18.0 + golang.org/x/net v0.26.0 + golang.org/x/oauth2 v0.21.0 + golang.org/x/sys v0.21.0 + golang.org/x/text v0.16.0 + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d + google.golang.org/grpc v1.60.1 + google.golang.org/protobuf v1.33.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 mvdan.cc/xurls/v2 v2.5.0 + strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 xorm.io/builder v0.3.13 - xorm.io/xorm v1.3.9 + xorm.io/xorm v1.3.7 ) require ( - cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect - github.com/andybalholm/brotli v1.1.1 // indirect - github.com/andybalholm/cascadia v1.3.3 // indirect + github.com/ClickHouse/ch-go v0.61.5 // indirect + github.com/ClickHouse/clickhouse-go/v2 v2.24.0 // indirect + github.com/DataDog/zstd v1.5.5 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/RoaringBitmap/roaring v1.7.0 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/andybalholm/cascadia v1.3.2 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.22.0 // indirect - github.com/blevesearch/bleve_index_api v1.2.8 // indirect - github.com/blevesearch/geo v0.2.3 // indirect - github.com/blevesearch/go-faiss v1.0.25 // indirect + github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/blevesearch/bleve_index_api v1.1.6 // indirect + github.com/blevesearch/geo v0.1.20 // indirect + github.com/blevesearch/go-faiss v1.0.13 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect github.com/blevesearch/gtreap v0.1.1 // indirect github.com/blevesearch/mmap-go v1.0.4 // indirect - github.com/blevesearch/scorch_segment_api/v2 v2.3.10 // indirect + github.com/blevesearch/scorch_segment_api/v2 v2.2.9 // indirect github.com/blevesearch/segment v0.9.1 // indirect github.com/blevesearch/snowballstem v0.9.0 // indirect github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect - github.com/blevesearch/vellum v1.1.0 // indirect - github.com/blevesearch/zapx/v11 v11.4.2 // indirect - github.com/blevesearch/zapx/v12 v12.4.2 // indirect - github.com/blevesearch/zapx/v13 v13.4.2 // indirect - github.com/blevesearch/zapx/v14 v14.4.2 // indirect - github.com/blevesearch/zapx/v15 v15.4.2 // indirect - github.com/blevesearch/zapx/v16 v16.2.4 // indirect + github.com/blevesearch/vellum v1.0.10 // indirect + github.com/blevesearch/zapx/v11 v11.3.10 // indirect + github.com/blevesearch/zapx/v12 v12.3.10 // indirect + github.com/blevesearch/zapx/v13 v13.3.10 // indirect + github.com/blevesearch/zapx/v14 v14.3.10 // indirect + github.com/blevesearch/zapx/v15 v15.3.13 // indirect + github.com/blevesearch/zapx/v16 v16.0.12 // indirect github.com/boombuler/barcode v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect - github.com/caddyserver/zerossl v0.1.3 // indirect + github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/caddyserver/zerossl v0.1.2 // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cloudflare/circl v1.6.1 // indirect - github.com/cyphar/filepath-securejoin v0.3.6 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudflare/circl v1.3.7 // indirect + github.com/couchbase/go-couchbase v0.1.1 // indirect + github.com/couchbase/gomemcached v0.3.0 // indirect + github.com/couchbase/goutils v0.1.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidmz/go-pageant v1.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/dlclark/regexp2 v1.11.0 // indirect github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect - github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/fxamacker/cbor/v2 v2.8.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect - github.com/go-fed/httpsig v1.1.0 // indirect + github.com/go-faster/city v1.0.1 // indirect + github.com/go-faster/errors v0.7.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.6.2 // indirect - github.com/go-ini/ini v1.67.0 // indirect - github.com/go-openapi/jsonpointer v0.21.1 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/swag v0.23.1 // indirect - github.com/go-webauthn/x v0.1.21 // indirect - github.com/goccy/go-json v0.10.5 // indirect - github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/go-openapi/analysis v0.22.2 // indirect + github.com/go-openapi/errors v0.21.0 // indirect + github.com/go-openapi/inflect v0.19.0 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/loads v0.21.5 // indirect + github.com/go-openapi/runtime v0.26.2 // indirect + github.com/go-openapi/spec v0.20.14 // indirect + github.com/go-openapi/strfmt v0.22.0 // indirect + github.com/go-openapi/swag v0.22.7 // indirect + github.com/go-openapi/validate v0.22.6 // indirect + github.com/go-webauthn/x v0.1.6 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/go-tpm v0.9.5 // indirect + github.com/google/go-tpm v0.9.0 // indirect + github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect github.com/gorilla/css v1.0.1 // indirect + github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect + github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jessevdk/go-flags v1.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect - github.com/libdns/libdns v1.0.0-beta.1 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/libdns/libdns v0.2.2 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/markbates/going v1.0.3 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mholt/acmez/v3 v3.1.2 // indirect - github.com/miekg/dns v1.1.63 // indirect - github.com/minio/crc64nvme v1.0.1 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mholt/acmez/v2 v2.0.1 // indirect + github.com/miekg/dns v1.1.59 // indirect github.com/minio/md5-simd v1.1.2 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect github.com/mschoch/smat v0.2.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nwaples/rardecode v1.1.3 // indirect + github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect - github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect + github.com/paulmach/orb v0.11.1 // indirect + github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect - github.com/pjbgf/sha1cd v0.3.2 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.62.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.46.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/rhysd/actionlint v1.6.27 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect - github.com/rs/xid v1.6.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rs/xid v1.5.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect + github.com/segmentio/asm v1.2.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.3.0 // indirect + github.com/skeema/knownhosts v1.2.1 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.18.2 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - github.com/tinylib/msgp v1.3.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/toqueteos/webbrowser v1.2.0 // indirect + github.com/unknwon/com v1.0.1 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect - github.com/zeebo/assert v1.3.0 // indirect - github.com/zeebo/blake3 v0.2.4 // indirect - go.etcd.io/bbolt v1.4.0 // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/zeebo/blake3 v0.2.3 // indirect + go.etcd.io/bbolt v1.3.9 // indirect + go.mongodb.org/mongo-driver v1.13.1 // indirect + go.opentelemetry.io/otel v1.26.0 // indirect + go.opentelemetry.io/otel/trace v1.26.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - go.uber.org/zap/exp v0.3.0 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 -replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.28.0 +replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 + +replace github.com/nektos/act => gitea.com/gitea/act v0.261.1 + +exclude github.com/gofrs/uuid v3.2.0+incompatible + +exclude github.com/gofrs/uuid v4.0.0+incompatible + +exclude github.com/goccy/go-json v0.4.11 + +exclude github.com/satori/go.uuid v1.2.0 replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1 - -replace github.com/gliderlabs/ssh => code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 - -replace git.sr.ht/~mariusor/go-xsd-duration => code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078 diff --git a/go.sum b/go.sum index 639880e2ce..df7c7ccf02 100644 --- a/go.sum +++ b/go.sum @@ -1,147 +1,159 @@ -cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFsAE= -code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ= -code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU= -code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM= -code.forgejo.org/forgejo/act v1.28.0 h1:96njNC7C1YNyjWq5OWvLZMF/nw0PMthzIA8Nwbnn7jo= -code.forgejo.org/forgejo/act v1.28.0/go.mod h1:dFuiwAmD5vyrzecysHB2kL/GM3wRpoVPl+WdbCTC8Bs= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +code.forgejo.org/f3/gof3/v3 v3.4.0 h1:60LOo47tAKvr9nVu2qqNjbgRnCKeKx68mRMRBo/hIuA= +code.forgejo.org/f3/gof3/v3 v3.4.0/go.mod h1:9v7foN46KlEr5gywOSQPn1k5BVpPeuBozsLKlgOQ3YM= code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE= code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= -code.forgejo.org/forgejo/go-rpmutils v1.0.0 h1:RZGGeKt70p/WaIEL97pyT6uiiEIoN8/aLmS5Z6WmX0M= -code.forgejo.org/forgejo/go-rpmutils v1.0.0/go.mod h1:cg+VbgLXfrDPza9T+kBsMb3TVmmzPN4XseT6gDGLSUk= -code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:RArF5AsF9LH4nEoJxqRxcP5r8hhRfWcId84G82YbqzA= -code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= -code.forgejo.org/forgejo/levelqueue v1.0.0 h1:9krYpU6BM+j/1Ntj6m+VCAIu0UNnne1/UfU/XgPpLuE= -code.forgejo.org/forgejo/levelqueue v1.0.0/go.mod h1:fmG6zhVuqim2rxSFOoasgXO8V2W/k9U31VVYqLIRLhQ= code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ= code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U= -code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 h1:kEZL84+02jY9RxXM4zHBWZ3Fml0B09cmP1LGkDsCfIA= -code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= -code.forgejo.org/go-chi/binding v1.0.1 h1:coKNI+X1NzRN7X85LlrpvBRqk0TXpJ+ja28vusQWEuY= -code.forgejo.org/go-chi/binding v1.0.1/go.mod h1:oTFFDg/dkwFbmVuusiULB1OlrIJM95cOGK7Nc3GYcoo= -code.forgejo.org/go-chi/cache v1.0.1 h1:w6IsDcPbeEnEYZn7M2HJe3/3/Ehtcw/72VjcVK7+lBw= -code.forgejo.org/go-chi/cache v1.0.1/go.mod h1:K3aQSyRIN4xiuqV1kanfQ6O4ToDpzDpY3bNOyGjFe3U= -code.forgejo.org/go-chi/captcha v1.0.2 h1:vyHDPXkpjDv8bLO9NqtWzZayzstD/WpJ5xwEkAaqZGQ= -code.forgejo.org/go-chi/captcha v1.0.2/go.mod h1:lxiPLcJ76UCZHoH31/Wbum4GUi2NgjfFZLrJkKv1lLE= -code.forgejo.org/go-chi/session v1.0.2 h1:pG+AXre9L9VXJmTaADXkmeEPuRalhmBXyv6tG2Rvjcc= -code.forgejo.org/go-chi/session v1.0.2/go.mod h1:HnEGyBny7WPzCiVLP2vzL5ssma+3gCSl/vLpuVNYrqc= code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU= code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas= -code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4= -code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA= +code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI= +code.gitea.io/gitea-vet v0.2.3/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= +code.gitea.io/sdk/gitea v0.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8= +code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM= codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 h1:TXbikPqa7YRtfU9vS6QJBg77pUvbEb6StRdZO8t1bEY= codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM= -connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= -connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= +connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= +git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= +gitea.com/gitea/act v0.261.1 h1:iACWLc/k8wct9fCF2WdYKqn2Hxx6NjW9zbOP79HF4H4= +gitea.com/gitea/act v0.261.1/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= +gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso= +gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw= +gitea.com/go-chi/cache v0.2.0 h1:E0npuTfDW6CT1yD8NMDVc1SK6IeRjfmRL2zlEsCEd7w= +gitea.com/go-chi/cache v0.2.0/go.mod h1:iQlVK2aKTZ/rE9UcHyz9pQWGvdP9i1eI2spOpzgCrtE= +gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo= +gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098/go.mod h1:LjzIOHlRemuUyO7WR12fmm18VZIlCAaOt9L3yKw40pk= +gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96 h1:IFDiMBObsP6CZIRaDLd54SR6zPYAffPXiXck5Xslu0Q= +gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96/go.mod h1:0iEpFKnwO5dG0aF98O4eq6FMsAiXkNBaDIlUOlq4BtM= +gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o= +gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= -github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs= -github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM= -github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920 h1:mWAVGlovzUfREJBhm0GwJnDNu21yRrL9QH9NIzAU3rg= -github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920/go.mod h1:zWxcT7BIWOe05xVJL0VMvO/PJ6RpoCux10heb77H6Q8= +github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H+XXKmDA1dfFMIN1AislhlA/ps= +github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU= github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U= github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4= +github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= +github.com/ClickHouse/clickhouse-go/v2 v2.24.0 h1:L/n/pVVpk95KtkHOiKuSnO7cu2ckeW4gICbbOh5qs74= +github.com/ClickHouse/clickhouse-go/v2 v2.24.0/go.mod h1:iDTViXk2Fgvf1jn2dbJd1ys+fBkdD1UMRnXlwmhijhQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= -github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= -github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo= -github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y= -github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg= -github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0= -github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 h1:cSXom2MoKJ9KPPw29RoZtHvUETY4F4n/kXl8m9btnQ0= -github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2/go.mod h1:JitQWJ8JuV4Y87l8VsHiiwhb3cgdyn68mX40s7NT6PA= -github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= -github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE= +github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= +github.com/RoaringBitmap/roaring v1.7.0 h1:OZF303tJCER1Tj3x+aArx/S5X7hrT186ri6JjrGvG68= +github.com/RoaringBitmap/roaring v1.7.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= +github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= +github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4= -github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk= +github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= +github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= -github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= -github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= -github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= -github.com/blevesearch/bleve/v2 v2.5.2 h1:Ab0r0MODV2C5A6BEL87GqLBySqp/s9xFgceCju6BQk8= -github.com/blevesearch/bleve/v2 v2.5.2/go.mod h1:5Dj6dUQxZM6aqYT3eutTD/GpWKGFSsV8f7LDidFbwXo= -github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y= -github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0= -github.com/blevesearch/geo v0.2.3 h1:K9/vbGI9ehlXdxjxDRJtoAMt7zGAsMIzc6n8zWcwnhg= -github.com/blevesearch/geo v0.2.3/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8= -github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U= -github.com/blevesearch/go-faiss v1.0.25/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk= +github.com/blevesearch/bleve/v2 v2.4.0 h1:2xyg+Wv60CFHYccXc+moGxbL+8QKT/dZK09AewHgKsg= +github.com/blevesearch/bleve/v2 v2.4.0/go.mod h1:IhQHoFAbHgWKYavb9rQgQEJJVMuY99cKdQ0wPpst2aY= +github.com/blevesearch/bleve_index_api v1.1.6 h1:orkqDFCBuNU2oHW9hN2YEJmet+TE9orml3FCGbl1cKk= +github.com/blevesearch/bleve_index_api v1.1.6/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8= +github.com/blevesearch/geo v0.1.20 h1:paaSpu2Ewh/tn5DKn/FB5SzvH0EWupxHEIwbCk/QPqM= +github.com/blevesearch/geo v0.1.20/go.mod h1:DVG2QjwHNMFmjo+ZgzrIq2sfCh6rIHzy9d9d0B59I6w= +github.com/blevesearch/go-faiss v1.0.13 h1:zfFs7ZYD0NqXVSY37j0JZjZT1BhE9AE4peJfcx/NB4A= +github.com/blevesearch/go-faiss v1.0.13/go.mod h1:jrxHrbl42X/RnDPI+wBoZU8joxxuRwedrxqswQ3xfU8= github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= -github.com/blevesearch/scorch_segment_api/v2 v2.3.10 h1:Yqk0XD1mE0fDZAJXTjawJ8If/85JxnLd8v5vG/jWE/s= -github.com/blevesearch/scorch_segment_api/v2 v2.3.10/go.mod h1:Z3e6ChN3qyN35yaQpl00MfI5s8AxUJbpTR/DL8QOQ+8= +github.com/blevesearch/scorch_segment_api/v2 v2.2.9 h1:3nBaSBRFokjE4FtPW3eUDgcAu3KphBg1GP07zy/6Uyk= +github.com/blevesearch/scorch_segment_api/v2 v2.2.9/go.mod h1:ckbeb7knyOOvAdZinn/ASbB7EA3HoagnJkmEV3J7+sg= github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A= github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ= -github.com/blevesearch/vellum v1.1.0 h1:CinkGyIsgVlYf8Y2LUQHvdelgXr6PYuvoDIajq6yR9w= -github.com/blevesearch/vellum v1.1.0/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y= -github.com/blevesearch/zapx/v11 v11.4.2 h1:l46SV+b0gFN+Rw3wUI1YdMWdSAVhskYuvxlcgpQFljs= -github.com/blevesearch/zapx/v11 v11.4.2/go.mod h1:4gdeyy9oGa/lLa6D34R9daXNUvfMPZqUYjPwiLmekwc= -github.com/blevesearch/zapx/v12 v12.4.2 h1:fzRbhllQmEMUuAQ7zBuMvKRlcPA5ESTgWlDEoB9uQNE= -github.com/blevesearch/zapx/v12 v12.4.2/go.mod h1:TdFmr7afSz1hFh/SIBCCZvcLfzYvievIH6aEISCte58= -github.com/blevesearch/zapx/v13 v13.4.2 h1:46PIZCO/ZuKZYgxI8Y7lOJqX3Irkc3N8W82QTK3MVks= -github.com/blevesearch/zapx/v13 v13.4.2/go.mod h1:knK8z2NdQHlb5ot/uj8wuvOq5PhDGjNYQQy0QDnopZk= -github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT7fWYz0= -github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8= -github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k= -github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw= -github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww= -github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs= +github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI= +github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k= +github.com/blevesearch/zapx/v11 v11.3.10 h1:hvjgj9tZ9DeIqBCxKhi70TtSZYMdcFn7gDb71Xo/fvk= +github.com/blevesearch/zapx/v11 v11.3.10/go.mod h1:0+gW+FaE48fNxoVtMY5ugtNHHof/PxCqh7CnhYdnMzQ= +github.com/blevesearch/zapx/v12 v12.3.10 h1:yHfj3vXLSYmmsBleJFROXuO08mS3L1qDCdDK81jDl8s= +github.com/blevesearch/zapx/v12 v12.3.10/go.mod h1:0yeZg6JhaGxITlsS5co73aqPtM04+ycnI6D1v0mhbCs= +github.com/blevesearch/zapx/v13 v13.3.10 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIqMGahDE8= +github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk= +github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU= +github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns= +github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wyhnpDHHQ= +github.com/blevesearch/zapx/v15 v15.3.13/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg= +github.com/blevesearch/zapx/v16 v16.0.12 h1:Uccxvjmn+hQ6ywQP+wIiTpdq9LnAviGoryJOmGwAo/I= +github.com/blevesearch/zapx/v16 v16.0.12/go.mod h1:MYnOshRfSm4C4drxx1LGRI+MVFByykJ2anDY1fxdk9Q= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= -github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= +github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/buildkite/terminal-to-html/v3 v3.16.8 h1:QN/daUob6cmK8GcdKnwn9+YTlPr1vNj+oeAIiJK6fPc= -github.com/buildkite/terminal-to-html/v3 v3.16.8/go.mod h1:+k1KVKROZocrTLsEQ9PEf9A+8+X8uaVV5iO1ZIOwKYM= -github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU= -github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4= -github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= -github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= +github.com/buildkite/terminal-to-html/v3 v3.10.1 h1:znT9eD26LQ59dDJJEpMCwkP4wEptEAPi74hsTBuHdEo= +github.com/buildkite/terminal-to-html/v3 v3.10.1/go.mod h1:qtuRyYs6/Sw3FS9jUyVEaANHgHGqZsGqMknPLyau5cQ= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/caddyserver/certmagic v0.21.0 h1:yDoifClc4hIxhHer3AxUj4buhF+NzRR6torw/AOnuUE= +github.com/caddyserver/certmagic v0.21.0/go.mod h1:OgUZNXYV/ylYoFJNmoYVR5nntydLNMQISePPgqZTyhc= +github.com/caddyserver/zerossl v0.1.2 h1:tlEu1VzWGoqcCpivs9liKAKhfpJWYJkHEMmlxRbVAxE= +github.com/caddyserver/zerossl v0.1.2/go.mod h1:wtiJEHbdvunr40ZzhXlnIkOB8Xj4eKtBKizCcZitJiQ= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chi-middleware/proxy v1.1.1 h1:4HaXUp8o2+bhHr1OhVy+VjN0+L7/07JDcn6v7YrTjrQ= github.com/chi-middleware/proxy v1.1.1/go.mod h1:jQwMEJct2tz9VmtCELxvnXoMfa+SOdikvbVJVHv/M+0= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= @@ -150,17 +162,29 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= -github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/couchbase/go-couchbase v0.1.1 h1:ClFXELcKj/ojyoTYbsY34QUrrYCBi/1G749sXSCkdhk= +github.com/couchbase/go-couchbase v0.1.1/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A= +github.com/couchbase/gomemcached v0.3.0 h1:XkMDdP6w7rtvLijDE0/RhcccX+XvAk5cboyBv1YcI0U= +github.com/couchbase/gomemcached v0.3.0/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo= +github.com/couchbase/goutils v0.1.2 h1:gWr8B6XNWPIhfalHNog3qQKfGiYyh4K4VhO3P2o9BCs= +github.com/couchbase/goutils v0.1.2/go.mod h1:h89Ek/tiOxxqjz30nPPlwZdQbdB8BwgnuBxeoUe/ViE= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= -github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= +github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= +github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/djherbis/buffer v1.1.0/go.mod h1:VwN8VdFkMY0DCALdY8o00d3IZ6Amz/UNVMWcSaJT44o= @@ -171,18 +195,18 @@ github.com/djherbis/nio/v3 v3.0.1/go.mod h1:Ng4h80pbZFMla1yKzm61cF0tqqilXZYrogmW github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= -github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= -github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= -github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/editorconfig/editorconfig-core-go/v2 v2.6.3 h1:XVUp6qW3BIkmM3/1EkrHpa6bL56APOynfXcZEmIgOhs= -github.com/editorconfig/editorconfig-core-go/v2 v2.6.3/go.mod h1:ThHVc+hqbUsmE1wmK/MASpQEhCleWu1JDJDNhUOMy0c= -github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM= -github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= +github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 h1:dKG8sc7n321deIVRcQtwlMNoBEra7j0qQ8RwxO8RN0w= +github.com/editorconfig/editorconfig-core-go/v2 v2.6.2/go.mod h1:7dvD3GCm7eBw53xZ/lsiq72LqobdMg3ITbMBxnmJmqY= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA= github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY= github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4= @@ -194,16 +218,22 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= -github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= +github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= +github.com/felixge/fgprof v0.9.4/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= -github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= +github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 h1:j2TrkUG/NATGi/EQS+MvEoF79CxiRUmT16ErFroNcKI= github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9/go.mod h1:cJ9Ye0ZNSMN7RzZDBRY3E+8M3Bpf/R1JX22Ir9yX6WI= github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 h1:I2nuhyVI/48VXoRCCZR2hYBgnSXa+EuDJf/VyX06TC0= @@ -213,120 +243,162 @@ github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5La github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= -github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0= +github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= -github.com/go-enry/go-enry/v2 v2.9.2 h1:giOQAtCgBX08kosrX818DCQJTCNtKwoPBGu0qb6nKTY= -github.com/go-enry/go-enry/v2 v2.9.2/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= +github.com/go-enry/go-enry/v2 v2.8.8 h1:EhfxWpw4DQ3WEFB1Y77X8vKqZL0D0EDUUWYDUAIv9/4= +github.com/go-enry/go-enry/v2 v2.8.8/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= -github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= +github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= +github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= +github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= +github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= +github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8= +github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= -github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= -github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= -github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= -github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= +github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= -github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= -github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= -github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-openapi/analysis v0.22.2 h1:ZBmNoP2h5omLKr/srIC9bfqrUGzT6g6gNv03HE9Vpj0= +github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo= +github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= +github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho= +github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= +github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/loads v0.21.5 h1:jDzF4dSoHw6ZFADCGltDb2lE4F6De7aWSpe+IcsRzT0= +github.com/go-openapi/loads v0.21.5/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8= +github.com/go-openapi/runtime v0.26.2 h1:elWyB9MacRzvIVgAZCBJmqTi7hBzU0hlKD4IvfX0Zl0= +github.com/go-openapi/runtime v0.26.2/go.mod h1:O034jyRZ557uJKzngbMDJXkcKJVzXJiymdSfgejrcRw= +github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do= +github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= +github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= +github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= +github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8= +github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= +github.com/go-openapi/validate v0.22.6 h1:+NhuwcEYpWdO5Nm4bmvhGLW0rt1Fcc532Mu3wpypXfo= +github.com/go-openapi/validate v0.22.6/go.mod h1:eaddXSqKeTg5XpSmj1dYyFTK/95n/XHwcOY+BMxKMyM= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-swagger/go-swagger v0.30.5 h1:SQ2+xSonWjjoEMOV5tcOnZJVlfyUfCBhGQGArS1b9+U= +github.com/go-swagger/go-swagger v0.30.5/go.mod h1:cWUhSyCNqV7J1wkkxfr5QmbcnCewetCdvEXqgPvbc/Q= +github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= +github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= -github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-webauthn/webauthn v0.13.0 h1:cJIL1/1l+22UekVhipziAaSgESJxokYkowUqAIsWs0Y= -github.com/go-webauthn/webauthn v0.13.0/go.mod h1:Oy9o2o79dbLKRPZWWgRIOdtBGAhKnDIaBp2PFkICRHs= -github.com/go-webauthn/x v0.1.21 h1:nFbckQxudvHEJn2uy1VEi713MeSpApoAv9eRqsb9AdQ= -github.com/go-webauthn/x v0.1.21/go.mod h1:sEYohtg1zL4An1TXIUIQ5csdmoO+WO0R4R2pGKaHYKA= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-testfixtures/testfixtures/v3 v3.11.0 h1:XxQr8AnPORcZkyNd7go5UNLPD3dULN8ixYISlzrlfEQ= +github.com/go-testfixtures/testfixtures/v3 v3.11.0/go.mod h1:THmudHF1Ixq++J2/UodcJpxUphfyEd77m83TvDtryqE= +github.com/go-webauthn/webauthn v0.10.0 h1:yuW2e1tXnRAwAvKrR4q4LQmc6XtCMH639/ypZGhZCwk= +github.com/go-webauthn/webauthn v0.10.0/go.mod h1:l0NiauXhL6usIKqNLCUM3Qir43GK7ORg8ggold0Uv/Y= +github.com/go-webauthn/x v0.1.6 h1:QNAX+AWeqRt9loE8mULeWJCqhVG5D/jvdmJ47fIWCkQ= +github.com/go-webauthn/x v0.1.6/go.mod h1:W8dFVZ79o4f+nY1eOUICy/uq5dhrRl7mxQkYhXTo0FA= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= -github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= -github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/geo v0.0.0-20230421003525-6adc56603217 h1:HKlyj6in2JV6wVkmQ4XmG/EIm+SCYlPZ+V4GWit7Z+I= +github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1IxZfeH3/5I97CI8i5cLGsYe7xNhQGs9U= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-github/v64 v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKbyUb2Qdg= -github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo= +github.com/google/go-github/v57 v57.0.0 h1:L+Y3UPTY8ALM8x+TV0lg+IEBI+upibemtBD8Q9u7zHs= +github.com/google/go-github/v57 v57.0.0/go.mod h1:s0omdnye0hvK/ecLvpsGfJMiRt85PimQh4oygmLIxHw= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU= -github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= +github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc= github.com/gorilla/feeds v1.2.0/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= -github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= +github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= +github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE= +github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= @@ -335,34 +407,72 @@ github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISH github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= +github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jhillyerd/enmime/v2 v2.1.0 h1:c8Qwi5Xq5EdtMN6byQWoZ/8I2RMTo6OJ7Xay+s1oPO0= -github.com/jhillyerd/enmime/v2 v2.1.0/go.mod h1:EJ74dcRbBcqHSP2TBu08XRoy6y3Yx0cevwb1YkGMEmQ= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jhillyerd/enmime v1.2.0 h1:dIu1IPEymQgoT2dzuB//ttA/xcV40NMPpQtmd4wslHk= +github.com/jhillyerd/enmime v1.2.0/go.mod h1:FRFuUPCLh8PByQv+8xRcLO9QHqaqTqreYhopv5eyk4I= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4= +github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= -github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= @@ -375,16 +485,20 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libdns/libdns v1.0.0-beta.1 h1:KIf4wLfsrEpXpZ3vmc/poM8zCATXT2klbdPe6hyOBjQ= -github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= +github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= +github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= +github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 h1:F/3FfGmKdiKFa8kL3YrpZ7pe9H4l4AzA1pbaOUnRvPI= +github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0/go.mod h1:JEfTc3+2DF9Z4PXhLLvXL42zexJyh8rIq3OzUj/0rAk= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/markbates/going v1.0.3 h1:mY45T5TvW+Xz5A6jY7lf4+NLg9D8+iuStIHyR7M8qsE= github.com/markbates/going v1.0.3/go.mod h1:fQiT6v6yQar9UD6bd/D4Z5Afbk9J6BBVBtLiyY4gp2o= github.com/markbates/goth v1.80.0 h1:NnvatczZDzOs1hn9Ug+dVYf2Viwwkp/ZDX5K+GLjan8= @@ -395,73 +509,87 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= -github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/meilisearch/meilisearch-go v0.31.0 h1:yZRhY1qJqdH8h6GFZALGtkDLyj8f9v5aJpsNMyrUmnY= -github.com/meilisearch/meilisearch-go v0.31.0/go.mod h1:aNtyuwurDg/ggxQIcKqWH6G9g2ptc8GyY7PLY4zMn/g= -github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= -github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= -github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= -github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= -github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= -github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= -github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY= -github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/meilisearch/meilisearch-go v0.26.1 h1:3bmo2uLijX7kvBmiZ9LupVfC95TFcRJDgrRTzbOoE4A= +github.com/meilisearch/meilisearch-go v0.26.1/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= +github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k= +github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U= +github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= +github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= +github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= +github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM= -github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc= +github.com/minio/minio-go/v7 v7.0.70 h1:1u9NtMgfK1U42kUxcsl5v0yj6TEOPR497OAQxpJnn2g= +github.com/minio/minio-go/v7 v7.0.70/go.mod h1:4yBA8v80xGA30cfM3fz0DKYMXunWl/AV/6tWEs9ryzo= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 h1:j2kD3MT1z4PXCiUllUJF9mWUESr9TWKS7iEKsQ/IipM= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= -github.com/msteinert/pam/v2 v2.1.0 h1:er5F9TKV5nGFuTt12ubtqPHEUdeBwReP7vd3wovidGY= -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.8.0 h1:WyGLaajLLp8JbQzkmapZ1y0MOzKuKV47HkZRloi+HGY= -github.com/niklasfasching/go-org v1.8.0/go.mod h1:e2A9zJs7cdONrEGs3gvxCcaAEpwwPNPG7csDpXckMNg= +github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE= +github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek= +github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o= 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= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E= github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= -github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= +github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= -github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -470,16 +598,18 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= -github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= +github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw= +github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= +github.com/redis/go-redis/v9 v9.5.2 h1:L0L3fcSNReTRGyZ6AqAEN0K56wYeYAwapBIhkvh0f3E= +github.com/redis/go-redis/v9 v9.5.2/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw= @@ -491,20 +621,60 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sassoftware/go-rpmutils v0.2.1-0.20240124161140-277b154961dd h1:KpbqRPDwcAQTyaP+L+YudTRb3CnJlQ64Hfn1SF/zHBA= +github.com/sassoftware/go-rpmutils v0.2.1-0.20240124161140-277b154961dd/go.mod h1:TJJQYtLe/BeEmEjelI3b7xNZjzAukEkeWKmoakvaOoI= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= -github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= -github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= +github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= +github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= +github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= +github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= -github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= +github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.1 h1:T/YLemO5Yp7KPzS+lVtu+WsHn8yoSwTfItdAd1r3cck= +github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -514,124 +684,162 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww= -github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= +github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= -github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I= -github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= +github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= +github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= +github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= +github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/go-gitlab v0.96.0 h1:LGkZ+wSNMRtHIBaYE4Hq3dZVjprwHv3Y1+rhKU3WETs= +github.com/xanzy/go-gitlab v0.96.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= -github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= -github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js= github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= -github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= -github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= -github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= +github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= +github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= +github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= +github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= +github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -gitlab.com/gitlab-org/api/client-go v0.130.1 h1:1xF5C5Zq3sFeNg3PzS2z63oqrxifne3n/OnbI7nptRc= -gitlab.com/gitlab-org/api/client-go v0.130.1/go.mod h1:ZhSxLAWadqP6J9lMh40IAZOlOxBLPRh7yFOXR/bMJWM= -go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= -go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= +go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= +go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= -go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= -golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -639,68 +847,88 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= -google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -712,6 +940,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -723,9 +952,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= @@ -750,7 +979,9 @@ modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8= mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= +strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= +strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo= xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU= -xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw= +xorm.io/xorm v1.3.7 h1:mLceAGu0b87r9pD4qXyxGHxifOXIIrAdVcA6k95/osw= +xorm.io/xorm v1.3.7/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw= diff --git a/main.go b/main.go index ade43881cf..b8cc5668e1 100644 --- a/main.go +++ b/main.go @@ -10,18 +10,18 @@ import ( "strings" "time" - "forgejo.org/cmd" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/cmd" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" // register supported doc types - _ "forgejo.org/modules/markup/asciicast" - _ "forgejo.org/modules/markup/console" - _ "forgejo.org/modules/markup/csv" - _ "forgejo.org/modules/markup/markdown" - _ "forgejo.org/modules/markup/orgmode" + _ "code.gitea.io/gitea/modules/markup/asciicast" + _ "code.gitea.io/gitea/modules/markup/console" + _ "code.gitea.io/gitea/modules/markup/csv" + _ "code.gitea.io/gitea/modules/markup/markdown" + _ "code.gitea.io/gitea/modules/markup/orgmode" - "github.com/urfave/cli/v3" + "github.com/urfave/cli/v2" ) // these flags will be set by the build flags diff --git a/manifest.scm b/manifest.scm deleted file mode 100644 index f9605bc2d9..0000000000 --- a/manifest.scm +++ /dev/null @@ -1,38 +0,0 @@ -;;; Copyright 2025 The Forgejo Authors. All rights reserved. -;;; SPDX-License-Identifier: MIT -;;; -;;; Commentary: -;;; -;;; This is a GNU Guix manifest that can be used to create a -;;; development environment to build and test Forgejo. -;;; -;;; The following is a usage example to create a containerized -;;; environment, with HOME shared for the Go cache and the network -;;; made available to fetch required Go and Node dependencies. -;;; -#| -guix shell -CNF --share=$HOME -m manifest.scm -export GOTOOLCHAIN=local # to use the Go binary from Guix -export CC=gcc CGO_ENABLED=1 -export TAGS="timetzdata sqlite sqlite_unlock_notify" -make clean -make -j$(nproc) -make test -j$(nproc) # run unit tests -make test-sqlite -j$(nproc) # run integration tests -make watch # run an instance/rebuild on changes -|# -(specifications->manifest - (list "bash-minimal" - "coreutils" - "findutils" - "gcc-toolchain" - "git" ;libpcre support is required - "git-lfs" - "gnupg" - "go" - "grep" - "make" - "node" - "nss-certs" - "openssh" - "sed")) diff --git a/models/actions/artifact.go b/models/actions/artifact.go index 10cd3868a1..3d0a288e62 100644 --- a/models/actions/artifact.go +++ b/models/actions/artifact.go @@ -11,9 +11,9 @@ import ( "errors" "time" - "forgejo.org/models/db" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -69,7 +69,7 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa OwnerID: t.OwnerID, CommitSHA: t.CommitSHA, Status: int64(ArtifactStatusUploadPending), - ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays), + ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + 3600*24*expiredDays), } if _, err := db.GetEngine(ctx).Insert(artifact); err != nil { return nil, err @@ -78,13 +78,6 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa } else if err != nil { return nil, err } - - if _, err := db.GetEngine(ctx).ID(artifact.ID).Cols("expired_unix").Update(&ActionArtifact{ - ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays), - }); err != nil { - return nil, err - } - return artifact, nil } diff --git a/models/actions/forgejo.go b/models/actions/forgejo.go index ce3f8b0c8b..243262facd 100644 --- a/models/actions/forgejo.go +++ b/models/actions/forgejo.go @@ -4,17 +4,17 @@ package actions import ( "context" - "crypto/subtle" + "encoding/hex" "fmt" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/modules/util" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/util" gouuid "github.com/google/uuid" ) -func RegisterRunner(ctx context.Context, ownerID, repoID int64, token string, labels *[]string, name, version string) (*ActionRunner, error) { +func RegisterRunner(ctx context.Context, ownerID, repoID int64, token string, labels []string, name, version string) (*ActionRunner, error) { uuid, err := gouuid.FromBytes([]byte(token[:16])) if err != nil { return nil, fmt.Errorf("gouuid.FromBytes %v", err) @@ -26,28 +26,22 @@ func RegisterRunner(ctx context.Context, ownerID, repoID int64, token string, la has, err := db.GetEngine(ctx).Where("uuid=?", uuidString).Get(&runner) if err != nil { return nil, fmt.Errorf("GetRunner %v", err) - } - - var mustUpdateSecret bool - if has { - // - // The runner exists, check if the rest of the token has changed. - // - mustUpdateSecret = subtle.ConstantTimeCompare( - []byte(runner.TokenHash), - []byte(auth_model.HashToken(token, runner.TokenSalt)), - ) != 1 - } else { + } else if !has { // // The runner does not exist yet, create it // - runner = ActionRunner{ - UUID: uuidString, - AgentLabels: []string{}, + saltBytes, err := util.CryptoRandomBytes(16) + if err != nil { + return nil, fmt.Errorf("CryptoRandomBytes %v", err) } + salt := hex.EncodeToString(saltBytes) - if err := runner.UpdateSecret(token); err != nil { - return &runner, fmt.Errorf("can't set new runner's secret: %w", err) + hash := auth_model.HashToken(token, salt) + + runner = ActionRunner{ + UUID: uuidString, + TokenHash: hash, + TokenSalt: salt, } if err := CreateRunner(ctx, &runner); err != nil { @@ -60,23 +54,13 @@ func RegisterRunner(ctx context.Context, ownerID, repoID int64, token string, la // name, _ = util.SplitStringAtByteN(name, 255) - cols := []string{"name", "owner_id", "repo_id", "version"} runner.Name = name runner.OwnerID = ownerID runner.RepoID = repoID runner.Version = version - if labels != nil { - runner.AgentLabels = *labels - cols = append(cols, "agent_labels") - } - if mustUpdateSecret { - if err := runner.UpdateSecret(token); err != nil { - return &runner, fmt.Errorf("can't change runner's secret: %w", err) - } - cols = append(cols, "token_hash", "token_salt") - } + runner.AgentLabels = labels - if err := UpdateRunner(ctx, &runner, cols...); err != nil { + if err := UpdateRunner(ctx, &runner, "name", "owner_id", "repo_id", "version", "agent_labels"); err != nil { return &runner, fmt.Errorf("can't update the runner %+v %w", runner, err) } diff --git a/models/actions/forgejo_test.go b/models/actions/forgejo_test.go index 5702068c1b..a8583c3d00 100644 --- a/models/actions/forgejo_test.go +++ b/models/actions/forgejo_test.go @@ -6,173 +6,24 @@ import ( "crypto/subtle" "testing" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -func TestActions_RegisterRunner_Token(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) +func TestActions_RegisterRunner(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) ownerID := int64(0) repoID := int64(0) token := "0123456789012345678901234567890123456789" labels := []string{} name := "runner" version := "v1.2.3" - runner, err := RegisterRunner(db.DefaultContext, ownerID, repoID, token, &labels, name, version) - require.NoError(t, err) - assert.Equal(t, name, runner.Name) + runner, err := RegisterRunner(db.DefaultContext, ownerID, repoID, token, labels, name, version) + assert.NoError(t, err) + assert.EqualValues(t, name, runner.Name) - assert.Equal(t, 1, subtle.ConstantTimeCompare([]byte(runner.TokenHash), []byte(auth_model.HashToken(token, runner.TokenSalt))), "the token cannot be verified with the same method as routers/api/actions/runner/interceptor.go as of 8228751c55d6a4263f0fec2932ca16181c09c97d") -} - -// TestActions_RegisterRunner_TokenUpdate tests that a token's secret is updated -// when a runner already exists and RegisterRunner is called with a token -// parameter whose first 16 bytes match that record but where the last 24 bytes -// do not match. -func TestActions_RegisterRunner_TokenUpdate(t *testing.T) { - const recordID = 12345678 - oldToken := "7e577e577e577e57feedfacefeedfacefeedface" - newToken := "7e577e577e577e57deadbeefdeadbeefdeadbeef" - require.NoError(t, unittest.PrepareTestDatabase()) - before := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - require.Equal(t, - before.TokenHash, auth_model.HashToken(oldToken, before.TokenSalt), - "the initial token should match the runner's secret", - ) - - RegisterRunner(db.DefaultContext, before.OwnerID, before.RepoID, newToken, nil, before.Name, before.Version) - - after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - - assert.Equal(t, before.UUID, after.UUID) - assert.NotEqual(t, - after.TokenHash, auth_model.HashToken(oldToken, after.TokenSalt), - "the old token can still be verified", - ) - assert.Equal(t, - after.TokenHash, auth_model.HashToken(newToken, after.TokenSalt), - "the new token cannot be verified", - ) -} - -func TestActions_RegisterRunner_CreateWithLabels(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - ownerID := int64(0) - repoID := int64(0) - token := "0123456789012345678901234567890123456789" - name := "runner" - version := "v1.2.3" - labels := []string{"woop", "doop"} - labelsCopy := labels // labels may be affected by the tested function so we copy them - - runner, err := RegisterRunner(db.DefaultContext, ownerID, repoID, token, &labels, name, version) - require.NoError(t, err) - - // Check that the returned record has been updated, except for the labels - assert.Equal(t, ownerID, runner.OwnerID) - assert.Equal(t, repoID, runner.RepoID) - assert.Equal(t, name, runner.Name) - assert.Equal(t, version, runner.Version) - assert.Equal(t, labelsCopy, runner.AgentLabels) - - // Check that whatever is in the DB has been updated, except for the labels - after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: runner.ID}) - assert.Equal(t, ownerID, after.OwnerID) - assert.Equal(t, repoID, after.RepoID) - assert.Equal(t, name, after.Name) - assert.Equal(t, version, after.Version) - assert.Equal(t, labelsCopy, after.AgentLabels) -} - -func TestActions_RegisterRunner_CreateWithoutLabels(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - ownerID := int64(0) - repoID := int64(0) - token := "0123456789012345678901234567890123456789" - name := "runner" - version := "v1.2.3" - - runner, err := RegisterRunner(db.DefaultContext, ownerID, repoID, token, nil, name, version) - require.NoError(t, err) - - // Check that the returned record has been updated, except for the labels - assert.Equal(t, ownerID, runner.OwnerID) - assert.Equal(t, repoID, runner.RepoID) - assert.Equal(t, name, runner.Name) - assert.Equal(t, version, runner.Version) - assert.Equal(t, []string{}, runner.AgentLabels) - - // Check that whatever is in the DB has been updated, except for the labels - after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: runner.ID}) - assert.Equal(t, ownerID, after.OwnerID) - assert.Equal(t, repoID, after.RepoID) - assert.Equal(t, name, after.Name) - assert.Equal(t, version, after.Version) - assert.Equal(t, []string{}, after.AgentLabels) -} - -func TestActions_RegisterRunner_UpdateWithLabels(t *testing.T) { - const recordID = 12345678 - token := "7e577e577e577e57feedfacefeedfacefeedface" - require.NoError(t, unittest.PrepareTestDatabase()) - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - - newOwnerID := int64(1) - newRepoID := int64(1) - newName := "rennur" - newVersion := "v4.5.6" - newLabels := []string{"warp", "darp"} - labelsCopy := newLabels // labels may be affected by the tested function so we copy them - - runner, err := RegisterRunner(db.DefaultContext, newOwnerID, newRepoID, token, &newLabels, newName, newVersion) - require.NoError(t, err) - - // Check that the returned record has been updated - assert.Equal(t, newOwnerID, runner.OwnerID) - assert.Equal(t, newRepoID, runner.RepoID) - assert.Equal(t, newName, runner.Name) - assert.Equal(t, newVersion, runner.Version) - assert.Equal(t, labelsCopy, runner.AgentLabels) - - // Check that whatever is in the DB has been updated - after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - assert.Equal(t, newOwnerID, after.OwnerID) - assert.Equal(t, newRepoID, after.RepoID) - assert.Equal(t, newName, after.Name) - assert.Equal(t, newVersion, after.Version) - assert.Equal(t, labelsCopy, after.AgentLabels) -} - -func TestActions_RegisterRunner_UpdateWithoutLabels(t *testing.T) { - const recordID = 12345678 - token := "7e577e577e577e57feedfacefeedfacefeedface" - require.NoError(t, unittest.PrepareTestDatabase()) - before := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - - newOwnerID := int64(1) - newRepoID := int64(1) - newName := "rennur" - newVersion := "v4.5.6" - - runner, err := RegisterRunner(db.DefaultContext, newOwnerID, newRepoID, token, nil, newName, newVersion) - require.NoError(t, err) - - // Check that the returned record has been updated, except for the labels - assert.Equal(t, newOwnerID, runner.OwnerID) - assert.Equal(t, newRepoID, runner.RepoID) - assert.Equal(t, newName, runner.Name) - assert.Equal(t, newVersion, runner.Version) - assert.Equal(t, before.AgentLabels, runner.AgentLabels) - - // Check that whatever is in the DB has been updated, except for the labels - after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - assert.Equal(t, newOwnerID, after.OwnerID) - assert.Equal(t, newRepoID, after.RepoID) - assert.Equal(t, newName, after.Name) - assert.Equal(t, newVersion, after.Version) - assert.Equal(t, before.AgentLabels, after.AgentLabels) + assert.EqualValues(t, 1, subtle.ConstantTimeCompare([]byte(runner.TokenHash), []byte(auth_model.HashToken(token, runner.TokenSalt))), "the token cannot be verified with the same method as routers/api/actions/runner/interceptor.go as of 8228751c55d6a4263f0fec2932ca16181c09c97d") } diff --git a/models/actions/main_test.go b/models/actions/main_test.go index 2eb923d9d0..3cfb395e62 100644 --- a/models/actions/main_test.go +++ b/models/actions/main_test.go @@ -6,14 +6,13 @@ package actions import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ FixtureFiles: []string{ "action_runner.yml", - "repository.yml", "action_runner_token.yml", }, }) diff --git a/models/actions/run.go b/models/actions/run.go index 69592120e9..8b40cb7ba8 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -5,21 +5,20 @@ package actions import ( "context" - "errors" "fmt" "slices" "strings" "time" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" - "forgejo.org/modules/json" - api "forgejo.org/modules/structs" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" - webhook_module "forgejo.org/modules/webhook" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/json" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/nektos/act/pkg/jobparser" "xorm.io/builder" @@ -38,7 +37,6 @@ type ActionRun struct { TriggerUser *user_model.User `xorm:"-"` ScheduleID int64 Ref string `xorm:"index"` // the commit/tag/… that caused the run - IsRefDeleted bool `xorm:"-"` CommitSHA string IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow. NeedApproval bool // may need approval if it's a fork pull request @@ -55,7 +53,6 @@ type ActionRun struct { PreviousDuration time.Duration Created timeutil.TimeStamp `xorm:"created"` Updated timeutil.TimeStamp `xorm:"updated"` - NotifyEmail bool } func init() { @@ -149,11 +146,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) { } func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) { - if run.Event == webhook_module.HookEventPullRequest || - run.Event == webhook_module.HookEventPullRequestSync || - run.Event == webhook_module.HookEventPullRequestAssign || - run.Event == webhook_module.HookEventPullRequestMilestone || - run.Event == webhook_module.HookEventPullRequestLabel { + if run.Event == webhook_module.HookEventPullRequest || run.Event == webhook_module.HookEventPullRequestSync { var payload api.PullRequestPayload if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil { return nil, err @@ -187,9 +180,76 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err return err } +// CancelPreviousJobs cancels all previous jobs of the same repository, reference, workflow, and event. +// It's useful when a new run is triggered, and all previous runs needn't be continued anymore. +func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) error { + // Find all runs in the specified repository, reference, and workflow with non-final status + runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{ + RepoID: repoID, + Ref: ref, + WorkflowID: workflowID, + TriggerEvent: event, + Status: []Status{StatusRunning, StatusWaiting, StatusBlocked}, + }) + if err != nil { + return err + } + + // If there are no runs found, there's no need to proceed with cancellation, so return nil. + if total == 0 { + return nil + } + + // Iterate over each found run and cancel its associated jobs. + for _, run := range runs { + // Find all jobs associated with the current run. + jobs, err := db.Find[ActionRunJob](ctx, FindRunJobOptions{ + RunID: run.ID, + }) + if err != nil { + return err + } + + // Iterate over each job and attempt to cancel it. + for _, job := range jobs { + // Skip jobs that are already in a terminal state (completed, cancelled, etc.). + status := job.Status + if status.IsDone() { + continue + } + + // If the job has no associated task (probably an error), set its status to 'Cancelled' and stop it. + if job.TaskID == 0 { + job.Status = StatusCancelled + job.Stopped = timeutil.TimeStampNow() + + // Update the job's status and stopped time in the database. + n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}, "status", "stopped") + if err != nil { + return err + } + + // If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again. + if n == 0 { + return fmt.Errorf("job has changed, try again") + } + + // Continue with the next job. + continue + } + + // If the job has an associated task, try to stop the task, effectively cancelling the job. + if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil { + return err + } + } + } + + // Return nil to indicate successful cancellation of all running and waiting jobs. + return nil +} + // InsertRun inserts a run -// The title will be cut off at 255 characters if it's longer than 255 characters. -// We don't have to send the ActionRunNowDone notification here because there are no runs that start in a not done status. func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error { ctx, commiter, err := db.TxContext(ctx) if err != nil { @@ -202,7 +262,6 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork return err } run.Index = index - run.Title, _ = util.SplitStringAtByteN(run.Title, 255) if err := db.Insert(ctx, run); err != nil { return err @@ -224,38 +283,29 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork var hasWaiting bool for _, v := range jobs { id, job := v.Job() - status := StatusFailure - payload := []byte{} - needs := []string{} - name := run.Title - runsOn := []string{} - if job != nil { - needs = job.Needs() - if err := v.SetJob(id, job.EraseNeeds()); err != nil { - return err - } - payload, _ = v.Marshal() - - if len(needs) > 0 || run.NeedApproval { - status = StatusBlocked - } else { - status = StatusWaiting - hasWaiting = true - } - name, _ = util.SplitStringAtByteN(job.Name, 255) - runsOn = job.RunsOn() + needs := job.Needs() + if err := v.SetJob(id, job.EraseNeeds()); err != nil { + return err } + payload, _ := v.Marshal() + status := StatusWaiting + if len(needs) > 0 || run.NeedApproval { + status = StatusBlocked + } else { + hasWaiting = true + } + job.Name, _ = util.SplitStringAtByteN(job.Name, 255) runJobs = append(runJobs, &ActionRunJob{ RunID: run.ID, RepoID: run.RepoID, OwnerID: run.OwnerID, CommitSHA: run.CommitSHA, IsForkPullRequest: run.IsForkPullRequest, - Name: name, + Name: job.Name, WorkflowPayload: payload, JobID: id, Needs: needs, - RunsOn: runsOn, + RunsOn: job.RunsOn(), Status: status, }) } @@ -284,12 +334,6 @@ func GetLatestRun(ctx context.Context, repoID int64) (*ActionRun, error) { return &run, nil } -func GetRunBefore(ctx context.Context, _ *ActionRun) (*ActionRun, error) { - // TODO return the most recent run related to the run given in argument - // see https://codeberg.org/forgejo/user-research/issues/63 for context - return nil, nil -} - func GetLatestRunForBranchAndWorkflow(ctx context.Context, repoID int64, branch, workflowFile, event string) (*ActionRun, error) { var run ActionRun q := db.GetEngine(ctx).Where("repo_id=?", repoID).And("workflow_id=?", workflowFile) @@ -338,20 +382,17 @@ func GetRunByIndex(ctx context.Context, repoID, index int64) (*ActionRun, error) // UpdateRun updates a run. // It requires the inputted run has Version set. // It will return error if the version is not matched (it means the run has been changed after loaded). -// All calls to UpdateRunWithoutNotification that change run.Status from a not done status to a done status must call the ActionRunNowDone notification channel. -// Use the wrapper function UpdateRun instead. -func UpdateRunWithoutNotification(ctx context.Context, run *ActionRun, cols ...string) error { +func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error { sess := db.GetEngine(ctx).ID(run.ID) if len(cols) > 0 { sess.Cols(cols...) } - run.Title, _ = util.SplitStringAtByteN(run.Title, 255) affected, err := sess.Update(run) if err != nil { return err } if affected == 0 { - return errors.New("run has changed") + return fmt.Errorf("run has changed") // It's impossible that the run is not found, since Gitea never deletes runs. } diff --git a/models/actions/run_job.go b/models/actions/run_job.go index 1fadb4b7c7..4b8664077d 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -9,10 +9,9 @@ import ( "slices" "time" - "forgejo.org/models/db" - "forgejo.org/modules/container" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -72,15 +71,6 @@ func (job *ActionRunJob) LoadAttributes(ctx context.Context) error { return job.Run.LoadAttributes(ctx) } -func (job *ActionRunJob) ItRunsOn(labels []string) bool { - if len(labels) == 0 || len(job.RunsOn) == 0 { - return false - } - labelSet := make(container.Set[string]) - labelSet.AddMultiple(labels...) - return labelSet.IsSubset(job.RunsOn) -} - func GetRunJobByID(ctx context.Context, id int64) (*ActionRunJob, error) { var job ActionRunJob has, err := db.GetEngine(ctx).Where("id=?", id).Get(&job) @@ -101,9 +91,7 @@ func GetRunJobsByRunID(ctx context.Context, runID int64) ([]*ActionRunJob, error return jobs, nil } -// All calls to UpdateRunJobWithoutNotification that change run.Status for any run from a not done status to a done status must call the ActionRunNowDone notification channel. -// Use the wrapper function UpdateRunJob instead. -func UpdateRunJobWithoutNotification(ctx context.Context, job *ActionRunJob, cond builder.Cond, cols ...string) (int64, error) { +func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, cols ...string) (int64, error) { e := db.GetEngine(ctx) sess := e.ID(job.ID) @@ -149,15 +137,14 @@ func UpdateRunJobWithoutNotification(ctx context.Context, job *ActionRunJob, con if err != nil { return 0, err } - run.Status = AggregateJobStatus(jobs) + run.Status = aggregateJobStatus(jobs) if run.Started.IsZero() && run.Status.IsRunning() { run.Started = timeutil.TimeStampNow() } if run.Stopped.IsZero() && run.Status.IsDone() { run.Stopped = timeutil.TimeStampNow() } - // As the caller has to ensure the ActionRunNowDone notification is sent we can ignore doing so here. - if err := UpdateRunWithoutNotification(ctx, run, "status", "started", "stopped"); err != nil { + if err := UpdateRun(ctx, run, "status", "started", "stopped"); err != nil { return 0, fmt.Errorf("update run %d: %w", run.ID, err) } } @@ -165,35 +152,29 @@ func UpdateRunJobWithoutNotification(ctx context.Context, job *ActionRunJob, con return affected, nil } -func AggregateJobStatus(jobs []*ActionRunJob) Status { - allSuccessOrSkipped := len(jobs) != 0 - allSkipped := len(jobs) != 0 - var hasFailure, hasCancelled, hasWaiting, hasRunning, hasBlocked bool +func aggregateJobStatus(jobs []*ActionRunJob) Status { + allDone := true + allWaiting := true + hasFailure := false for _, job := range jobs { - allSuccessOrSkipped = allSuccessOrSkipped && (job.Status == StatusSuccess || job.Status == StatusSkipped) - allSkipped = allSkipped && job.Status == StatusSkipped - hasFailure = hasFailure || job.Status == StatusFailure - hasCancelled = hasCancelled || job.Status == StatusCancelled - hasWaiting = hasWaiting || job.Status == StatusWaiting - hasRunning = hasRunning || job.Status == StatusRunning - hasBlocked = hasBlocked || job.Status == StatusBlocked + if !job.Status.IsDone() { + allDone = false + } + if job.Status != StatusWaiting && !job.Status.IsDone() { + allWaiting = false + } + if job.Status == StatusFailure || job.Status == StatusCancelled { + hasFailure = true + } } - switch { - case allSkipped: - return StatusSkipped - case allSuccessOrSkipped: + if allDone { + if hasFailure { + return StatusFailure + } return StatusSuccess - case hasCancelled: - return StatusCancelled - case hasFailure: - return StatusFailure - case hasRunning: - return StatusRunning - case hasWaiting: - return StatusWaiting - case hasBlocked: - return StatusBlocked - default: - return StatusUnknown // it shouldn't happen } + if allWaiting { + return StatusWaiting + } + return StatusRunning } diff --git a/models/actions/run_job_list.go b/models/actions/run_job_list.go index afc754f26a..6c5d3b3252 100644 --- a/models/actions/run_job_list.go +++ b/models/actions/run_job_list.go @@ -6,9 +6,9 @@ package actions import ( "context" - "forgejo.org/models/db" - "forgejo.org/modules/container" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" ) @@ -54,8 +54,6 @@ type FindRunJobOptions struct { CommitSHA string Statuses []Status UpdatedBefore timeutil.TimeStamp - Events []string // []webhook_module.HookEventType - RunNumber int64 } func (opts FindRunJobOptions) ToConds() builder.Cond { @@ -78,11 +76,5 @@ func (opts FindRunJobOptions) ToConds() builder.Cond { if opts.UpdatedBefore > 0 { cond = cond.And(builder.Lt{"updated": opts.UpdatedBefore}) } - if len(opts.Events) > 0 { - cond = cond.And(builder.In("event", opts.Events)) - } - if opts.RunNumber > 0 { - cond = cond.And(builder.Eq{"`index`": opts.RunNumber}) - } return cond } diff --git a/models/actions/run_job_status_test.go b/models/actions/run_job_status_test.go deleted file mode 100644 index 04fd9ceba7..0000000000 --- a/models/actions/run_job_status_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package actions - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestAggregateJobStatus(t *testing.T) { - testStatuses := func(expected Status, statuses []Status) { - t.Helper() - var jobs []*ActionRunJob - for _, v := range statuses { - jobs = append(jobs, &ActionRunJob{Status: v}) - } - actual := AggregateJobStatus(jobs) - if !assert.Equal(t, expected, actual) { - var statusStrings []string - for _, s := range statuses { - statusStrings = append(statusStrings, s.String()) - } - t.Errorf("AggregateJobStatus(%v) = %v, want %v", statusStrings, statusNames[actual], statusNames[expected]) - } - } - - cases := []struct { - statuses []Status - expected Status - }{ - // unknown cases, maybe it shouldn't happen in real world - {[]Status{}, StatusUnknown}, - {[]Status{StatusUnknown, StatusSuccess}, StatusUnknown}, - {[]Status{StatusUnknown, StatusSkipped}, StatusUnknown}, - {[]Status{StatusUnknown, StatusFailure}, StatusFailure}, - {[]Status{StatusUnknown, StatusCancelled}, StatusCancelled}, - {[]Status{StatusUnknown, StatusWaiting}, StatusWaiting}, - {[]Status{StatusUnknown, StatusRunning}, StatusRunning}, - {[]Status{StatusUnknown, StatusBlocked}, StatusBlocked}, - - // success with other status - {[]Status{StatusSuccess}, StatusSuccess}, - {[]Status{StatusSuccess, StatusSkipped}, StatusSuccess}, // skipped doesn't affect success - {[]Status{StatusSuccess, StatusFailure}, StatusFailure}, - {[]Status{StatusSuccess, StatusCancelled}, StatusCancelled}, - {[]Status{StatusSuccess, StatusWaiting}, StatusWaiting}, - {[]Status{StatusSuccess, StatusRunning}, StatusRunning}, - {[]Status{StatusSuccess, StatusBlocked}, StatusBlocked}, - - // any cancelled, then cancelled - {[]Status{StatusCancelled}, StatusCancelled}, - {[]Status{StatusCancelled, StatusSuccess}, StatusCancelled}, - {[]Status{StatusCancelled, StatusSkipped}, StatusCancelled}, - {[]Status{StatusCancelled, StatusFailure}, StatusCancelled}, - {[]Status{StatusCancelled, StatusWaiting}, StatusCancelled}, - {[]Status{StatusCancelled, StatusRunning}, StatusCancelled}, - {[]Status{StatusCancelled, StatusBlocked}, StatusCancelled}, - - // failure with other status, fail fast - // Should "running" win? Maybe no: old code does make "running" win, but GitHub does fail fast. - {[]Status{StatusFailure}, StatusFailure}, - {[]Status{StatusFailure, StatusSuccess}, StatusFailure}, - {[]Status{StatusFailure, StatusSkipped}, StatusFailure}, - {[]Status{StatusFailure, StatusCancelled}, StatusCancelled}, - {[]Status{StatusFailure, StatusWaiting}, StatusFailure}, - {[]Status{StatusFailure, StatusRunning}, StatusFailure}, - {[]Status{StatusFailure, StatusBlocked}, StatusFailure}, - - // skipped with other status - // TODO: need to clarify whether a PR with "skipped" job status is considered as "mergeable" or not. - {[]Status{StatusSkipped}, StatusSkipped}, - {[]Status{StatusSkipped, StatusSuccess}, StatusSuccess}, - {[]Status{StatusSkipped, StatusFailure}, StatusFailure}, - {[]Status{StatusSkipped, StatusCancelled}, StatusCancelled}, - {[]Status{StatusSkipped, StatusWaiting}, StatusWaiting}, - {[]Status{StatusSkipped, StatusRunning}, StatusRunning}, - {[]Status{StatusSkipped, StatusBlocked}, StatusBlocked}, - } - - for _, c := range cases { - testStatuses(c.expected, c.statuses) - } -} diff --git a/models/actions/run_job_test.go b/models/actions/run_job_test.go deleted file mode 100644 index 50a4ba10d8..0000000000 --- a/models/actions/run_job_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT - -package actions - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestActionRunJob_ItRunsOn(t *testing.T) { - actionJob := ActionRunJob{RunsOn: []string{"ubuntu"}} - agentLabels := []string{"ubuntu", "node-20"} - - assert.True(t, actionJob.ItRunsOn(agentLabels)) - assert.False(t, actionJob.ItRunsOn([]string{})) - - actionJob.RunsOn = append(actionJob.RunsOn, "node-20") - - assert.True(t, actionJob.ItRunsOn(agentLabels)) - - agentLabels = []string{"ubuntu"} - - assert.False(t, actionJob.ItRunsOn(agentLabels)) - - actionJob.RunsOn = []string{} - - assert.False(t, actionJob.ItRunsOn(agentLabels)) -} diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 92be510569..4046c7d369 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -6,12 +6,11 @@ package actions import ( "context" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/container" - "forgejo.org/modules/translation" - webhook_module "forgejo.org/modules/webhook" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" + webhook_module "code.gitea.io/gitea/modules/webhook" "xorm.io/builder" ) @@ -113,14 +112,14 @@ type StatusInfo struct { } // GetStatusInfoList returns a slice of StatusInfo -func GetStatusInfoList(ctx context.Context, lang translation.Locale) []StatusInfo { +func GetStatusInfoList(ctx context.Context) []StatusInfo { // same as those in aggregateJobStatus allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning} statusInfoList := make([]StatusInfo, 0, 4) for _, s := range allStatus { statusInfoList = append(statusInfoList, StatusInfo{ Status: int(s), - DisplayedStatus: s.LocaleString(lang), + DisplayedStatus: s.String(), }) } return statusInfoList diff --git a/models/actions/run_test.go b/models/actions/run_test.go deleted file mode 100644 index c9a552a2b2..0000000000 --- a/models/actions/run_test.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package actions - -import ( - "testing" -) - -func TestGetRunBefore(t *testing.T) { -} diff --git a/models/actions/runner.go b/models/actions/runner.go index bece1ae301..cfe936c495 100644 --- a/models/actions/runner.go +++ b/models/actions/runner.go @@ -6,46 +6,32 @@ package actions import ( "context" "encoding/binary" - "encoding/hex" "fmt" "strings" "time" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/shared/types" - user_model "forgejo.org/models/user" - "forgejo.org/modules/log" - "forgejo.org/modules/optional" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/translation" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/shared/types" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/util" runnerv1 "code.gitea.io/actions-proto-go/runner/v1" "xorm.io/builder" ) // ActionRunner represents runner machines -// -// It can be: -// 1. global runner, OwnerID is 0 and RepoID is 0 -// 2. org/user level runner, OwnerID is org/user ID and RepoID is 0 -// 3. repo level runner, OwnerID is 0 and RepoID is repo ID -// -// Please note that it's not acceptable to have both OwnerID and RepoID to be non-zero, -// or it will be complicated to find runners belonging to a specific owner. -// For example, conditions like `OwnerID = 1` will also return runner {OwnerID: 1, RepoID: 1}, -// but it's a repo level runner, not an org/user level runner. -// To avoid this, make it clear with {OwnerID: 0, RepoID: 1} for repo level runners. type ActionRunner struct { ID int64 UUID string `xorm:"CHAR(36) UNIQUE"` Name string `xorm:"VARCHAR(255)"` Version string `xorm:"VARCHAR(64)"` - OwnerID int64 `xorm:"index"` + OwnerID int64 `xorm:"index"` // org level runner, 0 means system Owner *user_model.User `xorm:"-"` - RepoID int64 `xorm:"index"` + RepoID int64 `xorm:"index"` // repo level runner, if OwnerID also is zero, then it's a global Repo *repo_model.Repository `xorm:"-"` Description string `xorm:"TEXT"` Base int // 0 native 1 docker 2 virtual machine @@ -88,10 +74,9 @@ func (r *ActionRunner) BelongsToOwnerType() types.OwnerType { return types.OwnerTypeRepository } if r.OwnerID != 0 { - switch r.Owner.Type { - case user_model.UserTypeOrganization: + if r.Owner.Type == user_model.UserTypeOrganization { return types.OwnerTypeOrganization - case user_model.UserTypeIndividual: + } else if r.Owner.Type == user_model.UserTypeIndividual { return types.OwnerTypeIndividual } } @@ -166,17 +151,6 @@ func (r *ActionRunner) GenerateToken() (err error) { return err } -// UpdateSecret updates the hash based on the specified token. It does not -// ensure that the runner's UUID matches the first 16 bytes of the token. -func (r *ActionRunner) UpdateSecret(token string) error { - salt := hex.EncodeToString(util.CryptoRandomBytes(16)) - - r.Token = token - r.TokenSalt = salt - r.TokenHash = auth_model.HashToken(token, salt) - return nil -} - func init() { db.RegisterModel(&ActionRunner{}) } @@ -184,7 +158,7 @@ func init() { type FindRunnerOptions struct { db.ListOptions RepoID int64 - OwnerID int64 // it will be ignored if RepoID is set + OwnerID int64 Sort string Filter string IsOnline optional.Option[bool] @@ -201,7 +175,8 @@ func (opts FindRunnerOptions) ToConds() builder.Cond { c = c.Or(builder.Eq{"repo_id": 0, "owner_id": 0}) } cond = cond.And(c) - } else if opts.OwnerID > 0 { // OwnerID is ignored if RepoID is set + } + if opts.OwnerID > 0 { c := builder.NewCond().And(builder.Eq{"owner_id": opts.OwnerID}) if opts.WithAvailable { c = c.Or(builder.Eq{"repo_id": 0, "owner_id": 0}) @@ -268,7 +243,6 @@ func GetRunnerByID(ctx context.Context, id int64) (*ActionRunner, error) { // UpdateRunner updates runner's information. func UpdateRunner(ctx context.Context, r *ActionRunner, cols ...string) error { e := db.GetEngine(ctx) - r.Name, _ = util.SplitStringAtByteN(r.Name, 255) var err error if len(cols) == 0 { _, err = e.ID(r.ID).AllCols().Update(r) @@ -279,33 +253,32 @@ func UpdateRunner(ctx context.Context, r *ActionRunner, cols ...string) error { } // DeleteRunner deletes a runner by given ID. -func DeleteRunner(ctx context.Context, r *ActionRunner) error { +func DeleteRunner(ctx context.Context, id int64) error { + runner, err := GetRunnerByID(ctx, id) + if err != nil { + return err + } + // Replace the UUID, which was either based on the secret's first 16 bytes or an UUIDv4, // with a sequence of 8 0xff bytes followed by the little-endian version of the record's // identifier. This will prevent the deleted record's identifier from colliding with any // new record. b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, uint64(r.ID)) - r.UUID = fmt.Sprintf("ffffffff-ffff-ffff-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x", + binary.LittleEndian.PutUint64(b, uint64(id)) + runner.UUID = fmt.Sprintf("ffffffff-ffff-ffff-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]) - err := UpdateRunner(ctx, r, "UUID") + err = UpdateRunner(ctx, runner, "UUID") if err != nil { return err } - _, err = db.DeleteByID[ActionRunner](ctx, r.ID) + _, err = db.DeleteByID[ActionRunner](ctx, id) return err } // CreateRunner creates new runner. func CreateRunner(ctx context.Context, t *ActionRunner) error { - if t.OwnerID != 0 && t.RepoID != 0 { - // It's trying to create a runner that belongs to a repository, but OwnerID has been set accidentally. - // Remove OwnerID to avoid confusion; it's not worth returning an error here. - t.OwnerID = 0 - } - t.Name, _ = util.SplitStringAtByteN(t.Name, 255) return db.Insert(ctx, t) } @@ -354,53 +327,3 @@ func FixRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) { } return res.RowsAffected() } - -func DeleteOfflineRunners(ctx context.Context, olderThan timeutil.TimeStamp, globalOnly bool) error { - log.Info("Doing: DeleteOfflineRunners") - - if olderThan.AsTime().After(timeutil.TimeStampNow().AddDuration(-RunnerOfflineTime).AsTime()) { - return fmt.Errorf("invalid `cron.cleanup_offline_runners.older_than`value: must be at least %q", RunnerOfflineTime) - } - - cond := builder.Or( - // never online - builder.And(builder.Eq{"last_online": 0}, builder.Lt{"created": olderThan}), - // was online but offline - builder.And(builder.Gt{"last_online": 0}, builder.Lt{"last_online": olderThan}), - ) - - if globalOnly { - cond = builder.And(cond, builder.Eq{"owner_id": 0}, builder.Eq{"repo_id": 0}) - } - - if err := db.Iterate( - ctx, - cond, - func(ctx context.Context, r *ActionRunner) error { - if err := DeleteRunner(ctx, r); err != nil { - return fmt.Errorf("DeleteOfflineRunners: %w", err) - } - lastOnline := r.LastOnline.AsTime() - olderThanTime := olderThan.AsTime() - if !lastOnline.IsZero() && lastOnline.Before(olderThanTime) { - log.Info( - "Deleted runner [ID: %d, Name: %s], last online %s ago", - r.ID, r.Name, olderThanTime.Sub(lastOnline).String(), - ) - } else { - log.Info( - "Deleted runner [ID: %d, Name: %s], unused since %s ago", - r.ID, r.Name, olderThanTime.Sub(r.Created.AsTime()).String(), - ) - } - - return nil - }, - ); err != nil { - return err - } - - log.Info("Finished: DeleteOfflineRunners") - - return nil -} diff --git a/models/actions/runner_list.go b/models/actions/runner_list.go index 6a64c46596..3ef8ebb254 100644 --- a/models/actions/runner_list.go +++ b/models/actions/runner_list.go @@ -6,10 +6,10 @@ package actions import ( "context" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/container" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" ) type RunnerList []*ActionRunner diff --git a/models/actions/runner_test.go b/models/actions/runner_test.go index 1916c35a76..a71f5f0044 100644 --- a/models/actions/runner_test.go +++ b/models/actions/runner_test.go @@ -6,42 +6,24 @@ import ( "encoding/binary" "fmt" "testing" - "time" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -// TestUpdateSecret checks that ActionRunner.UpdateSecret() sets the Token, -// TokenSalt and TokenHash fields based on the specified token. -func TestUpdateSecret(t *testing.T) { - runner := ActionRunner{} - token := "0123456789012345678901234567890123456789" - - err := runner.UpdateSecret(token) - - require.NoError(t, err) - assert.Equal(t, token, runner.Token) - assert.Regexp(t, "^[0-9a-f]{32}$", runner.TokenSalt) - assert.Equal(t, runner.TokenHash, auth_model.HashToken(token, runner.TokenSalt)) -} - func TestDeleteRunner(t *testing.T) { const recordID = 12345678 - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) before := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - err := DeleteRunner(db.DefaultContext, &ActionRunner{ID: recordID}) - require.NoError(t, err) + err := DeleteRunner(db.DefaultContext, recordID) + assert.NoError(t, err) var after ActionRunner found, err := db.GetEngine(db.DefaultContext).ID(recordID).Unscoped().Get(&after) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, found) // Most fields (namely Name, Version, OwnerID, RepoID, Description, Base, RepoRange, @@ -75,68 +57,3 @@ func TestDeleteRunner(t *testing.T) { idAsBinary[6], idAsBinary[7]) assert.Equal(t, idAsHexadecimal, after.UUID[19:]) } - -func TestDeleteOfflineRunnersRunnerGlobalOnly(t *testing.T) { - baseTime := time.Date(2024, 5, 19, 7, 40, 32, 0, time.UTC) - timeutil.MockSet(baseTime) - defer timeutil.MockUnset() - - require.NoError(t, unittest.PrepareTestDatabase()) - - olderThan := timeutil.TimeStampNow().Add(-timeutil.Hour) - - require.NoError(t, DeleteOfflineRunners(db.DefaultContext, olderThan, true)) - - // create at test base time - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 12345678}) - // last_online test base time - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000001}) - // created one month ago but a repo - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000002}) - // last online one hour ago - unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000003}) - // last online 10 seconds ago - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000004}) - // created 1 month ago - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000005}) - // created 1 hour ago - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000006}) - // last online 1 hour ago - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000007}) -} - -func TestDeleteOfflineRunnersAll(t *testing.T) { - baseTime := time.Date(2024, 5, 19, 7, 40, 32, 0, time.UTC) - timeutil.MockSet(baseTime) - defer timeutil.MockUnset() - - require.NoError(t, unittest.PrepareTestDatabase()) - - olderThan := timeutil.TimeStampNow().Add(-timeutil.Hour) - - require.NoError(t, DeleteOfflineRunners(db.DefaultContext, olderThan, false)) - - // create at test base time - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 12345678}) - // last_online test base time - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000001}) - // created one month ago - unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000002}) - // last online one hour ago - unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000003}) - // last online 10 seconds ago - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000004}) - // created 1 month ago - unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000005}) - // created 1 hour ago - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000006}) - // last online 1 hour ago - unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000007}) -} - -func TestDeleteOfflineRunnersErrorOnInvalidOlderThanValue(t *testing.T) { - baseTime := time.Date(2024, 5, 19, 7, 40, 32, 0, time.UTC) - timeutil.MockSet(baseTime) - defer timeutil.MockUnset() - require.Error(t, DeleteOfflineRunners(db.DefaultContext, timeutil.TimeStampNow(), false)) -} diff --git a/models/actions/runner_token.go b/models/actions/runner_token.go index a59304d8e8..ccd9bbccb3 100644 --- a/models/actions/runner_token.go +++ b/models/actions/runner_token.go @@ -7,31 +7,20 @@ import ( "context" "fmt" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) // ActionRunnerToken represents runner tokens -// -// It can be: -// 1. global token, OwnerID is 0 and RepoID is 0 -// 2. org/user level token, OwnerID is org/user ID and RepoID is 0 -// 3. repo level token, OwnerID is 0 and RepoID is repo ID -// -// Please note that it's not acceptable to have both OwnerID and RepoID to be non-zero, -// or it will be complicated to find tokens belonging to a specific owner. -// For example, conditions like `OwnerID = 1` will also return token {OwnerID: 1, RepoID: 1}, -// but it's a repo level token, not an org/user level token. -// To avoid this, make it clear with {OwnerID: 0, RepoID: 1} for repo level tokens. type ActionRunnerToken struct { ID int64 Token string `xorm:"UNIQUE"` - OwnerID int64 `xorm:"index"` + OwnerID int64 `xorm:"index"` // org level runner, 0 means system Owner *user_model.User `xorm:"-"` - RepoID int64 `xorm:"index"` + RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global Repo *repo_model.Repository `xorm:"-"` IsActive bool // true means it can be used @@ -69,14 +58,7 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string } // NewRunnerToken creates a new active runner token and invalidate all old tokens -// ownerID will be ignored and treated as 0 if repoID is non-zero. func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { - if ownerID != 0 && repoID != 0 { - // It's trying to create a runner token that belongs to a repository, but OwnerID has been set accidentally. - // Remove OwnerID to avoid confusion; it's not worth returning an error here. - ownerID = 0 - } - token, err := util.CryptoRandomString(40) if err != nil { return nil, err @@ -102,12 +84,6 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo // GetLatestRunnerToken returns the latest runner token func GetLatestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { - if ownerID != 0 && repoID != 0 { - // It's trying to get a runner token that belongs to a repository, but OwnerID has been set accidentally. - // Remove OwnerID to avoid confusion; it's not worth returning an error here. - ownerID = 0 - } - var runnerToken ActionRunnerToken has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=?", ownerID, repoID). OrderBy("id DESC").Get(&runnerToken) diff --git a/models/actions/runner_token_test.go b/models/actions/runner_token_test.go index 0de9ca5648..e85e99abe5 100644 --- a/models/actions/runner_token_test.go +++ b/models/actions/runner_token_test.go @@ -6,36 +6,35 @@ package actions import ( "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestGetLatestRunnerToken(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token := unittest.AssertExistsAndLoadBean(t, &ActionRunnerToken{ID: 3}) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) - require.NoError(t, err) - assert.Equal(t, expectedToken, token) + assert.NoError(t, err) + assert.EqualValues(t, token, expectedToken) } func TestNewRunnerToken(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token, err := NewRunnerToken(db.DefaultContext, 1, 0) - require.NoError(t, err) + assert.NoError(t, err) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) - require.NoError(t, err) - assert.Equal(t, expectedToken, token) + assert.NoError(t, err) + assert.EqualValues(t, token, expectedToken) } func TestUpdateRunnerToken(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token := unittest.AssertExistsAndLoadBean(t, &ActionRunnerToken{ID: 3}) token.IsActive = true - require.NoError(t, UpdateRunnerToken(db.DefaultContext, token)) + assert.NoError(t, UpdateRunnerToken(db.DefaultContext, token)) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) - require.NoError(t, err) - assert.Equal(t, expectedToken, token) + assert.NoError(t, err) + assert.EqualValues(t, token, expectedToken) } diff --git a/models/actions/schedule.go b/models/actions/schedule.go index cc68e9eafc..3646a046a0 100644 --- a/models/actions/schedule.go +++ b/models/actions/schedule.go @@ -5,16 +5,16 @@ package actions import ( "context" + "fmt" "time" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" - webhook_module "forgejo.org/modules/webhook" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/timeutil" + webhook_module "code.gitea.io/gitea/modules/webhook" - "xorm.io/builder" + "github.com/robfig/cron/v3" ) // ActionSchedule represents a schedule of a workflow file @@ -44,12 +44,17 @@ func init() { // GetSchedulesMapByIDs returns the schedules by given id slice. func GetSchedulesMapByIDs(ctx context.Context, ids []int64) (map[int64]*ActionSchedule, error) { schedules := make(map[int64]*ActionSchedule, len(ids)) - if len(ids) == 0 { - return schedules, nil - } return schedules, db.GetEngine(ctx).In("id", ids).Find(&schedules) } +// GetReposMapByIDs returns the repos by given id slice. +func GetReposMapByIDs(ctx context.Context, ids []int64) (map[int64]*repo_model.Repository, error) { + repos := make(map[int64]*repo_model.Repository, len(ids)) + return repos, db.GetEngine(ctx).In("id", ids).Find(&repos) +} + +var cronParser = cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor) + // CreateScheduleTask creates new schedule task. func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error { // Return early if there are no rows to insert @@ -66,7 +71,6 @@ func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error { // Loop through each schedule row for _, row := range rows { - row.Title, _ = util.SplitStringAtByteN(row.Title, 255) // Create new schedule row if err = db.Insert(ctx, row); err != nil { return err @@ -76,21 +80,19 @@ func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error { now := time.Now() for _, spec := range row.Specs { - specRow := &ActionScheduleSpec{ - RepoID: row.RepoID, - ScheduleID: row.ID, - Spec: spec, - } // Parse the spec and check for errors - schedule, err := specRow.Parse() + schedule, err := cronParser.Parse(spec) if err != nil { continue // skip to the next spec if there's an error } - specRow.Next = timeutil.TimeStamp(schedule.Next(now).Unix()) - // Insert the new schedule spec row - if err = db.Insert(ctx, specRow); err != nil { + if err = db.Insert(ctx, &ActionScheduleSpec{ + RepoID: row.RepoID, + ScheduleID: row.ID, + Spec: spec, + Next: timeutil.TimeStamp(schedule.Next(now).Unix()), + }); err != nil { return err } } @@ -118,24 +120,21 @@ func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error { return committer.Commit() } -type FindScheduleOptions struct { - db.ListOptions - RepoID int64 - OwnerID int64 -} - -func (opts FindScheduleOptions) ToConds() builder.Cond { - cond := builder.NewCond() - if opts.RepoID > 0 { - cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) +func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) error { + // If actions disabled when there is schedule task, this will remove the outdated schedule tasks + // There is no other place we can do this because the app.ini will be changed manually + if err := DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil { + return fmt.Errorf("DeleteCronTaskByRepo: %v", err) } - if opts.OwnerID > 0 { - cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) + // cancel running cron jobs of this repository and delete old schedules + if err := CancelPreviousJobs( + ctx, + repo.ID, + repo.DefaultBranch, + "", + webhook_module.HookEventSchedule, + ); err != nil { + return fmt.Errorf("CancelPreviousJobs: %v", err) } - - return cond -} - -func (opts FindScheduleOptions) ToOrders() string { - return "`id` DESC" + return nil } diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go new file mode 100644 index 0000000000..5361b94801 --- /dev/null +++ b/models/actions/schedule_list.go @@ -0,0 +1,83 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "context" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" + + "xorm.io/builder" +) + +type ScheduleList []*ActionSchedule + +// GetUserIDs returns a slice of user's id +func (schedules ScheduleList) GetUserIDs() []int64 { + return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) { + return schedule.TriggerUserID, true + }) +} + +func (schedules ScheduleList) GetRepoIDs() []int64 { + return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) { + return schedule.RepoID, true + }) +} + +func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error { + userIDs := schedules.GetUserIDs() + users := make(map[int64]*user_model.User, len(userIDs)) + if err := db.GetEngine(ctx).In("id", userIDs).Find(&users); err != nil { + return err + } + for _, schedule := range schedules { + if schedule.TriggerUserID == user_model.ActionsUserID { + schedule.TriggerUser = user_model.NewActionsUser() + } else { + schedule.TriggerUser = users[schedule.TriggerUserID] + if schedule.TriggerUser == nil { + schedule.TriggerUser = user_model.NewGhostUser() + } + } + } + return nil +} + +func (schedules ScheduleList) LoadRepos(ctx context.Context) error { + repoIDs := schedules.GetRepoIDs() + repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs) + if err != nil { + return err + } + for _, schedule := range schedules { + schedule.Repo = repos[schedule.RepoID] + } + return nil +} + +type FindScheduleOptions struct { + db.ListOptions + RepoID int64 + OwnerID int64 +} + +func (opts FindScheduleOptions) ToConds() builder.Cond { + cond := builder.NewCond() + if opts.RepoID > 0 { + cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) + } + if opts.OwnerID > 0 { + cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) + } + + return cond +} + +func (opts FindScheduleOptions) ToOrders() string { + return "`id` DESC" +} diff --git a/models/actions/schedule_spec.go b/models/actions/schedule_spec.go index 83bdceb850..91240459a0 100644 --- a/models/actions/schedule_spec.go +++ b/models/actions/schedule_spec.go @@ -5,12 +5,10 @@ package actions import ( "context" - "strings" - "time" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/timeutil" "github.com/robfig/cron/v3" ) @@ -34,29 +32,8 @@ type ActionScheduleSpec struct { Updated timeutil.TimeStamp `xorm:"updated"` } -// Parse parses the spec and returns a cron.Schedule -// Unlike the default cron parser, Parse uses UTC timezone as the default if none is specified. func (s *ActionScheduleSpec) Parse() (cron.Schedule, error) { - parser := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor) - schedule, err := parser.Parse(s.Spec) - if err != nil { - return nil, err - } - - // If the spec has specified a timezone, use it - if strings.HasPrefix(s.Spec, "TZ=") || strings.HasPrefix(s.Spec, "CRON_TZ=") { - return schedule, nil - } - - specSchedule, ok := schedule.(*cron.SpecSchedule) - // If it's not a spec schedule, like "@every 5m", timezone is not relevant - if !ok { - return schedule, nil - } - - // Set the timezone to UTC - specSchedule.Location = time.UTC - return specSchedule, nil + return cronParser.Parse(s.Spec) } func init() { diff --git a/models/actions/schedule_spec_list.go b/models/actions/schedule_spec_list.go index 0a09a60acb..4dc43f975b 100644 --- a/models/actions/schedule_spec_list.go +++ b/models/actions/schedule_spec_list.go @@ -6,9 +6,9 @@ package actions import ( "context" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/modules/container" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/container" "xorm.io/builder" ) @@ -36,7 +36,7 @@ func (specs SpecList) LoadSchedules(ctx context.Context) error { } repoIDs := specs.GetRepoIDs() - repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs) + repos, err := GetReposMapByIDs(ctx, repoIDs) if err != nil { return err } diff --git a/models/actions/schedule_spec_test.go b/models/actions/schedule_spec_test.go deleted file mode 100644 index 0c26fce4b2..0000000000 --- a/models/actions/schedule_spec_test.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package actions - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestActionScheduleSpec_Parse(t *testing.T) { - // Mock the local timezone is not UTC - local := time.Local - tz, err := time.LoadLocation("Asia/Shanghai") - require.NoError(t, err) - defer func() { - time.Local = local - }() - time.Local = tz - - now, err := time.Parse(time.RFC3339, "2024-07-31T15:47:55+08:00") - require.NoError(t, err) - - tests := []struct { - name string - spec string - want string - wantErr assert.ErrorAssertionFunc - }{ - { - name: "regular", - spec: "0 10 * * *", - want: "2024-07-31T10:00:00Z", - wantErr: assert.NoError, - }, - { - name: "invalid", - spec: "0 10 * *", - want: "", - wantErr: assert.Error, - }, - { - name: "with timezone", - spec: "TZ=America/New_York 0 10 * * *", - want: "2024-07-31T14:00:00Z", - wantErr: assert.NoError, - }, - { - name: "timezone irrelevant", - spec: "@every 5m", - want: "2024-07-31T07:52:55Z", - wantErr: assert.NoError, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &ActionScheduleSpec{ - Spec: tt.spec, - } - got, err := s.Parse() - tt.wantErr(t, err) - - if err == nil { - assert.Equal(t, tt.want, got.Next(now).UTC().Format(time.RFC3339)) - } - }) - } -} diff --git a/models/actions/status.go b/models/actions/status.go index e42c221121..eda2234137 100644 --- a/models/actions/status.go +++ b/models/actions/status.go @@ -4,7 +4,7 @@ package actions import ( - "forgejo.org/modules/translation" + "code.gitea.io/gitea/modules/translation" runnerv1 "code.gitea.io/actions-proto-go/runner/v1" ) @@ -34,15 +34,6 @@ var statusNames = map[Status]string{ StatusBlocked: "blocked", } -var nameToStatus = make(map[string]Status, len(statusNames)) - -func init() { - // Populate name to status lookup map - for status, name := range statusNames { - nameToStatus[name] = status - } -} - // String returns the string name of the Status func (s Status) String() string { return statusNames[s] @@ -111,8 +102,3 @@ func (s Status) AsResult() runnerv1.Result { } return runnerv1.Result_RESULT_UNSPECIFIED } - -func StatusFromString(name string) (Status, bool) { - status, exists := nameToStatus[name] - return status, exists -} diff --git a/models/actions/task.go b/models/actions/task.go index 93369db7e8..9946cf5233 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -9,16 +9,19 @@ import ( "fmt" "time" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unit" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + runnerv1 "code.gitea.io/actions-proto-go/runner/v1" lru "github.com/hashicorp/golang-lru/v2" "github.com/nektos/act/pkg/jobparser" + "google.golang.org/protobuf/types/known/timestamppb" "xorm.io/builder" ) @@ -32,7 +35,7 @@ type ActionTask struct { RunnerID int64 `xorm:"index"` Status Status `xorm:"index"` Started timeutil.TimeStamp `xorm:"index"` - Stopped timeutil.TimeStamp `xorm:"index(stopped_log_expired)"` + Stopped timeutil.TimeStamp RepoID int64 `xorm:"index"` OwnerID int64 `xorm:"index"` @@ -48,8 +51,8 @@ type ActionTask struct { LogInStorage bool // read log from database or from storage LogLength int64 // lines count LogSize int64 // blob size - LogIndexes LogIndexes `xorm:"LONGBLOB"` // line number to offset - LogExpired bool `xorm:"index(stopped_log_expired)"` // files that are too old will be deleted + LogIndexes LogIndexes `xorm:"LONGBLOB"` // line number to offset + LogExpired bool // files that are too old will be deleted Created timeutil.TimeStamp `xorm:"created"` Updated timeutil.TimeStamp `xorm:"updated index"` @@ -242,7 +245,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask var job *ActionRunJob log.Trace("runner labels: %v", runner.AgentLabels) for _, v := range jobs { - if v.ItRunsOn(runner.AgentLabels) { + if isSubset(runner.AgentLabels, v.RunsOn) { job = v break } @@ -311,8 +314,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask } job.TaskID = task.ID - // We never have to send a notification here because the job is started with a not done status. - if n, err := UpdateRunJobWithoutNotification(ctx, job, builder.Eq{"task_id": 0}); err != nil { + if n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}); err != nil { return nil, false, err } else if n != 1 { return nil, false, nil @@ -336,24 +338,161 @@ func UpdateTask(ctx context.Context, task *ActionTask, cols ...string) error { return err } -func FindOldTasksToExpire(ctx context.Context, olderThan timeutil.TimeStamp, limit int) ([]*ActionTask, error) { +// UpdateTaskByState updates the task by the state. +// It will always update the task if the state is not final, even there is no change. +// So it will update ActionTask.Updated to avoid the task being judged as a zombie task. +func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionTask, error) { + stepStates := map[int64]*runnerv1.StepState{} + for _, v := range state.Steps { + stepStates[v.Id] = v + } + + ctx, commiter, err := db.TxContext(ctx) + if err != nil { + return nil, err + } + defer commiter.Close() + e := db.GetEngine(ctx) - tasks := make([]*ActionTask, 0, limit) - // Check "stopped > 0" to avoid deleting tasks that are still running - return tasks, e.Where("stopped > 0 AND stopped < ? AND log_expired = ?", olderThan, false). - Limit(limit). - Find(&tasks) + task := &ActionTask{} + if has, err := e.ID(state.Id).Get(task); err != nil { + return nil, err + } else if !has { + return nil, util.ErrNotExist + } + + if task.Status.IsDone() { + // the state is final, do nothing + return task, nil + } + + // state.Result is not unspecified means the task is finished + if state.Result != runnerv1.Result_RESULT_UNSPECIFIED { + task.Status = Status(state.Result) + task.Stopped = timeutil.TimeStamp(state.StoppedAt.AsTime().Unix()) + if err := UpdateTask(ctx, task, "status", "stopped"); err != nil { + return nil, err + } + if _, err := UpdateRunJob(ctx, &ActionRunJob{ + ID: task.JobID, + Status: task.Status, + Stopped: task.Stopped, + }, nil); err != nil { + return nil, err + } + } else { + // Force update ActionTask.Updated to avoid the task being judged as a zombie task + task.Updated = timeutil.TimeStampNow() + if err := UpdateTask(ctx, task, "updated"); err != nil { + return nil, err + } + } + + if err := task.LoadAttributes(ctx); err != nil { + return nil, err + } + + for _, step := range task.Steps { + var result runnerv1.Result + if v, ok := stepStates[step.Index]; ok { + result = v.Result + step.LogIndex = v.LogIndex + step.LogLength = v.LogLength + step.Started = convertTimestamp(v.StartedAt) + step.Stopped = convertTimestamp(v.StoppedAt) + } + if result != runnerv1.Result_RESULT_UNSPECIFIED { + step.Status = Status(result) + } else if step.Started != 0 { + step.Status = StatusRunning + } + if _, err := e.ID(step.ID).Update(step); err != nil { + return nil, err + } + } + + if err := commiter.Commit(); err != nil { + return nil, err + } + + return task, nil +} + +func StopTask(ctx context.Context, taskID int64, status Status) error { + if !status.IsDone() { + return fmt.Errorf("cannot stop task with status %v", status) + } + e := db.GetEngine(ctx) + + task := &ActionTask{} + if has, err := e.ID(taskID).Get(task); err != nil { + return err + } else if !has { + return util.ErrNotExist + } + if task.Status.IsDone() { + return nil + } + + now := timeutil.TimeStampNow() + task.Status = status + task.Stopped = now + if _, err := UpdateRunJob(ctx, &ActionRunJob{ + ID: task.JobID, + Status: task.Status, + Stopped: task.Stopped, + }, nil); err != nil { + return err + } + + if err := UpdateTask(ctx, task, "status", "stopped"); err != nil { + return err + } + + if err := task.LoadAttributes(ctx); err != nil { + return err + } + + for _, step := range task.Steps { + if !step.Status.IsDone() { + step.Status = status + if step.Started == 0 { + step.Started = now + } + step.Stopped = now + } + if _, err := e.ID(step.ID).Update(step); err != nil { + return err + } + } + + return nil +} + +func isSubset(set, subset []string) bool { + m := make(container.Set[string], len(set)) + for _, v := range set { + m.Add(v) + } + + for _, v := range subset { + if !m.Contains(v) { + return false + } + } + return true +} + +func convertTimestamp(timestamp *timestamppb.Timestamp) timeutil.TimeStamp { + if timestamp.GetSeconds() == 0 && timestamp.GetNanos() == 0 { + return timeutil.TimeStamp(0) + } + return timeutil.TimeStamp(timestamp.AsTime().Unix()) } func logFileName(repoFullName string, taskID int64) string { - ret := fmt.Sprintf("%s/%02x/%d.log", repoFullName, taskID%256, taskID) - - if setting.Actions.LogCompression.IsZstd() { - ret += ".zst" - } - - return ret + return fmt.Sprintf("%s/%02x/%d.log", repoFullName, taskID%256, taskID) } func getTaskIDFromCache(token string) int64 { diff --git a/models/actions/task_list.go b/models/actions/task_list.go index fe4c028c2c..df4b43c5ef 100644 --- a/models/actions/task_list.go +++ b/models/actions/task_list.go @@ -6,9 +6,9 @@ package actions import ( "context" - "forgejo.org/models/db" - "forgejo.org/modules/container" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" ) @@ -50,7 +50,7 @@ type FindTaskOptions struct { RepoID int64 OwnerID int64 CommitSHA string - Status []Status + Status Status UpdatedBefore timeutil.TimeStamp StartedBefore timeutil.TimeStamp RunnerID int64 @@ -67,8 +67,8 @@ func (opts FindTaskOptions) ToConds() builder.Cond { if opts.CommitSHA != "" { cond = cond.And(builder.Eq{"commit_sha": opts.CommitSHA}) } - if opts.Status != nil { - cond = cond.And(builder.In("status", opts.Status)) + if opts.Status > StatusUnknown { + cond = cond.And(builder.Eq{"status": opts.Status}) } if opts.UpdatedBefore > 0 { cond = cond.And(builder.Lt{"updated": opts.UpdatedBefore}) diff --git a/models/actions/task_output.go b/models/actions/task_output.go index fa13cadd53..eab5b93118 100644 --- a/models/actions/task_output.go +++ b/models/actions/task_output.go @@ -6,7 +6,7 @@ package actions import ( "context" - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" ) // ActionTaskOutput represents an output of ActionTask. diff --git a/models/actions/task_step.go b/models/actions/task_step.go index 1f20157271..3af1fe3f5a 100644 --- a/models/actions/task_step.go +++ b/models/actions/task_step.go @@ -7,8 +7,8 @@ import ( "context" "time" - "forgejo.org/models/db" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" ) // ActionTaskStep represents a step of ActionTask diff --git a/models/actions/tasks_version.go b/models/actions/tasks_version.go index a5c357888f..d8df353593 100644 --- a/models/actions/tasks_version.go +++ b/models/actions/tasks_version.go @@ -6,9 +6,9 @@ package actions import ( "context" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/timeutil" ) // ActionTasksVersion diff --git a/models/actions/utils.go b/models/actions/utils.go index d8e053b0ba..12657942fc 100644 --- a/models/actions/utils.go +++ b/models/actions/utils.go @@ -12,9 +12,9 @@ import ( "io" "time" - auth_model "forgejo.org/models/auth" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) func generateSaltedToken() (string, string, string, string, error) { @@ -22,7 +22,11 @@ func generateSaltedToken() (string, string, string, string, error) { if err != nil { return "", "", "", "", err } - token := hex.EncodeToString(util.CryptoRandomBytes(20)) + buf, err := util.CryptoRandomBytes(20) + if err != nil { + return "", "", "", "", err + } + token := hex.EncodeToString(buf) hash := auth_model.HashToken(token, salt) return token, salt, hash, token[len(token)-8:], nil } diff --git a/models/actions/utils_test.go b/models/actions/utils_test.go index af6fd04a6a..98c048d4ef 100644 --- a/models/actions/utils_test.go +++ b/models/actions/utils_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/modules/timeutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/models/actions/variable.go b/models/actions/variable.go index 203065487c..8aff844659 100644 --- a/models/actions/variable.go +++ b/models/actions/variable.go @@ -5,27 +5,16 @@ package actions import ( "context" + "errors" "strings" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" ) -// ActionVariable represents a variable that can be used in actions -// -// It can be: -// 1. global variable, OwnerID is 0 and RepoID is 0 -// 2. org/user level variable, OwnerID is org/user ID and RepoID is 0 -// 3. repo level variable, OwnerID is 0 and RepoID is repo ID -// -// Please note that it's not acceptable to have both OwnerID and RepoID to be non-zero, -// or it will be complicated to find variables belonging to a specific owner. -// For example, conditions like `OwnerID = 1` will also return variable {OwnerID: 1, RepoID: 1}, -// but it's a repo level variable, not an org/user level variable. -// To avoid this, make it clear with {OwnerID: 0, RepoID: 1} for repo level variables. type ActionVariable struct { ID int64 `xorm:"pk autoincr"` OwnerID int64 `xorm:"UNIQUE(owner_repo_name)"` @@ -40,26 +29,30 @@ func init() { db.RegisterModel(new(ActionVariable)) } -func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*ActionVariable, error) { - if ownerID != 0 && repoID != 0 { - // It's trying to create a variable that belongs to a repository, but OwnerID has been set accidentally. - // Remove OwnerID to avoid confusion; it's not worth returning an error here. - ownerID = 0 +func (v *ActionVariable) Validate() error { + if v.OwnerID != 0 && v.RepoID != 0 { + return errors.New("a variable should not be bound to an owner and a repository at the same time") } + return nil +} +func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*ActionVariable, error) { variable := &ActionVariable{ OwnerID: ownerID, RepoID: repoID, Name: strings.ToUpper(name), Data: data, } + if err := variable.Validate(); err != nil { + return variable, err + } return variable, db.Insert(ctx, variable) } type FindVariablesOpts struct { db.ListOptions + OwnerID int64 RepoID int64 - OwnerID int64 // it will be ignored if RepoID is set Name string } @@ -67,13 +60,8 @@ func (opts FindVariablesOpts) ToConds() builder.Cond { cond := builder.NewCond() // Since we now support instance-level variables, // there is no need to check for null values for `owner_id` and `repo_id` + cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) - if opts.RepoID != 0 { // if RepoID is set - // ignore OwnerID and treat it as 0 - cond = cond.And(builder.Eq{"owner_id": 0}) - } else { - cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) - } if opts.Name != "" { cond = cond.And(builder.Eq{"name": strings.ToUpper(opts.Name)}) @@ -86,7 +74,7 @@ func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariab } func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) { - count, err := db.GetEngine(ctx).ID(variable.ID).Where("owner_id = ? AND repo_id = ?", variable.OwnerID, variable.RepoID).Cols("name", "data"). + count, err := db.GetEngine(ctx).ID(variable.ID).Cols("name", "data"). Update(&ActionVariable{ Name: variable.Name, Data: variable.Data, @@ -94,9 +82,11 @@ func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) return count != 0, err } -func DeleteVariable(ctx context.Context, variableID, ownerID, repoID int64) (bool, error) { - count, err := db.GetEngine(ctx).Table("action_variable").Where("id = ? AND owner_id = ? AND repo_id = ?", variableID, ownerID, repoID).Delete() - return count != 0, err +func DeleteVariable(ctx context.Context, id int64) error { + if _, err := db.DeleteByID[ActionVariable](ctx, id); err != nil { + return err + } + return nil } func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) { diff --git a/models/activities/action.go b/models/activities/action.go index f928ad6784..b6c816f096 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -1,13 +1,11 @@ // Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2019 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package activities import ( "context" - "errors" "fmt" "net/url" "path" @@ -16,20 +14,20 @@ import ( "strings" "time" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - "forgejo.org/models/organization" - access_model "forgejo.org/models/perm/access" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unit" - user_model "forgejo.org/models/user" - "forgejo.org/modules/base" - "forgejo.org/modules/container" - "forgejo.org/modules/git" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/structs" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" "xorm.io/xorm/schemas" @@ -249,18 +247,9 @@ func (a *Action) GetActDisplayNameTitle(ctx context.Context) string { return a.GetActFullName(ctx) } -// GetRepo returns the repository of the action. -func (a *Action) GetRepo(ctx context.Context) *repo_model.Repository { - a.loadRepo(ctx) - return a.Repo -} - // GetRepoUserName returns the name of the action repository owner. func (a *Action) GetRepoUserName(ctx context.Context) string { a.loadRepo(ctx) - if a.Repo == nil { - return "(non-existing-repo)" - } return a.Repo.OwnerName } @@ -273,9 +262,6 @@ func (a *Action) ShortRepoUserName(ctx context.Context) string { // GetRepoName returns the name of the action repository. func (a *Action) GetRepoName(ctx context.Context) string { a.loadRepo(ctx) - if a.Repo == nil { - return "(non-existing-repo)" - } return a.Repo.Name } @@ -442,12 +428,6 @@ func (a *Action) GetIssueContent(ctx context.Context) string { return a.Issue.Content } -func GetActivityByID(ctx context.Context, id int64) (*Action, error) { - var act Action - _, err := db.GetEngine(ctx).ID(id).Get(&act) - return &act, err -} - // GetFeedsOptions options for retrieving feeds type GetFeedsOptions struct { db.ListOptions @@ -465,7 +445,7 @@ type GetFeedsOptions struct { // GetFeeds returns actions according to the provided options func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) { if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil { - return nil, 0, errors.New("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") + return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") } cond, err := activityQueryCondition(ctx, opts) @@ -604,14 +584,13 @@ func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error) } // NotifyWatchers creates batch of actions for every watcher. -func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) { +func NotifyWatchers(ctx context.Context, actions ...*Action) error { var watchers []*repo_model.Watch var repo *repo_model.Repository var err error var permCode []bool var permIssue []bool var permPR []bool - var out []Action e := db.GetEngine(ctx) @@ -622,14 +601,14 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) { // Add feeds for user self and all watchers. watchers, err = repo_model.GetWatchers(ctx, act.RepoID) if err != nil { - return nil, fmt.Errorf("get watchers: %w", err) + return fmt.Errorf("get watchers: %w", err) } // Be aware that optimizing this correctly into the `GetWatchers` SQL // query is for most cases less performant than doing this. blockedDoerUserIDs, err := user_model.ListBlockedByUsersID(ctx, act.ActUserID) if err != nil { - return nil, fmt.Errorf("user_model.ListBlockedByUsersID: %w", err) + return fmt.Errorf("user_model.ListBlockedByUsersID: %w", err) } if len(blockedDoerUserIDs) > 0 { @@ -644,9 +623,8 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) { // Add feed for actioner. act.UserID = act.ActUserID if _, err = e.Insert(act); err != nil { - return nil, fmt.Errorf("insert new actioner: %w", err) + return fmt.Errorf("insert new actioner: %w", err) } - out = append(out, *act) if repoChanged { act.loadRepo(ctx) @@ -654,7 +632,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) { // check repo owner exist. if err := act.Repo.LoadOwner(ctx); err != nil { - return nil, fmt.Errorf("can't get repo owner: %w", err) + return fmt.Errorf("can't get repo owner: %w", err) } } else if act.Repo == nil { act.Repo = repo @@ -665,7 +643,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) { act.ID = 0 act.UserID = act.Repo.Owner.ID if err = db.Insert(ctx, act); err != nil { - return nil, fmt.Errorf("insert new actioner: %w", err) + return fmt.Errorf("insert new actioner: %w", err) } } @@ -718,29 +696,26 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) { } if err = db.Insert(ctx, act); err != nil { - return nil, fmt.Errorf("insert new action: %w", err) + return fmt.Errorf("insert new action: %w", err) } } } - return out, nil + return nil } // NotifyWatchersActions creates batch of actions for every watcher. -func NotifyWatchersActions(ctx context.Context, acts []*Action) ([]Action, error) { +func NotifyWatchersActions(ctx context.Context, acts []*Action) error { ctx, committer, err := db.TxContext(ctx) if err != nil { - return nil, err + return err } defer committer.Close() - var out []Action for _, act := range acts { - as, err := NotifyWatchers(ctx, act) - if err != nil { - return nil, err + if err := NotifyWatchers(ctx, act); err != nil { + return err } - out = append(out, as...) } - return out, committer.Commit() + return committer.Commit() } // DeleteIssueActions delete all actions related with issueID diff --git a/models/activities/action_list.go b/models/activities/action_list.go index 64b92bbda1..aafb7f8a26 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -8,12 +8,12 @@ import ( "fmt" "strconv" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/container" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) diff --git a/models/activities/action_test.go b/models/activities/action_test.go index 161d05bbfa..5467bd35fb 100644 --- a/models/activities/action_test.go +++ b/models/activities/action_test.go @@ -8,20 +8,19 @@ import ( "path" "testing" - activities_model "forgejo.org/models/activities" - "forgejo.org/models/db" - issue_model "forgejo.org/models/issues" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - "forgejo.org/modules/setting" + activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" + issue_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestAction_GetRepoPath(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) action := &activities_model.Action{RepoID: repo.ID} @@ -29,7 +28,7 @@ func TestAction_GetRepoPath(t *testing.T) { } func TestAction_GetRepoLink(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 2}) @@ -43,7 +42,7 @@ func TestAction_GetRepoLink(t *testing.T) { func TestGetFeeds(t *testing.T) { // test with an individual user - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ @@ -53,10 +52,10 @@ func TestGetFeeds(t *testing.T) { OnlyPerformedBy: false, IncludeDeleted: true, }) - require.NoError(t, err) + assert.NoError(t, err) if assert.Len(t, actions, 1) { assert.EqualValues(t, 1, actions[0].ID) - assert.Equal(t, user.ID, actions[0].UserID) + assert.EqualValues(t, user.ID, actions[0].UserID) } assert.Equal(t, int64(1), count) @@ -66,13 +65,13 @@ func TestGetFeeds(t *testing.T) { IncludePrivate: false, OnlyPerformedBy: false, }) - require.NoError(t, err) - assert.Empty(t, actions) + assert.NoError(t, err) + assert.Len(t, actions, 0) assert.Equal(t, int64(0), count) } func TestGetFeedsForRepos(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}) @@ -82,8 +81,8 @@ func TestGetFeedsForRepos(t *testing.T) { RequestedRepo: privRepo, IncludePrivate: true, }) - require.NoError(t, err) - assert.Empty(t, actions) + assert.NoError(t, err) + assert.Len(t, actions, 0) assert.Equal(t, int64(0), count) // public repo & no login @@ -91,7 +90,7 @@ func TestGetFeedsForRepos(t *testing.T) { RequestedRepo: pubRepo, IncludePrivate: true, }) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, actions, 1) assert.Equal(t, int64(1), count) @@ -101,7 +100,7 @@ func TestGetFeedsForRepos(t *testing.T) { IncludePrivate: true, Actor: user, }) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, actions, 1) assert.Equal(t, int64(1), count) @@ -111,14 +110,14 @@ func TestGetFeedsForRepos(t *testing.T) { IncludePrivate: true, Actor: user, }) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, actions, 1) assert.Equal(t, int64(1), count) } func TestGetFeeds2(t *testing.T) { // test with an organization user - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) @@ -129,11 +128,11 @@ func TestGetFeeds2(t *testing.T) { OnlyPerformedBy: false, IncludeDeleted: true, }) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, actions, 1) if assert.Len(t, actions, 1) { assert.EqualValues(t, 2, actions[0].ID) - assert.Equal(t, org.ID, actions[0].UserID) + assert.EqualValues(t, org.ID, actions[0].UserID) } assert.Equal(t, int64(1), count) @@ -144,8 +143,8 @@ func TestGetFeeds2(t *testing.T) { OnlyPerformedBy: false, IncludeDeleted: true, }) - require.NoError(t, err) - assert.Empty(t, actions) + assert.NoError(t, err) + assert.Len(t, actions, 0) assert.Equal(t, int64(0), count) } @@ -190,15 +189,14 @@ func TestActivityReadable(t *testing.T) { } func TestNotifyWatchers(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) action := &activities_model.Action{ ActUserID: 8, RepoID: 1, OpType: activities_model.ActionStarRepo, } - _, err := activities_model.NotifyWatchers(db.DefaultContext, action) - require.NoError(t, err) + assert.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action)) // One watchers are inactive, thus action is only created for user 8, 1, 4, 11 unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ @@ -228,7 +226,7 @@ func TestNotifyWatchers(t *testing.T) { } func TestGetFeedsCorrupted(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ ID: 8, @@ -240,8 +238,8 @@ func TestGetFeedsCorrupted(t *testing.T) { Actor: user, IncludePrivate: true, }) - require.NoError(t, err) - assert.Empty(t, actions) + assert.NoError(t, err) + assert.Len(t, actions, 0) assert.Equal(t, int64(0), count) } @@ -249,73 +247,74 @@ func TestConsistencyUpdateAction(t *testing.T) { if !setting.Database.Type.IsSQLite3() { t.Skip("Test is only for SQLite database.") } - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) id := 8 unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ ID: int64(id), }) _, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id) - require.NoError(t, err) + assert.NoError(t, err) actions := make([]*activities_model.Action, 0, 1) // // XORM returns an error when created_unix is a string // err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions) - require.ErrorContains(t, err, "type string to a int64: invalid syntax") - + if assert.Error(t, err) { + assert.Contains(t, err.Error(), "type string to a int64: invalid syntax") + } // // Get rid of incorrectly set created_unix // count, err := activities_model.CountActionCreatedUnixString(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 1, count) count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 1, count) count, err = activities_model.CountActionCreatedUnixString(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 0, count) count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 0, count) // // XORM must be happy now // - require.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)) + assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)) unittest.CheckConsistencyFor(t, &activities_model.Action{}) } func TestDeleteIssueActions(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) // load an issue issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4}) - assert.NotEqual(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex + assert.NotEqualValues(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex // insert a comment err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID}) - require.NoError(t, err) + assert.NoError(t, err) comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID}) // truncate action table and insert some actions err = db.TruncateBeans(db.DefaultContext, &activities_model.Action{}) - require.NoError(t, err) + assert.NoError(t, err) err = db.Insert(db.DefaultContext, &activities_model.Action{ OpType: activities_model.ActionCommentIssue, CommentID: comment.ID, }) - require.NoError(t, err) + assert.NoError(t, err) err = db.Insert(db.DefaultContext, &activities_model.Action{ OpType: activities_model.ActionCreateIssue, RepoID: issue.RepoID, Content: fmt.Sprintf("%d|content...", issue.Index), }) - require.NoError(t, err) + assert.NoError(t, err) // assert that the actions exist, then delete them unittest.AssertCount(t, &activities_model.Action{}, 2) - require.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index)) + assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index)) unittest.AssertCount(t, &activities_model.Action{}, 0) } diff --git a/models/activities/federated_user_activity.go b/models/activities/federated_user_activity.go deleted file mode 100644 index 1ff3a855d0..0000000000 --- a/models/activities/federated_user_activity.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activities - -import ( - "context" - "fmt" - - "forgejo.org/models/db" - user_model "forgejo.org/models/user" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/validation" - - ap "github.com/go-ap/activitypub" -) - -type FederatedUserActivity struct { - ID int64 `xorm:"pk autoincr"` - UserID int64 `xorm:"NOT NULL"` - ActorID int64 - ActorURI string - Actor *user_model.User `xorm:"-"` // transient - NoteContent string `xorm:"TEXT"` - NoteURL string `xorm:"VARCHAR(255)"` - OriginalNote string `xorm:"TEXT"` - Created timeutil.TimeStamp `xorm:"created"` -} - -func init() { - db.RegisterModel(new(FederatedUserActivity)) -} - -func NewFederatedUserActivity(userID, actorID int64, actorURI, noteContent, noteURL string, originalNote ap.Activity) (FederatedUserActivity, error) { - jsonString, err := json.Marshal(originalNote) - if err != nil { - return FederatedUserActivity{}, err - } - result := FederatedUserActivity{ - UserID: userID, - ActorID: actorID, - ActorURI: actorURI, - NoteContent: noteContent, - NoteURL: noteURL, - OriginalNote: string(jsonString), - } - if valid, err := validation.IsValid(result); !valid { - return FederatedUserActivity{}, err - } - return result, nil -} - -func (federatedUserActivity FederatedUserActivity) Validate() []string { - var result []string - result = append(result, validation.ValidateNotEmpty(federatedUserActivity.UserID, "UserID")...) - result = append(result, validation.ValidateNotEmpty(federatedUserActivity.ActorID, "ActorID")...) - result = append(result, validation.ValidateNotEmpty(federatedUserActivity.ActorURI, "ActorURI")...) - result = append(result, validation.ValidateNotEmpty(federatedUserActivity.NoteContent, "NoteContent")...) - result = append(result, validation.ValidateNotEmpty(federatedUserActivity.NoteURL, "NoteURL")...) - result = append(result, validation.ValidateNotEmpty(federatedUserActivity.OriginalNote, "OriginalNote")...) - return result -} - -func CreateUserActivity(ctx context.Context, federatedUserActivity *FederatedUserActivity) error { - if valid, err := validation.IsValid(federatedUserActivity); !valid { - return err - } - _, err := db.GetEngine(ctx).Insert(federatedUserActivity) - return err -} - -type GetFollowingFeedsOptions struct { - db.ListOptions -} - -func GetFollowingFeeds(ctx context.Context, actorID int64, opts GetFollowingFeedsOptions) ([]*FederatedUserActivity, int64, error) { - log.Debug("user_id = %s", actorID) - sess := db.GetEngine(ctx).Where("user_id = ?", actorID) - opts.SetDefaultValues() - sess = db.SetSessionPagination(sess, &opts) - - actions := make([]*FederatedUserActivity, 0, opts.PageSize) - count, err := sess.FindAndCount(&actions) - if err != nil { - return nil, 0, fmt.Errorf("FindAndCount: %w", err) - } - for _, act := range actions { - if err := act.loadActor(ctx); err != nil { - return nil, 0, err - } - } - return actions, count, err -} - -func (federatedUserActivity *FederatedUserActivity) loadActor(ctx context.Context) error { - log.Debug("for activity %s", federatedUserActivity) - actorUser, _, err := user_model.GetFederatedUserByUserID(ctx, federatedUserActivity.ActorID) - if err != nil { - return err - } - federatedUserActivity.Actor = actorUser - - return nil -} diff --git a/models/activities/federated_user_activity_test.go b/models/activities/federated_user_activity_test.go deleted file mode 100644 index 9bf4f77984..0000000000 --- a/models/activities/federated_user_activity_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activities - -import ( - "testing" - - "forgejo.org/modules/validation" -) - -func Test_FederatedUserActivityValidation(t *testing.T) { - sut := FederatedUserActivity{} - sut.UserID = 13 - sut.ActorID = 33 - sut.ActorURI = "33" - sut.NoteContent = "Any content!" - sut.NoteURL = "https://example.org/note/17" - sut.OriginalNote = "federatedUserActivityNote-17" - - if res, _ := validation.IsValid(sut); !res { - t.Errorf("sut expected to be valid: %v\n", sut.Validate()) - } -} diff --git a/models/activities/main_test.go b/models/activities/main_test.go index a5245ab1d3..43afb84ef1 100644 --- a/models/activities/main_test.go +++ b/models/activities/main_test.go @@ -6,11 +6,10 @@ package activities_test import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" - _ "forgejo.org/models" - _ "forgejo.org/models/actions" - _ "forgejo.org/models/forgefed" + _ "code.gitea.io/gitea/models" + _ "code.gitea.io/gitea/models/actions" ) func TestMain(m *testing.M) { diff --git a/models/activities/notification.go b/models/activities/notification.go index 4d13900459..09cc640224 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -9,14 +9,14 @@ import ( "net/url" "strconv" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - "forgejo.org/models/organization" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/organization" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) diff --git a/models/activities/notification_list.go b/models/activities/notification_list.go index 9b266f5d96..32d2a5c051 100644 --- a/models/activities/notification_list.go +++ b/models/activities/notification_list.go @@ -6,14 +6,14 @@ package activities import ( "context" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - access_model "forgejo.org/models/perm/access" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unit" - user_model "forgejo.org/models/user" - "forgejo.org/modules/container" - "forgejo.org/modules/log" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" "xorm.io/builder" ) @@ -107,7 +107,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n return err } toNotify.AddMultiple(issueWatches...) - if !issue.IsPull || !issues_model.HasWorkInProgressPrefix(issue.Title) { + if !(issue.IsPull && issues_model.HasWorkInProgressPrefix(issue.Title)) { repoWatches, err := repo_model.GetRepoWatchersIDs(ctx, issue.RepoID) if err != nil { return err diff --git a/models/activities/notification_test.go b/models/activities/notification_test.go index dfce92d491..52f0eacba1 100644 --- a/models/activities/notification_test.go +++ b/models/activities/notification_test.go @@ -7,21 +7,20 @@ import ( "context" "testing" - activities_model "forgejo.org/models/activities" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" + activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestCreateOrUpdateIssueNotifications(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) - require.NoError(t, activities_model.CreateOrUpdateIssueNotifications(db.DefaultContext, issue.ID, 0, 2, 0)) + assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(db.DefaultContext, issue.ID, 0, 2, 0)) // User 9 is inactive, thus notifications for user 1 and 4 are created notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 1, IssueID: issue.ID}) @@ -33,7 +32,7 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) { } func TestNotificationsForUser(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) notfs, err := db.Find[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{ UserID: user.ID, @@ -42,37 +41,37 @@ func TestNotificationsForUser(t *testing.T) { activities_model.NotificationStatusUnread, }, }) - require.NoError(t, err) + assert.NoError(t, err) if assert.Len(t, notfs, 3) { assert.EqualValues(t, 5, notfs[0].ID) - assert.Equal(t, user.ID, notfs[0].UserID) + assert.EqualValues(t, user.ID, notfs[0].UserID) assert.EqualValues(t, 4, notfs[1].ID) - assert.Equal(t, user.ID, notfs[1].UserID) + assert.EqualValues(t, user.ID, notfs[1].UserID) assert.EqualValues(t, 2, notfs[2].ID) - assert.Equal(t, user.ID, notfs[2].UserID) + assert.EqualValues(t, user.ID, notfs[2].UserID) } } func TestNotification_GetRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1}) repo, err := notf.GetRepo(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, repo, notf.Repository) - assert.Equal(t, notf.RepoID, repo.ID) + assert.EqualValues(t, notf.RepoID, repo.ID) } func TestNotification_GetIssue(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1}) issue, err := notf.GetIssue(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, issue, notf.Issue) - assert.Equal(t, notf.IssueID, issue.ID) + assert.EqualValues(t, notf.IssueID, issue.ID) } func TestGetNotificationCount(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) cnt, err := db.Count[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{ UserID: user.ID, @@ -80,7 +79,7 @@ func TestGetNotificationCount(t *testing.T) { activities_model.NotificationStatusRead, }, }) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 0, cnt) cnt, err = db.Count[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{ @@ -89,28 +88,28 @@ func TestGetNotificationCount(t *testing.T) { activities_model.NotificationStatusUnread, }, }) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 1, cnt) } func TestSetNotificationStatus(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead}) _, err := activities_model.SetNotificationStatus(db.DefaultContext, notf.ID, user, activities_model.NotificationStatusPinned) - require.NoError(t, err) + assert.NoError(t, err) unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: notf.ID, Status: activities_model.NotificationStatusPinned}) _, err = activities_model.SetNotificationStatus(db.DefaultContext, 1, user, activities_model.NotificationStatusRead) - require.Error(t, err) + assert.Error(t, err) _, err = activities_model.SetNotificationStatus(db.DefaultContext, unittest.NonexistentID, user, activities_model.NotificationStatusRead) - require.Error(t, err) + assert.Error(t, err) } func TestUpdateNotificationStatuses(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) notfUnread := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusUnread}) @@ -118,7 +117,7 @@ func TestUpdateNotificationStatuses(t *testing.T) { &activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead}) notfPinned := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusPinned}) - require.NoError(t, activities_model.UpdateNotificationStatuses(db.DefaultContext, user, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead)) + assert.NoError(t, activities_model.UpdateNotificationStatuses(db.DefaultContext, user, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead)) unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: notfUnread.ID, Status: activities_model.NotificationStatusRead}) unittest.AssertExistsAndLoadBean(t, @@ -128,14 +127,14 @@ func TestUpdateNotificationStatuses(t *testing.T) { } func TestSetIssueReadBy(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) - require.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error { + assert.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error { return activities_model.SetIssueReadBy(ctx, issue.ID, user.ID) })) nt, err := activities_model.GetIssueNotification(db.DefaultContext, user.ID, issue.ID) - require.NoError(t, err) - assert.Equal(t, activities_model.NotificationStatusRead, nt.Status) + assert.NoError(t, err) + assert.EqualValues(t, activities_model.NotificationStatusRead, nt.Status) } diff --git a/models/activities/repo_activity.go b/models/activities/repo_activity.go index 3d15c22e19..ba5e4959f0 100644 --- a/models/activities/repo_activity.go +++ b/models/activities/repo_activity.go @@ -9,12 +9,12 @@ import ( "sort" "time" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" - "forgejo.org/modules/gitrepo" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" "xorm.io/xorm" ) @@ -34,7 +34,6 @@ type ActivityStats struct { OpenedPRAuthorCount int64 MergedPRs issues_model.PullRequestList MergedPRAuthorCount int64 - ActiveIssues issues_model.IssueList OpenedIssues issues_model.IssueList OpenedIssueAuthorCount int64 ClosedIssues issues_model.IssueList @@ -173,7 +172,7 @@ func (stats *ActivityStats) MergedPRPerc() int { // ActiveIssueCount returns total active issue count func (stats *ActivityStats) ActiveIssueCount() int { - return len(stats.ActiveIssues) + return stats.OpenedIssueCount() + stats.ClosedIssueCount() } // OpenedIssueCount returns open issue count @@ -286,21 +285,13 @@ func (stats *ActivityStats) FillIssues(ctx context.Context, repoID int64, fromTi stats.ClosedIssueAuthorCount = count // New issues - sess = newlyCreatedIssues(ctx, repoID, fromTime) + sess = issuesForActivityStatement(ctx, repoID, fromTime, false, false) sess.OrderBy("issue.created_unix ASC") stats.OpenedIssues = make(issues_model.IssueList, 0) if err = sess.Find(&stats.OpenedIssues); err != nil { return err } - // Active issues - sess = activeIssues(ctx, repoID, fromTime) - sess.OrderBy("issue.created_unix ASC") - stats.ActiveIssues = make(issues_model.IssueList, 0) - if err = sess.Find(&stats.ActiveIssues); err != nil { - return err - } - // Opened issue authors sess = issuesForActivityStatement(ctx, repoID, fromTime, false, false) if _, err = sess.Select("count(distinct issue.poster_id) as `count`").Table("issue").Get(&count); err != nil { @@ -326,22 +317,6 @@ func (stats *ActivityStats) FillUnresolvedIssues(ctx context.Context, repoID int return sess.Find(&stats.UnresolvedIssues) } -func newlyCreatedIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session { - sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID). - And("issue.is_pull = ?", false). // Retain the is_pull check to exclude pull requests - And("issue.created_unix >= ?", fromTime.Unix()) // Include all issues created after fromTime - - return sess -} - -func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session { - sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID). - And("issue.is_pull = ?", false). - And("issue.created_unix >= ? OR issue.closed_unix >= ?", fromTime.Unix(), fromTime.Unix()) - - return sess -} - func issuesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time, closed, unresolved bool) *xorm.Session { sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID). And("issue.is_closed = ?", closed) diff --git a/models/activities/repo_activity_test.go b/models/activities/repo_activity_test.go deleted file mode 100644 index ce930ada2d..0000000000 --- a/models/activities/repo_activity_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activities - -import ( - "testing" - "time" - - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGetActivityStats(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - - stats, err := GetActivityStats(db.DefaultContext, repo, time.Unix(0, 0), true, true, true, true) - require.NoError(t, err) - - assert.Equal(t, 2, stats.ActiveIssueCount()) - assert.Equal(t, 2, stats.OpenedIssueCount()) - assert.Equal(t, 0, stats.ClosedIssueCount()) - assert.Equal(t, 3, stats.ActivePRCount()) -} diff --git a/models/activities/statistic.go b/models/activities/statistic.go index 4c15cb2898..ff81ad78a1 100644 --- a/models/activities/statistic.go +++ b/models/activities/statistic.go @@ -6,18 +6,18 @@ package activities import ( "context" - asymkey_model "forgejo.org/models/asymkey" - "forgejo.org/models/auth" - "forgejo.org/models/db" - git_model "forgejo.org/models/git" - issues_model "forgejo.org/models/issues" - "forgejo.org/models/organization" - access_model "forgejo.org/models/perm/access" - project_model "forgejo.org/models/project" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/models/webhook" - "forgejo.org/modules/setting" + asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" + project_model "code.gitea.io/gitea/models/project" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/models/webhook" + "code.gitea.io/gitea/modules/setting" ) // Statistic contains the database statistics diff --git a/models/activities/user_heatmap.go b/models/activities/user_heatmap.go index 11badb77e2..080075d793 100644 --- a/models/activities/user_heatmap.go +++ b/models/activities/user_heatmap.go @@ -6,17 +6,11 @@ package activities import ( "context" - "forgejo.org/models/db" - "forgejo.org/models/organization" - user_model "forgejo.org/models/user" - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" -) - -const ( - // contributionsMaxAgeSeconds How old data to retrieve for the heatmap. - // 371 days to cover the entire heatmap (53 *full* weeks) - contributionsMaxAgeSeconds = 32054400 + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/organization" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" ) // UserHeatmapData represents the data needed to create a heatmap @@ -68,7 +62,7 @@ func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organi Select(groupBy+" AS timestamp, count(user_id) as contributions"). Table("action"). Where(cond). - And("created_unix >= ?", timeutil.TimeStampNow()-contributionsMaxAgeSeconds). + And("created_unix > ?", timeutil.TimeStampNow()-31536000). GroupBy("timestamp"). OrderBy("timestamp"). Find(&hdata) diff --git a/models/activities/user_heatmap_test.go b/models/activities/user_heatmap_test.go index 34308cb3d4..b7babcbde1 100644 --- a/models/activities/user_heatmap_test.go +++ b/models/activities/user_heatmap_test.go @@ -4,18 +4,18 @@ package activities_test import ( + "fmt" "testing" "time" - activities_model "forgejo.org/models/activities" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - "forgejo.org/modules/json" - "forgejo.org/modules/timeutil" + activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/timeutil" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestGetUserHeatmapDataByUser(t *testing.T) { @@ -54,13 +54,9 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { "multiple actions performed with two grouped together", 10, 10, 3, `[{"timestamp":1603009800,"contributions":1},{"timestamp":1603010700,"contributions":2}]`, }, - { - "test cutoff within", - 40, 40, 1, `[{"timestamp":1577404800,"contributions":1}]`, - }, } // Prepare - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) // Mock time timeutil.MockSet(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)) @@ -71,7 +67,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { doer := &user_model.User{ID: tc.doerID} _, err := unittest.LoadBeanIfExists(doer) - require.NoError(t, err) + assert.NoError(t, err) if tc.doerID == 0 { doer = nil } @@ -84,7 +80,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { OnlyPerformedBy: true, IncludeDeleted: true, }) - require.NoError(t, err) + assert.NoError(t, err) // Get the heatmap and compare heatmap, err := activities_model.GetUserHeatmapDataByUser(db.DefaultContext, user, doer) @@ -92,14 +88,14 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { for _, hm := range heatmap { contributions += int(hm.Contributions) } - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, actions, contributions, "invalid action count: did the test data became too old?") assert.Equal(t, count, int64(contributions)) - assert.Equal(t, tc.CountResult, contributions, tc.desc) + assert.Equal(t, tc.CountResult, contributions, fmt.Sprintf("testcase '%s'", tc.desc)) // Test JSON rendering jsonData, err := json.Marshal(heatmap) - require.NoError(t, err) - assert.JSONEq(t, tc.JSONResult, string(jsonData)) + assert.NoError(t, err) + assert.Equal(t, tc.JSONResult, string(jsonData)) } } diff --git a/models/admin/task.go b/models/admin/task.go index b4e1ac0134..c8bc95f981 100644 --- a/models/admin/task.go +++ b/models/admin/task.go @@ -7,16 +7,16 @@ import ( "context" "fmt" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/json" - "forgejo.org/modules/migration" - "forgejo.org/modules/secret" - "forgejo.org/modules/setting" - "forgejo.org/modules/structs" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/migration" + "code.gitea.io/gitea/modules/secret" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) // Task represents a task @@ -44,7 +44,7 @@ func init() { // TranslatableMessage represents JSON struct that can be translated with a Locale type TranslatableMessage struct { Format string - Args []any `json:",omitempty"` + Args []any `json:"omitempty"` } // LoadRepo loads repository of the task diff --git a/models/asymkey/asymkey.go b/models/asymkey/asymkey.go deleted file mode 100644 index 1f04e8dada..0000000000 --- a/models/asymkey/asymkey.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later -package asymkey - -import ( - "context" - - "forgejo.org/models/db" -) - -// HasAsymKeyByUID returns true if the user has a GPG key or SSH key associated -// with its account. -func HasAsymKeyByUID(ctx context.Context, userID int64) (bool, error) { - hasGPGKey, err := db.Exist[GPGKey](ctx, FindGPGKeyOptions{ - OwnerID: userID, - IncludeSubKeys: true, - }.ToConds()) - if err != nil { - return false, err - } - if hasGPGKey { - return true, nil - } - - return db.Exist[PublicKey](ctx, FindPublicKeyOptions{ - OwnerID: userID, - KeyTypes: []KeyType{KeyTypeUser}, - }.ToConds()) -} diff --git a/models/asymkey/asymkey_test.go b/models/asymkey/asymkey_test.go deleted file mode 100644 index 1eeb593e40..0000000000 --- a/models/asymkey/asymkey_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later -package asymkey - -import ( - "testing" - - "forgejo.org/models/unittest" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestUserHasAsymKey(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - t.Run("No key", func(t *testing.T) { - ok, err := HasAsymKeyByUID(t.Context(), 1) - require.NoError(t, err) - assert.False(t, ok) - }) - - t.Run("SSH key", func(t *testing.T) { - ok, err := HasAsymKeyByUID(t.Context(), 2) - require.NoError(t, err) - assert.True(t, ok) - }) - - t.Run("GPG key", func(t *testing.T) { - ok, err := HasAsymKeyByUID(t.Context(), 36) - require.NoError(t, err) - assert.True(t, ok) - }) -} diff --git a/models/asymkey/error.go b/models/asymkey/error.go index fc0dd88232..03bc82302f 100644 --- a/models/asymkey/error.go +++ b/models/asymkey/error.go @@ -6,7 +6,7 @@ package asymkey import ( "fmt" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) // ErrKeyUnableVerify represents a "KeyUnableVerify" kind of error. @@ -192,6 +192,28 @@ func (err ErrGPGKeyIDAlreadyUsed) Unwrap() error { return util.ErrAlreadyExist } +// ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error. +type ErrGPGKeyAccessDenied struct { + UserID int64 + KeyID int64 +} + +// IsErrGPGKeyAccessDenied checks if an error is a ErrGPGKeyAccessDenied. +func IsErrGPGKeyAccessDenied(err error) bool { + _, ok := err.(ErrGPGKeyAccessDenied) + return ok +} + +// Error pretty-prints an error of type ErrGPGKeyAccessDenied. +func (err ErrGPGKeyAccessDenied) Error() string { + return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d]", + err.UserID, err.KeyID) +} + +func (err ErrGPGKeyAccessDenied) Unwrap() error { + return util.ErrPermissionDenied +} + // ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. type ErrKeyAccessDenied struct { UserID int64 diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go index 64866da076..5236b2d450 100644 --- a/models/asymkey/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -5,17 +5,16 @@ package asymkey import ( "context" - "errors" "fmt" "strings" "time" - "forgejo.org/models/db" - user_model "forgejo.org/models/user" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/timeutil" - "github.com/ProtonMail/go-crypto/openpgp" - "github.com/ProtonMail/go-crypto/openpgp/packet" + "github.com/keybase/go-crypto/openpgp" + "github.com/keybase/go-crypto/openpgp/packet" "xorm.io/builder" ) @@ -142,12 +141,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified // Parse Subkeys subkeys := make([]*GPGKey, len(e.Subkeys)) for i, k := range e.Subkeys { - subKeyExpiry := expiry - if k.Sig.KeyLifetimeSecs != nil { - subKeyExpiry = k.PublicKey.CreationTime.Add(time.Duration(*k.Sig.KeyLifetimeSecs) * time.Second) - } - - subs, err := parseSubGPGKey(ownerID, pubkey.KeyIdString(), k.PublicKey, subKeyExpiry) + subs, err := parseSubGPGKey(ownerID, pubkey.KeyIdString(), k.PublicKey, expiry) if err != nil { return nil, ErrGPGKeyParsing{ParseError: err} } @@ -162,8 +156,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified emails := make([]*user_model.EmailAddress, 0, len(e.Identities)) for _, ident := range e.Identities { - // Check if the identity is revoked. - if ident.Revoked(time.Now()) { + if ident.Revocation != nil { continue } email := strings.ToLower(strings.TrimSpace(ident.UserId.Email)) @@ -210,7 +203,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified // deleteGPGKey does the actual key deletion func deleteGPGKey(ctx context.Context, keyID string) (int64, error) { if keyID == "" { - return 0, errors.New("empty KeyId forbidden") // Should never happen but just to be sure + return 0, fmt.Errorf("empty KeyId forbidden") // Should never happen but just to be sure } // Delete imported key n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport)) diff --git a/models/asymkey/gpg_key_add.go b/models/asymkey/gpg_key_add.go index 06cfd09a3e..11124b1366 100644 --- a/models/asymkey/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -7,10 +7,10 @@ import ( "context" "strings" - "forgejo.org/models/db" - "forgejo.org/modules/log" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" - "github.com/ProtonMail/go-crypto/openpgp" + "github.com/keybase/go-crypto/openpgp" ) // __________________ ________ ____ __. @@ -83,12 +83,12 @@ func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature str verified := false // Handle provided signature if signature != "" { - signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature), nil) + signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature)) if err != nil { - signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature), nil) + signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature)) } if err != nil { - signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature), nil) + signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature)) } if err != nil { log.Error("Unable to validate token signature. Error: %v", err) diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 73b066b17c..9aa606405e 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -6,9 +6,9 @@ package asymkey import ( "context" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" ) // __________________ ________ ____ __. diff --git a/models/asymkey/gpg_key_common.go b/models/asymkey/gpg_key_common.go index 5b8a22fe63..9c015582f1 100644 --- a/models/asymkey/gpg_key_common.go +++ b/models/asymkey/gpg_key_common.go @@ -7,16 +7,15 @@ import ( "bytes" "crypto" "encoding/base64" - "errors" "fmt" "hash" "io" "strings" "time" - "github.com/ProtonMail/go-crypto/openpgp" - "github.com/ProtonMail/go-crypto/openpgp/armor" - "github.com/ProtonMail/go-crypto/openpgp/packet" + "github.com/keybase/go-crypto/openpgp" + "github.com/keybase/go-crypto/openpgp/armor" + "github.com/keybase/go-crypto/openpgp/packet" ) // __________________ ________ ____ __. @@ -76,7 +75,7 @@ func base64DecPubKey(content string) (*packet.PublicKey, error) { // Check type pkey, ok := p.(*packet.PublicKey) if !ok { - return nil, errors.New("key is not a public key") + return nil, fmt.Errorf("key is not a public key") } return pkey, nil } @@ -89,7 +88,7 @@ func getExpiryTime(e *openpgp.Entity) time.Time { for _, ident := range e.Identities { if selfSig == nil { selfSig = ident.SelfSignature - } else if ident.SelfSignature != nil && ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { + } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { selfSig = ident.SelfSignature break } @@ -115,7 +114,7 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) { return nil, err } if block.Type != openpgp.SignatureType { - return nil, fmt.Errorf("expected %q, got: %s", openpgp.SignatureType, block.Type) + return nil, fmt.Errorf("expected '" + openpgp.SignatureType + "', got: " + block.Type) } return block.Body, nil } @@ -123,15 +122,15 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) { func extractSignature(s string) (*packet.Signature, error) { r, err := readArmoredSign(strings.NewReader(s)) if err != nil { - return nil, errors.New("Failed to read signature armor") + return nil, fmt.Errorf("Failed to read signature armor") } p, err := packet.Read(r) if err != nil { - return nil, errors.New("Failed to read signature packet") + return nil, fmt.Errorf("Failed to read signature packet") } sig, ok := p.(*packet.Signature) if !ok { - return nil, errors.New("Packet is not a signature") + return nil, fmt.Errorf("Packet is not a signature") } return sig, nil } @@ -140,7 +139,7 @@ func tryGetKeyIDFromSignature(sig *packet.Signature) string { if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { return fmt.Sprintf("%016X", *sig.IssuerKeyId) } - if len(sig.IssuerFingerprint) > 0 { + if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 { return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20]) } return "" diff --git a/models/asymkey/gpg_key_import.go b/models/asymkey/gpg_key_import.go index 8a63ea4a35..c9d46d29e5 100644 --- a/models/asymkey/gpg_key_import.go +++ b/models/asymkey/gpg_key_import.go @@ -6,7 +6,7 @@ package asymkey import ( "context" - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" ) // __________________ ________ ____ __. diff --git a/models/asymkey/gpg_key_list.go b/models/asymkey/gpg_key_list.go index b2d4fb11f6..89548e495e 100644 --- a/models/asymkey/gpg_key_list.go +++ b/models/asymkey/gpg_key_list.go @@ -6,7 +6,7 @@ package asymkey import ( "context" - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" ) type GPGKeyList []*GPGKey diff --git a/models/asymkey/gpg_key_object_verification.go b/models/asymkey/gpg_key_object_verification.go index 745ed04869..e5c31a74a7 100644 --- a/models/asymkey/gpg_key_object_verification.go +++ b/models/asymkey/gpg_key_object_verification.go @@ -6,19 +6,18 @@ package asymkey import ( "context" - "errors" "fmt" "hash" "strings" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" - "github.com/ProtonMail/go-crypto/openpgp/packet" + "github.com/keybase/go-crypto/openpgp/packet" ) // This file provides functions related to object (commit, tag) verification @@ -45,8 +44,6 @@ const ( BadDefaultSignature = "gpg.error.probable_bad_default_signature" // NoKeyFound is used as the reason when no key can be found to verify the signature. NoKeyFound = "gpg.error.no_gpg_keys_found" - // NotSigned is used as the reason when the commit is not signed. - NotSigned = "gpg.error.not_signed_commit" ) type GitObject struct { @@ -104,8 +101,8 @@ func ParseObjectWithSignature(ctx context.Context, c *GitObject) *ObjectVerifica if c.Signature == nil { return &ObjectVerification{ CommittingUser: committer, - Verified: false, // Default value - Reason: NotSigned, // Default value + Verified: false, // Default value + Reason: "gpg.error.not_signed_commit", // Default value } } @@ -204,7 +201,7 @@ func ParseObjectWithSignature(ctx context.Context, c *GitObject) *ObjectVerifica } } - if setting.Repository.Signing.Format == "openpgp" && setting.Repository.Signing.SigningKey != "" && setting.Repository.Signing.SigningKey != "default" && setting.Repository.Signing.SigningKey != "none" { + if setting.Repository.Signing.SigningKey != "" && setting.Repository.Signing.SigningKey != "default" && setting.Repository.Signing.SigningKey != "none" { // OK we should try the default key gpgSettings := git.GPGSettings{ Sign: true, @@ -317,7 +314,7 @@ func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, si func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error { // Check if key can sign if !k.CanSign { - return errors.New("key can not sign") + return fmt.Errorf("key can not sign") } // Decode key pkey, err := base64DecPubKey(k.Content) diff --git a/models/asymkey/gpg_key_tag_verification.go b/models/asymkey/gpg_key_tag_verification.go index f054525e8f..5fd3983e54 100644 --- a/models/asymkey/gpg_key_tag_verification.go +++ b/models/asymkey/gpg_key_tag_verification.go @@ -6,7 +6,7 @@ package asymkey import ( "context" - "forgejo.org/modules/git" + "code.gitea.io/gitea/modules/git" ) func ParseTagWithSignature(ctx context.Context, gitRepo *git.Repository, t *git.Tag) *ObjectVerification { diff --git a/models/asymkey/gpg_key_test.go b/models/asymkey/gpg_key_test.go index d265f438eb..d3fbb01d82 100644 --- a/models/asymkey/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -7,15 +7,14 @@ import ( "testing" "time" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" - "github.com/ProtonMail/go-crypto/openpgp/packet" + "github.com/keybase/go-crypto/openpgp/packet" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestCheckArmoredGPGKeyString(t *testing.T) { @@ -51,7 +50,7 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg== -----END PGP PUBLIC KEY BLOCK-----` key, err := checkArmoredGPGKeyString(testGPGArmor) - require.NoError(t, err, "Could not parse a valid GPG public armored rsa key", key) + assert.NoError(t, err, "Could not parse a valid GPG public armored rsa key", key) // TODO verify value of key } @@ -72,7 +71,7 @@ OyjLLnFQiVmq7kEA/0z0CQe3ZQiQIq5zrs7Nh1XRkFAo8GlU/SGC9XFFi722 -----END PGP PUBLIC KEY BLOCK-----` key, err := checkArmoredGPGKeyString(testGPGArmor) - require.NoError(t, err, "Could not parse a valid GPG public armored brainpoolP256r1 key", key) + assert.NoError(t, err, "Could not parse a valid GPG public armored brainpoolP256r1 key", key) // TODO verify value of key } @@ -112,11 +111,11 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg== return } ekey := keys[0] - require.NoError(t, err, "Could not parse a valid GPG armored key", ekey) + assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey) pubkey := ekey.PrimaryKey content, err := base64EncPubKey(pubkey) - require.NoError(t, err, "Could not base64 encode a valid PublicKey content", ekey) + assert.NoError(t, err, "Could not base64 encode a valid PublicKey content", ekey) key := &GPGKey{ KeyID: pubkey.KeyIdString(), @@ -177,27 +176,27 @@ Unknown GPG key with good email ` // Reading Sign goodSig, err := extractSignature(testGoodSigArmor) - require.NoError(t, err, "Could not parse a valid GPG armored signature", testGoodSigArmor) + assert.NoError(t, err, "Could not parse a valid GPG armored signature", testGoodSigArmor) badSig, err := extractSignature(testBadSigArmor) - require.NoError(t, err, "Could not parse a valid GPG armored signature", testBadSigArmor) + assert.NoError(t, err, "Could not parse a valid GPG armored signature", testBadSigArmor) // Generating hash of commit goodHash, err := populateHash(goodSig.Hash, []byte(testGoodPayload)) - require.NoError(t, err, "Could not generate a valid hash of payload", testGoodPayload) + assert.NoError(t, err, "Could not generate a valid hash of payload", testGoodPayload) badHash, err := populateHash(badSig.Hash, []byte(testBadPayload)) - require.NoError(t, err, "Could not generate a valid hash of payload", testBadPayload) + assert.NoError(t, err, "Could not generate a valid hash of payload", testBadPayload) // Verify err = verifySign(goodSig, goodHash, key) - require.NoError(t, err, "Could not validate a good signature") + assert.NoError(t, err, "Could not validate a good signature") err = verifySign(badSig, badHash, key) - require.Error(t, err, "Validate a bad signature") + assert.Error(t, err, "Validate a bad signature") err = verifySign(goodSig, goodHash, cannotsignkey) - require.Error(t, err, "Validate a bad signature with a kay that can not sign") + assert.Error(t, err, "Validate a bad signature with a kay that can not sign") } func TestCheckGPGUserEmail(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) @@ -233,7 +232,7 @@ Q0KHb+QcycSgbDx0ZAvdIacuKvBBcbxrsmFUI4LR+oIup0G9gUc0roPvr014jYQL -----END PGP PUBLIC KEY BLOCK-----` keys, err := AddGPGKey(db.DefaultContext, 1, testEmailWithUpperCaseLetters, "", "") - require.NoError(t, err) + assert.NoError(t, err) if assert.NotEmpty(t, keys) { key := keys[0] if assert.Len(t, key.Emails, 1) { @@ -242,66 +241,6 @@ Q0KHb+QcycSgbDx0ZAvdIacuKvBBcbxrsmFUI4LR+oIup0G9gUc0roPvr014jYQL } } -func TestCheckGPGRevokedIdentity(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - require.NoError(t, db.Insert(db.DefaultContext, &user_model.EmailAddress{UID: 1, Email: "no-reply@golang.com", IsActivated: true})) - require.NoError(t, db.Insert(db.DefaultContext, &user_model.EmailAddress{UID: 1, Email: "revoked@golang.com", IsActivated: true})) - _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - - revokedUserKey := `-----BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFsgO5EBCADhREPmcjsPkXe1z7ctvyWL0S7oa9JaoGZ9oPDHFDlQxd0qlX2e -DZJZDg0qYvVixmaULIulApq1puEsaJCn3lHUbHlb4PYKwLEywYXM28JN91KtLsz/ -uaEX2KC5WqeP40utmzkNLq+oRX/xnRMgwbO7yUNVG2UlEa6eI+xOXO3YtLdmJMBW -ClQ066ZnOIzEo1JxnIwha1CDBMWLLfOLrg6l8InUqaXbtEBbnaIYO6fXVXELUjkx -nmk7t/QOk0tXCy8muH9UDqJkwDUESY2l79XwBAcx9riX8vY7vwC34pm22fAUVLCJ -x1SJx0J8bkeNp38jKM2Zd9SUQqSbfBopQ4pPABEBAAG0I0dvbGFuZyBHb3BoZXIg -PG5vLXJlcGx5QGdvbGFuZy5jb20+iQFUBBMBCgA+FiEE5Ik5JLcNx6l6rZfw1oFy -9I6cUoMFAlsgO5ECGwMFCQPCZwAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ -1oFy9I6cUoMIkwf8DNPeD23i4jRwd/pylbvxwZintZl1fSwTJW1xcOa1emXaEtX2 -depuqhP04fjlRQGfsYAQh7X9jOJxAHjTmhqFBi5sD7QvKU00cPFYbJ/JTx0B41bl -aXnSbGhRPh63QtEZL7ACAs+shwvvojJqysx7kyVRu0EW2wqjXdHwR/SJO6nhNBa2 -DXzSiOU/SUA42mmG+5kjF8Aabq9wPwT9wjraHShEweNerNMmOqJExBOy3yFeyDpa -XwEZFzBfOKoxFNkIaVf5GSdIUGhFECkGvBMB935khftmgR8APxdU4BE7XrXexFJU -8RCuPXonm4WQOwTWR0vQg64pb2WKAzZ8HhwTGbQiR29sYW5nIEdvcGhlciA8cmV2 -b2tlZEBnb2xhbmcuY29tPokBNgQwAQoAIBYhBOSJOSS3Dcepeq2X8NaBcvSOnFKD -BQJbIDv3Ah0AAAoJENaBcvSOnFKDfWMIAKhI/Tvu3h8fSUxp/gSAcduT6bC1JttG -0lYQ5ilKB/58lBUA5CO3ZrKDKlzW3M8VEcvohVaqeTMKeoQd5rCZq8KxHn/KvN6N -s85REfXfniCKfAbnGgVXX3kDmZ1g63pkxrFu0fDZjVDXC6vy+I0sGyI/Inro0Pzb -tvn0QCsxjapKK15BtmSrpgHgzVqVg0cUp8vqZeKFxarYbYB2idtGRci4b9tObOK0 -BSTVFy26+I/mrFGaPrySYiy2Kz5NMEcRhjmTxJ8jSwEr2O2sUR0yjbgUAXbTxDVE -/jg5fQZ1ACvBRQnB7LvMHcInbzjyeTM3FazkkSYQD6b97+dkWwb1iWG5AQ0EWyA7 -kQEIALkg04REDZo1JgdYV4x8HJKFS4xAYWbIva1ZPqvDNmZRUbQZR2+gpJGEwn7z -VofGvnOYiGW56AS5j31SFf5kro1+1bZQ5iOONBng08OOo58/l1hRseIIVGB5TGSa -PCdChKKHreJI6hS3mShxH6hdfFtiZuB45rwoaArMMsYcjaezLwKeLc396cpUwwcZ -snLUNd1Xu5EWEF2OdFkZ2a1qYdxBvAYdQf4+1Nr+NRIx1u1NS9c8jp3PuMOkrQEi -bNtc1v6v0Jy52mKLG4y7mC/erIkvkQBYJdxPaP7LZVaPYc3/xskcyijrJ/5ufoD8 -K71/ShtsZUXSQn9jlRaYR0EbojMAEQEAAYkBPAQYAQoAJhYhBOSJOSS3Dcepeq2X -8NaBcvSOnFKDBQJbIDuRAhsMBQkDwmcAAAoJENaBcvSOnFKDkFMIAIt64bVZ8x7+ -TitH1bR4pgcNkaKmgKoZz6FXu80+SnbuEt2NnDyf1cLOSimSTILpwLIuv9Uft5Pb -OraQbYt3xi9yrqdKqGLv80bxqK0NuryNkvh9yyx5WoG1iKqMj9/FjGghuPrRaT4l -QinNAghGVkEy1+aXGFrG2DsOC1FFI51CC2WVTzZ5RwR2GpiNRfESsU1rZAUqf/2V -yJl9bD5R4SUNy8oQmhOxi+gbhD4Ao34e4W0ilibslI/uawvCiOwlu5NGd8zv5n+U -heiQvzkApQup5c+BhH5zFDFdKJ2CBByxw9+7QjMFI/wgLixKuE0Ob2kAokXf7RlB -7qTZOahrETw= -=IKnw ------END PGP PUBLIC KEY BLOCK----- -` - - keys, err := AddGPGKey(db.DefaultContext, 1, revokedUserKey, "", "") - require.NoError(t, err) - assert.Len(t, keys, 1) - assert.Len(t, keys[0].Emails, 1) - assert.Equal(t, "no-reply@golang.com", keys[0].Emails[0].Email) - - primaryKeyID := "D68172F48E9C5283" - // Assert primary key - unittest.AssertExistsAndLoadBean(t, &GPGKey{OwnerID: 1, KeyID: primaryKeyID, Content: "xsBNBFsgO5EBCADhREPmcjsPkXe1z7ctvyWL0S7oa9JaoGZ9oPDHFDlQxd0qlX2eDZJZDg0qYvVixmaULIulApq1puEsaJCn3lHUbHlb4PYKwLEywYXM28JN91KtLsz/uaEX2KC5WqeP40utmzkNLq+oRX/xnRMgwbO7yUNVG2UlEa6eI+xOXO3YtLdmJMBWClQ066ZnOIzEo1JxnIwha1CDBMWLLfOLrg6l8InUqaXbtEBbnaIYO6fXVXELUjkxnmk7t/QOk0tXCy8muH9UDqJkwDUESY2l79XwBAcx9riX8vY7vwC34pm22fAUVLCJx1SJx0J8bkeNp38jKM2Zd9SUQqSbfBopQ4pPABEBAAE="}) - // Assert subkey - unittest.AssertExistsAndLoadBean(t, &GPGKey{OwnerID: 1, KeyID: "2C56900BE5486AF8", PrimaryKeyID: primaryKeyID, Content: "zsBNBFsgO5EBCAC5INOERA2aNSYHWFeMfByShUuMQGFmyL2tWT6rwzZmUVG0GUdvoKSRhMJ+81aHxr5zmIhluegEuY99UhX+ZK6NftW2UOYjjjQZ4NPDjqOfP5dYUbHiCFRgeUxkmjwnQoSih63iSOoUt5kocR+oXXxbYmbgeOa8KGgKzDLGHI2nsy8Cni3N/enKVMMHGbJy1DXdV7uRFhBdjnRZGdmtamHcQbwGHUH+PtTa/jUSMdbtTUvXPI6dz7jDpK0BImzbXNb+r9CcudpiixuMu5gv3qyJL5EAWCXcT2j+y2VWj2HN/8bJHMoo6yf+bn6A/Cu9f0obbGVF0kJ/Y5UWmEdBG6IzABEBAAE="}) -} - func TestCheckGParseGPGExpire(t *testing.T) { testIssue6599 := `-----BEGIN PGP PUBLIC KEY BLOCK----- @@ -447,7 +386,7 @@ epiDVQ== -----END PGP PUBLIC KEY BLOCK----- ` keys, err := checkArmoredGPGKeyString(testIssue6599) - require.NoError(t, err) + assert.NoError(t, err) if assert.NotEmpty(t, keys) { ekey := keys[0] expire := getExpiryTime(ekey) diff --git a/models/asymkey/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go index 2b5ea7a1ac..01812a2d54 100644 --- a/models/asymkey/gpg_key_verify.go +++ b/models/asymkey/gpg_key_verify.go @@ -8,10 +8,10 @@ import ( "strconv" "time" - "forgejo.org/models/db" - user_model "forgejo.org/models/user" - "forgejo.org/modules/base" - "forgejo.org/modules/log" + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/log" ) // __________________ ________ ____ __. diff --git a/models/asymkey/main_test.go b/models/asymkey/main_test.go index 316e8f1d54..87b5c22c4a 100644 --- a/models/asymkey/main_test.go +++ b/models/asymkey/main_test.go @@ -6,7 +6,7 @@ package asymkey import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { diff --git a/models/asymkey/ssh_key.go b/models/asymkey/ssh_key.go index 7f76009e7f..a409d8e841 100644 --- a/models/asymkey/ssh_key.go +++ b/models/asymkey/ssh_key.go @@ -10,13 +10,13 @@ import ( "strings" "time" - "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/perm" - user_model "forgejo.org/models/user" - "forgejo.org/modules/log" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "golang.org/x/crypto/ssh" "xorm.io/builder" @@ -229,26 +229,35 @@ func UpdatePublicKeyUpdated(ctx context.Context, id int64) error { // PublicKeysAreExternallyManaged returns whether the provided KeyID represents an externally managed Key func PublicKeysAreExternallyManaged(ctx context.Context, keys []*PublicKey) ([]bool, error) { - sourceCache := make(map[int64]*auth.Source, len(keys)) + sources := make([]*auth.Source, 0, 5) externals := make([]bool, len(keys)) - +keyloop: for i, key := range keys { if key.LoginSourceID == 0 { externals[i] = false - continue + continue keyloop } - source, ok := sourceCache[key.LoginSourceID] - if !ok { + var source *auth.Source + + sourceloop: + for _, s := range sources { + if s.ID == key.LoginSourceID { + source = s + break sourceloop + } + } + + if source == nil { var err error source, err = auth.GetSourceByID(ctx, key.LoginSourceID) if err != nil { if auth.IsErrSourceNotExist(err) { externals[i] = false - sourceCache[key.LoginSourceID] = &auth.Source{ + sources[i] = &auth.Source{ ID: key.LoginSourceID, } - continue + continue keyloop } return nil, err } diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go index d3bf6fe886..d3f9f3f3be 100644 --- a/models/asymkey/ssh_key_authorized_keys.go +++ b/models/asymkey/ssh_key_authorized_keys.go @@ -14,10 +14,10 @@ import ( "sync" "time" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) // _____ __ .__ .__ .___ @@ -87,17 +87,20 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error { } defer f.Close() - fi, err := f.Stat() - if err != nil { - return err - } - - // .ssh directory should have mode 700, and authorized_keys file should have mode 600. - if fi.Mode().Perm() > 0o600 { - log.Error("authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String()) - if err = f.Chmod(0o600); err != nil { + // Note: chmod command does not support in Windows. + if !setting.IsWindows { + fi, err := f.Stat() + if err != nil { return err } + + // .ssh directory should have mode 700, and authorized_keys file should have mode 600. + if fi.Mode().Perm() > 0o600 { + log.Error("authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String()) + if err = f.Chmod(0o600); err != nil { + return err + } + } } for _, key := range keys { diff --git a/models/asymkey/ssh_key_authorized_principals.go b/models/asymkey/ssh_key_authorized_principals.go index 0b4fe13ba7..f85de12aae 100644 --- a/models/asymkey/ssh_key_authorized_principals.go +++ b/models/asymkey/ssh_key_authorized_principals.go @@ -13,10 +13,10 @@ import ( "strings" "time" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) // _____ __ .__ .__ .___ diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go index 22e80840af..923c5020ed 100644 --- a/models/asymkey/ssh_key_deploy.go +++ b/models/asymkey/ssh_key_deploy.go @@ -8,9 +8,9 @@ import ( "fmt" "time" - "forgejo.org/models/db" - "forgejo.org/models/perm" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" ) @@ -105,6 +105,14 @@ func addDeployKey(ctx context.Context, keyID, repoID int64, name, fingerprint st return key, db.Insert(ctx, key) } +// HasDeployKey returns true if public key is a deploy key of given repository. +func HasDeployKey(ctx context.Context, keyID, repoID int64) bool { + has, _ := db.GetEngine(ctx). + Where("key_id = ? AND repo_id = ?", keyID, repoID). + Get(new(DeployKey)) + return has +} + // AddDeployKey add new deploy key to database and authorized_keys file. func AddDeployKey(ctx context.Context, repoID int64, name, content string, readOnly bool) (*DeployKey, error) { fingerprint, err := CalcFingerprint(content) diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go index 11112e4bc3..1ed3b5df2a 100644 --- a/models/asymkey/ssh_key_fingerprint.go +++ b/models/asymkey/ssh_key_fingerprint.go @@ -8,11 +8,11 @@ import ( "fmt" "strings" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/process" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "golang.org/x/crypto/ssh" "xorm.io/builder" diff --git a/models/asymkey/ssh_key_object_verification.go b/models/asymkey/ssh_key_object_verification.go index 5d933d35f9..5ad6fdb0a9 100644 --- a/models/asymkey/ssh_key_object_verification.go +++ b/models/asymkey/ssh_key_object_verification.go @@ -9,13 +9,11 @@ import ( "fmt" "strings" - "forgejo.org/models/db" - user_model "forgejo.org/models/user" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" "github.com/42wim/sshsig" - "golang.org/x/crypto/ssh" ) // ParseObjectWithSSHSignature check if signature is good against keystore. @@ -64,22 +62,6 @@ func ParseObjectWithSSHSignature(ctx context.Context, c *GitObject, committer *u } } - // If the SSH instance key is set, try to verify it with that key. - if setting.SSHInstanceKey != nil { - instanceSSHKey := &PublicKey{ - Content: string(ssh.MarshalAuthorizedKey(setting.SSHInstanceKey)), - Fingerprint: ssh.FingerprintSHA256(setting.SSHInstanceKey), - } - instanceUser := &user_model.User{ - Name: setting.Repository.Signing.SigningName, - Email: setting.Repository.Signing.SigningEmail, - } - commitVerification := verifySSHObjectVerification(c.Signature.Signature, c.Signature.Payload, instanceSSHKey, committer, instanceUser, setting.Repository.Signing.SigningEmail) - if commitVerification != nil { - return commitVerification - } - } - return &ObjectVerification{ CommittingUser: committer, Verified: false, diff --git a/models/asymkey/ssh_key_object_verification_test.go b/models/asymkey/ssh_key_object_verification_test.go index 4bfd79d56e..4e229c9b13 100644 --- a/models/asymkey/ssh_key_object_verification_test.go +++ b/models/asymkey/ssh_key_object_verification_test.go @@ -4,23 +4,20 @@ package asymkey import ( - "os" "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "golang.org/x/crypto/ssh" ) func TestParseCommitWithSSHSignature(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) sshKey := unittest.AssertExistsAndLoadBean(t, &PublicKey{ID: 1000, OwnerID: 2}) @@ -152,43 +149,4 @@ muPLbvEduU+Ze/1Ol1pgk= assert.Equal(t, "user2 / SHA256:TKfwbZMR7e9OnlV2l1prfah1TXH8CmqR0PvFEXVCXA4", commitVerification.Reason) assert.Equal(t, sshKey, commitVerification.SigningSSHKey) }) - - t.Run("Instance key", func(t *testing.T) { - pubKeyContent, err := os.ReadFile("../../tests/integration/ssh-signing-key.pub") - require.NoError(t, err) - pubKey, _, _, _, err := ssh.ParseAuthorizedKey(pubKeyContent) - require.NoError(t, err) - - defer test.MockVariableValue(&setting.Repository.Signing.SigningName, "UwU")() - defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "fox@example.com")() - defer test.MockVariableValue(&setting.SSHInstanceKey, pubKey)() - - gitCommit := &git.Commit{ - Committer: &git.Signature{ - Email: "fox@example.com", - }, - Signature: &git.ObjectSignature{ - Payload: `tree f96f1a4f1a51dc42e2983592f503980b60b8849c -parent 93f84db542dd8c6e952c8130bc2fcbe2e299b8b4 -author OwO 1738961379 +0100 -committer UwU 1738961379 +0100 - -Fox -`, - Signature: `-----BEGIN SSH SIGNATURE----- -U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgV5ELwZ8XJe2LLR/UTuEu/vsFdb -t7ry0W8hyzz/b1iocAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 -AAAAQCnyMRkWVVNoZxZkvi/ZoknUhs4LNBmEwZs9e9214WIt+mhKfc6BiHoE2qeluR2McD -Y5RzHnA8Ke9wXddEePCQE= ------END SSH SIGNATURE----- -`, - }, - } - - o := commitToGitObject(gitCommit) - commitVerification := ParseObjectWithSSHSignature(db.DefaultContext, &o, user2) - assert.True(t, commitVerification.Verified) - assert.Equal(t, "UwU / SHA256:QttK41r/zMUeAW71b5UgVSb8xGFF/DlZJ6TyADW+uoI", commitVerification.Reason) - assert.Equal(t, "SHA256:QttK41r/zMUeAW71b5UgVSb8xGFF/DlZJ6TyADW+uoI", commitVerification.SigningSSHKey.Fingerprint) - }) } diff --git a/models/asymkey/ssh_key_parse.go b/models/asymkey/ssh_key_parse.go index 8177db6439..94b1cf112b 100644 --- a/models/asymkey/ssh_key_parse.go +++ b/models/asymkey/ssh_key_parse.go @@ -10,17 +10,16 @@ import ( "encoding/base64" "encoding/binary" "encoding/pem" - "errors" "fmt" "math/big" "os" "strconv" "strings" - "forgejo.org/modules/log" - "forgejo.org/modules/process" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "golang.org/x/crypto/ssh" ) @@ -94,7 +93,7 @@ func parseKeyString(content string) (string, error) { block, _ := pem.Decode([]byte(content)) if block == nil { - return "", errors.New("failed to parse PEM block containing the public key") + return "", fmt.Errorf("failed to parse PEM block containing the public key") } if strings.Contains(block.Type, "PRIVATE") { return "", ErrKeyIsPrivate @@ -220,14 +219,9 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) { return "", 0, fmt.Errorf("ParsePublicKey: %w", err) } - pkeyType := pkey.Type() - if certPkey, ok := pkey.(*ssh.Certificate); ok { - pkeyType = certPkey.Key.Type() - } - // The ssh library can parse the key, so next we find out what key exactly we have. - switch pkeyType { - case ssh.KeyAlgoDSA: //nolint:staticcheck + switch pkey.Type() { + case ssh.KeyAlgoDSA: rawPub := struct { Name string P, Q, G, Y *big.Int diff --git a/models/asymkey/ssh_key_principals.go b/models/asymkey/ssh_key_principals.go index ba2a1a8c7d..4e7dee2c91 100644 --- a/models/asymkey/ssh_key_principals.go +++ b/models/asymkey/ssh_key_principals.go @@ -8,11 +8,11 @@ import ( "fmt" "strings" - "forgejo.org/models/db" - "forgejo.org/models/perm" - user_model "forgejo.org/models/user" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) // AddPrincipalKey adds new principal to database and authorized_principals file. diff --git a/models/asymkey/ssh_key_test.go b/models/asymkey/ssh_key_test.go index bc8cd7d36b..d3e886b97f 100644 --- a/models/asymkey/ssh_key_test.go +++ b/models/asymkey/ssh_key_test.go @@ -12,13 +12,10 @@ import ( "strings" "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/42wim/sshsig" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_SSHParsePublicKey(t *testing.T) { @@ -29,22 +26,22 @@ func Test_SSHParsePublicKey(t *testing.T) { length int content string }{ + {"dsa-1024", false, "dsa", 1024, "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment"}, {"rsa-1024", false, "rsa", 1024, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n"}, {"rsa-2048", false, "rsa", 2048, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMZXh+1OBUwSH9D45wTaxErQIN9IoC9xl7MKJkqvTvv6O5RR9YW/IK9FbfjXgXsppYGhsCZo1hFOOsXHMnfOORqu/xMDx4yPuyvKpw4LePEcg4TDipaDFuxbWOqc/BUZRZcXu41QAWfDLrInwsltWZHSeG7hjhpacl4FrVv9V1pS6Oc5Q1NxxEzTzuNLS/8diZrTm/YAQQ/+B+mzWI3zEtF4miZjjAljWd1LTBPvU23d29DcBmmFahcZ441XZsTeAwGxG/Q6j8NgNXj9WxMeWwxXV2jeAX/EBSpZrCVlCQ1yJswT6xCp8TuBnTiGWYMBNTbOZvPC4e0WI2/yZW/s5F nocomment"}, {"ecdsa-256", false, "ecdsa", 256, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFQacN3PrOll7PXmN5B/ZNVahiUIqI05nbBlZk1KXsO3d06ktAWqbNflv2vEmA38bTFTfJ2sbn2B5ksT52cDDbA= nocomment"}, {"ecdsa-384", false, "ecdsa", 384, "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBINmioV+XRX1Fm9Qk2ehHXJ2tfVxW30ypUWZw670Zyq5GQfBAH6xjygRsJ5wWsHXBsGYgFUXIHvMKVAG1tpw7s6ax9oA+dJOJ7tj+vhn8joFqT+sg3LYHgZkHrfqryRasQ== nocomment"}, {"ecdsa-sk", true, "ecdsa-sk", 256, "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment"}, {"ed25519-sk", true, "ed25519-sk", 256, "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIE7kM1R02+4ertDKGKEDcKG0s+2vyDDcIvceJ0Gqv5f1AAAABHNzaDo= nocomment"}, - {"ed25519-cert-v01", true, "ed25519", 256, "ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIAlIAPlEj0mYQzQo8Ks0Nm/Ct8ceNkyJSf4DLuF5l7+5AAAAIEuWAoaBo2tT29/oMNnoDfdAPRCIdM2RGapKUhY4nDfLRgPQwfnRoc0AAAABAAAAcHZhdWx0LW9pZGMtNmRhYjdiZDgtNDg5YS00MDFkLTg3ZmItNjdjNTlhMDZkZDkxLTNjNTk2M2YyMGRmMDM3MDkyMzc1YmNiYmNiNzkxY2EyZWIxM2I0NGZhMzc2NTcwMWI0MjMwODU0MWFmNjhkNTgAAAALAAAAB2Zvcmdlam8AAAAAZ6/RUQAAAABn115vAAAAAAAAAAAAAAAAAAACFwAAAAdzc2gtcnNhAAAAAwEAAQAAAgEAySnM/TvD117GyKgOgMatDB2t+fCHORFaWVmH5SaadAzNJ2DfDAauRSLfnim1xdgAOMTzsPEEHH47zyYMjE85o2AiJxrfUBMw3O/7AbNc6+HyLr/txH4+vD9tWQknKnpVWM+3Z9wiHDcOdKRoXCmFZKJH1vxs16GNWjwbrfNiimv7Oi0fadgvTDKX603gpLTuVDXqs9eQFLCONptei86JYBAJqaHvg51k8YUCKt9WFqKAj7BJUWmrDvhv5VFMOsnZieJjqxkoxnpsQNlXfPzxK0vIpJofbYfWwscv/g9WZypHwO1ZR2PqzKm99YrSdr8w5256l0f44vsF0NSP0N7bDQEfYYnRGj8zWTYCBFD+uYF7AxIeaRUpZoTQO8MvCHOLMIDinNgEeCUvNA2v9zHl4BGq+PQjzUKAgJiKj0MZeiCDAmQ22g83ggQlB6BOrBb1fNa/S1cmTbGHQ2oAN358aqkmHVCBhPOyA2Rf65D2M2vzDlUdOsNDUIWAHk7GbwSNGDgcYfTWqtR5fTzp2MJovMh1dDUDXjOvojbhzjJtSy9+rzUYIv18aXdOitzVBgPMWdeVCZFZv4OKF+5MiqxQvedUvfiSjsdxZWLxyT1CJ88G3MzxNMS/Djm86T8h/Oa55bdvFtqpsLfvpIqq0pnXq1V/vF2j1MWwRB5z5Xh/HtEAAAIUAAAADHJzYS1zaGEyLTI1NgAAAgB2I2gzqemQl8/ETxtakALlm/2BpUcbhADcFWuoH6BCPnWHuTSwf3OayM6KXv1PQfL3YFRoi9Afrp8kVFL6DePsmKH+0BUEMz71sZ7v1ty7pwfzibItGnpTbQXhzbEiNYAFoz77rl7oaXF7pV6JNZhj3DVAB5gVA2oN5KRNVxijz+6uyuFJEw1HIl1C7GworvGwZcN7BThTEh3i72/Vntejy9Z8uGVjSFjS0rjRo2oXK1LKN0rVt66p3TmCWHouLkVnOTk0qrhLGlL2HVyo24OYHbkAAObD9b6aMDYlmluk6NsaiTKsSTsvMrbIbjtFQlh7nNyoPhZ0VMwaT1l10pDQ5uxWWZjKGIkz4xM1ZfpBszjJNPo+ivYQnTSjj9LwkbLAT9a/5LawSj80TGcLEMO+0eyPdJsP0wYmOVRFAZeRiBgwb3HrzcF6Wqr8icj1EjYkKSy9YFHGTnFBGknpdh3HGwghRXrCUwAnSM76db9pv4/qowT8LthtJ3dY5Epe0OJ1Tqm+q8bkGH4gB+7uqLSqM5pIHSKLp7lfHQBt1J6xa7H2saiweaWjU+QGTgQ2Lg+uUC5DXJrmm60CeFJ4BoGhUenDlgijbQpjH/l6330PbwefgjWtUK/pqaEA4lCoPyvJ+eF2DbYfPiAIBAFQnhVJJae4AH+XoCt29nb2j30ztg== nocomment"}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Run("Native", func(t *testing.T) { keyTypeN, lengthN, err := SSHNativeParsePublicKey(tc.content) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, tc.keyType, keyTypeN) - assert.Equal(t, tc.length, lengthN) + assert.EqualValues(t, tc.length, lengthN) }) if tc.skipSSHKeygen { return @@ -54,19 +51,19 @@ func Test_SSHParsePublicKey(t *testing.T) { if err != nil { // Some servers do not support ecdsa format. if !strings.Contains(err.Error(), "line 1 too long:") { - require.NoError(t, err) + assert.FailNow(t, "%v", err) } } assert.Equal(t, tc.keyType, keyTypeK) - assert.Equal(t, tc.length, lengthK) + assert.EqualValues(t, tc.length, lengthK) }) t.Run("SSHParseKeyNative", func(t *testing.T) { keyTypeK, lengthK, err := SSHNativeParsePublicKey(tc.content) if err != nil { - require.NoError(t, err) + assert.FailNow(t, "%v", err) } assert.Equal(t, tc.keyType, keyTypeK) - assert.Equal(t, tc.length, lengthK) + assert.EqualValues(t, tc.length, lengthK) }) }) } @@ -78,6 +75,7 @@ func Test_CheckPublicKeyString(t *testing.T) { for _, test := range []struct { content string }{ + {"ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment"}, {"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n"}, {"ssh-rsa AAAAB3NzaC1yc2EA\r\nAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+\r\nBZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNx\r\nfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\r\n\r\n"}, {"ssh-rsa AAAAB3NzaC1yc2EA\r\nAAADAQABAAAAgQDAu7tvI\nvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+\r\nBZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvW\nqIwC4prx/WVk2wLTJjzBAhyNx\r\nfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\r\n\r\n"}, @@ -148,7 +146,7 @@ AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf `}, } { _, err := CheckPublicKeyString(test.content) - require.NoError(t, err) + assert.NoError(t, err) } setting.SSH.MinimumKeySizeCheck = oldValue for _, invalidKeys := range []struct { @@ -161,7 +159,7 @@ AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf {"\r\ntest \r\ngitea\r\n\r\n"}, } { _, err := CheckPublicKeyString(invalidKeys.content) - require.Error(t, err) + assert.Error(t, err) } } @@ -172,6 +170,7 @@ func Test_calcFingerprint(t *testing.T) { fp string content string }{ + {"dsa-1024", false, "SHA256:fSIHQlpKMDsGPVAXI8BPYfRp+e2sfvSt1sMrPsFiXrc", "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment"}, {"rsa-1024", false, "SHA256:vSnDkvRh/xM6kMxPidLgrUhq3mCN7CDaronCEm2joyQ", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n"}, {"rsa-2048", false, "SHA256:ZHD//a1b9VuTq9XSunAeYjKeU1xDa2tBFZYrFr2Okkg", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMZXh+1OBUwSH9D45wTaxErQIN9IoC9xl7MKJkqvTvv6O5RR9YW/IK9FbfjXgXsppYGhsCZo1hFOOsXHMnfOORqu/xMDx4yPuyvKpw4LePEcg4TDipaDFuxbWOqc/BUZRZcXu41QAWfDLrInwsltWZHSeG7hjhpacl4FrVv9V1pS6Oc5Q1NxxEzTzuNLS/8diZrTm/YAQQ/+B+mzWI3zEtF4miZjjAljWd1LTBPvU23d29DcBmmFahcZ441XZsTeAwGxG/Q6j8NgNXj9WxMeWwxXV2jeAX/EBSpZrCVlCQ1yJswT6xCp8TuBnTiGWYMBNTbOZvPC4e0WI2/yZW/s5F nocomment"}, {"ecdsa-256", false, "SHA256:Bqx/xgWqRKLtkZ0Lr4iZpgb+5lYsFpSwXwVZbPwuTRw", "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFQacN3PrOll7PXmN5B/ZNVahiUIqI05nbBlZk1KXsO3d06ktAWqbNflv2vEmA38bTFTfJ2sbn2B5ksT52cDDbA= nocomment"}, @@ -184,7 +183,7 @@ func Test_calcFingerprint(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Run("Native", func(t *testing.T) { fpN, err := calcFingerprintNative(tc.content) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, tc.fp, fpN) }) if tc.skipSSHKeygen { @@ -192,7 +191,7 @@ func Test_calcFingerprint(t *testing.T) { } t.Run("SSHKeygen", func(t *testing.T) { fpK, err := calcFingerprintSSHKeygen(tc.content) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, tc.fp, fpK) }) }) @@ -504,11 +503,3 @@ func runErr(t *testing.T, stdin []byte, args ...string) { t.Fatal("expected error") } } - -func Test_PublicKeysAreExternallyManaged(t *testing.T) { - key1 := unittest.AssertExistsAndLoadBean(t, &PublicKey{ID: 1}) - externals, err := PublicKeysAreExternallyManaged(db.DefaultContext, []*PublicKey{key1}) - require.NoError(t, err) - assert.Len(t, externals, 1) - assert.False(t, externals[0]) -} diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index 5dd26ccc9a..208288c77b 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -7,8 +7,8 @@ import ( "bytes" "context" - "forgejo.org/models/db" - "forgejo.org/modules/log" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" "github.com/42wim/sshsig" ) diff --git a/models/auth/TestOrphanedOAuth2Applications/oauth2_application.yaml b/models/auth/TestOrphanedOAuth2Applications/oauth2_application.yaml index cccb404ab1..b188770a30 100644 --- a/models/auth/TestOrphanedOAuth2Applications/oauth2_application.yaml +++ b/models/auth/TestOrphanedOAuth2Applications/oauth2_application.yaml @@ -23,11 +23,3 @@ redirect_uris: '["http://127.0.0.1", "https://127.0.0.1"]' created_unix: 1712358091 updated_unix: 1712358091 -- - id: 1003 - uid: 0 - name: "Global Auth source that should be kept" - client_id: "2f3467c1-7b3b-463d-ab04-2ae2b2712826" - redirect_uris: '["http://example.com/globalapp", "https://example.com/globalapp"]' - created_unix: 1732387292 - updated_unix: 1732387292 diff --git a/models/auth/access_token.go b/models/auth/access_token.go index 695702b7a0..63331b4841 100644 --- a/models/auth/access_token.go +++ b/models/auth/access_token.go @@ -11,10 +11,10 @@ import ( "fmt" "time" - "forgejo.org/models/db" - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" lru "github.com/hashicorp/golang-lru/v2" "xorm.io/builder" @@ -98,24 +98,20 @@ func init() { // NewAccessToken creates new access token. func NewAccessToken(ctx context.Context, t *AccessToken) error { - err := generateAccessToken(t) - if err != nil { - return err - } - _, err = db.GetEngine(ctx).Insert(t) - return err -} - -func generateAccessToken(t *AccessToken) error { salt, err := util.CryptoRandomString(10) if err != nil { return err } + token, err := util.CryptoRandomBytes(20) + if err != nil { + return err + } t.TokenSalt = salt - t.Token = hex.EncodeToString(util.CryptoRandomBytes(20)) + t.Token = hex.EncodeToString(token) t.TokenHash = HashToken(t.Token, t.TokenSalt) t.TokenLastEight = t.Token[len(t.Token)-8:] - return nil + _, err = db.GetEngine(ctx).Insert(t) + return err } // DisplayPublicOnly whether to display this as a public-only token. @@ -238,25 +234,3 @@ func DeleteAccessTokenByID(ctx context.Context, id, userID int64) error { } return nil } - -// RegenerateAccessTokenByID regenerates access token by given ID. -// It regenerates token and salt, as well as updates the creation time. -func RegenerateAccessTokenByID(ctx context.Context, id, userID int64) (*AccessToken, error) { - t := &AccessToken{} - found, err := db.GetEngine(ctx).Where("id = ? AND uid = ?", id, userID).Get(t) - if err != nil { - return nil, err - } else if !found { - return nil, ErrAccessTokenNotExist{} - } - - err = generateAccessToken(t) - if err != nil { - return nil, err - } - - // Reset the creation time, token is unused - t.UpdatedUnix = timeutil.TimeStampNow() - - return t, UpdateAccessToken(ctx, t) -} diff --git a/models/auth/access_token_scope.go b/models/auth/access_token_scope.go index d14838cf02..003ca5c9ab 100644 --- a/models/auth/access_token_scope.go +++ b/models/auth/access_token_scope.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - "forgejo.org/models/perm" + "code.gitea.io/gitea/models/perm" ) // AccessTokenScopeCategory represents the scope category for an access token @@ -283,10 +283,6 @@ func (s AccessTokenScope) Normalize() (AccessTokenScope, error) { return bitmap.toScope(), nil } -func (s AccessTokenScope) HasPermissionScope() bool { - return s != "" && s != AccessTokenScopePublicOnly -} - // PublicOnly checks if this token scope is limited to public resources func (s AccessTokenScope) PublicOnly() (bool, error) { bitmap, err := s.parse() diff --git a/models/auth/access_token_test.go b/models/auth/access_token_test.go index 913118433c..4360f1a214 100644 --- a/models/auth/access_token_test.go +++ b/models/auth/access_token_test.go @@ -6,21 +6,20 @@ package auth_test import ( "testing" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestNewAccessToken(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token := &auth_model.AccessToken{ UID: 3, Name: "Token C", } - require.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token)) + assert.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token)) unittest.AssertExistsAndLoadBean(t, token) invalidToken := &auth_model.AccessToken{ @@ -28,13 +27,13 @@ func TestNewAccessToken(t *testing.T) { UID: 2, Name: "Token F", } - require.Error(t, auth_model.NewAccessToken(db.DefaultContext, invalidToken)) + assert.Error(t, auth_model.NewAccessToken(db.DefaultContext, invalidToken)) } func TestAccessTokenByNameExists(t *testing.T) { name := "Token Gitea" - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token := &auth_model.AccessToken{ UID: 3, Name: name, @@ -42,16 +41,16 @@ func TestAccessTokenByNameExists(t *testing.T) { // Check to make sure it doesn't exists already exist, err := auth_model.AccessTokenByNameExists(db.DefaultContext, token) - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, exist) // Save it to the database - require.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token)) + assert.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token)) unittest.AssertExistsAndLoadBean(t, token) // This token must be found by name in the DB now exist, err = auth_model.AccessTokenByNameExists(db.DefaultContext, token) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, exist) user4Token := &auth_model.AccessToken{ @@ -62,32 +61,32 @@ func TestAccessTokenByNameExists(t *testing.T) { // Name matches but different user ID, this shouldn't exists in the // database exist, err = auth_model.AccessTokenByNameExists(db.DefaultContext, user4Token) - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, exist) } func TestGetAccessTokenBySHA(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "d2c6c1ba3890b309189a8e618c72a162e4efbf36") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, int64(1), token.UID) assert.Equal(t, "Token A", token.Name) assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash) assert.Equal(t, "e4efbf36", token.TokenLastEight) _, err = auth_model.GetAccessTokenBySHA(db.DefaultContext, "notahash") - require.Error(t, err) + assert.Error(t, err) assert.True(t, auth_model.IsErrAccessTokenNotExist(err)) _, err = auth_model.GetAccessTokenBySHA(db.DefaultContext, "") - require.Error(t, err) + assert.Error(t, err) assert.True(t, auth_model.IsErrAccessTokenEmpty(err)) } func TestListAccessTokens(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) tokens, err := db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 1}) - require.NoError(t, err) + assert.NoError(t, err) if assert.Len(t, tokens, 2) { assert.Equal(t, int64(1), tokens[0].UID) assert.Equal(t, int64(1), tokens[1].UID) @@ -96,63 +95,38 @@ func TestListAccessTokens(t *testing.T) { } tokens, err = db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 2}) - require.NoError(t, err) + assert.NoError(t, err) if assert.Len(t, tokens, 1) { assert.Equal(t, int64(2), tokens[0].UID) assert.Equal(t, "Token A", tokens[0].Name) } tokens, err = db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 100}) - require.NoError(t, err) + assert.NoError(t, err) assert.Empty(t, tokens) } func TestUpdateAccessToken(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c") - require.NoError(t, err) + assert.NoError(t, err) token.Name = "Token Z" - require.NoError(t, auth_model.UpdateAccessToken(db.DefaultContext, token)) + assert.NoError(t, auth_model.UpdateAccessToken(db.DefaultContext, token)) unittest.AssertExistsAndLoadBean(t, token) } func TestDeleteAccessTokenByID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, int64(1), token.UID) - require.NoError(t, auth_model.DeleteAccessTokenByID(db.DefaultContext, token.ID, 1)) + assert.NoError(t, auth_model.DeleteAccessTokenByID(db.DefaultContext, token.ID, 1)) unittest.AssertNotExistsBean(t, token) err = auth_model.DeleteAccessTokenByID(db.DefaultContext, 100, 100) - require.Error(t, err) + assert.Error(t, err) assert.True(t, auth_model.IsErrAccessTokenNotExist(err)) } - -func TestRegenerateAccessTokenByID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c") - require.NoError(t, err) - - newToken, err := auth_model.RegenerateAccessTokenByID(db.DefaultContext, token.ID, 1) - require.NoError(t, err) - unittest.AssertNotExistsBean(t, &auth_model.AccessToken{ID: token.ID, UID: token.UID, TokenHash: token.TokenHash}) - newToken = &auth_model.AccessToken{ - ID: newToken.ID, - UID: newToken.UID, - TokenHash: newToken.TokenHash, - } - unittest.AssertExistsAndLoadBean(t, newToken) - - // Token has been recreated, new salt and hash, but should retain the same ID, UID, Name and Scope - assert.Equal(t, token.ID, newToken.ID) - assert.NotEqual(t, token.TokenHash, newToken.TokenHash) - assert.NotEqual(t, token.TokenSalt, newToken.TokenSalt) - assert.Equal(t, token.UID, newToken.UID) - assert.Equal(t, token.Name, newToken.Name) - assert.Equal(t, token.Scope, newToken.Scope) -} diff --git a/models/auth/auth_token.go b/models/auth/auth_token.go index d09aebcf85..2c3ca90734 100644 --- a/models/auth/auth_token.go +++ b/models/auth/auth_token.go @@ -10,36 +10,17 @@ import ( "fmt" "time" - "forgejo.org/models/db" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) -type AuthorizationPurpose string - -var ( - // Used to store long term authorization tokens. - LongTermAuthorization AuthorizationPurpose = "long_term_authorization" - - // Used to activate a user account. - UserActivation AuthorizationPurpose = "user_activation" - - // Used to reset the password. - PasswordReset AuthorizationPurpose = "password_reset" -) - -// Used to activate the specified email address for a user. -func EmailActivation(email string) AuthorizationPurpose { - return AuthorizationPurpose("email_activation:" + email) -} - // AuthorizationToken represents a authorization token to a user. type AuthorizationToken struct { ID int64 `xorm:"pk autoincr"` UID int64 `xorm:"INDEX"` LookupKey string `xorm:"INDEX UNIQUE"` HashedValidator string - Purpose AuthorizationPurpose `xorm:"NOT NULL DEFAULT 'long_term_authorization'"` Expiry timeutil.TimeStamp } @@ -60,10 +41,13 @@ func (authToken *AuthorizationToken) IsExpired() bool { // GenerateAuthToken generates a new authentication token for the given user. // It returns the lookup key and validator values that should be passed to the // user via a long-term cookie. -func GenerateAuthToken(ctx context.Context, userID int64, expiry timeutil.TimeStamp, purpose AuthorizationPurpose) (lookupKey, validator string, err error) { +func GenerateAuthToken(ctx context.Context, userID int64, expiry timeutil.TimeStamp) (lookupKey, validator string, err error) { // Request 64 random bytes. The first 32 bytes will be used for the lookupKey // and the other 32 bytes will be used for the validator. - rBytes := util.CryptoRandomBytes(64) + rBytes, err := util.CryptoRandomBytes(64) + if err != nil { + return "", "", err + } hexEncoded := hex.EncodeToString(rBytes) validator, lookupKey = hexEncoded[64:], hexEncoded[:64] @@ -72,15 +56,14 @@ func GenerateAuthToken(ctx context.Context, userID int64, expiry timeutil.TimeSt Expiry: expiry, LookupKey: lookupKey, HashedValidator: HashValidator(rBytes[32:]), - Purpose: purpose, }) return lookupKey, validator, err } // FindAuthToken will find a authorization token via the lookup key. -func FindAuthToken(ctx context.Context, lookupKey string, purpose AuthorizationPurpose) (*AuthorizationToken, error) { +func FindAuthToken(ctx context.Context, lookupKey string) (*AuthorizationToken, error) { var authToken AuthorizationToken - has, err := db.GetEngine(ctx).Where("lookup_key = ? AND purpose = ?", lookupKey, purpose).Get(&authToken) + has, err := db.GetEngine(ctx).Where("lookup_key = ?", lookupKey).Get(&authToken) if err != nil { return nil, err } else if !has { diff --git a/models/auth/main_test.go b/models/auth/main_test.go index b30db24483..d772ea6b1c 100644 --- a/models/auth/main_test.go +++ b/models/auth/main_test.go @@ -6,14 +6,13 @@ package auth_test import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" - _ "forgejo.org/models" - _ "forgejo.org/models/actions" - _ "forgejo.org/models/activities" - _ "forgejo.org/models/auth" - _ "forgejo.org/models/forgefed" - _ "forgejo.org/models/perm/access" + _ "code.gitea.io/gitea/models" + _ "code.gitea.io/gitea/models/actions" + _ "code.gitea.io/gitea/models/activities" + _ "code.gitea.io/gitea/models/auth" + _ "code.gitea.io/gitea/models/perm/access" ) func TestMain(m *testing.M) { diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index fa68197cf0..125d64b36f 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -14,11 +14,11 @@ import ( "net/url" "strings" - "forgejo.org/models/db" - "forgejo.org/modules/container" - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" uuid "github.com/google/uuid" "golang.org/x/crypto/bcrypt" @@ -184,9 +184,13 @@ var base32Lower = base32.NewEncoding(lowerBase32Chars).WithPadding(base32.NoPadd // GenerateClientSecret will generate the client secret and returns the plaintext and saves the hash at the database func (app *OAuth2Application) GenerateClientSecret(ctx context.Context) (string, error) { + rBytes, err := util.CryptoRandomBytes(32) + if err != nil { + return "", err + } // Add a prefix to the base32, this is in order to make it easier // for code scanners to grab sensitive tokens. - clientSecret := "gto_" + base32Lower.EncodeToString(util.CryptoRandomBytes(32)) + clientSecret := "gto_" + base32Lower.EncodeToString(rBytes) hashedSecret, err := bcrypt.GenerateFromPassword([]byte(clientSecret), bcrypt.DefaultCost) if err != nil { @@ -471,9 +475,13 @@ func (grant *OAuth2Grant) TableName() string { // GenerateNewAuthorizationCode generates a new authorization code for a grant and saves it to the database func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redirectURI, codeChallenge, codeChallengeMethod string) (code *OAuth2AuthorizationCode, err error) { + rBytes, err := util.CryptoRandomBytes(32) + if err != nil { + return &OAuth2AuthorizationCode{}, err + } // Add a prefix to the base32, this is in order to make it easier // for code scanners to grab sensitive tokens. - codeSecret := "gta_" + base32Lower.EncodeToString(util.CryptoRandomBytes(32)) + codeSecret := "gta_" + base32Lower.EncodeToString(rBytes) code = &OAuth2AuthorizationCode{ Grant: grant, @@ -649,7 +657,6 @@ func CountOrphanedOAuth2Applications(ctx context.Context) (int64, error) { Table("`oauth2_application`"). Join("LEFT", "`user`", "`oauth2_application`.`uid` = `user`.`id`"). Where(builder.IsNull{"`user`.id"}). - Where(builder.Neq{"uid": 0}). // exclude instance-wide admin applications Where(builder.NotIn("`oauth2_application`.`client_id`", BuiltinApplicationsClientIDs())). Select("COUNT(`oauth2_application`.`id`)"). Count() @@ -661,7 +668,6 @@ func DeleteOrphanedOAuth2Applications(ctx context.Context) (int64, error) { From("`oauth2_application`"). Join("LEFT", "`user`", "`oauth2_application`.`uid` = `user`.`id`"). Where(builder.IsNull{"`user`.id"}). - Where(builder.Neq{"uid": 0}). // exclude instance-wide admin applications Where(builder.NotIn("`oauth2_application`.`client_id`", BuiltinApplicationsClientIDs())) b := builder.Delete(builder.In("id", subQuery)).From("`oauth2_application`") diff --git a/models/auth/oauth2_list.go b/models/auth/oauth2_list.go index 6f508833a0..c55f10b3c8 100644 --- a/models/auth/oauth2_list.go +++ b/models/auth/oauth2_list.go @@ -4,7 +4,7 @@ package auth import ( - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" "xorm.io/builder" ) diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go index 9c6836ed0d..a6fbcdaa4f 100644 --- a/models/auth/oauth2_test.go +++ b/models/auth/oauth2_test.go @@ -4,28 +4,29 @@ package auth_test import ( + "path/filepath" "slices" "testing" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestOAuth2Application_GenerateClientSecret(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1}) secret, err := app.GenerateClientSecret(db.DefaultContext) - require.NoError(t, err) - assert.NotEmpty(t, secret) + assert.NoError(t, err) + assert.True(t, len(secret) > 0) unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1, ClientSecret: app.ClientSecret}) } func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) { - require.NoError(b, unittest.PrepareTestDatabase()) + assert.NoError(b, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1}) for i := 0; i < b.N; i++ { _, _ = app.GenerateClientSecret(db.DefaultContext) @@ -76,29 +77,29 @@ func TestOAuth2Application_ContainsRedirect_Slash(t *testing.T) { } func TestOAuth2Application_ValidateClientSecret(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1}) secret, err := app.GenerateClientSecret(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, app.ValidateClientSecret([]byte(secret))) assert.False(t, app.ValidateClientSecret([]byte("fewijfowejgfiowjeoifew"))) } func TestGetOAuth2ApplicationByClientID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) app, err := auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "da7da3ba-9a13-4167-856f-3899de0b0138") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "da7da3ba-9a13-4167-856f-3899de0b0138", app.ClientID) app, err = auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "invalid client id") - require.Error(t, err) + assert.Error(t, err) assert.Nil(t, app) } func TestCreateOAuth2Application(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) app, err := auth_model.CreateOAuth2Application(db.DefaultContext, auth_model.CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1}) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "newapp", app.Name) assert.Len(t, app.ClientID, 36) unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{Name: "newapp"}) @@ -109,51 +110,51 @@ func TestOAuth2Application_TableName(t *testing.T) { } func TestOAuth2Application_GetGrantByUserID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1}) grant, err := app.GetGrantByUserID(db.DefaultContext, 1) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, int64(1), grant.UserID) grant, err = app.GetGrantByUserID(db.DefaultContext, 34923458) - require.NoError(t, err) + assert.NoError(t, err) assert.Nil(t, grant) } func TestOAuth2Application_CreateGrant(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1}) grant, err := app.CreateGrant(db.DefaultContext, 2, "") - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, grant) assert.Equal(t, int64(2), grant.UserID) assert.Equal(t, int64(1), grant.ApplicationID) - assert.Empty(t, grant.Scope) + assert.Equal(t, "", grant.Scope) } //////////////////// Grant func TestGetOAuth2GrantByID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) grant, err := auth_model.GetOAuth2GrantByID(db.DefaultContext, 1) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, int64(1), grant.ID) grant, err = auth_model.GetOAuth2GrantByID(db.DefaultContext, 34923458) - require.NoError(t, err) + assert.NoError(t, err) assert.Nil(t, grant) } func TestOAuth2Grant_IncreaseCounter(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 1}) - require.NoError(t, grant.IncreaseCounter(db.DefaultContext)) + assert.NoError(t, grant.IncreaseCounter(db.DefaultContext)) assert.Equal(t, int64(2), grant.Counter) unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 2}) } func TestOAuth2Grant_ScopeContains(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Scope: "openid profile"}) assert.True(t, grant.ScopeContains("openid")) assert.True(t, grant.ScopeContains("profile")) @@ -162,12 +163,12 @@ func TestOAuth2Grant_ScopeContains(t *testing.T) { } func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1}) code, err := grant.GenerateNewAuthorizationCode(db.DefaultContext, "https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256") - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, code) - assert.Greater(t, len(code.Code), 32) // secret length > 32 + assert.True(t, len(code.Code) > 32) // secret length > 32 } func TestOAuth2Grant_TableName(t *testing.T) { @@ -175,36 +176,36 @@ func TestOAuth2Grant_TableName(t *testing.T) { } func TestGetOAuth2GrantsByUserID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) result, err := auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 1) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, result, 1) assert.Equal(t, int64(1), result[0].ID) assert.Equal(t, result[0].ApplicationID, result[0].Application.ID) result, err = auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 34134) - require.NoError(t, err) + assert.NoError(t, err) assert.Empty(t, result) } func TestRevokeOAuth2Grant(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - require.NoError(t, auth_model.RevokeOAuth2Grant(db.DefaultContext, 1, 1)) + assert.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, auth_model.RevokeOAuth2Grant(db.DefaultContext, 1, 1)) unittest.AssertNotExistsBean(t, &auth_model.OAuth2Grant{ID: 1, UserID: 1}) } //////////////////// Authorization Code func TestGetOAuth2AuthorizationByCode(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) code, err := auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "authcode") - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, code) assert.Equal(t, "authcode", code.Code) assert.Equal(t, int64(1), code.ID) code, err = auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "does not exist") - require.NoError(t, err) + assert.NoError(t, err) assert.Nil(t, code) } @@ -247,18 +248,18 @@ func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) { } redirect, err := code.GenerateRedirectURI("thestate") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "https://example.com/callback?code=thecode&state=thestate", redirect.String()) redirect, err = code.GenerateRedirectURI("") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "https://example.com/callback?code=thecode", redirect.String()) } func TestOAuth2AuthorizationCode_Invalidate(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) code := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"}) - require.NoError(t, code.Invalidate(db.DefaultContext)) + assert.NoError(t, code.Invalidate(db.DefaultContext)) unittest.AssertNotExistsBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"}) } @@ -269,24 +270,29 @@ func TestOAuth2AuthorizationCode_TableName(t *testing.T) { func TestBuiltinApplicationsClientIDs(t *testing.T) { clientIDs := auth_model.BuiltinApplicationsClientIDs() slices.Sort(clientIDs) - assert.Equal(t, []string{"a4792ccc-144e-407e-86c9-5e7d8d9c3269", "d57cb8c4-630c-4168-8324-ec79935e18d4", "e90ee53c-94e2-48ac-9358-a874fb9e0662"}, clientIDs) + assert.EqualValues(t, []string{"a4792ccc-144e-407e-86c9-5e7d8d9c3269", "d57cb8c4-630c-4168-8324-ec79935e18d4", "e90ee53c-94e2-48ac-9358-a874fb9e0662"}, clientIDs) } func TestOrphanedOAuth2Applications(t *testing.T) { - defer unittest.OverrideFixtures("models/auth/TestOrphanedOAuth2Applications")() - require.NoError(t, unittest.PrepareTestDatabase()) + defer unittest.OverrideFixtures( + unittest.FixturesOptions{ + Dir: filepath.Join(setting.AppWorkPath, "models/fixtures/"), + Base: setting.AppWorkPath, + Dirs: []string{"models/auth/TestOrphanedOAuth2Applications/"}, + }, + )() + assert.NoError(t, unittest.PrepareTestDatabase()) count, err := auth_model.CountOrphanedOAuth2Applications(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 1, count) unittest.AssertExistsIf(t, true, &auth_model.OAuth2Application{ID: 1002}) _, err = auth_model.DeleteOrphanedOAuth2Applications(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) count, err = auth_model.CountOrphanedOAuth2Applications(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 0, count) unittest.AssertExistsIf(t, false, &auth_model.OAuth2Application{ID: 1002}) - unittest.AssertExistsIf(t, true, &auth_model.OAuth2Application{ID: 1003}) } diff --git a/models/auth/session.go b/models/auth/session.go index b3724dafb6..75a205f702 100644 --- a/models/auth/session.go +++ b/models/auth/session.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "forgejo.org/models/db" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" ) diff --git a/models/auth/session_test.go b/models/auth/session_test.go index 0f07038187..8cc0abc737 100644 --- a/models/auth/session_test.go +++ b/models/auth/session_test.go @@ -7,17 +7,16 @@ import ( "testing" "time" - "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/timeutil" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestAuthSession(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) defer timeutil.MockUnset() key := "I-Like-Free-Software" @@ -25,30 +24,30 @@ func TestAuthSession(t *testing.T) { t.Run("Create Session", func(t *testing.T) { // Ensure it doesn't exist. ok, err := auth.ExistSession(db.DefaultContext, key) - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, ok) preCount, err := auth.CountSessions(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) now := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC) timeutil.MockSet(now) // New session is created. sess, err := auth.ReadSession(db.DefaultContext, key) - require.NoError(t, err) - assert.Equal(t, key, sess.Key) + assert.NoError(t, err) + assert.EqualValues(t, key, sess.Key) assert.Empty(t, sess.Data) assert.EqualValues(t, now.Unix(), sess.Expiry) // Ensure it exists. ok, err = auth.ExistSession(db.DefaultContext, key) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, ok) // Ensure the session is taken into account for count.. postCount, err := auth.CountSessions(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.Greater(t, postCount, preCount) }) @@ -59,16 +58,16 @@ func TestAuthSession(t *testing.T) { // Update session. err := auth.UpdateSession(db.DefaultContext, key, data) - require.NoError(t, err) + assert.NoError(t, err) timeutil.MockSet(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)) // Read updated session. // Ensure data is updated and expiry is set from the update session call. sess, err := auth.ReadSession(db.DefaultContext, key) - require.NoError(t, err) - assert.Equal(t, key, sess.Key) - assert.Equal(t, data, sess.Data) + assert.NoError(t, err) + assert.EqualValues(t, key, sess.Key) + assert.EqualValues(t, data, sess.Data) assert.EqualValues(t, now.Unix(), sess.Expiry) timeutil.MockSet(now) @@ -77,23 +76,23 @@ func TestAuthSession(t *testing.T) { t.Run("Delete session", func(t *testing.T) { // Ensure it't exist. ok, err := auth.ExistSession(db.DefaultContext, key) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, ok) preCount, err := auth.CountSessions(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) err = auth.DestroySession(db.DefaultContext, key) - require.NoError(t, err) + assert.NoError(t, err) // Ensure it doesn't exists. ok, err = auth.ExistSession(db.DefaultContext, key) - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, ok) // Ensure the session is taken into account for count.. postCount, err := auth.CountSessions(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.Less(t, postCount, preCount) }) @@ -101,43 +100,43 @@ func TestAuthSession(t *testing.T) { timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)) _, err := auth.ReadSession(db.DefaultContext, "sess-1") - require.NoError(t, err) + assert.NoError(t, err) // One minute later. timeutil.MockSet(time.Date(2023, 1, 1, 0, 1, 0, 0, time.UTC)) _, err = auth.ReadSession(db.DefaultContext, "sess-2") - require.NoError(t, err) + assert.NoError(t, err) // 5 minutes, shouldn't clean up anything. err = auth.CleanupSessions(db.DefaultContext, 5*60) - require.NoError(t, err) + assert.NoError(t, err) ok, err := auth.ExistSession(db.DefaultContext, "sess-1") - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, ok) ok, err = auth.ExistSession(db.DefaultContext, "sess-2") - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, ok) // 1 minute, should clean up sess-1. err = auth.CleanupSessions(db.DefaultContext, 60) - require.NoError(t, err) + assert.NoError(t, err) ok, err = auth.ExistSession(db.DefaultContext, "sess-1") - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, ok) ok, err = auth.ExistSession(db.DefaultContext, "sess-2") - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, ok) // Now, should clean up sess-2. err = auth.CleanupSessions(db.DefaultContext, 0) - require.NoError(t, err) + assert.NoError(t, err) ok, err = auth.ExistSession(db.DefaultContext, "sess-2") - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, ok) }) } diff --git a/models/auth/source.go b/models/auth/source.go index ecd3abc39d..d03d4975dc 100644 --- a/models/auth/source.go +++ b/models/auth/source.go @@ -9,11 +9,11 @@ import ( "fmt" "reflect" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/optional" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" "xorm.io/xorm" @@ -32,7 +32,7 @@ const ( PAM // 4 DLDAP // 5 OAuth2 // 6 - _ // 7 (was SSPI) + SSPI // 7 Remote // 8 ) @@ -53,6 +53,7 @@ var Names = map[Type]string{ SMTP: "SMTP", PAM: "PAM", OAuth2: "OAuth2", + SSPI: "SPNEGO with SSPI", Remote: "Remote", } @@ -177,6 +178,11 @@ func (source *Source) IsOAuth2() bool { return source.Type == OAuth2 } +// IsSSPI returns true of this source is of the SSPI type. +func (source *Source) IsSSPI() bool { + return source.Type == SSPI +} + func (source *Source) IsRemote() bool { return source.Type == Remote } @@ -259,6 +265,20 @@ func (opts FindSourcesOptions) ToConds() builder.Cond { return conds } +// IsSSPIEnabled returns true if there is at least one activated login +// source of type LoginSSPI +func IsSSPIEnabled(ctx context.Context) bool { + exist, err := db.Exist[Source](ctx, FindSourcesOptions{ + IsActive: optional.Some(true), + LoginType: SSPI, + }.ToConds()) + if err != nil { + log.Error("IsSSPIEnabled: failed to query active SSPI sources: %v", err) + return false + } + return exist +} + // GetSourceByID returns login source by given ID. func GetSourceByID(ctx context.Context, id int64) (*Source, error) { source := new(Source) @@ -279,6 +299,17 @@ func GetSourceByID(ctx context.Context, id int64) (*Source, error) { return source, nil } +func GetSourceByName(ctx context.Context, name string) (*Source, error) { + source := &Source{} + has, err := db.GetEngine(ctx).Where("name = ?", name).Get(source) + if err != nil { + return nil, err + } else if !has { + return nil, ErrSourceNotExist{} + } + return source, nil +} + // UpdateSource updates a Source record in DB. func UpdateSource(ctx context.Context, source *Source) error { var originalSource *Source diff --git a/models/auth/source_test.go b/models/auth/source_test.go index ed21aef253..36e76d5e28 100644 --- a/models/auth/source_test.go +++ b/models/auth/source_test.go @@ -7,13 +7,12 @@ import ( "strings" "testing" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - "forgejo.org/modules/json" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "xorm.io/xorm/schemas" ) @@ -36,10 +35,10 @@ func (source *TestSource) ToDB() ([]byte, error) { } func TestDumpAuthSource(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) authSourceSchema, err := db.TableInfo(new(auth_model.Source)) - require.NoError(t, err) + assert.NoError(t, err) auth_model.RegisterTypeConfig(auth_model.OAuth2, new(TestSource)) diff --git a/models/auth/two_factor.go b/models/auth/two_factor.go deleted file mode 100644 index e8f19c33cc..0000000000 --- a/models/auth/two_factor.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later -package auth - -import ( - "context" -) - -// HasTwoFactorByUID returns true if the user has TOTP or WebAuthn enabled for -// their account. -func HasTwoFactorByUID(ctx context.Context, userID int64) (bool, error) { - hasTOTP, err := HasTOTPByUID(ctx, userID) - if err != nil { - return false, err - } - if hasTOTP { - return true, nil - } - - return HasWebAuthnRegistrationsByUID(ctx, userID) -} diff --git a/models/auth/two_factor_test.go b/models/auth/two_factor_test.go deleted file mode 100644 index 36e0404ae2..0000000000 --- a/models/auth/two_factor_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later -package auth - -import ( - "testing" - - "forgejo.org/models/unittest" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestHasTwoFactorByUID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - t.Run("No twofactor", func(t *testing.T) { - ok, err := HasTwoFactorByUID(t.Context(), 2) - require.NoError(t, err) - assert.False(t, ok) - }) - - t.Run("WebAuthn credential", func(t *testing.T) { - ok, err := HasTwoFactorByUID(t.Context(), 32) - require.NoError(t, err) - assert.True(t, ok) - }) - - t.Run("TOTP", func(t *testing.T) { - ok, err := HasTwoFactorByUID(t.Context(), 24) - require.NoError(t, err) - assert.True(t, ok) - }) -} diff --git a/models/auth/twofactor.go b/models/auth/twofactor.go index 9a53ad30e0..d0c341a192 100644 --- a/models/auth/twofactor.go +++ b/models/auth/twofactor.go @@ -5,16 +5,19 @@ package auth import ( "context" + "crypto/md5" "crypto/sha256" "crypto/subtle" "encoding/base32" + "encoding/base64" "encoding/hex" "fmt" - "forgejo.org/models/db" - "forgejo.org/modules/keying" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/secret" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "github.com/pquerna/otp/totp" "golang.org/x/crypto/pbkdf2" @@ -46,9 +49,9 @@ func (err ErrTwoFactorNotEnrolled) Unwrap() error { // TwoFactor represents a two-factor authentication token. type TwoFactor struct { - ID int64 `xorm:"pk autoincr"` - UID int64 `xorm:"UNIQUE"` - Secret []byte `xorm:"BLOB"` + ID int64 `xorm:"pk autoincr"` + UID int64 `xorm:"UNIQUE"` + Secret string ScratchSalt string ScratchHash string LastUsedPasscode string `xorm:"VARCHAR(10)"` @@ -61,13 +64,17 @@ func init() { } // GenerateScratchToken recreates the scratch token the user is using. -func (t *TwoFactor) GenerateScratchToken() string { +func (t *TwoFactor) GenerateScratchToken() (string, error) { + tokenBytes, err := util.CryptoRandomBytes(6) + if err != nil { + return "", err + } // these chars are specially chosen, avoid ambiguous chars like `0`, `O`, `1`, `I`. const base32Chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" - token := base32.NewEncoding(base32Chars).WithPadding(base32.NoPadding).EncodeToString(util.CryptoRandomBytes(6)) + token := base32.NewEncoding(base32Chars).WithPadding(base32.NoPadding).EncodeToString(tokenBytes) t.ScratchSalt, _ = util.CryptoRandomString(10) t.ScratchHash = HashToken(token, t.ScratchSalt) - return token + return token, nil } // HashToken return the hashable salt @@ -85,35 +92,39 @@ func (t *TwoFactor) VerifyScratchToken(token string) bool { return subtle.ConstantTimeCompare([]byte(t.ScratchHash), []byte(tempHash)) == 1 } +func (t *TwoFactor) getEncryptionKey() []byte { + k := md5.Sum([]byte(setting.SecretKey)) + return k[:] +} + // SetSecret sets the 2FA secret. -func (t *TwoFactor) SetSecret(secretString string) { - key := keying.DeriveKey(keying.ContextTOTP) - t.Secret = key.Encrypt([]byte(secretString), keying.ColumnAndID("secret", t.ID)) +func (t *TwoFactor) SetSecret(secretString string) error { + secretBytes, err := secret.AesEncrypt(t.getEncryptionKey(), []byte(secretString)) + if err != nil { + return err + } + t.Secret = base64.StdEncoding.EncodeToString(secretBytes) + return nil } // ValidateTOTP validates the provided passcode. func (t *TwoFactor) ValidateTOTP(passcode string) (bool, error) { - key := keying.DeriveKey(keying.ContextTOTP) - secret, err := key.Decrypt(t.Secret, keying.ColumnAndID("secret", t.ID)) + decodedStoredSecret, err := base64.StdEncoding.DecodeString(t.Secret) if err != nil { return false, err } - return totp.Validate(passcode, string(secret)), nil + secretBytes, err := secret.AesDecrypt(t.getEncryptionKey(), decodedStoredSecret) + if err != nil { + return false, err + } + secretStr := string(secretBytes) + return totp.Validate(passcode, secretStr), nil } // NewTwoFactor creates a new two-factor authentication token. -func NewTwoFactor(ctx context.Context, t *TwoFactor, secret string) error { - return db.WithTx(ctx, func(ctx context.Context) error { - sess := db.GetEngine(ctx) - _, err := sess.Insert(t) - if err != nil { - return err - } - - t.SetSecret(secret) - _, err = sess.Cols("secret").ID(t.ID).Update(t) - return err - }) +func NewTwoFactor(ctx context.Context, t *TwoFactor) error { + _, err := db.GetEngine(ctx).Insert(t) + return err } // UpdateTwoFactor updates a two-factor authentication token. @@ -135,9 +146,9 @@ func GetTwoFactorByUID(ctx context.Context, uid int64) (*TwoFactor, error) { return twofa, nil } -// HasTOTPByUID returns the TOTP authentication token associated with -// the user, if the user has TOTP enabled for their account. -func HasTOTPByUID(ctx context.Context, uid int64) (bool, error) { +// HasTwoFactorByUID returns the two-factor authentication token associated with +// the user, if any. +func HasTwoFactorByUID(ctx context.Context, uid int64) (bool, error) { return db.GetEngine(ctx).Where("uid=?", uid).Exist(&TwoFactor{}) } diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go index 5b86a6e6f2..a65d2e1e34 100644 --- a/models/auth/webauthn.go +++ b/models/auth/webauthn.go @@ -8,9 +8,9 @@ import ( "fmt" "strings" - "forgejo.org/models/db" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "github.com/go-webauthn/webauthn/webauthn" ) @@ -40,7 +40,7 @@ func IsErrWebAuthnCredentialNotExist(err error) bool { } // WebAuthnCredential represents the WebAuthn credential data for a public-key -// credential conformant to WebAuthn Level 3 +// credential conformant to WebAuthn Level 1 type WebAuthnCredential struct { ID int64 `xorm:"pk autoincr"` Name string @@ -52,12 +52,8 @@ type WebAuthnCredential struct { AAGUID []byte SignCount uint32 `xorm:"BIGINT"` CloneWarning bool - BackupEligible bool `xorm:"NOT NULL DEFAULT false"` - BackupState bool `xorm:"NOT NULL DEFAULT false"` - // If legacy is set to true, backup_eligible and backup_state isn't set. - Legacy bool `xorm:"NOT NULL DEFAULT true"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` } func init() { @@ -75,12 +71,6 @@ func (cred *WebAuthnCredential) UpdateSignCount(ctx context.Context) error { return err } -// UpdateFromLegacy update the values that aren't present on legacy credentials. -func (cred *WebAuthnCredential) UpdateFromLegacy(ctx context.Context) error { - _, err := db.GetEngine(ctx).ID(cred.ID).Cols("legacy", "backup_eligible", "backup_state").Update(cred) - return err -} - // BeforeInsert will be invoked by XORM before updating a record func (cred *WebAuthnCredential) BeforeInsert() { cred.LowerName = strings.ToLower(cred.Name) @@ -107,10 +97,6 @@ func (list WebAuthnCredentialList) ToCredentials() []webauthn.Credential { ID: cred.CredentialID, PublicKey: cred.PublicKey, AttestationType: cred.AttestationType, - Flags: webauthn.CredentialFlags{ - BackupEligible: cred.BackupEligible, - BackupState: cred.BackupState, - }, Authenticator: webauthn.Authenticator{ AAGUID: cred.AAGUID, SignCount: cred.SignCount, @@ -181,9 +167,6 @@ func CreateCredential(ctx context.Context, userID int64, name string, cred *weba AAGUID: cred.Authenticator.AAGUID, SignCount: cred.Authenticator.SignCount, CloneWarning: false, - BackupEligible: cred.Flags.BackupEligible, - BackupState: cred.Flags.BackupState, - Legacy: false, } if err := db.Insert(ctx, c); err != nil { diff --git a/models/auth/webauthn_test.go b/models/auth/webauthn_test.go index abf8e34408..f1cf398adf 100644 --- a/models/auth/webauthn_test.go +++ b/models/auth/webauthn_test.go @@ -6,32 +6,31 @@ package auth_test import ( "testing" - auth_model "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/go-webauthn/webauthn/webauthn" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestGetWebAuthnCredentialByID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) res, err := auth_model.GetWebAuthnCredentialByID(db.DefaultContext, 1) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "WebAuthn credential", res.Name) _, err = auth_model.GetWebAuthnCredentialByID(db.DefaultContext, 342432) - require.Error(t, err) + assert.Error(t, err) assert.True(t, auth_model.IsErrWebAuthnCredentialNotExist(err)) } func TestGetWebAuthnCredentialsByUID(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) res, err := auth_model.GetWebAuthnCredentialsByUID(db.DefaultContext, 32) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, res, 1) assert.Equal(t, "WebAuthn credential", res[0].Name) } @@ -41,38 +40,28 @@ func TestWebAuthnCredential_TableName(t *testing.T) { } func TestWebAuthnCredential_UpdateSignCount(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred.SignCount = 1 - require.NoError(t, cred.UpdateSignCount(db.DefaultContext)) + assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1}) } func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred.SignCount = 0xffffffff - require.NoError(t, cred.UpdateSignCount(db.DefaultContext)) + assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff}) } -func TestWebAuthenCredential_UpdateFromLegacy(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1, Legacy: true}) - cred.Legacy = false - cred.BackupEligible = true - cred.BackupState = true - require.NoError(t, cred.UpdateFromLegacy(db.DefaultContext)) - unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, BackupEligible: true, BackupState: true}, "legacy = false") -} - func TestCreateCredential(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) - res, err := auth_model.CreateCredential(db.DefaultContext, 1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test"), Flags: webauthn.CredentialFlags{BackupEligible: true, BackupState: true}}) - require.NoError(t, err) + res, err := auth_model.CreateCredential(db.DefaultContext, 1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")}) + assert.NoError(t, err) assert.Equal(t, "WebAuthn Created Credential", res.Name) assert.Equal(t, []byte("Test"), res.CredentialID) - unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1, BackupEligible: true, BackupState: true}, "legacy = false") + unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1}) } diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go index ad59bd8769..9c56e0f9a0 100644 --- a/models/avatars/avatar.go +++ b/models/avatars/avatar.go @@ -14,12 +14,12 @@ import ( "strings" "sync/atomic" - "forgejo.org/models/db" - "forgejo.org/modules/cache" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" - "code.forgejo.org/forgejo-contrib/go-libravatar" + "strk.kbt.io/projects/go/libravatar" ) const ( diff --git a/models/avatars/avatar_test.go b/models/avatars/avatar_test.go index 7850d2c096..c8f7a6574b 100644 --- a/models/avatars/avatar_test.go +++ b/models/avatars/avatar_test.go @@ -6,28 +6,27 @@ package avatars_test import ( "testing" - avatars_model "forgejo.org/models/avatars" - "forgejo.org/models/db" - system_model "forgejo.org/models/system" - "forgejo.org/modules/setting" - "forgejo.org/modules/setting/config" + avatars_model "code.gitea.io/gitea/models/avatars" + "code.gitea.io/gitea/models/db" + system_model "code.gitea.io/gitea/models/system" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/setting/config" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const gravatarSource = "https://secure.gravatar.com/avatar/" func disableGravatar(t *testing.T) { err := system_model.SetSettings(db.DefaultContext, map[string]string{setting.Config().Picture.EnableFederatedAvatar.DynKey(): "false"}) - require.NoError(t, err) + assert.NoError(t, err) err = system_model.SetSettings(db.DefaultContext, map[string]string{setting.Config().Picture.DisableGravatar.DynKey(): "true"}) - require.NoError(t, err) + assert.NoError(t, err) } func enableGravatar(t *testing.T) { err := system_model.SetSettings(db.DefaultContext, map[string]string{setting.Config().Picture.DisableGravatar.DynKey(): "false"}) - require.NoError(t, err) + assert.NoError(t, err) setting.GravatarSource = gravatarSource } diff --git a/models/avatars/main_test.go b/models/avatars/main_test.go index bdc66954b1..c721a7dc2a 100644 --- a/models/avatars/main_test.go +++ b/models/avatars/main_test.go @@ -6,11 +6,11 @@ package avatars_test import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" - _ "forgejo.org/models" - _ "forgejo.org/models/activities" - _ "forgejo.org/models/perm/access" + _ "code.gitea.io/gitea/models" + _ "code.gitea.io/gitea/models/activities" + _ "code.gitea.io/gitea/models/perm/access" ) func TestMain(m *testing.M) { diff --git a/models/db/collation.go b/models/db/collation.go index 768ada89e6..39d28fa2ff 100644 --- a/models/db/collation.go +++ b/models/db/collation.go @@ -8,9 +8,9 @@ import ( "fmt" "strings" - "forgejo.org/modules/container" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" "xorm.io/xorm/schemas" diff --git a/models/db/common.go b/models/db/common.go index c9b012597c..f3fd3e72ae 100644 --- a/models/db/common.go +++ b/models/db/common.go @@ -6,8 +6,8 @@ package db import ( "strings" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) diff --git a/models/db/context.go b/models/db/context.go index 3e035cd733..43f612518a 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -141,7 +141,7 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) { return nil, nil, err } - return newContext(parentCtx, sess, true), sess, nil + return newContext(DefaultContext, sess, true), sess, nil } // WithTx represents executing database operations on a transaction, if the transaction exist, @@ -269,9 +269,6 @@ func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([ // DecrByIDs decreases the given column for entities of the "bean" type with one of the given ids by one // Timestamps of the entities won't be updated func DecrByIDs(ctx context.Context, ids []int64, decrCol string, bean any) error { - if len(ids) == 0 { - return nil - } _, err := GetEngine(ctx).Decr(decrCol).In("id", ids).NoAutoCondition().NoAutoTime().Update(bean) return err } diff --git a/models/db/context_committer_test.go b/models/db/context_committer_test.go index 849c5dea41..38e91f22ed 100644 --- a/models/db/context_committer_test.go +++ b/models/db/context_committer_test.go @@ -4,7 +4,7 @@ package db // it's not db_test, because this file is for testing the private type halfCommitter import ( - "errors" + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -80,7 +80,7 @@ func Test_halfCommitter(t *testing.T) { testWithCommitter(mockCommitter, func(committer Committer) error { defer committer.Close() if true { - return errors.New("error") + return fmt.Errorf("error") } return committer.Commit() }) @@ -94,7 +94,7 @@ func Test_halfCommitter(t *testing.T) { testWithCommitter(mockCommitter, func(committer Committer) error { committer.Close() committer.Commit() - return errors.New("error") + return fmt.Errorf("error") }) mockCommitter.Assert(t) diff --git a/models/db/context_test.go b/models/db/context_test.go index d12d79ebe1..95a01d4a26 100644 --- a/models/db/context_test.go +++ b/models/db/context_test.go @@ -7,93 +7,80 @@ import ( "context" "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestInTransaction(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) assert.False(t, db.InTransaction(db.DefaultContext)) - require.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error { + assert.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error { assert.True(t, db.InTransaction(ctx)) return nil })) ctx, committer, err := db.TxContext(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) defer committer.Close() assert.True(t, db.InTransaction(ctx)) - require.NoError(t, db.WithTx(ctx, func(ctx context.Context) error { + assert.NoError(t, db.WithTx(ctx, func(ctx context.Context) error { assert.True(t, db.InTransaction(ctx)) return nil })) } func TestTxContext(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) { // create new transaction ctx, committer, err := db.TxContext(db.DefaultContext) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, db.InTransaction(ctx)) - require.NoError(t, committer.Commit()) + assert.NoError(t, committer.Commit()) } { // reuse the transaction created by TxContext and commit it ctx, committer, err := db.TxContext(db.DefaultContext) engine := db.GetEngine(ctx) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, db.InTransaction(ctx)) { ctx, committer, err := db.TxContext(ctx) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, db.InTransaction(ctx)) assert.Equal(t, engine, db.GetEngine(ctx)) - require.NoError(t, committer.Commit()) + assert.NoError(t, committer.Commit()) } - require.NoError(t, committer.Commit()) + assert.NoError(t, committer.Commit()) } { // reuse the transaction created by TxContext and close it ctx, committer, err := db.TxContext(db.DefaultContext) engine := db.GetEngine(ctx) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, db.InTransaction(ctx)) { ctx, committer, err := db.TxContext(ctx) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, db.InTransaction(ctx)) assert.Equal(t, engine, db.GetEngine(ctx)) - require.NoError(t, committer.Close()) + assert.NoError(t, committer.Close()) } - require.NoError(t, committer.Close()) + assert.NoError(t, committer.Close()) } { // reuse the transaction created by WithTx - require.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error { + assert.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error { assert.True(t, db.InTransaction(ctx)) { ctx, committer, err := db.TxContext(ctx) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, db.InTransaction(ctx)) - require.NoError(t, committer.Commit()) + assert.NoError(t, committer.Commit()) } return nil })) } - - t.Run("Reuses parent context", func(t *testing.T) { - type unique struct{} - - ctx := context.WithValue(db.DefaultContext, unique{}, "yes!") - assert.False(t, db.InTransaction(ctx)) - - require.NoError(t, db.WithTx(ctx, func(ctx context.Context) error { - assert.Equal(t, "yes!", ctx.Value(unique{})) - return nil - })) - }) } diff --git a/models/db/convert.go b/models/db/convert.go index 1f37e49176..b8b15382e7 100644 --- a/models/db/convert.go +++ b/models/db/convert.go @@ -6,10 +6,9 @@ package db import ( "fmt" "strconv" - "strings" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" "xorm.io/xorm/schemas" @@ -26,8 +25,7 @@ func ConvertDatabaseTable() error { return err } - databaseName := strings.SplitN(setting.Database.Name, "?", 2)[0] - _, err = x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", databaseName, r.ExpectedCollation)) + _, err = x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", setting.Database.Name, r.ExpectedCollation)) if err != nil { return err } @@ -58,7 +56,6 @@ func Cell2Int64(val xorm.Cell) int64 { v, _ := strconv.ParseInt(string((*val).([]uint8)), 10, 64) return v - default: - return (*val).(int64) } + return (*val).(int64) } diff --git a/models/db/engine.go b/models/db/engine.go index 05a119b08d..61649592e7 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -11,12 +11,11 @@ import ( "fmt" "io" "reflect" - "runtime/trace" "strings" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" "xorm.io/xorm/contexts" @@ -95,70 +94,34 @@ func init() { } } -// newXORMEngineGroup creates an xorm.EngineGroup (with one master and one or more slaves). -// It assumes you have separate master and slave DSNs defined via the settings package. -func newXORMEngineGroup() (Engine, error) { - // Retrieve master DSN from settings. - masterConnStr, err := setting.DBMasterConnStr() +// newXORMEngine returns a new XORM engine from the configuration +func newXORMEngine() (*xorm.Engine, error) { + connStr, err := setting.DBConnStr() if err != nil { - return nil, fmt.Errorf("failed to determine master DSN: %w", err) + return nil, err } - var masterEngine *xorm.Engine - // For PostgreSQL: if a schema is provided, we use the special "postgresschema" driver. + var engine *xorm.Engine + if setting.Database.Type.IsPostgreSQL() && len(setting.Database.Schema) > 0 { + // OK whilst we sort out our schema issues - create a schema aware postgres registerPostgresSchemaDriver() - masterEngine, err = xorm.NewEngine("postgresschema", masterConnStr) + engine, err = xorm.NewEngine("postgresschema", connStr) } else { - masterEngine, err = xorm.NewEngine(setting.Database.Type.String(), masterConnStr) + engine, err = xorm.NewEngine(setting.Database.Type.String(), connStr) } + if err != nil { - return nil, fmt.Errorf("failed to create master engine: %w", err) + return nil, err } if setting.Database.Type.IsMySQL() { - masterEngine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"}) + engine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"}) } - masterEngine.SetSchema(setting.Database.Schema) - - slaveConnStrs, err := setting.DBSlaveConnStrs() - if err != nil { - return nil, fmt.Errorf("failed to load slave DSNs: %w", err) - } - - var slaveEngines []*xorm.Engine - // Iterate over all slave DSNs and create engines - for _, dsn := range slaveConnStrs { - slaveEngine, err := xorm.NewEngine(setting.Database.Type.String(), dsn) - if err != nil { - return nil, fmt.Errorf("failed to create slave engine for dsn %q: %w", dsn, err) - } - if setting.Database.Type.IsMySQL() { - slaveEngine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"}) - } - slaveEngine.SetSchema(setting.Database.Schema) - slaveEngines = append(slaveEngines, slaveEngine) - } - - policy := setting.BuildLoadBalancePolicy(&setting.Database, slaveEngines) - - // Create the EngineGroup using the selected policy - group, err := xorm.NewEngineGroup(masterEngine, slaveEngines, policy) - if err != nil { - return nil, fmt.Errorf("failed to create engine group: %w", err) - } - return engineGroupWrapper{group}, nil + engine.SetSchema(setting.Database.Schema) + return engine, nil } -type engineGroupWrapper struct { - *xorm.EngineGroup -} - -func (w engineGroupWrapper) AddHook(hook contexts.Hook) bool { - w.EngineGroup.AddHook(hook) - return true -} - -// SyncAllTables sync the schemas of all tables +// SyncAllTables sync the schemas of all tables, is required by unit test code func SyncAllTables() error { _, err := x.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ WarnIfDatabaseColumnMissed: true, @@ -166,61 +129,50 @@ func SyncAllTables() error { return err } -// InitEngine initializes the xorm EngineGroup and sets it as db.DefaultContext +// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext func InitEngine(ctx context.Context) error { - xormEngine, err := newXORMEngineGroup() + xormEngine, err := newXORMEngine() if err != nil { return fmt.Errorf("failed to connect to database: %w", err) } - // Try to cast to the concrete type to access diagnostic methods - if eng, ok := xormEngine.(engineGroupWrapper); ok { - eng.SetMapper(names.GonicMapper{}) - // WARNING: for serv command, MUST remove the output to os.Stdout, - // so use a log file instead of printing to stdout. - eng.SetLogger(NewXORMLogger(setting.Database.LogSQL)) - eng.ShowSQL(setting.Database.LogSQL) - eng.SetMaxOpenConns(setting.Database.MaxOpenConns) - eng.SetMaxIdleConns(setting.Database.MaxIdleConns) - eng.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) - eng.SetConnMaxIdleTime(setting.Database.ConnMaxIdleTime) - eng.SetDefaultContext(ctx) - if setting.Database.SlowQueryThreshold > 0 { - eng.AddHook(&SlowQueryHook{ - Threshold: setting.Database.SlowQueryThreshold, - Logger: log.GetLogger("xorm"), - }) - } + xormEngine.SetMapper(names.GonicMapper{}) + // WARNING: for serv command, MUST remove the output to os.stdout, + // so use log file to instead print to stdout. + xormEngine.SetLogger(NewXORMLogger(setting.Database.LogSQL)) + xormEngine.ShowSQL(setting.Database.LogSQL) + xormEngine.SetMaxOpenConns(setting.Database.MaxOpenConns) + xormEngine.SetMaxIdleConns(setting.Database.MaxIdleConns) + xormEngine.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) + xormEngine.SetConnMaxIdleTime(setting.Database.ConnMaxIdleTime) + xormEngine.SetDefaultContext(ctx) - errorLogger := log.GetLogger("xorm") - if setting.IsInTesting { - errorLogger = log.GetLogger(log.DEFAULT) - } - - eng.AddHook(&ErrorQueryHook{ - Logger: errorLogger, + if setting.Database.SlowQueryThreshold > 0 { + xormEngine.AddHook(&SlowQueryHook{ + Treshold: setting.Database.SlowQueryThreshold, + Logger: log.GetLogger("xorm"), }) - - eng.AddHook(&TracingHook{}) - - SetDefaultEngine(ctx, eng) - } else { - // Fallback: if type assertion fails, set default engine without extended diagnostics - SetDefaultEngine(ctx, xormEngine) } + + errorLogger := log.GetLogger("xorm") + if setting.IsInTesting { + errorLogger = log.GetLogger(log.DEFAULT) + } + + xormEngine.AddHook(&ErrorQueryHook{ + Logger: errorLogger, + }) + + SetDefaultEngine(ctx, xormEngine) return nil } -// SetDefaultEngine sets the default engine for db. -func SetDefaultEngine(ctx context.Context, eng Engine) { - masterEngine, err := GetMasterEngine(eng) - if err == nil { - x = masterEngine - } - +// SetDefaultEngine sets the default engine for db +func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) { + x = eng DefaultContext = &Context{ Context: ctx, - e: eng, + e: x, } } @@ -236,12 +188,12 @@ func UnsetDefaultEngine() { DefaultContext = nil } -// InitEngineWithMigration initializes a new xorm EngineGroup, runs migrations, and sets it as db.DefaultContext +// InitEngineWithMigration initializes a new xorm.Engine and sets it as the db.DefaultContext // This function must never call .Sync() if the provided migration function fails. // When called from the "doctor" command, the migration function is a version check // that prevents the doctor from fixing anything in the database if the migration level // is different from the expected value. -func InitEngineWithMigration(ctx context.Context, migrateFunc func(Engine) error) (err error) { +func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) { if err = InitEngine(ctx); err != nil { return err } @@ -275,14 +227,14 @@ func InitEngineWithMigration(ctx context.Context, migrateFunc func(Engine) error return nil } -// NamesToBean returns a list of beans given names +// NamesToBean return a list of beans or an error func NamesToBean(names ...string) ([]any, error) { beans := []any{} if len(names) == 0 { beans = append(beans, tables...) return beans, nil } - // Map provided names to beans + // Need to map provided names to beans... beanMap := make(map[string]any) for _, bean := range tables { beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean @@ -304,7 +256,7 @@ func NamesToBean(names ...string) ([]any, error) { return beans, nil } -// DumpDatabase dumps all data from database using special SQL syntax to the file system. +// DumpDatabase dumps all data from database according the special database SQL syntax to file system. func DumpDatabase(filePath, dbType string) error { var tbs []*schemas.Table for _, t := range tables { @@ -340,58 +292,35 @@ func MaxBatchInsertSize(bean any) int { return 999 / len(t.ColumnsSeq()) } -// IsTableNotEmpty returns true if the table has at least one record +// IsTableNotEmpty returns true if table has at least one record func IsTableNotEmpty(beanOrTableName any) (bool, error) { return x.Table(beanOrTableName).Exist() } -// DeleteAllRecords deletes all records in the given table. +// DeleteAllRecords will delete all the records of this table func DeleteAllRecords(tableName string) error { _, err := x.Exec(fmt.Sprintf("DELETE FROM %s", tableName)) return err } -// GetMaxID returns the maximum id in the table +// GetMaxID will return max id of the table func GetMaxID(beanOrTableName any) (maxID int64, err error) { _, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) return maxID, err } func SetLogSQL(ctx context.Context, on bool) { - ctxEngine := GetEngine(ctx) - - if sess, ok := ctxEngine.(*xorm.Session); ok { + e := GetEngine(ctx) + if x, ok := e.(*xorm.Engine); ok { + x.ShowSQL(on) + } else if sess, ok := e.(*xorm.Session); ok { sess.Engine().ShowSQL(on) - } else if wrapper, ok := ctxEngine.(engineGroupWrapper); ok { - // Handle engineGroupWrapper directly - wrapper.ShowSQL(on) - } else if masterEngine, err := GetMasterEngine(ctxEngine); err == nil { - masterEngine.ShowSQL(on) } } -type TracingHook struct{} - -var _ contexts.Hook = &TracingHook{} - -type sqlTask struct{} - -func (TracingHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) { - ctx, task := trace.NewTask(c.Ctx, "sql") - ctx = context.WithValue(ctx, sqlTask{}, task) - trace.Log(ctx, "query", c.SQL) - trace.Logf(ctx, "args", "%v", c.Args) - return ctx, nil -} - -func (TracingHook) AfterProcess(c *contexts.ContextHook) error { - c.Ctx.Value(sqlTask{}).(*trace.Task).End() - return nil -} - type SlowQueryHook struct { - Threshold time.Duration - Logger log.Logger + Treshold time.Duration + Logger log.Logger } var _ contexts.Hook = &SlowQueryHook{} @@ -401,7 +330,7 @@ func (SlowQueryHook) BeforeProcess(c *contexts.ContextHook) (context.Context, er } func (h *SlowQueryHook) AfterProcess(c *contexts.ContextHook) error { - if c.ExecuteTime >= h.Threshold { + if c.ExecuteTime >= h.Treshold { h.Logger.Log(8, log.WARN, "[Slow SQL Query] %s %v - %v", c.SQL, c.Args, c.ExecuteTime) } return nil @@ -423,18 +352,3 @@ func (h *ErrorQueryHook) AfterProcess(c *contexts.ContextHook) error { } return nil } - -// GetMasterEngine extracts the master xorm.Engine from the provided xorm.Engine. -// This handles both direct xorm.Engine cases and engines that implement a Master() method. -func GetMasterEngine(x Engine) (*xorm.Engine, error) { - if getter, ok := x.(interface{ Master() *xorm.Engine }); ok { - return getter.Master(), nil - } - - engine, ok := x.(*xorm.Engine) - if !ok { - return nil, fmt.Errorf("unsupported engine type: %T", x) - } - - return engine, nil -} diff --git a/models/db/engine_test.go b/models/db/engine_test.go index 98cc90c251..f050c5ca28 100644 --- a/models/db/engine_test.go +++ b/models/db/engine_test.go @@ -8,22 +8,21 @@ import ( "testing" "time" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - "forgejo.org/models/unittest" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" - _ "forgejo.org/cmd" // for TestPrimaryKeys + _ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "xorm.io/xorm" ) func TestDumpDatabase(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) dir := t.TempDir() @@ -31,32 +30,32 @@ func TestDumpDatabase(t *testing.T) { ID int64 `xorm:"pk autoincr"` Version int64 } - require.NoError(t, db.GetEngine(db.DefaultContext).Sync(new(Version))) + assert.NoError(t, db.GetEngine(db.DefaultContext).Sync(new(Version))) for _, dbType := range setting.SupportedDatabaseTypes { - require.NoError(t, db.DumpDatabase(filepath.Join(dir, dbType+".sql"), dbType)) + assert.NoError(t, db.DumpDatabase(filepath.Join(dir, dbType+".sql"), dbType)) } } func TestDeleteOrphanedObjects(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) countBefore, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{}) - require.NoError(t, err) + assert.NoError(t, err) _, err = db.GetEngine(db.DefaultContext).Insert(&issues_model.PullRequest{IssueID: 1000}, &issues_model.PullRequest{IssueID: 1001}, &issues_model.PullRequest{IssueID: 1003}) - require.NoError(t, err) + assert.NoError(t, err) orphaned, err := db.CountOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id") - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 3, orphaned) err = db.DeleteOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id") - require.NoError(t, err) + assert.NoError(t, err) countAfter, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{}) - require.NoError(t, err) - assert.Equal(t, countBefore, countAfter) + assert.NoError(t, err) + assert.EqualValues(t, countBefore, countAfter) } func TestPrimaryKeys(t *testing.T) { @@ -64,7 +63,7 @@ func TestPrimaryKeys(t *testing.T) { // https://github.com/go-gitea/gitea/issues/21086 // https://github.com/go-gitea/gitea/issues/16802 // To avoid creating tables without primary key again, this test will check them. - // Import "forgejo.org/cmd" to make sure each db.RegisterModel in init functions has been called. + // Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called. beans, err := db.NamesToBean() if err != nil { @@ -103,8 +102,8 @@ func TestSlowQuery(t *testing.T) { // It's not possible to clean this up with XORM, but it's luckily not harmful // to leave around. engine.AddHook(&db.SlowQueryHook{ - Threshold: time.Second * 10, - Logger: log.GetLogger("slow-query"), + Treshold: time.Second * 10, + Logger: log.GetLogger("slow-query"), }) // NOOP query. @@ -114,8 +113,8 @@ func TestSlowQuery(t *testing.T) { assert.False(t, stopped) engine.AddHook(&db.SlowQueryHook{ - Threshold: 0, // Every query should be logged. - Logger: log.GetLogger("slow-query"), + Treshold: 0, // Every query should be logged. + Logger: log.GetLogger("slow-query"), }) // NOOP query. diff --git a/models/db/error.go b/models/db/error.go index 6b70c40eb3..665e970e17 100644 --- a/models/db/error.go +++ b/models/db/error.go @@ -6,7 +6,7 @@ package db import ( "fmt" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) // ErrCancelled represents an error due to context cancellation diff --git a/models/db/index.go b/models/db/index.go index 4c15dbe8a1..259ddd6ade 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -9,7 +9,7 @@ import ( "fmt" "strconv" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // ResourceIndex represents a resource index which could be used as issue/release and others diff --git a/models/db/index_test.go b/models/db/index_test.go index b64a816bd2..5fce0a6012 100644 --- a/models/db/index_test.go +++ b/models/db/index_test.go @@ -9,11 +9,10 @@ import ( "fmt" "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) type TestIndex db.ResourceIndex @@ -32,98 +31,96 @@ func getCurrentResourceIndex(ctx context.Context, tableName string, groupID int6 } func TestSyncMaxResourceIndex(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - xe, err := unittest.GetXORMEngine() - require.NoError(t, err) - require.NoError(t, xe.Sync(&TestIndex{})) + assert.NoError(t, unittest.PrepareTestDatabase()) + xe := unittest.GetXORMEngine() + assert.NoError(t, xe.Sync(&TestIndex{})) - err = db.SyncMaxResourceIndex(db.DefaultContext, "test_index", 10, 51) - require.NoError(t, err) + err := db.SyncMaxResourceIndex(db.DefaultContext, "test_index", 10, 51) + assert.NoError(t, err) // sync new max index maxIndex, err := getCurrentResourceIndex(db.DefaultContext, "test_index", 10) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 51, maxIndex) // smaller index doesn't change err = db.SyncMaxResourceIndex(db.DefaultContext, "test_index", 10, 30) - require.NoError(t, err) + assert.NoError(t, err) maxIndex, err = getCurrentResourceIndex(db.DefaultContext, "test_index", 10) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 51, maxIndex) // larger index changes err = db.SyncMaxResourceIndex(db.DefaultContext, "test_index", 10, 62) - require.NoError(t, err) + assert.NoError(t, err) maxIndex, err = getCurrentResourceIndex(db.DefaultContext, "test_index", 10) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 62, maxIndex) // commit transaction err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { err = db.SyncMaxResourceIndex(ctx, "test_index", 10, 73) - require.NoError(t, err) + assert.NoError(t, err) maxIndex, err = getCurrentResourceIndex(ctx, "test_index", 10) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 73, maxIndex) return nil }) - require.NoError(t, err) + assert.NoError(t, err) maxIndex, err = getCurrentResourceIndex(db.DefaultContext, "test_index", 10) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 73, maxIndex) // rollback transaction err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { err = db.SyncMaxResourceIndex(ctx, "test_index", 10, 84) maxIndex, err = getCurrentResourceIndex(ctx, "test_index", 10) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 84, maxIndex) return errors.New("test rollback") }) - require.Error(t, err) + assert.Error(t, err) maxIndex, err = getCurrentResourceIndex(db.DefaultContext, "test_index", 10) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 73, maxIndex) // the max index doesn't change because the transaction was rolled back } func TestGetNextResourceIndex(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - xe, err := unittest.GetXORMEngine() - require.NoError(t, err) - require.NoError(t, xe.Sync(&TestIndex{})) + assert.NoError(t, unittest.PrepareTestDatabase()) + xe := unittest.GetXORMEngine() + assert.NoError(t, xe.Sync(&TestIndex{})) // create a new record maxIndex, err := db.GetNextResourceIndex(db.DefaultContext, "test_index", 20) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 1, maxIndex) // increase the existing record maxIndex, err = db.GetNextResourceIndex(db.DefaultContext, "test_index", 20) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 2, maxIndex) // commit transaction err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { maxIndex, err = db.GetNextResourceIndex(ctx, "test_index", 20) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 3, maxIndex) return nil }) - require.NoError(t, err) + assert.NoError(t, err) maxIndex, err = getCurrentResourceIndex(db.DefaultContext, "test_index", 20) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 3, maxIndex) // rollback transaction err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { maxIndex, err = db.GetNextResourceIndex(ctx, "test_index", 20) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 4, maxIndex) return errors.New("test rollback") }) - require.Error(t, err) + assert.Error(t, err) maxIndex, err = getCurrentResourceIndex(db.DefaultContext, "test_index", 20) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 3, maxIndex) // the max index doesn't change because the transaction was rolled back } diff --git a/models/db/install/db.go b/models/db/install/db.go index e64e85cf01..d4c1139637 100644 --- a/models/db/install/db.go +++ b/models/db/install/db.go @@ -4,12 +4,14 @@ package install import ( - "forgejo.org/models/db" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" ) -func getXORMEngine() db.Engine { - return db.DefaultContext.(*db.Context).Engine() +func getXORMEngine() *xorm.Engine { + return db.DefaultContext.(*db.Context).Engine().(*xorm.Engine) } // CheckDatabaseConnection checks the database connection diff --git a/models/db/iterate.go b/models/db/iterate.go index 450c7d3389..e1caefa72b 100644 --- a/models/db/iterate.go +++ b/models/db/iterate.go @@ -6,7 +6,7 @@ package db import ( "context" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "xorm.io/builder" ) diff --git a/models/db/iterate_test.go b/models/db/iterate_test.go index bdeaa876d5..0f6ba2cc94 100644 --- a/models/db/iterate_test.go +++ b/models/db/iterate_test.go @@ -7,29 +7,27 @@ import ( "context" "testing" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestIterate(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - xe, err := unittest.GetXORMEngine() - require.NoError(t, err) - require.NoError(t, xe.Sync(&repo_model.RepoUnit{})) + assert.NoError(t, unittest.PrepareTestDatabase()) + xe := unittest.GetXORMEngine() + assert.NoError(t, xe.Sync(&repo_model.RepoUnit{})) cnt, err := db.GetEngine(db.DefaultContext).Count(&repo_model.RepoUnit{}) - require.NoError(t, err) + assert.NoError(t, err) var repoUnitCnt int err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repo *repo_model.RepoUnit) error { repoUnitCnt++ return nil }) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, cnt, repoUnitCnt) err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error { @@ -40,7 +38,9 @@ func TestIterate(t *testing.T) { if !has { return db.ErrNotExist{Resource: "repo_unit", ID: repoUnit.ID} } + assert.EqualValues(t, repoUnit.RepoID, repoUnit.RepoID) + assert.EqualValues(t, repoUnit.CreatedUnix, repoUnit.CreatedUnix) return nil }) - require.NoError(t, err) + assert.NoError(t, err) } diff --git a/models/db/list.go b/models/db/list.go index 057221936c..5c005a0350 100644 --- a/models/db/list.go +++ b/models/db/list.go @@ -6,7 +6,7 @@ package db import ( "context" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "xorm.io/builder" "xorm.io/xorm" diff --git a/models/db/list_test.go b/models/db/list_test.go index 502372782d..45194611f8 100644 --- a/models/db/list_test.go +++ b/models/db/list_test.go @@ -6,12 +6,11 @@ package db_test import ( "testing" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "xorm.io/builder" ) @@ -28,27 +27,26 @@ func (opts mockListOptions) ToConds() builder.Cond { } func TestFind(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - xe, err := unittest.GetXORMEngine() - require.NoError(t, err) - require.NoError(t, xe.Sync(&repo_model.RepoUnit{})) + assert.NoError(t, unittest.PrepareTestDatabase()) + xe := unittest.GetXORMEngine() + assert.NoError(t, xe.Sync(&repo_model.RepoUnit{})) var repoUnitCount int - _, err = db.GetEngine(db.DefaultContext).SQL("SELECT COUNT(*) FROM repo_unit").Get(&repoUnitCount) - require.NoError(t, err) + _, err := db.GetEngine(db.DefaultContext).SQL("SELECT COUNT(*) FROM repo_unit").Get(&repoUnitCount) + assert.NoError(t, err) assert.NotEmpty(t, repoUnitCount) opts := mockListOptions{} repoUnits, err := db.Find[repo_model.RepoUnit](db.DefaultContext, opts) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, repoUnits, repoUnitCount) cnt, err := db.Count[repo_model.RepoUnit](db.DefaultContext, opts) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, repoUnitCount, cnt) repoUnits, newCnt, err := db.FindAndCount[repo_model.RepoUnit](db.DefaultContext, opts) - require.NoError(t, err) - assert.Equal(t, cnt, newCnt) + assert.NoError(t, err) + assert.EqualValues(t, cnt, newCnt) assert.Len(t, repoUnits, repoUnitCount) } diff --git a/models/db/log.go b/models/db/log.go index 387709cc50..307788ea2e 100644 --- a/models/db/log.go +++ b/models/db/log.go @@ -7,7 +7,7 @@ import ( "fmt" "sync/atomic" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" xormlog "xorm.io/xorm/log" ) @@ -67,11 +67,8 @@ func (l *XORMLogBridge) Warn(v ...any) { l.Log(stackLevel, log.WARN, "%s", fmt.Sprint(v...)) } -// Warnf show warning log +// Warnf show warnning log func (l *XORMLogBridge) Warnf(format string, v ...any) { - if format == "Table %s Column %s db default is %s, struct default is %s" || format == "Table %s Column %s db nullable is %v, struct nullable is %v" { - return - } l.Log(stackLevel, log.WARN, format, v...) } diff --git a/models/db/main_test.go b/models/db/main_test.go index 4b06923950..7d80b400fe 100644 --- a/models/db/main_test.go +++ b/models/db/main_test.go @@ -6,10 +6,10 @@ package db_test import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" - _ "forgejo.org/models" - _ "forgejo.org/models/repo" + _ "code.gitea.io/gitea/models" + _ "code.gitea.io/gitea/models/repo" ) func TestMain(m *testing.M) { diff --git a/models/db/name.go b/models/db/name.go index 29b60b2373..51be33a8bc 100644 --- a/models/db/name.go +++ b/models/db/name.go @@ -9,7 +9,7 @@ import ( "strings" "unicode/utf8" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) var ( diff --git a/models/db/paginator/main_test.go b/models/db/paginator/main_test.go index e2528be121..47993aed6b 100644 --- a/models/db/paginator/main_test.go +++ b/models/db/paginator/main_test.go @@ -6,7 +6,7 @@ package paginator import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { diff --git a/models/db/paginator/paginator_test.go b/models/db/paginator/paginator_test.go index c6d0569aaa..20602212d9 100644 --- a/models/db/paginator/paginator_test.go +++ b/models/db/paginator/paginator_test.go @@ -6,8 +6,8 @@ package paginator import ( "testing" - "forgejo.org/models/db" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) diff --git a/models/db/sequence.go b/models/db/sequence.go index 1740e74c52..f49ad935de 100644 --- a/models/db/sequence.go +++ b/models/db/sequence.go @@ -8,7 +8,7 @@ import ( "fmt" "regexp" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // CountBadSequences looks for broken sequences from recreate-table mistakes diff --git a/models/db/sql_postgres_with_schema.go b/models/db/sql_postgres_with_schema.go index 376f984dc6..ec63447f6f 100644 --- a/models/db/sql_postgres_with_schema.go +++ b/models/db/sql_postgres_with_schema.go @@ -8,7 +8,7 @@ import ( "database/sql/driver" "sync" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/lib/pq" "xorm.io/xorm/dialects" diff --git a/models/dbfs/dbfile.go b/models/dbfs/dbfile.go index 12c0398abc..dd27b5c36b 100644 --- a/models/dbfs/dbfile.go +++ b/models/dbfs/dbfile.go @@ -14,7 +14,7 @@ import ( "strings" "time" - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" ) var defaultFileBlockSize int64 = 32 * 1024 diff --git a/models/dbfs/dbfs.go b/models/dbfs/dbfs.go index ba57e50151..f68b4a2b70 100644 --- a/models/dbfs/dbfs.go +++ b/models/dbfs/dbfs.go @@ -10,7 +10,7 @@ import ( "path" "time" - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" ) /* diff --git a/models/dbfs/dbfs_test.go b/models/dbfs/dbfs_test.go index 10da231e44..96cb1014c7 100644 --- a/models/dbfs/dbfs_test.go +++ b/models/dbfs/dbfs_test.go @@ -9,10 +9,9 @@ import ( "os" "testing" - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func changeDefaultFileBlockSize(n int64) (restore func()) { @@ -28,102 +27,102 @@ func TestDbfsBasic(t *testing.T) { // test basic write/read f, err := OpenFile(db.DefaultContext, "test.txt", os.O_RDWR|os.O_CREATE) - require.NoError(t, err) + assert.NoError(t, err) n, err := f.Write([]byte("0123456789")) // blocks: 0123 4567 89 - require.NoError(t, err) - assert.Equal(t, 10, n) + assert.NoError(t, err) + assert.EqualValues(t, 10, n) _, err = f.Seek(0, io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) buf, err := io.ReadAll(f) - require.NoError(t, err) - assert.Equal(t, 10, n) - assert.Equal(t, "0123456789", string(buf)) + assert.NoError(t, err) + assert.EqualValues(t, 10, n) + assert.EqualValues(t, "0123456789", string(buf)) // write some new data _, err = f.Seek(1, io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Write([]byte("bcdefghi")) // blocks: 0bcd efgh i9 - require.NoError(t, err) + assert.NoError(t, err) // read from offset buf, err = io.ReadAll(f) - require.NoError(t, err) - assert.Equal(t, "9", string(buf)) + assert.NoError(t, err) + assert.EqualValues(t, "9", string(buf)) // read all _, err = f.Seek(0, io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) buf, err = io.ReadAll(f) - require.NoError(t, err) - assert.Equal(t, "0bcdefghi9", string(buf)) + assert.NoError(t, err) + assert.EqualValues(t, "0bcdefghi9", string(buf)) // write to new size _, err = f.Seek(-1, io.SeekEnd) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Write([]byte("JKLMNOP")) // blocks: 0bcd efgh iJKL MNOP - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Seek(0, io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) buf, err = io.ReadAll(f) - require.NoError(t, err) - assert.Equal(t, "0bcdefghiJKLMNOP", string(buf)) + assert.NoError(t, err) + assert.EqualValues(t, "0bcdefghiJKLMNOP", string(buf)) // write beyond EOF and fill with zero _, err = f.Seek(5, io.SeekCurrent) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Write([]byte("xyzu")) // blocks: 0bcd efgh iJKL MNOP 0000 0xyz u - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Seek(0, io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) buf, err = io.ReadAll(f) - require.NoError(t, err) - assert.Equal(t, "0bcdefghiJKLMNOP\x00\x00\x00\x00\x00xyzu", string(buf)) + assert.NoError(t, err) + assert.EqualValues(t, "0bcdefghiJKLMNOP\x00\x00\x00\x00\x00xyzu", string(buf)) // write to the block with zeros _, err = f.Seek(-6, io.SeekCurrent) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Write([]byte("ABCD")) // blocks: 0bcd efgh iJKL MNOP 000A BCDz u - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Seek(0, io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) buf, err = io.ReadAll(f) - require.NoError(t, err) - assert.Equal(t, "0bcdefghiJKLMNOP\x00\x00\x00ABCDzu", string(buf)) + assert.NoError(t, err) + assert.EqualValues(t, "0bcdefghiJKLMNOP\x00\x00\x00ABCDzu", string(buf)) - require.NoError(t, f.Close()) + assert.NoError(t, f.Close()) // test rename err = Rename(db.DefaultContext, "test.txt", "test2.txt") - require.NoError(t, err) + assert.NoError(t, err) _, err = OpenFile(db.DefaultContext, "test.txt", os.O_RDONLY) - require.Error(t, err) + assert.Error(t, err) f, err = OpenFile(db.DefaultContext, "test2.txt", os.O_RDONLY) - require.NoError(t, err) - require.NoError(t, f.Close()) + assert.NoError(t, err) + assert.NoError(t, f.Close()) // test remove err = Remove(db.DefaultContext, "test2.txt") - require.NoError(t, err) + assert.NoError(t, err) _, err = OpenFile(db.DefaultContext, "test2.txt", os.O_RDONLY) - require.Error(t, err) + assert.Error(t, err) // test stat f, err = OpenFile(db.DefaultContext, "test/test.txt", os.O_RDWR|os.O_CREATE) - require.NoError(t, err) + assert.NoError(t, err) stat, err := f.Stat() - require.NoError(t, err) - assert.Equal(t, "test.txt", stat.Name()) + assert.NoError(t, err) + assert.EqualValues(t, "test.txt", stat.Name()) assert.EqualValues(t, 0, stat.Size()) _, err = f.Write([]byte("0123456789")) - require.NoError(t, err) + assert.NoError(t, err) stat, err = f.Stat() - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 10, stat.Size()) } @@ -131,61 +130,61 @@ func TestDbfsReadWrite(t *testing.T) { defer changeDefaultFileBlockSize(4)() f1, err := OpenFile(db.DefaultContext, "test.log", os.O_RDWR|os.O_CREATE) - require.NoError(t, err) + assert.NoError(t, err) defer f1.Close() f2, err := OpenFile(db.DefaultContext, "test.log", os.O_RDONLY) - require.NoError(t, err) + assert.NoError(t, err) defer f2.Close() _, err = f1.Write([]byte("line 1\n")) - require.NoError(t, err) + assert.NoError(t, err) f2r := bufio.NewReader(f2) line, err := f2r.ReadString('\n') - require.NoError(t, err) - assert.Equal(t, "line 1\n", line) + assert.NoError(t, err) + assert.EqualValues(t, "line 1\n", line) _, err = f2r.ReadString('\n') - require.ErrorIs(t, err, io.EOF) + assert.ErrorIs(t, err, io.EOF) _, err = f1.Write([]byte("line 2\n")) - require.NoError(t, err) + assert.NoError(t, err) line, err = f2r.ReadString('\n') - require.NoError(t, err) - assert.Equal(t, "line 2\n", line) + assert.NoError(t, err) + assert.EqualValues(t, "line 2\n", line) _, err = f2r.ReadString('\n') - require.ErrorIs(t, err, io.EOF) + assert.ErrorIs(t, err, io.EOF) } func TestDbfsSeekWrite(t *testing.T) { defer changeDefaultFileBlockSize(4)() f, err := OpenFile(db.DefaultContext, "test2.log", os.O_RDWR|os.O_CREATE) - require.NoError(t, err) + assert.NoError(t, err) defer f.Close() n, err := f.Write([]byte("111")) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Seek(int64(n), io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Write([]byte("222")) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Seek(int64(n), io.SeekStart) - require.NoError(t, err) + assert.NoError(t, err) _, err = f.Write([]byte("333")) - require.NoError(t, err) + assert.NoError(t, err) fr, err := OpenFile(db.DefaultContext, "test2.log", os.O_RDONLY) - require.NoError(t, err) + assert.NoError(t, err) defer f.Close() buf, err := io.ReadAll(fr) - require.NoError(t, err) - assert.Equal(t, "111333", string(buf)) + assert.NoError(t, err) + assert.EqualValues(t, "111333", string(buf)) } diff --git a/models/dbfs/main_test.go b/models/dbfs/main_test.go index 3d4b2bc235..537ba0935d 100644 --- a/models/dbfs/main_test.go +++ b/models/dbfs/main_test.go @@ -6,7 +6,7 @@ package dbfs import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { diff --git a/models/error.go b/models/error.go index ebaa8a135d..75c53245de 100644 --- a/models/error.go +++ b/models/error.go @@ -7,9 +7,9 @@ package models import ( "fmt" - repo_model "forgejo.org/models/repo" - "forgejo.org/modules/git" - "forgejo.org/modules/util" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/util" ) // ErrUserOwnRepos represents a "UserOwnRepos" kind of error. @@ -151,6 +151,25 @@ func (err *ErrInvalidCloneAddr) Unwrap() error { return util.ErrInvalidArgument } +// ErrUpdateTaskNotExist represents a "UpdateTaskNotExist" kind of error. +type ErrUpdateTaskNotExist struct { + UUID string +} + +// IsErrUpdateTaskNotExist checks if an error is a ErrUpdateTaskNotExist. +func IsErrUpdateTaskNotExist(err error) bool { + _, ok := err.(ErrUpdateTaskNotExist) + return ok +} + +func (err ErrUpdateTaskNotExist) Error() string { + return fmt.Sprintf("update task does not exist [uuid: %s]", err.UUID) +} + +func (err ErrUpdateTaskNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrInvalidTagName represents a "InvalidTagName" kind of error. type ErrInvalidTagName struct { TagName string @@ -414,7 +433,7 @@ func IsErrSHAOrCommitIDNotProvided(err error) bool { } func (err ErrSHAOrCommitIDNotProvided) Error() string { - return "a SHA or commit ID must be provided when updating a file" + return "a SHA or commit ID must be proved when updating a file" } // ErrInvalidMergeStyle represents an error if merging with disabled merge strategy diff --git a/models/fixture_generation.go b/models/fixture_generation.go new file mode 100644 index 0000000000..6234caefad --- /dev/null +++ b/models/fixture_generation.go @@ -0,0 +1,50 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package models + +import ( + "context" + "fmt" + "strings" + + "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" +) + +// GetYamlFixturesAccess returns a string containing the contents +// for the access table, as recalculated using repo.RecalculateAccesses() +func GetYamlFixturesAccess(ctx context.Context) (string, error) { + repos := make([]*repo_model.Repository, 0, 50) + if err := db.GetEngine(ctx).Find(&repos); err != nil { + return "", err + } + + for _, repo := range repos { + repo.MustOwner(ctx) + if err := access_model.RecalculateAccesses(ctx, repo); err != nil { + return "", err + } + } + + var b strings.Builder + + accesses := make([]*access_model.Access, 0, 200) + if err := db.GetEngine(ctx).OrderBy("user_id, repo_id").Find(&accesses); err != nil { + return "", err + } + + for i, a := range accesses { + fmt.Fprintf(&b, "-\n") + fmt.Fprintf(&b, " id: %d\n", i+1) + fmt.Fprintf(&b, " user_id: %d\n", a.UserID) + fmt.Fprintf(&b, " repo_id: %d\n", a.RepoID) + fmt.Fprintf(&b, " mode: %d\n", a.Mode) + if i < len(accesses)-1 { + fmt.Fprintf(&b, "\n") + } + } + + return b.String(), nil +} diff --git a/models/fixture_test.go b/models/fixture_test.go new file mode 100644 index 0000000000..de5f412388 --- /dev/null +++ b/models/fixture_test.go @@ -0,0 +1,37 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package models + +import ( + "context" + "os" + "path/filepath" + "testing" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" +) + +func TestFixtureGeneration(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + test := func(ctx context.Context, gen func(ctx context.Context) (string, error), name string) { + expected, err := gen(ctx) + if !assert.NoError(t, err) { + return + } + p := filepath.Join(unittest.FixturesDir(), name+".yml") + bytes, err := os.ReadFile(p) + if !assert.NoError(t, err) { + return + } + data := string(util.NormalizeEOL(bytes)) + assert.EqualValues(t, expected, data, "Differences detected for %s", p) + } + + test(db.DefaultContext, GetYamlFixturesAccess, "access") +} diff --git a/models/fixtures/ModerationFeatures/abuse_report.yml b/models/fixtures/ModerationFeatures/abuse_report.yml deleted file mode 100644 index f2e371ee35..0000000000 --- a/models/fixtures/ModerationFeatures/abuse_report.yml +++ /dev/null @@ -1,21 +0,0 @@ -- - id: 1 - status: 1 - reporter_id: 2 # @user2 - content_type: 4 # Comment - content_id: 18 # user2/repo2/issues/2#issuecomment-18 - category: 2 # Spam - remarks: The comment I'm reporting is pure SPAM. - shadow_copy_id: null - created_unix: 1752697980 # 2025-07-16 20:33:00 - -- - id: 2 - status: 1 # Open - reporter_id: 2 # @user2 - content_type: 1 # User (users or organizations) - content_id: 1002 # @alexsmith - category: 2 # Spam - remarks: This user just posted a spammy comment on my issue. - shadow_copy_id: null - created_unix: 1752698010 # 2025-07-16 20:33:30 diff --git a/models/fixtures/ModerationFeatures/comment.yml b/models/fixtures/ModerationFeatures/comment.yml deleted file mode 100644 index a4d41ad997..0000000000 --- a/models/fixtures/ModerationFeatures/comment.yml +++ /dev/null @@ -1,7 +0,0 @@ -- # This is a spam comment (abusive content), created for testing moderation functionalities. - id: 18 - type: 0 # Standard comment - poster_id: 1002 # @alexsmith - issue_id: 7 # user2/repo2#2 - content: If anyone needs help for promoting their business online using SEO, just contact me (check my profile page). - created_unix: 1752697860 # 2025-07-16 20:31:00 diff --git a/models/fixtures/ModerationFeatures/user.yml b/models/fixtures/ModerationFeatures/user.yml deleted file mode 100644 index 662c61a3e9..0000000000 --- a/models/fixtures/ModerationFeatures/user.yml +++ /dev/null @@ -1,22 +0,0 @@ -- # This user is a spammer and will create abusive content (for testing moderation functionalities). - id: 1002 - lower_name: alexsmith - name: alexsmith - full_name: Alex Smith - email: alexsmith@example.org - keep_email_private: false - passwd: passwdSalt:password - passwd_hash_algo: dummy - type: 0 - location: '@master@seo.net' - website: http://promote-your-business.biz - pronouns: SEO - salt: passwdSalt - description: I can help you promote your business online using SEO. - created_unix: 1752697800 # 2025-07-16 20:30:00 - is_active: true - is_admin: false - is_restricted: false - avatar: avatar-hash-1002 - avatar_email: alexsmith@example.org - use_custom_avatar: false diff --git a/models/fixtures/PrivateIssueProjects/project.yml b/models/fixtures/PrivateIssueProjects/project.yml deleted file mode 100644 index 8950b33606..0000000000 --- a/models/fixtures/PrivateIssueProjects/project.yml +++ /dev/null @@ -1,23 +0,0 @@ -- - id: 1001 - title: Org project that contains private and public issues - owner_id: 3 - repo_id: 0 - is_closed: false - creator_id: 2 - board_type: 1 - type: 3 - created_unix: 1738000000 - updated_unix: 1738000000 - -- - id: 1002 - title: User project that contains private and public issues - owner_id: 2 - repo_id: 0 - is_closed: false - creator_id: 2 - board_type: 1 - type: 1 - created_unix: 1738000000 - updated_unix: 1738000000 diff --git a/models/fixtures/PrivateIssueProjects/project_board.yml b/models/fixtures/PrivateIssueProjects/project_board.yml deleted file mode 100644 index 3f1fe1e705..0000000000 --- a/models/fixtures/PrivateIssueProjects/project_board.yml +++ /dev/null @@ -1,17 +0,0 @@ -- - id: 1001 - project_id: 1001 - title: Triage - creator_id: 2 - default: true - created_unix: 1738000000 - updated_unix: 1738000000 - -- - id: 1002 - project_id: 1002 - title: Triage - creator_id: 2 - default: true - created_unix: 1738000000 - updated_unix: 1738000000 diff --git a/models/fixtures/PrivateIssueProjects/project_issue.yml b/models/fixtures/PrivateIssueProjects/project_issue.yml deleted file mode 100644 index 0245fb47f3..0000000000 --- a/models/fixtures/PrivateIssueProjects/project_issue.yml +++ /dev/null @@ -1,23 +0,0 @@ -- - id: 1001 - issue_id: 6 - project_id: 1001 - project_board_id: 1001 - -- - id: 1002 - issue_id: 7 - project_id: 1002 - project_board_id: 1002 - -- - id: 1003 - issue_id: 16 - project_id: 1001 - project_board_id: 1001 - -- - id: 1004 - issue_id: 1 - project_id: 1002 - project_board_id: 1002 diff --git a/models/fixtures/TestActivateUserEmail/email_address.yml b/models/fixtures/TestActivateUserEmail/email_address.yml deleted file mode 100644 index cf41ff8241..0000000000 --- a/models/fixtures/TestActivateUserEmail/email_address.yml +++ /dev/null @@ -1,7 +0,0 @@ -- - id: 1001 - uid: 1001 - email: AnotherTestUserWithUpperCaseEmail@otto.splvs.net - lower_email: anothertestuserwithuppercaseemail@otto.splvs.net - is_activated: false - is_primary: true diff --git a/models/fixtures/TestActivateUserEmail/user.yml b/models/fixtures/TestActivateUserEmail/user.yml deleted file mode 100644 index 0a68e70a4a..0000000000 --- a/models/fixtures/TestActivateUserEmail/user.yml +++ /dev/null @@ -1,12 +0,0 @@ -- - id: 1001 - lower_name: user1001 - name: user1001 - full_name: User That loves Upper Cases - email: AnotherTestUserWithUpperCaseEmail@otto.splvs.net - passwd: ZogKvWdyEx:password - passwd_hash_algo: dummy - avatar: '' - avatar_email: anothertestuserwithuppercaseemail@otto.splvs.net - login_name: user1 - created_unix: 1672578000 diff --git a/models/fixtures/TestAddTeamReviewRequest/issue.yml b/models/fixtures/TestAddTeamReviewRequest/issue.yml deleted file mode 100644 index a1bcf2921f..0000000000 --- a/models/fixtures/TestAddTeamReviewRequest/issue.yml +++ /dev/null @@ -1,16 +0,0 @@ -- - id: 23 - repo_id: 2 - index: 3 - poster_id: 2 - original_author_id: 0 - name: protected branch pull - content: pull request to a protected branch - milestone_id: 0 - priority: 0 - is_pull: true - is_closed: false - num_comments: 0 - created_unix: 1707270422 - updated_unix: 1707270422 - is_locked: false \ No newline at end of file diff --git a/models/fixtures/TestAddTeamReviewRequest/protected_branch.yml b/models/fixtures/TestAddTeamReviewRequest/protected_branch.yml deleted file mode 100644 index 93909bd991..0000000000 --- a/models/fixtures/TestAddTeamReviewRequest/protected_branch.yml +++ /dev/null @@ -1,28 +0,0 @@ -- id: 1 - repo_id: 2 - branch_name: protected-main - can_push: false - enable_whitelist: true - whitelist_user_i_ds: [1] - whitelist_team_i_ds: [] - enable_merge_whitelist: true - whitelist_deploy_keys: false - merge_whitelist_user_i_ds: [1] - merge_whitelist_team_i_ds: [] - enable_status_check: false - status_check_contexts: [] - enable_approvals_whitelist: true - approvals_whitelist_user_i_ds: [] - approvals_whitelist_team_i_ds: [1] - required_approvals: 1 - block_on_rejected_reviews: true - block_on_official_review_requests: true - block_on_outdated_branch: true - dismiss_stale_approvals: true - ignore_stale_approvals: false - require_signed_commits: false - protected_file_patterns: "" - unprotected_file_patterns: "" - apply_to_admins: true - created_unix: 1752513073 - updated_unix: 1752513073 \ No newline at end of file diff --git a/models/fixtures/TestAddTeamReviewRequest/pull_request.yml b/models/fixtures/TestAddTeamReviewRequest/pull_request.yml deleted file mode 100644 index 067bb01324..0000000000 --- a/models/fixtures/TestAddTeamReviewRequest/pull_request.yml +++ /dev/null @@ -1,12 +0,0 @@ -- - id: 11 - type: 0 # gitea pull request - status: 2 # mergeable - issue_id: 23 - index: 3 - head_repo_id: 2 - base_repo_id: 2 - head_branch: feature/protected-branch-pr - base_branch: protected-main - merge_base: 4a357436d925b5c974181ff12a994538ddc5a269 - has_merged: false \ No newline at end of file diff --git a/models/fixtures/TestGetUsedForUser/action_artifact.yaml b/models/fixtures/TestGetUsedForUser/action_artifact.yaml deleted file mode 100644 index db5392126d..0000000000 --- a/models/fixtures/TestGetUsedForUser/action_artifact.yaml +++ /dev/null @@ -1,17 +0,0 @@ -- - id: 1001 - run_id: 792 - runner_id: 1 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - storage_path: "27/5/1730330775594233150.chunk" - file_size: 693147180559 - file_compressed_size: 693147180559 - content_encoding: "application/zip" - artifact_path: "big-file.zip" - artifact_name: "big-file" - status: 4 - created_unix: 1730330775 - updated_unix: 1730330775 - expired_unix: 1738106775 diff --git a/models/fixtures/TestPackagesGetOrInsertBlob/package_blob.yml b/models/fixtures/TestPackagesGetOrInsertBlob/package_blob.yml deleted file mode 100644 index ec90787c43..0000000000 --- a/models/fixtures/TestPackagesGetOrInsertBlob/package_blob.yml +++ /dev/null @@ -1,17 +0,0 @@ -- - id: 1 - size: 10 - hash_md5: HASHMD5_1 - hash_sha1: HASHSHA1_1 - hash_sha256: HASHSHA256_1 - hash_sha512: HASHSHA512_1 - hash_blake2b: HASHBLAKE2B_1 - created_unix: 946687980 -- - id: 2 - size: 20 - hash_md5: HASHMD5_2 - hash_sha1: HASHSHA1_2 - hash_sha256: HASHSHA256_2 - hash_sha512: HASHSHA512_2 - created_unix: 946687980 diff --git a/models/fixtures/TestPrivateRepoProjects/access.yml b/models/fixtures/TestPrivateRepoProjects/access.yml deleted file mode 100644 index 4149e34b0b..0000000000 --- a/models/fixtures/TestPrivateRepoProjects/access.yml +++ /dev/null @@ -1,5 +0,0 @@ -- - id: 1001 - user_id: 29 - repo_id: 3 - mode: 1 diff --git a/models/fixtures/TestPrivateRepoProjects/project.yml b/models/fixtures/TestPrivateRepoProjects/project.yml deleted file mode 100644 index f66e4c8676..0000000000 --- a/models/fixtures/TestPrivateRepoProjects/project.yml +++ /dev/null @@ -1,11 +0,0 @@ -- - id: 1001 - title: Org project that contains private issues - owner_id: 3 - repo_id: 0 - is_closed: false - creator_id: 2 - board_type: 1 - type: 3 - created_unix: 1738000000 - updated_unix: 1738000000 diff --git a/models/fixtures/TestPrivateRepoProjects/project_board.yml b/models/fixtures/TestPrivateRepoProjects/project_board.yml deleted file mode 100644 index 9829cf7e27..0000000000 --- a/models/fixtures/TestPrivateRepoProjects/project_board.yml +++ /dev/null @@ -1,8 +0,0 @@ -- - id: 1001 - project_id: 1001 - title: Triage - creator_id: 2 - default: true - created_unix: 1738000000 - updated_unix: 1738000000 diff --git a/models/fixtures/TestPrivateRepoProjects/project_issue.yml b/models/fixtures/TestPrivateRepoProjects/project_issue.yml deleted file mode 100644 index 3e8c1dca9e..0000000000 --- a/models/fixtures/TestPrivateRepoProjects/project_issue.yml +++ /dev/null @@ -1,11 +0,0 @@ -- - id: 1001 - issue_id: 6 - project_id: 1001 - project_board_id: 1001 - -- - id: 1002 - issue_id: 15 - project_id: 1001 - project_board_id: 1001 diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml index f1592d4569..b2febb4ed8 100644 --- a/models/fixtures/action.yml +++ b/models/fixtures/action.yml @@ -74,11 +74,3 @@ is_private: false created_unix: 1680454039 content: '4|' # issueId 5 - -- id: 10 - user_id: 40 - op_type: 1 # create repo - act_user_id: 40 - repo_id: 60 # public - is_private: false - created_unix: 1577404800 # end of heatmap \ No newline at end of file diff --git a/models/fixtures/action_artifact.yml b/models/fixtures/action_artifact.yml deleted file mode 100644 index 2c51c11ebd..0000000000 --- a/models/fixtures/action_artifact.yml +++ /dev/null @@ -1,71 +0,0 @@ -- - id: 1 - run_id: 791 - runner_id: 1 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - storage_path: "26/1/1712166500347189545.chunk" - file_size: 1024 - file_compressed_size: 1024 - content_encoding: "" - artifact_path: "abc.txt" - artifact_name: "artifact-download" - status: 1 - created_unix: 1712338649 - updated_unix: 1712338649 - expired_unix: 1720114649 - -- - id: 19 - run_id: 791 - runner_id: 1 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - storage_path: "26/19/1712348022422036662.chunk" - file_size: 1024 - file_compressed_size: 1024 - content_encoding: "" - artifact_path: "abc.txt" - artifact_name: "multi-file-download" - status: 2 - created_unix: 1712348022 - updated_unix: 1712348022 - expired_unix: 1720124022 - -- - id: 20 - run_id: 791 - runner_id: 1 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - storage_path: "26/20/1712348022423431524.chunk" - file_size: 1024 - file_compressed_size: 1024 - content_encoding: "" - artifact_path: "xyz/def.txt" - artifact_name: "multi-file-download" - status: 2 - created_unix: 1712348022 - updated_unix: 1712348022 - expired_unix: 1720124022 - -- - id: 22 - run_id: 792 - runner_id: 1 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - storage_path: "27/5/1730330775594233150.chunk" - file_size: 1024 - file_compressed_size: 1024 - content_encoding: "application/zip" - artifact_path: "artifact-v4-download.zip" - artifact_name: "artifact-v4-download" - status: 2 - created_unix: 1730330775 - updated_unix: 1730330775 - expired_unix: 1738106775 diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml index 5b6f89ae0e..9c60b352f9 100644 --- a/models/fixtures/action_run.yml +++ b/models/fixtures/action_run.yml @@ -413,44 +413,6 @@ }, "total_commits": 0 } -- - id: 793 - title: "job output" - repo_id: 4 - owner_id: 1 - workflow_id: "test.yaml" - index: 189 - trigger_user_id: 1 - ref: "refs/heads/master" - commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" - event: "push" - is_fork_pull_request: 0 - status: 1 - started: 1683636528 - stopped: 1683636626 - created: 1683636108 - updated: 1683636626 - need_approval: 0 - approved_by: 0 -- - id: 794 - title: "job output" - repo_id: 4 - owner_id: 1 - workflow_id: "test.yaml" - index: 190 - trigger_user_id: 1 - ref: "refs/heads/test" - commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" - event: "push" - is_fork_pull_request: 0 - status: 1 - started: 1683636528 - stopped: 1683636626 - created: 1683636108 - updated: 1683636626 - need_approval: 0 - approved_by: 0 - id: 891 title: "update actions" @@ -471,64 +433,3 @@ need_approval: 0 approved_by: 0 event_payload: '{"head_commit":{"id":"5f22f7d0d95d614d25a5b68592adb345a4b5c7fd"}}' - - -# GET action run(s) test -- - id: 892 - title: "successful push run" - repo_id: 63 - owner_id: 2 - workflow_id: "success.yaml" - index: 1 - trigger_user_id: 2 - ref: "refs/heads/main" - commit_sha: "97f29ee599c373c729132a5c46a046978311e0ee" - event: "push" - is_fork_pull_request: 0 - status: 1 # success - started: 1683636528 - stopped: 1683636626 - created: 1683636108 - updated: 1683636626 - need_approval: 0 - approved_by: 0 - -- - id: 893 - title: "failed pull_request run" - repo_id: 63 - owner_id: 2 - workflow_id: "failed.yaml" - index: 2 - trigger_user_id: 2 - ref: "refs/heads/bugfix-1" - commit_sha: "35c5cddfc19397501ec8f4f7bb808a7c8f04445f" - event: "pull_request" - is_fork_pull_request: 0 - status: 2 # failure - started: 1683636528 - stopped: 1683636626 - created: 1683636108 - updated: 1683636626 - need_approval: 0 - approved_by: 0 - -- - id: 894 - title: "running workflow_dispatch run" - repo_id: 63 - owner_id: 2 - workflow_id: "running.yaml" - index: 3 - trigger_user_id: 2 - ref: "refs/heads/main" - commit_sha: "97f29ee599c373c729132a5c46a046978311e0ee" - event: "workflow_dispatch" - is_fork_pull_request: 0 - status: 6 # running - started: 1683636528 - created: 1683636108 - updated: 1683636626 - need_approval: 0 - approved_by: 0 diff --git a/models/fixtures/action_run_job.yml b/models/fixtures/action_run_job.yml index 702c6bc832..0b02d0e17e 100644 --- a/models/fixtures/action_run_job.yml +++ b/models/fixtures/action_run_job.yml @@ -26,49 +26,6 @@ status: 1 started: 1683636528 stopped: 1683636626 -- - id: 194 - run_id: 793 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - name: job1 (1) - attempt: 1 - job_id: job1 - task_id: 49 - status: 1 - started: 1683636528 - stopped: 1683636626 -- - id: 195 - run_id: 793 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - name: job1 (2) - attempt: 1 - job_id: job1 - task_id: 50 - status: 1 - started: 1683636528 - stopped: 1683636626 -- - id: 196 - run_id: 793 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - name: job2 - attempt: 1 - job_id: job2 - needs: [job1] - task_id: 51 - status: 5 - started: 1683636528 - stopped: 1683636626 - id: 292 run_id: 891 @@ -83,48 +40,3 @@ status: 1 started: 1683636528 stopped: 1683636626 -- - id: 393 - run_id: 891 - repo_id: 1 - owner_id: 1 - commit_sha: 985f0301dba5e7b34be866819cd15ad3d8f508ee - is_fork_pull_request: 0 - name: job_2 - attempt: 1 - job_id: job_2 - task_id: 47 - status: 5 - runs_on: '["ubuntu-latest"]' - started: 1683636528 - stopped: 1683636626 -- - id: 394 - run_id: 891 - repo_id: 1 - owner_id: 2 - commit_sha: 985f0301dba5e7b34be866819cd15ad3d8f508ee - is_fork_pull_request: 0 - name: job_2 - attempt: 1 - job_id: job_2 - task_id: 47 - status: 5 - runs_on: '["debian-latest"]' - started: 1683636528 - stopped: 1683636626 -- - id: 395 - run_id: 891 - repo_id: 1 - owner_id: 3 - commit_sha: 985f0301dba5e7b34be866819cd15ad3d8f508ee - is_fork_pull_request: 0 - name: job_2 - attempt: 1 - job_id: job_2 - task_id: 47 - status: 5 - runs_on: '["fedora"]' - started: 1683636528 - stopped: 1683636626 diff --git a/models/fixtures/action_runner.yml b/models/fixtures/action_runner.yml index fcf26d49b6..d2615f08eb 100644 --- a/models/fixtures/action_runner.yml +++ b/models/fixtures/action_runner.yml @@ -14,126 +14,7 @@ token_salt: "832f8529db6151a1c3c605dd7570b58f" last_online: 0 last_active: 0 - agent_labels: '["woop", "doop"]' + agent_labels: '[""]' created: 1716104432 updated: 1716104432 deleted: ~ -- id: 10000001 - uuid: 10d3b248-6460-4bf5-b819-1f5b3109e10f - name: global-online - version: v6.3.1+7-gc4c0ca0 - owner_id: 0 - repo_id: 0 - description: "" - base: 0 - repo_range: "" - token_hash: 7e9ed71f64e98ce1f70e94c63f3cb6c41a8cb0b90de3e1daf7ec5c35361d60ed44da67c5ac393b7aaf443dcfc766007dc828 - token_salt: WUcgZWl7mW - last_online: 1716104422 - last_active: 0 - agent_labels: '["docker"]' - created: 1716104431 - updated: 1716104422 - deleted: ~ -- id: 10000002 - uuid: 1d188484-dd97-4a70-b707-5e87b578ab6b - name: repo-never-used - version: v6.3.1+7-gc4c0ca0 - owner_id: 0 - repo_id: 1 - description: "" - base: 0 - repo_range: "" - token_hash: 51e88c17ac8b54dd101dc2e4f530a71643c703adba7170f4b1a28f1cb483b4cfb107798c521e0532ef3c6480b64518a5c6a5 - token_salt: 4rh8ncXYIO - last_online: 0 - last_active: 0 - agent_labels: '["docker"]' - created: 1713512432 - updated: 1713512432 - deleted: ~ -- id: 10000003 - uuid: 7a039c6b-b0b2-4cf5-a93d-715d617f99e2 - name: global-offline - version: v6.3.1+7-gc4c0ca0 - owner_id: 0 - repo_id: 0 - description: "" - base: 0 - repo_range: "" - token_hash: c76960c56bc6069f0d1648991ec626500abe8c15286f5c355d565c3b5ba945d7d6f1272a6c77849e592528179511b94f5d69 - token_salt: TFMe2jhOkB - last_online: 1715499632 - last_active: 0 - agent_labels: '["docker"]' - created: 1715499632 - updated: 1715499632 - deleted: ~ -- id: 10000004 - uuid: 93ca7fdd-faca-4df6-a474-8345263ef10b - name: user-online - version: v6.3.1+7-gc4c0ca0 - owner_id: 1 - repo_id: 0 - description: "" - base: 0 - repo_range: "" - token_hash: 6ddf7f0f2301d2b3f66418145dc497a6d09fa6586e659afcb5ae2a0c5b639561d795aff8062537db9df73b396842ea826134 - token_salt: QcdGuReAp4 - last_online: 1716104422 - last_active: 0 - agent_labels: '["docker"]' - created: 1716104431 - updated: 1716104422 - deleted: ~ -- id: 10000005 - uuid: a8534df6-c4be-40f4-9714-903b69d973d9 - name: user-never-used - version: v6.3.1+7-gc4c0ca0 - owner_id: 1 - repo_id: 0 - description: desc - base: 0 - repo_range: "" - token_hash: 4441de7defcfc3d21baa608dec66a562cf23307abddaabdbb836907ac5f48c8780c354891916c525b79ec7af8e95be7a09b4 - token_salt: ONNqIOnj3t - last_online: 0 - last_active: 0 - agent_labels: '["docker"]' - created: 1713512433 - updated: 1713512433 - deleted: ~ -- id: 10000006 - uuid: e1c5bb6c-de68-4335-8955-5192f76708ac - name: orga-fresh-created - version: v6.3.1+7-gc4c0ca0 - owner_id: 35 - repo_id: 0 - description: "" - base: 0 - repo_range: "" - token_hash: a61f9ee48c6847d243ace0a8936efe80af9277c7bc46d6da6e03d1d406608b8023ee66600ad24f0effaa8e3338f92ac97ac9 - token_salt: fZJKjrFGWA - last_online: 0 - last_active: 0 - agent_labels: '["docker"]' - created: 1716100832 - updated: 1716100832 - deleted: ~ -- id: 10000007 - uuid: ff755f06-948e-479b-8031-5b3e9f123e32 - name: orga-offline - version: v6.3.1+7-gc4c0ca0 - owner_id: 35 - repo_id: 0 - description: "" - base: 0 - repo_range: "" - token_hash: 9372efb38f9b64efe65065380abe2f24ef34a59d9619f4cdc08f1151e9849f0b6e722aa10538e8730288de6e2f09acdac695 - token_salt: TnU7iiIdCb - last_online: 1716100832 - last_active: 0 - agent_labels: '["docker"]' - created: 1736085520 - updated: 1716100832 - deleted: ~ diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml index 506a47d8a0..443effe08c 100644 --- a/models/fixtures/action_task.yml +++ b/models/fixtures/action_task.yml @@ -1,22 +1,3 @@ -- - id: 46 - attempt: 3 - runner_id: 1 - status: 3 # 3 is the status code for "cancelled" - started: 1683636528 - stopped: 1683636626 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: 6d8ef48297195edcc8e22c70b3020eaa06c52976db67d39b4260c64a69a2cc1508825121b7b8394e48e00b1bf8718b2aaaaa - token_salt: eeeeeeee - token_last_eight: eeeeeeee - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 707 - log_size: 90179 - log_expired: 0 - id: 47 job_id: 192 @@ -57,63 +38,3 @@ log_length: 707 log_size: 90179 log_expired: 0 -- - id: 49 - job_id: 194 - attempt: 1 - runner_id: 1 - status: 1 # success - started: 1683636528 - stopped: 1683636626 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784220 - token_salt: ffffffffff - token_last_eight: ffffffff - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 707 - log_size: 90179 - log_expired: 0 -- - id: 50 - job_id: 195 - attempt: 1 - runner_id: 1 - status: 1 # success - started: 1683636528 - stopped: 1683636626 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784221 - token_salt: ffffffffff - token_last_eight: ffffffff - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 707 - log_size: 90179 - log_expired: 0 -- - id: 51 - job_id: 196 - attempt: 1 - runner_id: 1 - status: 6 # running - started: 1683636528 - stopped: 1683636626 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784222 - token_salt: ffffffffff - token_last_eight: ffffffff - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 707 - log_size: 90179 - log_expired: 0 diff --git a/models/fixtures/action_task_output.yml b/models/fixtures/action_task_output.yml deleted file mode 100644 index 314e9f7115..0000000000 --- a/models/fixtures/action_task_output.yml +++ /dev/null @@ -1,20 +0,0 @@ -- - id: 1 - task_id: 49 - output_key: output_a - output_value: abc -- - id: 2 - task_id: 49 - output_key: output_b - output_value: '' -- - id: 3 - task_id: 50 - output_key: output_a - output_value: '' -- - id: 4 - task_id: 50 - output_key: output_b - output_value: bbb diff --git a/models/fixtures/action_variable.yml b/models/fixtures/action_variable.yml deleted file mode 100644 index ca780a73aa..0000000000 --- a/models/fixtures/action_variable.yml +++ /dev/null @@ -1 +0,0 @@ -[] # empty diff --git a/models/fixtures/branch.yml b/models/fixtures/branch.yml index 2a9e3105e6..93003049c6 100644 --- a/models/fixtures/branch.yml +++ b/models/fixtures/branch.yml @@ -45,27 +45,3 @@ is_deleted: false deleted_by_id: 0 deleted_unix: 0 - -- - id: 15 - repo_id: 4 - name: 'master' - commit_id: 'c7cd3cd144e6d23c9d6f3d07e52b2c1a956e0338' - commit_message: 'add Readme' - commit_time: 1588147171 - pusher_id: 13 - is_deleted: false - deleted_by_id: 0 - deleted_unix: 0 - -- - id: 16 - repo_id: 62 - name: 'main' - commit_id: '774f93df12d14931ea93259ae93418da4482fcc1' - commit_message: 'Add workflow test-dispatch.yml' - commit_time: 1717317522 - pusher_id: 1 - is_deleted: false - deleted_by_id: 0 - deleted_unix: 0 diff --git a/models/fixtures/comment.yml b/models/fixtures/comment.yml index 6908d85dda..fdf8908206 100644 --- a/models/fixtures/comment.yml +++ b/models/fixtures/comment.yml @@ -14,7 +14,6 @@ content: "good work!" created_unix: 946684811 updated_unix: 946684811 - content_version: 1 - id: 3 type: 0 # comment @@ -34,7 +33,6 @@ tree_path: "README.md" created_unix: 946684812 invalidated: false - content_version: 1 - id: 5 type: 21 # code comment @@ -94,399 +92,3 @@ content: "test markup light/dark-mode-only ![GitHub-Mark-Light](https://user-images.githubusercontent.com/3369400/139447912-e0f43f33-6d9f-45f8-be46-2df5bbc91289.png#gh-dark-mode-only)![GitHub-Mark-Dark](https://user-images.githubusercontent.com/3369400/139448065-39a229ba-4b06-434b-bc67-616e2ed80c8f.png#gh-light-mode-only)" created_unix: 946684813 updated_unix: 946684813 - -- - id: 11 - type: 22 # review - poster_id: 5 - issue_id: 3 # in repo_id 1 - content: "reviewed by user5" - review_id: 21 - created_unix: 946684816 - -- - id: 12 - type: 27 # review request - poster_id: 2 - issue_id: 3 # in repo_id 1 - content: "review request for user5" - review_id: 22 - assignee_id: 5 - created_unix: 946684817 - -- - id: 13 - type: 29 # push - poster_id: 2 - issue_id: 19 # in repo_id 58 - content: '{"is_force_push":false,"commit_ids":["4ca8bcaf27e28504df7bf996819665986b01c847","96cef4a7b72b3c208340ae6f0cf55a93e9077c93","c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2"]}' - created_unix: 1688672373 - -- - id: 14 - type: 29 # push - poster_id: 2 - issue_id: 19 # in repo_id 58 - content: '{"is_force_push":false,"commit_ids":["23576dd018294e476c06e569b6b0f170d0558705"]}' - created_unix: 1688672374 - -- - id: 15 - type: 29 # push - poster_id: 2 - issue_id: 19 # in repo_id 58 - content: '{"is_force_push":false,"commit_ids":["3e64625bd6eb5bcba69ac97de6c8f507402df861", "c704db5794097441aa2d9dd834d5b7e2f8f08108"]}' - created_unix: 1688672375 - -- - id: 16 - type: 29 # push - poster_id: 2 - issue_id: 19 # in repo_id 58 - content: '{"is_force_push":false,"commit_ids":["811d46c7e518f4f180afb862c0db5cb8c80529ce", "747ddb3506a4fa04a7747808eb56ae16f9e933dc", "837d5c8125633d7d258f93b998e867eab0145520", "1978192d98bb1b65e11c2cf37da854fbf94bffd6"]}' - created_unix: 1688672376 - -- - id: 17 - type: 29 # push - poster_id: 2 - issue_id: 19 # in repo_id 58 - content: '{"is_force_push":true,"commit_ids":["1978192d98bb1b65e11c2cf37da854fbf94bffd6", "9b93963cf6de4dc33f915bb67f192d099c301f43"]}' - created_unix: 1749734240 - -- - id: 2000 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 1 - old_milestone_id: 0 - created_unix: 946684820 - -- - id: 2001 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 2 - old_milestone_id: 1 - created_unix: 946684920 - -- - id: 2002 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 0 - old_milestone_id: 2 - created_unix: 946685020 - -- - id: 2003 - type: 8 # milestone - poster_id: 1 - issue_id: 1 # in repo_id 1 - milestone_id: 10 # not existing 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 - poster_id: 1 - issue_id: 1 # in repo_id 1 - project_id: 1 - old_project_id: 0 - created_unix: 946685120 - -- - id: 2011 - type: 30 # project - poster_id: 1 - issue_id: 1 # in repo_id 1 - project_id: 2 - old_project_id: 1 - created_unix: 946685220 - -- - id: 2012 - type: 30 # project - poster_id: 1 - issue_id: 1 # in repo_id 1 - project_id: 0 - old_project_id: 2 - created_unix: 946685320 - -- - id: 2013 - type: 30 # project - poster_id: 1 - issue_id: 1 # in repo_id 1 - project_id: 10 # not existing project - old_project_id: 0 - created_unix: 946685420 - -- - id: 2020 - type: 7 # label - poster_id: 1 - issue_id: 1 # in repo_id 1 - label_id: 1 - content: 1 # add label - created_unix: 946685520 - -- - id: 2021 - type: 7 # label - poster_id: 1 - issue_id: 1 - label_id: 2 - content: 1 # add label - created_unix: 946685620 - -- - id: 2022 - type: 7 # label - poster_id: 2 - issue_id: 1 # in repo_id 1 - label_id: 1 - content: 0 # remove label - created_unix: 946685720 - -- - id: 2023 - type: 7 # label - poster_id: 1 - issue_id: 1 # in repo_id 1 - label_id: 1 - content: 1 # add label - created_unix: 946685720 - -- - id: 2024 - type: 7 # label - poster_id: 1 - issue_id: 1 # in repo_id 1 - label_id: 2 - content: 0 # remove label - created_unix: 946685720 - -- - id: 2025 - type: 7 # label - poster_id: 2 - issue_id: 1 # in repo_id 1 - label_id: 2 - content: 1 # add label - created_unix: 946685820 - -- - id: 2026 - type: 7 # label - poster_id: 1 - issue_id: 1 # in repo_id 1 - label_id: 1 - content: 0 # remove label - created_unix: 946685920 - -- - id: 2027 - type: 7 # label - poster_id: 1 - issue_id: 1 # in repo_id 1 - label_id: 2 - content: 0 # remove label - created_unix: 946685920 - -- id: 2040 - type: 9 # assignee - poster_id: 1 - issue_id: 1 # in repo_id 1 - assignee_id: 1 # self - removed_assignee: false # add assignee - created_unix: 946688020 - -- id: 2041 - type: 9 # assignee - poster_id: 2 - issue_id: 1 # in repo_id 1 - assignee_id: 1 - removed_assignee: true # remove assignee - created_unix: 946688120 - -- id: 2042 - type: 9 # assignee - poster_id: 1 - issue_id: 1 # in repo_id 1 - assignee_id: 2 - removed_assignee: false # add assignee - created_unix: 946688220 - -- id: 2043 - type: 9 # assignee - poster_id: 2 - issue_id: 1 # in repo_id 1 - assignee_id: 2 # self - removed_assignee: true # remove assignee - created_unix: 946688320 - -- id: 2050 - type: 23 # lock - poster_id: 1 - issue_id: 1 # in repo_id 1 - created_unix: 946688420 - -- id: 2051 - type: 24 # unlock - poster_id: 1 - issue_id: 1 # in repo_id 1 - created_unix: 946688520 - -- id: 2052 - type: 23 # lock - poster_id: 1 - issue_id: 1 # in repo_id 1 - content: "Too heated" - created_unix: 946688620 - -- id: 2053 - type: 24 # unlock - poster_id: 1 - issue_id: 1 # in repo_id 1 - created_unix: 946688720 - -- id: 2060 - type: 36 # pin - poster_id: 1 - issue_id: 1 # in repo_id 1 - created_unix: 946688820 - -- id: 2061 - type: 37 # unpin - poster_id: 1 - issue_id: 1 # in repo_id 1 - created_unix: 946688920 - -- id: 2070 - type: 2 # close - poster_id: 1 - issue_id: 1 # in repo_id 1 - created_unix: 946689020 - -- id: 2071 - type: 1 # reopen - poster_id: 2 - issue_id: 1 # in repo_id 1 - created_unix: 946689220 - -- id: 2072 - type: 2 # close - poster_id: 1 - issue_id: 2 # pull in repo_id 1 - created_unix: 946689320 - -- id: 2073 - type: 1 # reopen - poster_id: 2 - issue_id: 2 # pull in repo_id 1 - created_unix: 946689420 - -- id: 2080 - type: 3 # issue reference - poster_id: 1 - issue_id: 1 # issue in repo_id 1 - ref_repo_id: 1 - ref_issue_id: 5 # issue in repo_id 1 - created_unix: 946689500 - -- id: 2081 - type: 3 # issue reference - poster_id: 1 - issue_id: 1 # issue in repo_id 1 - ref_repo_id: 1 - ref_issue_id: 2 # pull in repo_id 1 - created_unix: 946689600 - -- id: 2082 - type: 3 # issue reference - poster_id: 1 - issue_id: 1 # issue in repo_id 1 - ref_repo_id: 32 - ref_issue_id: 16 # issue in repo_id 32 - created_unix: 946689700 - -- id: 2083 - type: 3 # issue reference - poster_id: 1 - issue_id: 1 # issue in repo_id 1 - ref_repo_id: 10 - ref_issue_id: 8 # pull in repo_id 10 - created_unix: 946689800 - -- id: 2090 - type: 6 # pull reference - poster_id: 1 - issue_id: 2 # pull in repo_id 1 - ref_repo_id: 1 - ref_issue_id: 1 # issue in repo_id 1 - created_unix: 946689900 - -- id: 2091 - type: 6 # pull reference - poster_id: 1 - issue_id: 2 # pull in repo_id 1 - ref_repo_id: 1 - ref_issue_id: 2 # pull in repo_id 1 - created_unix: 946690000 - -- id: 2092 - type: 6 # pull reference - poster_id: 1 - issue_id: 2 # pull in repo_id 1 - ref_repo_id: 32 - ref_issue_id: 16 # issue in repo_id 32 - created_unix: 946690050 - -- id: 2093 - type: 6 # pull reference - poster_id: 1 - issue_id: 2 # pull in repo_id 1 - ref_repo_id: 10 - ref_issue_id: 8 # pull in repo_id 10 - created_unix: 946690100 diff --git a/models/fixtures/commit_status.yml b/models/fixtures/commit_status.yml index c568e89cea..0ba6caafe9 100644 --- a/models/fixtures/commit_status.yml +++ b/models/fixtures/commit_status.yml @@ -7,7 +7,6 @@ target_url: https://example.com/builds/ description: My awesome CI-service context: ci/awesomeness - context_hash: c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7 creator_id: 2 - @@ -19,7 +18,6 @@ target_url: https://example.com/coverage/ description: My awesome Coverage service context: cov/awesomeness - context_hash: 3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe creator_id: 2 - @@ -31,7 +29,6 @@ target_url: https://example.com/coverage/ description: My awesome Coverage service context: cov/awesomeness - context_hash: 3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe creator_id: 2 - @@ -43,7 +40,6 @@ target_url: https://example.com/builds/ description: My awesome CI-service context: ci/awesomeness - context_hash: c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7 creator_id: 2 - @@ -55,41 +51,15 @@ target_url: https://example.com/builds/ description: My awesome deploy service context: deploy/awesomeness - context_hash: ae9547713a6665fc4261d0756904932085a41cf2 creator_id: 2 - id: 6 - index: 1 + index: 6 repo_id: 62 state: "failure" sha: "774f93df12d14931ea93259ae93418da4482fcc1" target_url: "/user2/test_workflows/actions" description: My awesome deploy service context: deploy/awesomeness - context_hash: ae9547713a6665fc4261d0756904932085a41cf2 - creator_id: 2 - -- - id: 7 - index: 6 - repo_id: 1 - state: "pending" - sha: "1234123412341234123412341234123412341234" - target_url: https://example.com/builds/ - description: My awesome deploy service - context: deploy/awesomeness - context_hash: ae9547713a6665fc4261d0756904932085a41cf2 - creator_id: 2 - -- - id: 8 - index: 2 - repo_id: 62 - state: "error" - sha: "774f93df12d14931ea93259ae93418da4482fcc1" - target_url: "/user2/test_workflows/actions" - description: "My awesome deploy service - v2" - context: deploy/awesomeness - context_hash: ae9547713a6665fc4261d0756904932085a41cf2 creator_id: 2 diff --git a/models/fixtures/federated_user.yml b/models/fixtures/federated_user.yml deleted file mode 100644 index ca780a73aa..0000000000 --- a/models/fixtures/federated_user.yml +++ /dev/null @@ -1 +0,0 @@ -[] # empty diff --git a/models/fixtures/federation_host.yml b/models/fixtures/federation_host.yml deleted file mode 100644 index ca780a73aa..0000000000 --- a/models/fixtures/federation_host.yml +++ /dev/null @@ -1 +0,0 @@ -[] # empty diff --git a/models/fixtures/follow.yml b/models/fixtures/follow.yml index da3d4a60c1..b8d35828bf 100644 --- a/models/fixtures/follow.yml +++ b/models/fixtures/follow.yml @@ -17,13 +17,3 @@ id: 4 user_id: 31 follow_id: 33 - -- - id: 5 - user_id: 4 - follow_id: 8 - -- - id: 6 - user_id: 5 - follow_id: 8 diff --git a/models/fixtures/hook_task.yml b/models/fixtures/hook_task.yml index c62d451868..fc0e03bca1 100644 --- a/models/fixtures/hook_task.yml +++ b/models/fixtures/hook_task.yml @@ -18,7 +18,7 @@ id: 2 hook_id: 1 uuid: uuid2 - is_delivered: true + is_delivered: false - id: 3 @@ -40,4 +40,4 @@ id: 4 hook_id: 3 uuid: uuid4 - is_delivered: true + is_delivered: false diff --git a/models/fixtures/label.yml b/models/fixtures/label.yml index acfac74968..2242b90dcd 100644 --- a/models/fixtures/label.yml +++ b/models/fixtures/label.yml @@ -96,14 +96,3 @@ num_issues: 0 num_closed_issues: 0 archived_unix: 0 - -- - id: 10 - repo_id: 3 - org_id: 0 - name: repo3label1 - color: '#112233' - exclusive: false - num_issues: 0 - num_closed_issues: 0 - archived_unix: 0 diff --git a/models/fixtures/pull_auto_merge.yml b/models/fixtures/pull_auto_merge.yml deleted file mode 100644 index ca780a73aa..0000000000 --- a/models/fixtures/pull_auto_merge.yml +++ /dev/null @@ -1 +0,0 @@ -[] # empty diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index 79051ffb6c..9a16316e5a 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -64,8 +64,6 @@ base_branch: branch2 merge_base: 985f0301dba5e7b34be866819cd15ad3d8f508ee has_merged: false - allow_maintainer_edit: true - commits_behind: 1 - id: 6 diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml index 773f238645..6dac78f588 100644 --- a/models/fixtures/repo_unit.yml +++ b/models/fixtures/repo_unit.yml @@ -788,17 +788,3 @@ type: 10 config: "{}" created_unix: 946684810 - -- - id: 114 - repo_id: 4 - type: 10 - config: "{}" - created_unix: 946684810 - -- - id: 115 - repo_id: 63 - type: 10 - config: "{}" - created_unix: 946684810 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index c383fa43ac..845dae7fc1 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -26,13 +26,10 @@ fork_id: 0 is_template: false template_id: 0 - size: 7597 + size: 7320 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - created_unix: 1731254961 - updated_unix: 1731254961 - topics: '[]' - + - id: 2 owner_id: 2 @@ -63,7 +60,7 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: true - topics: '[]' + - id: 3 owner_id: 3 @@ -94,9 +91,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - created_unix: 1700000001 - updated_unix: 1700000001 - topics: '[]' - id: 4 @@ -128,7 +122,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 5 @@ -136,7 +129,6 @@ owner_name: org3 lower_name: repo5 name: repo5 - default_branch: master num_watches: 0 num_stars: 0 num_forks: 0 @@ -160,9 +152,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - created_unix: 1700000002 - updated_unix: 1700000002 - topics: '[]' - id: 6 @@ -193,9 +182,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - created_unix: 1710000001 - updated_unix: 1710000001 - topics: '[]' - id: 7 @@ -226,9 +212,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - created_unix: 1710000003 - updated_unix: 1710000003 - topics: '[]' - id: 8 @@ -259,9 +242,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - created_unix: 1710000002 - updated_unix: 1710000002 - topics: '[]' - id: 9 @@ -292,7 +272,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 10 @@ -324,7 +303,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 11 @@ -356,7 +334,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 12 @@ -387,7 +364,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 13 @@ -418,7 +394,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 14 @@ -450,7 +425,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 15 @@ -482,7 +456,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 16 @@ -514,7 +487,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 17 @@ -545,7 +517,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 18 @@ -576,7 +547,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 19 @@ -607,7 +577,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 20 @@ -638,7 +607,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 21 @@ -669,7 +637,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 22 @@ -700,7 +667,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 23 @@ -731,7 +697,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 24 @@ -762,7 +727,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 25 @@ -793,7 +757,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 26 @@ -824,7 +787,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 27 @@ -855,7 +817,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 28 @@ -886,7 +847,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 29 @@ -917,7 +877,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 30 @@ -948,7 +907,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 31 @@ -980,7 +938,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 32 # org public repo @@ -1011,9 +968,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - created_unix: 1700000003 - updated_unix: 1700000003 - topics: '[]' - id: 33 @@ -1045,7 +999,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 34 @@ -1076,7 +1029,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 35 @@ -1107,7 +1059,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 36 @@ -1139,7 +1090,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 37 @@ -1171,7 +1121,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 38 @@ -1203,7 +1152,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 39 @@ -1235,7 +1183,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 40 @@ -1267,7 +1214,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 41 @@ -1299,7 +1245,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 42 @@ -1331,7 +1276,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 43 @@ -1362,7 +1306,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 44 @@ -1394,7 +1337,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 45 @@ -1425,7 +1367,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 46 @@ -1457,7 +1398,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 47 @@ -1489,7 +1429,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 48 @@ -1521,7 +1460,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 49 @@ -1554,7 +1492,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 50 @@ -1586,7 +1523,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 51 @@ -1618,7 +1554,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 52 @@ -1650,7 +1585,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 53 @@ -1679,7 +1613,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 54 @@ -1692,7 +1625,6 @@ is_archived: false is_private: true status: 0 - topics: '[]' - id: 55 @@ -1705,7 +1637,6 @@ is_private: true num_issues: 1 status: 0 - topics: '[]' - id: 56 @@ -1719,7 +1650,6 @@ is_private: true status: 0 num_issues: 0 - topics: '[]' - id: 57 @@ -1733,7 +1663,6 @@ is_private: false status: 0 num_issues: 0 - topics: '[]' - id: 58 # org public repo @@ -1765,7 +1694,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 1059 @@ -1779,7 +1707,6 @@ is_private: false status: 0 num_issues: 0 - topics: '[]' - id: 59 @@ -1793,7 +1720,6 @@ is_private: true status: 0 num_issues: 0 - topics: '[]' - id: 60 @@ -1825,7 +1751,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 61 @@ -1857,7 +1782,6 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - topics: '[]' - id: 62 owner_id: 2 @@ -1887,37 +1811,4 @@ template_id: 0 size: 0 is_fsck_enabled: true - close_issues_via_commit_in_any_branch: false - topics: '[]' - -- - id: 63 - owner_id: 2 - owner_name: user2 - lower_name: test_action_run_search - name: test_action_run_search - default_branch: main - num_watches: 0 - num_stars: 0 - num_forks: 0 - num_issues: 0 - num_closed_issues: 0 - num_pulls: 0 - num_closed_pulls: 0 - num_milestones: 0 - num_closed_milestones: 0 - num_projects: 0 - num_closed_projects: 0 - is_private: true - is_empty: false - is_archived: false - is_mirror: false - status: 0 - is_fork: false - fork_id: 0 - is_template: false - template_id: 0 - size: 0 - is_fsck_enabled: true - close_issues_via_commit_in_any_branch: false - topics: '[]' + close_issues_via_commit_in_any_branch: false \ No newline at end of file diff --git a/models/fixtures/review.yml b/models/fixtures/review.yml index 0438ceadae..ac97e24c2b 100644 --- a/models/fixtures/review.yml +++ b/models/fixtures/review.yml @@ -179,22 +179,3 @@ content: "Review Comment" updated_unix: 946684810 created_unix: 946684810 - -- - id: 21 - type: 2 - reviewer_id: 5 - issue_id: 3 - content: "reviewed by user5" - commit_id: 4a357436d925b5c974181ff12a994538ddc5a269 - updated_unix: 946684816 - created_unix: 946684816 - -- - id: 22 - type: 4 - reviewer_id: 5 - issue_id: 3 - content: "review request for user5" - updated_unix: 946684817 - created_unix: 946684817 diff --git a/models/fixtures/secret.yml b/models/fixtures/secret.yml deleted file mode 100644 index ca780a73aa..0000000000 --- a/models/fixtures/secret.yml +++ /dev/null @@ -1 +0,0 @@ -[] # empty diff --git a/models/fixtures/system_setting.yml b/models/fixtures/system_setting.yml index dcad176c89..30542bc82a 100644 --- a/models/fixtures/system_setting.yml +++ b/models/fixtures/system_setting.yml @@ -1,7 +1,7 @@ - id: 1 setting_key: 'picture.disable_gravatar' - setting_value: 'true' + setting_value: 'false' version: 1 created: 1653533198 updated: 1653533198 diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml index a863f1203a..149fe90888 100644 --- a/models/fixtures/team.yml +++ b/models/fixtures/team.yml @@ -239,15 +239,3 @@ num_members: 2 includes_all_repositories: false can_create_org_repo: false - -- - id: 25 - org_id: 17 - lower_name: super-user - name: super-user - description: "" - authorize: 3 - num_repos: 0 - num_members: 0 - includes_all_repositories: 0 - can_create_org_repo: 0 diff --git a/models/fixtures/team_unit.yml b/models/fixtures/team_unit.yml index 4d282a7eb5..de0e8d738b 100644 --- a/models/fixtures/team_unit.yml +++ b/models/fixtures/team_unit.yml @@ -1,49 +1,42 @@ - id: 1 team_id: 1 - org_id: 3 type: 1 access_mode: 4 - id: 2 team_id: 1 - org_id: 3 type: 2 access_mode: 4 - id: 3 team_id: 1 - org_id: 3 type: 3 access_mode: 4 - id: 4 team_id: 1 - org_id: 3 type: 4 access_mode: 4 - id: 5 team_id: 1 - org_id: 3 type: 5 access_mode: 4 - id: 6 team_id: 1 - org_id: 3 type: 6 access_mode: 4 - id: 7 team_id: 1 - org_id: 3 type: 7 access_mode: 4 @@ -329,10 +322,3 @@ team_id: 22 type: 3 access_mode: 1 - -- - id: 84 - org_id: 17 - team_id: 25 - type: 3 - access_mode: 3 diff --git a/models/fixtures/two_factor.yml b/models/fixtures/two_factor.yml index bca1109ea8..d8cb85274b 100644 --- a/models/fixtures/two_factor.yml +++ b/models/fixtures/two_factor.yml @@ -1,9 +1,9 @@ - - id: 1 - uid: 24 - secret: MrAed+7K+fKQKu1l3aU45oTDSWK/i5Ugtgk8CmORrKWTMwa2w97rniLU+h+2xq8ZF+16uuXGLzjWa0bOV5xg4NY6w5Ec/tkwQ5rEecOTvc/JZV5lrrlDi48B7Y5/lNcjAWBmH2nEUlM= - scratch_salt: Qb5bq2DyR2 - scratch_hash: 068eb9b8746e0bcfe332fac4457693df1bda55800eb0f6894d14ebb736ae6a24e0fc8fc5333c19f57f81599788f0b8e51ec1 - last_used_passcode: - created_unix: 1564253724 - updated_unix: 1564253724 + id: 1 + uid: 24 + secret: KlDporn6Ile4vFcKI8z7Z6sqK1Scj2Qp0ovtUzCZO6jVbRW2lAoT7UDxDPtrab8d2B9zKOocBRdBJnS8orsrUNrsyETY+jJHb79M82uZRioKbRUz15sfOpmJmEzkFeSg6S4LicUBQos= + scratch_salt: Qb5bq2DyR2 + scratch_hash: 068eb9b8746e0bcfe332fac4457693df1bda55800eb0f6894d14ebb736ae6a24e0fc8fc5333c19f57f81599788f0b8e51ec1 + last_used_passcode: + created_unix: 1564253724 + updated_unix: 1564253724 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index 00aa182540..8e216fbc7d 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -23,9 +23,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar1 avatar_email: user1@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -36,7 +36,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578000 - id: 2 @@ -45,7 +44,6 @@ full_name: ' < Ur Tw >< ' email: user2@example.com keep_email_private: true - keep_pronouns_private: true email_notifications_preference: enabled passwd: ZogKvWdyEx:password passwd_hash_algo: dummy @@ -53,7 +51,6 @@ login_source: 0 login_name: user2 type: 0 - website: https://keyoxide.org/eb114f5e6c0dc2bcdd183550a4b61a2dc5923710 salt: ZogKvWdyEx max_repo_creation: -1 is_active: true @@ -63,21 +60,19 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar2 avatar_email: user2@example.com - # cause a random avatar to be generated when referenced for test purposes use_custom_avatar: false num_followers: 2 num_following: 1 num_stars: 2 - num_repos: 18 + num_repos: 17 num_teams: 0 num_members: 0 visibility: 0 repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578010 - id: 3 @@ -94,7 +89,7 @@ login_name: org3 type: 1 salt: ZogKvWdyEx - max_repo_creation: 1000 + max_repo_creation: -1 is_active: false is_admin: false is_restricted: false @@ -102,9 +97,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar3 avatar_email: org3@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -115,7 +110,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578020 - id: 4 @@ -140,11 +134,11 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar4 avatar_email: user4@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 - num_following: 2 + num_following: 1 num_stars: 0 num_repos: 0 num_teams: 0 @@ -153,7 +147,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578030 - id: 5 @@ -178,11 +171,11 @@ allow_import_local: false allow_create_organization: false prohibit_login: false - avatar: "" + avatar: avatar5 avatar_email: user5@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 - num_following: 1 + num_following: 0 num_stars: 0 num_repos: 1 num_teams: 0 @@ -191,7 +184,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578040 - id: 6 @@ -216,9 +208,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar6 avatar_email: org6@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -229,7 +221,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578050 - id: 7 @@ -254,9 +245,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar7 avatar_email: org7@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -267,7 +258,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578060 - id: 8 @@ -292,10 +282,10 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar8 avatar_email: user8@example.com - use_custom_avatar: true - num_followers: 3 + use_custom_avatar: false + num_followers: 1 num_following: 1 num_stars: 0 num_repos: 0 @@ -305,7 +295,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578070 - id: 9 @@ -330,9 +319,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar9 avatar_email: user9@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -343,7 +332,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578080 - id: 10 @@ -352,7 +340,6 @@ full_name: User Ten email: user10@example.com keep_email_private: false - keep_pronouns_private: true email_notifications_preference: enabled passwd: ZogKvWdyEx:password passwd_hash_algo: dummy @@ -369,9 +356,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar10 avatar_email: user10@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -382,7 +369,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578090 - id: 11 @@ -407,9 +393,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar11 avatar_email: user11@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -420,7 +406,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578100 - id: 12 @@ -445,9 +430,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar12 avatar_email: user12@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -458,7 +443,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578110 - id: 13 @@ -483,9 +467,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar13 avatar_email: user13@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -496,7 +480,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578120 - id: 14 @@ -521,9 +504,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar14 avatar_email: user13@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -534,7 +517,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578130 - id: 15 @@ -559,9 +541,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar15 avatar_email: user15@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -572,7 +554,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578140 - id: 16 @@ -597,9 +578,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar16 avatar_email: user16@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -610,7 +591,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578150 - id: 17 @@ -635,20 +615,19 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar17 avatar_email: org17@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 num_repos: 2 - num_teams: 4 + num_teams: 3 num_members: 4 visibility: 0 repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578160 - id: 18 @@ -673,9 +652,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar18 avatar_email: user18@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -686,7 +665,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578170 - id: 19 @@ -711,9 +689,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar19 avatar_email: org19@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -724,7 +702,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578180 - id: 20 @@ -749,9 +726,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar20 avatar_email: user20@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -762,7 +739,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578190 - id: 21 @@ -787,9 +763,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar21 avatar_email: user21@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -800,7 +776,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578200 - id: 22 @@ -825,9 +800,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar22 avatar_email: limited_org@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -838,7 +813,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578210 - id: 23 @@ -863,9 +837,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar23 avatar_email: privated_org@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -876,7 +850,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578220 - id: 24 @@ -901,9 +874,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar24 avatar_email: user24@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -914,7 +887,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578230 - id: 25 @@ -939,9 +911,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar25 avatar_email: org25@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -952,7 +924,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578240 - id: 26 @@ -977,9 +948,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar26 avatar_email: org26@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -990,7 +961,6 @@ repo_admin_change_team_access: true theme: "" keep_activity_private: false - created_unix: 1672578250 - id: 27 @@ -1015,9 +985,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar27 avatar_email: user27@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1028,7 +998,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578260 - id: 28 @@ -1053,9 +1022,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar28 avatar_email: user28@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1066,7 +1035,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578270 - id: 29 @@ -1091,9 +1059,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar29 avatar_email: user29@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1104,7 +1072,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578280 - id: 30 @@ -1129,9 +1096,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar29 avatar_email: user30@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1142,7 +1109,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578290 - id: 31 @@ -1167,9 +1133,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar31 avatar_email: user31@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 1 num_stars: 0 @@ -1180,7 +1146,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578300 - id: 32 @@ -1205,9 +1170,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar32 avatar_email: user30@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1218,7 +1183,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578310 - id: 33 @@ -1243,9 +1207,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar33 avatar_email: user33@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 1 num_following: 0 num_stars: 0 @@ -1256,7 +1220,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578320 - id: 34 @@ -1282,7 +1245,7 @@ allow_import_local: false allow_create_organization: false prohibit_login: false - avatar: "" + avatar: avatar34 avatar_email: user34@example.com use_custom_avatar: true num_followers: 0 @@ -1295,7 +1258,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578330 - id: 35 @@ -1320,9 +1282,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar35 avatar_email: private_org35@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1333,7 +1295,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578340 - id: 36 @@ -1358,9 +1319,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar22 avatar_email: abcde@gitea.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1371,7 +1332,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578350 - id: 37 @@ -1396,9 +1356,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: true - avatar: "" + avatar: avatar29 avatar_email: user37@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1409,7 +1369,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578360 - id: 38 @@ -1434,9 +1393,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar38 avatar_email: user38@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1447,7 +1406,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578370 - id: 39 @@ -1472,9 +1430,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar39 avatar_email: user39@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1485,7 +1443,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578380 - id: 40 @@ -1510,9 +1467,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar40 avatar_email: user40@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1523,7 +1480,6 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578390 - id: 41 @@ -1548,9 +1504,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: "" + avatar: avatar41 avatar_email: org41@example.com - use_custom_avatar: true + use_custom_avatar: false num_followers: 0 num_following: 0 num_stars: 0 @@ -1561,4 +1517,3 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false - created_unix: 1672578400 diff --git a/models/fixtures/user_redirect.yml b/models/fixtures/user_redirect.yml index f471e94511..8ff7993398 100644 --- a/models/fixtures/user_redirect.yml +++ b/models/fixtures/user_redirect.yml @@ -2,4 +2,3 @@ id: 1 lower_name: olduser1 redirect_user_id: 1 - created_unix: 1730000000 diff --git a/models/fixtures/webauthn_credential.yml b/models/fixtures/webauthn_credential.yml index edf9935ebf..bc43127fcd 100644 --- a/models/fixtures/webauthn_credential.yml +++ b/models/fixtures/webauthn_credential.yml @@ -5,6 +5,5 @@ attestation_type: none sign_count: 0 clone_warning: false - legacy: true created_unix: 946684800 updated_unix: 946684800 diff --git a/models/forgefed/federationhost.go b/models/forgefed/federationhost.go index 978847bd95..b60c0c39cf 100644 --- a/models/forgefed/federationhost.go +++ b/models/forgefed/federationhost.go @@ -1,41 +1,33 @@ -// Copyright 2024, 2025 The Forgejo Authors. All rights reserved. +// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package forgefed import ( - "database/sql" "fmt" - "net/url" "strings" "time" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/validation" ) // FederationHost data type // swagger:model type FederationHost struct { - ID int64 `xorm:"pk autoincr"` - HostFqdn string `xorm:"host_fqdn UNIQUE(federation_host) INDEX VARCHAR(255) NOT NULL"` - HostPort uint16 `xorm:" UNIQUE(federation_host) INDEX NOT NULL DEFAULT 443"` - NodeInfo NodeInfo `xorm:"extends NOT NULL"` - HostSchema string `xorm:"NOT NULL DEFAULT 'https'"` - LatestActivity time.Time `xorm:"NOT NULL"` - KeyID sql.NullString `xorm:"key_id UNIQUE"` - PublicKey sql.Null[sql.RawBytes] `xorm:"BLOB"` - Created timeutil.TimeStamp `xorm:"created"` - Updated timeutil.TimeStamp `xorm:"updated"` + ID int64 `xorm:"pk autoincr"` + HostFqdn string `xorm:"host_fqdn UNIQUE INDEX VARCHAR(255) NOT NULL"` + NodeInfo NodeInfo `xorm:"extends NOT NULL"` + LatestActivity time.Time `xorm:"NOT NULL"` + Created timeutil.TimeStamp `xorm:"created"` + Updated timeutil.TimeStamp `xorm:"updated"` } // Factory function for FederationHost. Created struct is asserted to be valid. -func NewFederationHost(hostFqdn string, nodeInfo NodeInfo, port uint16, schema string) (FederationHost, error) { +func NewFederationHost(nodeInfo NodeInfo, hostFqdn string) (FederationHost, error) { result := FederationHost{ - HostFqdn: strings.ToLower(hostFqdn), - NodeInfo: nodeInfo, - HostPort: port, - HostSchema: schema, + HostFqdn: strings.ToLower(hostFqdn), + NodeInfo: nodeInfo, } if valid, err := validation.IsValid(result); !valid { return FederationHost{}, err @@ -43,20 +35,11 @@ func NewFederationHost(hostFqdn string, nodeInfo NodeInfo, port uint16, schema s return result, nil } -func (host FederationHost) AsURL() url.URL { - return url.URL{ - Scheme: host.HostSchema, - Host: fmt.Sprintf("%v:%v", host.HostFqdn, host.HostPort), - } -} - // Validate collects error strings in a slice and returns this func (host FederationHost) Validate() []string { var result []string result = append(result, validation.ValidateNotEmpty(host.HostFqdn, "HostFqdn")...) result = append(result, validation.ValidateMaxLen(host.HostFqdn, 255, "HostFqdn")...) - result = append(result, validation.ValidateNotEmpty(host.HostPort, "HostPort")...) - result = append(result, validation.ValidateNotEmpty(host.HostSchema, "HostSchema")...) result = append(result, host.NodeInfo.Validate()...) if host.HostFqdn != strings.ToLower(host.HostFqdn) { result = append(result, fmt.Sprintf("HostFqdn has to be lower case but was: %v", host.HostFqdn)) diff --git a/models/forgefed/federationhost_repository.go b/models/forgefed/federationhost_repository.go index 687966605f..03d8741c58 100644 --- a/models/forgefed/federationhost_repository.go +++ b/models/forgefed/federationhost_repository.go @@ -6,9 +6,10 @@ package forgefed import ( "context" "fmt" + "strings" - "forgejo.org/models/db" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/validation" ) func init() { @@ -29,9 +30,9 @@ func GetFederationHost(ctx context.Context, ID int64) (*FederationHost, error) { return host, nil } -func findFederationHostFromDB(ctx context.Context, searchKey, searchValue string) (*FederationHost, error) { +func FindFederationHostByFqdn(ctx context.Context, fqdn string) (*FederationHost, error) { host := new(FederationHost) - has, err := db.GetEngine(ctx).Where(searchKey, searchValue).Get(host) + has, err := db.GetEngine(ctx).Where("host_fqdn=?", strings.ToLower(fqdn)).Get(host) if err != nil { return nil, err } else if !has { @@ -43,24 +44,6 @@ func findFederationHostFromDB(ctx context.Context, searchKey, searchValue string return host, nil } -func FindFederationHostByFqdnAndPort(ctx context.Context, fqdn string, port uint16) (*FederationHost, error) { - host := new(FederationHost) - has, err := db.GetEngine(ctx).Where("host_fqdn=? AND host_port=?", fqdn, port).Get(host) - if err != nil { - return nil, err - } else if !has { - return nil, nil - } - if res, err := validation.IsValid(host); !res { - return nil, err - } - return host, nil -} - -func FindFederationHostByKeyID(ctx context.Context, keyID string) (*FederationHost, error) { - return findFederationHostFromDB(ctx, "key_id=?", keyID) -} - func CreateFederationHost(ctx context.Context, host *FederationHost) error { if res, err := validation.IsValid(host); !res { return err diff --git a/models/forgefed/federationhost_test.go b/models/forgefed/federationhost_test.go index d11affbae0..ea5494c6e9 100644 --- a/models/forgefed/federationhost_test.go +++ b/models/forgefed/federationhost_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/validation" ) func Test_FederationHostValidation(t *testing.T) { @@ -18,8 +18,6 @@ func Test_FederationHostValidation(t *testing.T) { SoftwareName: "forgejo", }, LatestActivity: time.Now(), - HostPort: 443, - HostSchema: "https", } if res, err := validation.IsValid(sut); !res { t.Errorf("sut should be valid but was %q", err) @@ -31,11 +29,9 @@ func Test_FederationHostValidation(t *testing.T) { SoftwareName: "forgejo", }, LatestActivity: time.Now(), - HostPort: 443, - HostSchema: "https", } if res, _ := validation.IsValid(sut); res { - t.Error("sut should be invalid: HostFqdn empty") + t.Errorf("sut should be invalid: HostFqdn empty") } sut = FederationHost{ @@ -44,22 +40,18 @@ func Test_FederationHostValidation(t *testing.T) { SoftwareName: "forgejo", }, LatestActivity: time.Now(), - HostPort: 443, - HostSchema: "https", } if res, _ := validation.IsValid(sut); res { - t.Error("sut should be invalid: HostFqdn too long (len=256)") + t.Errorf("sut should be invalid: HostFqdn too long (len=256)") } sut = FederationHost{ HostFqdn: "host.do.main", NodeInfo: NodeInfo{}, LatestActivity: time.Now(), - HostPort: 443, - HostSchema: "https", } if res, _ := validation.IsValid(sut); res { - t.Error("sut should be invalid: NodeInfo invalid") + t.Errorf("sut should be invalid: NodeInfo invalid") } sut = FederationHost{ @@ -68,11 +60,9 @@ func Test_FederationHostValidation(t *testing.T) { SoftwareName: "forgejo", }, LatestActivity: time.Now().Add(1 * time.Hour), - HostPort: 443, - HostSchema: "https", } if res, _ := validation.IsValid(sut); res { - t.Error("sut should be invalid: Future timestamp") + t.Errorf("sut should be invalid: Future timestamp") } sut = FederationHost{ @@ -81,10 +71,8 @@ func Test_FederationHostValidation(t *testing.T) { SoftwareName: "forgejo", }, LatestActivity: time.Now(), - HostPort: 443, - HostSchema: "https", } if res, _ := validation.IsValid(sut); res { - t.Error("sut should be invalid: HostFqdn lower case") + t.Errorf("sut should be invalid: HostFqdn lower case") } } diff --git a/models/forgefed/nodeinfo.go b/models/forgefed/nodeinfo.go index 38f51304c5..66d2eca7aa 100644 --- a/models/forgefed/nodeinfo.go +++ b/models/forgefed/nodeinfo.go @@ -6,7 +6,7 @@ package forgefed import ( "net/url" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/validation" "github.com/valyala/fastjson" ) @@ -17,14 +17,12 @@ type ( ) const ( - ForgejoSourceType SoftwareNameType = "forgejo" - GiteaSourceType SoftwareNameType = "gitea" - MastodonSourceType SoftwareNameType = "mastodon" - GoToSocialSourceType SoftwareNameType = "gotosocial" + ForgejoSourceType SoftwareNameType = "forgejo" + GiteaSourceType SoftwareNameType = "gitea" ) var KnownSourceTypes = []any{ - ForgejoSourceType, GiteaSourceType, MastodonSourceType, GoToSocialSourceType, + ForgejoSourceType, GiteaSourceType, } // ------------------------------------------------ NodeInfoWellKnown ------------------------------------------------ diff --git a/models/forgefed/nodeinfo_test.go b/models/forgefed/nodeinfo_test.go index a0c9781b90..4c73bb44d8 100644 --- a/models/forgefed/nodeinfo_test.go +++ b/models/forgefed/nodeinfo_test.go @@ -4,12 +4,12 @@ package forgefed import ( - "errors" + "fmt" "reflect" "strings" "testing" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/validation" ) func Test_NodeInfoWellKnownUnmarshalJSON(t *testing.T) { @@ -28,7 +28,7 @@ func Test_NodeInfoWellKnownUnmarshalJSON(t *testing.T) { }, "empty": { item: []byte(``), - wantErr: errors.New("cannot parse JSON: cannot parse empty string; unparsed tail: \"\""), + wantErr: fmt.Errorf("cannot parse JSON: cannot parse empty string; unparsed tail: \"\""), }, } @@ -74,7 +74,7 @@ func Test_NewNodeInfoWellKnown(t *testing.T) { _, err := NewNodeInfoWellKnown([]byte(`invalid`)) if err == nil { - t.Error("error was expected here") + t.Errorf("error was expected here") } } @@ -87,6 +87,6 @@ func Test_NewNodeInfo(t *testing.T) { _, err := NewNodeInfo([]byte(`invalid`)) if err == nil { - t.Error("error was expected here") + t.Errorf("error was expected here") } } diff --git a/models/forgejo/semver/main_test.go b/models/forgejo/semver/main_test.go index dcc9d588cd..fa56182627 100644 --- a/models/forgejo/semver/main_test.go +++ b/models/forgejo/semver/main_test.go @@ -5,12 +5,11 @@ package semver import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" - _ "forgejo.org/models" - _ "forgejo.org/models/actions" - _ "forgejo.org/models/activities" - _ "forgejo.org/models/forgefed" + _ "code.gitea.io/gitea/models" + _ "code.gitea.io/gitea/models/actions" + _ "code.gitea.io/gitea/models/activities" ) func TestMain(m *testing.M) { diff --git a/models/forgejo/semver/semver.go b/models/forgejo/semver/semver.go index 24a3db9181..7f122d2301 100644 --- a/models/forgejo/semver/semver.go +++ b/models/forgejo/semver/semver.go @@ -5,7 +5,7 @@ package semver import ( "context" - "forgejo.org/models/db" + "code.gitea.io/gitea/models/db" "github.com/hashicorp/go-version" ) diff --git a/models/forgejo/semver/semver_test.go b/models/forgejo/semver/semver_test.go index 10989ecad3..8aca7bee57 100644 --- a/models/forgejo/semver/semver_test.go +++ b/models/forgejo/semver/semver_test.go @@ -5,43 +5,42 @@ package semver import ( "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestForgejoSemVerSetGet(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) ctx := db.DefaultContext newVersion, err := version.NewVersion("v1.2.3") - require.NoError(t, err) - require.NoError(t, SetVersionString(ctx, newVersion.String())) + assert.NoError(t, err) + assert.NoError(t, SetVersionString(ctx, newVersion.String())) databaseVersion, err := GetVersion(ctx) - require.NoError(t, err) - assert.Equal(t, newVersion.String(), databaseVersion.String()) + assert.NoError(t, err) + assert.EqualValues(t, newVersion.String(), databaseVersion.String()) assert.True(t, newVersion.Equal(databaseVersion)) } func TestForgejoSemVerMissing(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) ctx := db.DefaultContext e := db.GetEngine(ctx) _, err := e.Exec("delete from forgejo_sem_ver") - require.NoError(t, err) + assert.NoError(t, err) v, err := GetVersion(ctx) - require.NoError(t, err) - assert.Equal(t, "1.0.0", v.String()) + assert.NoError(t, err) + assert.EqualValues(t, "1.0.0", v.String()) _, err = e.Exec("drop table forgejo_sem_ver") - require.NoError(t, err) + assert.NoError(t, err) v, err = GetVersion(ctx) - require.NoError(t, err) - assert.Equal(t, "1.0.0", v.String()) + assert.NoError(t, err) + assert.EqualValues(t, "1.0.0", v.String()) } diff --git a/models/forgejo_migrations/main_test.go b/models/forgejo_migrations/main_test.go index 031fe8090d..42579f8194 100644 --- a/models/forgejo_migrations/main_test.go +++ b/models/forgejo_migrations/main_test.go @@ -6,9 +6,9 @@ package forgejo_migrations //nolint:revive import ( "testing" - migration_tests "forgejo.org/models/migrations/test" + "code.gitea.io/gitea/models/migrations/base" ) func TestMain(m *testing.M) { - migration_tests.MainTest(m) + base.MainTest(m) } diff --git a/models/forgejo_migrations/migrate.go b/models/forgejo_migrations/migrate.go index 94469b7371..78c13f33a0 100644 --- a/models/forgejo_migrations/migrate.go +++ b/models/forgejo_migrations/migrate.go @@ -5,16 +5,15 @@ package forgejo_migrations //nolint:revive import ( "context" - "errors" "fmt" "os" - "forgejo.org/models/forgejo/semver" - forgejo_v1_20 "forgejo.org/models/forgejo_migrations/v1_20" - forgejo_v1_22 "forgejo.org/models/forgejo_migrations/v1_22" - "forgejo.org/modules/git" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/forgejo/semver" + forgejo_v1_20 "code.gitea.io/gitea/models/forgejo_migrations/v1_20" + forgejo_v1_22 "code.gitea.io/gitea/models/forgejo_migrations/v1_22" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" "xorm.io/xorm/names" @@ -59,58 +58,22 @@ var migrations = []*Migration{ NewMigration("Add the `apply_to_admins` column to the `protected_branch` table", forgejo_v1_22.AddApplyToAdminsSetting), // v9 -> v10 NewMigration("Add pronouns to user", forgejo_v1_22.AddPronounsToUser), - // v10 -> v11 - NewMigration("Add the `created` column to the `issue` table", forgejo_v1_22.AddCreatedToIssue), // v11 -> v12 - NewMigration("Add repo_archive_download_count table", forgejo_v1_22.AddRepoArchiveDownloadCount), + NewMigration("Add the `created` column to the `issue` table", forgejo_v1_22.AddCreatedToIssue), // v12 -> v13 - NewMigration("Add `hide_archive_links` column to `release` table", AddHideArchiveLinksToRelease), + NewMigration("Add repo_archive_download_count table", forgejo_v1_22.AddRepoArchiveDownloadCount), // v13 -> v14 - NewMigration("Remove Gitea-specific columns from the repository and badge tables", RemoveGiteaSpecificColumnsFromRepositoryAndBadge), + NewMigration("Add `hide_archive_links` column to `release` table", AddHideArchiveLinksToRelease), // v14 -> v15 - NewMigration("Create the `federation_host` table", CreateFederationHostTable), + NewMigration("Remove Gitea-specific columns from the repository and badge tables", RemoveGiteaSpecificColumnsFromRepositoryAndBadge), // v15 -> v16 - NewMigration("Create the `federated_user` table", CreateFederatedUserTable), + NewMigration("Create the `federation_host` table", CreateFederationHostTable), // v16 -> v17 - NewMigration("Add `normalized_federated_uri` column to `user` table", AddNormalizedFederatedURIToUser), + NewMigration("Create the `federated_user` table", CreateFederatedUserTable), // v17 -> v18 - NewMigration("Create the `following_repo` table", CreateFollowingRepoTable), + NewMigration("Add `normalized_federated_uri` column to `user` table", AddNormalizedFederatedURIToUser), // v18 -> v19 - NewMigration("Add external_url to attachment table", AddExternalURLColumnToAttachmentTable), - // v19 -> v20 - NewMigration("Creating Quota-related tables", CreateQuotaTables), - // v20 -> v21 - NewMigration("Add SSH keypair to `pull_mirror` table", AddSSHKeypairToPushMirror), - // v21 -> v22 - NewMigration("Add `legacy` to `web_authn_credential` table", AddLegacyToWebAuthnCredential), - // v22 -> v23 - NewMigration("Add `delete_branch_after_merge` to `auto_merge` table", AddDeleteBranchAfterMergeToAutoMerge), - // v23 -> v24 - NewMigration("Add `purpose` column to `forgejo_auth_token` table", AddPurposeToForgejoAuthToken), - // v24 -> v25 - NewMigration("Migrate `secret` column to store keying material", MigrateTwoFactorToKeying), - // v25 -> v26 - NewMigration("Add `hash_blake2b` column to `package_blob` table", AddHashBlake2bToPackageBlob), - // v26 -> v27 - NewMigration("Add `created_unix` column to `user_redirect` table", AddCreatedUnixToRedirect), - // v27 -> v28 - NewMigration("Add pronoun privacy settings to user", AddHidePronounsOptionToUser), - // v28 -> v29 - NewMigration("Add public key information to `FederatedUser` and `FederationHost`", AddPublicKeyInformationForFederation), - // v29 -> v30 - NewMigration("Migrate `User.NormalizedFederatedURI` column to extract port & schema into FederatedHost", MigrateNormalizedFederatedURI), - // v30 -> v31 - NewMigration("Normalize repository.topics to empty slice instead of null", SetTopicsAsEmptySlice), - // v31 -> v32 - NewMigration("Migrate maven package name concatenation", ChangeMavenArtifactConcatenation), - // v32 -> v33 - NewMigration("Add federated user activity tables, update the `federated_user` table & add indexes", FederatedUserActivityMigration), - // v33 -> v34 - NewMigration("Add `notify-email` column to `action_run` table", AddNotifyEmailToActionRun), - // v34 -> v35 - NewMigration("Noop because of https://codeberg.org/forgejo/forgejo/issues/8373", NoopAddIndexToActionRunStopped), - // v35 -> v36 - NewMigration("Fix wiki unit default permission", FixWikiUnitDefaultPermission), + NewMigration("Create the `following_repo` table", CreateFollowingRepoTable), } // GetCurrentDBVersion returns the current Forgejo database version. @@ -143,7 +106,7 @@ func EnsureUpToDate(x *xorm.Engine) error { } if currentDB < 0 { - return errors.New("database has not been initialized") + return fmt.Errorf("database has not been initialized") } expected := ExpectedVersion() diff --git a/models/forgejo_migrations/migrate_test.go b/models/forgejo_migrations/migrate_test.go index 20653929a3..2ae3c39fce 100644 --- a/models/forgejo_migrations/migrate_test.go +++ b/models/forgejo_migrations/migrate_test.go @@ -6,14 +6,14 @@ package forgejo_migrations //nolint:revive import ( "testing" - migration_tests "forgejo.org/models/migrations/test" + "code.gitea.io/gitea/models/migrations/base" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" ) // TestEnsureUpToDate tests the behavior of EnsureUpToDate. func TestEnsureUpToDate(t *testing.T) { - x, deferable := migration_tests.PrepareTestEnv(t, 0, new(ForgejoVersion)) + x, deferable := base.PrepareTestEnv(t, 0, new(ForgejoVersion)) defer deferable() if x == nil || t.Failed() { return @@ -21,19 +21,19 @@ func TestEnsureUpToDate(t *testing.T) { // Ensure error if there's no row in Forgejo Version. err := EnsureUpToDate(x) - require.Error(t, err) + assert.Error(t, err) // Insert 'good' Forgejo Version row. _, err = x.InsertOne(&ForgejoVersion{ID: 1, Version: ExpectedVersion()}) - require.NoError(t, err) + assert.NoError(t, err) err = EnsureUpToDate(x) - require.NoError(t, err) + assert.NoError(t, err) // Modify forgejo version to have a lower version. _, err = x.Exec("UPDATE `forgejo_version` SET version = ? WHERE id = 1", ExpectedVersion()-1) - require.NoError(t, err) + assert.NoError(t, err) err = EnsureUpToDate(x) - require.Error(t, err) + assert.Error(t, err) } diff --git a/models/forgejo_migrations/v14.go b/models/forgejo_migrations/v14.go index 53f1ef2223..f6dd35ecf0 100644 --- a/models/forgejo_migrations/v14.go +++ b/models/forgejo_migrations/v14.go @@ -4,7 +4,7 @@ package forgejo_migrations //nolint:revive import ( - "forgejo.org/models/migrations/base" + "code.gitea.io/gitea/models/migrations/base" "xorm.io/xorm" ) diff --git a/models/forgejo_migrations/v15.go b/models/forgejo_migrations/v15.go index 5e5588dd05..d7ed19ca7c 100644 --- a/models/forgejo_migrations/v15.go +++ b/models/forgejo_migrations/v15.go @@ -6,7 +6,7 @@ package forgejo_migrations //nolint:revive import ( "time" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/xorm" ) diff --git a/models/forgejo_migrations/v18.go b/models/forgejo_migrations/v18.go index e6c1493f0e..afccfbfe15 100644 --- a/models/forgejo_migrations/v18.go +++ b/models/forgejo_migrations/v18.go @@ -14,5 +14,5 @@ type FollowingRepo struct { } func CreateFollowingRepoTable(x *xorm.Engine) error { - return x.Sync(new(FollowingRepo)) + return x.Sync(new(FederatedUser)) } diff --git a/models/forgejo_migrations/v19.go b/models/forgejo_migrations/v19.go deleted file mode 100644 index 69b7746eb1..0000000000 --- a/models/forgejo_migrations/v19.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -func AddExternalURLColumnToAttachmentTable(x *xorm.Engine) error { - type Attachment struct { - ID int64 `xorm:"pk autoincr"` - ExternalURL string - } - return x.Sync(new(Attachment)) -} diff --git a/models/forgejo_migrations/v1_20/v1.go b/models/forgejo_migrations/v1_20/v1.go index 72beaf23de..1097613655 100644 --- a/models/forgejo_migrations/v1_20/v1.go +++ b/models/forgejo_migrations/v1_20/v1.go @@ -4,7 +4,7 @@ package forgejo_v1_20 //nolint:revive import ( - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/xorm" ) diff --git a/models/forgejo_migrations/v1_20/v3.go b/models/forgejo_migrations/v1_20/v3.go index cce227e6eb..caa4f1aa99 100644 --- a/models/forgejo_migrations/v1_20/v3.go +++ b/models/forgejo_migrations/v1_20/v3.go @@ -4,7 +4,7 @@ package forgejo_v1_20 //nolint:revive import ( - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/xorm" ) diff --git a/models/forgejo_migrations/v1_22/main_test.go b/models/forgejo_migrations/v1_22/main_test.go index 03c4c5272c..8ca5395a26 100644 --- a/models/forgejo_migrations/v1_22/main_test.go +++ b/models/forgejo_migrations/v1_22/main_test.go @@ -6,9 +6,9 @@ package v1_22 //nolint import ( "testing" - migration_tests "forgejo.org/models/migrations/test" + "code.gitea.io/gitea/models/migrations/base" ) func TestMain(m *testing.M) { - migration_tests.MainTest(m) + base.MainTest(m) } diff --git a/models/forgejo_migrations/v1_22/v11.go b/models/forgejo_migrations/v1_22/v11.go index 17bb592379..c693993565 100644 --- a/models/forgejo_migrations/v1_22/v11.go +++ b/models/forgejo_migrations/v1_22/v11.go @@ -4,7 +4,7 @@ package v1_22 //nolint import ( - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/modules/timeutil" "xorm.io/xorm" ) diff --git a/models/forgejo_migrations/v1_22/v8_test.go b/models/forgejo_migrations/v1_22/v8_test.go index baaba7290f..b8cd478daa 100644 --- a/models/forgejo_migrations/v1_22/v8_test.go +++ b/models/forgejo_migrations/v1_22/v8_test.go @@ -6,10 +6,9 @@ package v1_22 //nolint import ( "testing" - migration_tests "forgejo.org/models/migrations/test" + "code.gitea.io/gitea/models/migrations/base" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_RemoveSSHSignaturesFromReleaseNotes(t *testing.T) { @@ -19,17 +18,17 @@ func Test_RemoveSSHSignaturesFromReleaseNotes(t *testing.T) { Note string `xorm:"TEXT"` } - x, deferable := migration_tests.PrepareTestEnv(t, 0, new(Release)) + x, deferable := base.PrepareTestEnv(t, 0, new(Release)) defer deferable() - require.NoError(t, RemoveSSHSignaturesFromReleaseNotes(x)) + assert.NoError(t, RemoveSSHSignaturesFromReleaseNotes(x)) var releases []Release err := x.Table("release").OrderBy("id ASC").Find(&releases) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, releases, 3) - assert.Empty(t, releases[0].Note) + assert.Equal(t, "", releases[0].Note) assert.Equal(t, "A message.\n", releases[1].Note) assert.Equal(t, "no signature present here", releases[2].Note) } diff --git a/models/forgejo_migrations/v20.go b/models/forgejo_migrations/v20.go deleted file mode 100644 index 8ca9e91f73..0000000000 --- a/models/forgejo_migrations/v20.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -type ( - QuotaLimitSubject int - QuotaLimitSubjects []QuotaLimitSubject - - QuotaKind int -) - -type QuotaRule struct { - Name string `xorm:"pk not null"` - Limit int64 `xorm:"NOT NULL"` - Subjects QuotaLimitSubjects -} - -type QuotaGroup struct { - Name string `xorm:"pk NOT NULL"` -} - -type QuotaGroupRuleMapping struct { - ID int64 `xorm:"pk autoincr"` - GroupName string `xorm:"index unique(qgrm_gr) not null"` - RuleName string `xorm:"unique(qgrm_gr) not null"` -} - -type QuotaGroupMapping struct { - ID int64 `xorm:"pk autoincr"` - Kind QuotaKind `xorm:"unique(qgm_kmg) not null"` - MappedID int64 `xorm:"unique(qgm_kmg) not null"` - GroupName string `xorm:"index unique(qgm_kmg) not null"` -} - -func CreateQuotaTables(x *xorm.Engine) error { - if err := x.Sync(new(QuotaRule)); err != nil { - return err - } - - if err := x.Sync(new(QuotaGroup)); err != nil { - return err - } - - if err := x.Sync(new(QuotaGroupRuleMapping)); err != nil { - return err - } - - return x.Sync(new(QuotaGroupMapping)) -} diff --git a/models/forgejo_migrations/v21.go b/models/forgejo_migrations/v21.go deleted file mode 100644 index 53f141b2ab..0000000000 --- a/models/forgejo_migrations/v21.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -func AddSSHKeypairToPushMirror(x *xorm.Engine) error { - type PushMirror struct { - ID int64 `xorm:"pk autoincr"` - PublicKey string `xorm:"VARCHAR(100)"` - PrivateKey []byte `xorm:"BLOB"` - } - - return x.Sync(&PushMirror{}) -} diff --git a/models/forgejo_migrations/v22.go b/models/forgejo_migrations/v22.go deleted file mode 100644 index eeb738799c..0000000000 --- a/models/forgejo_migrations/v22.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -func AddLegacyToWebAuthnCredential(x *xorm.Engine) error { - type WebauthnCredential struct { - ID int64 `xorm:"pk autoincr"` - BackupEligible bool `xorm:"NOT NULL DEFAULT false"` - BackupState bool `xorm:"NOT NULL DEFAULT false"` - Legacy bool `xorm:"NOT NULL DEFAULT true"` - } - - return x.Sync(&WebauthnCredential{}) -} diff --git a/models/forgejo_migrations/v23.go b/models/forgejo_migrations/v23.go deleted file mode 100644 index 20a916a716..0000000000 --- a/models/forgejo_migrations/v23.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -// AddDeleteBranchAfterMergeToAutoMerge: add DeleteBranchAfterMerge column, setting existing rows to false -func AddDeleteBranchAfterMergeToAutoMerge(x *xorm.Engine) error { - type AutoMerge struct { - ID int64 `xorm:"pk autoincr"` - DeleteBranchAfterMerge bool `xorm:"NOT NULL DEFAULT false"` - } - - return x.Sync(&AutoMerge{}) -} diff --git a/models/forgejo_migrations/v24.go b/models/forgejo_migrations/v24.go deleted file mode 100644 index ebfb5fc1c4..0000000000 --- a/models/forgejo_migrations/v24.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -func AddPurposeToForgejoAuthToken(x *xorm.Engine) error { - type ForgejoAuthToken struct { - ID int64 `xorm:"pk autoincr"` - Purpose string `xorm:"NOT NULL DEFAULT 'long_term_authorization'"` - } - if err := x.Sync(new(ForgejoAuthToken)); err != nil { - return err - } - - _, err := x.Exec("UPDATE `forgejo_auth_token` SET purpose = 'long_term_authorization' WHERE purpose = ''") - return err -} diff --git a/models/forgejo_migrations/v25.go b/models/forgejo_migrations/v25.go deleted file mode 100644 index 8e3032a40c..0000000000 --- a/models/forgejo_migrations/v25.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import ( - "context" - "crypto/md5" - "encoding/base64" - "fmt" - - "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/modules/log" - "forgejo.org/modules/secret" - "forgejo.org/modules/setting" - - "xorm.io/xorm" - "xorm.io/xorm/schemas" -) - -func MigrateTwoFactorToKeying(x *xorm.Engine) error { - var err error - - // When upgrading from Forgejo v9 to v10, this migration will already be - // called from models/migrations/migrations.go migration 304 and must not - // be run twice. - var version int - _, err = x.Table("version").Where("`id` = 1").Select("version").Get(&version) - if err != nil { - // the version table does not exist when a test environment only applies Forgejo migrations - } else if version > 304 { - return nil - } - - switch x.Dialect().URI().DBType { - case schemas.MYSQL: - _, err = x.Exec("ALTER TABLE `two_factor` MODIFY `secret` BLOB") - case schemas.SQLITE: - _, err = x.Exec("ALTER TABLE `two_factor` RENAME COLUMN `secret` TO `secret_backup`") - if err != nil { - return err - } - _, err = x.Exec("ALTER TABLE `two_factor` ADD COLUMN `secret` BLOB") - if err != nil { - return err - } - _, err = x.Exec("UPDATE `two_factor` SET `secret` = `secret_backup`") - if err != nil { - return err - } - _, err = x.Exec("ALTER TABLE `two_factor` DROP COLUMN `secret_backup`") - case schemas.POSTGRES: - _, err = x.Exec("ALTER TABLE `two_factor` ALTER COLUMN `secret` SET DATA TYPE bytea USING secret::text::bytea") - } - if err != nil { - return err - } - - oldEncryptionKey := md5.Sum([]byte(setting.SecretKey)) - - messages := make([]string, 0, 100) - ids := make([]int64, 0, 100) - - err = db.Iterate(context.Background(), nil, func(ctx context.Context, bean *auth.TwoFactor) error { - decodedStoredSecret, err := base64.StdEncoding.DecodeString(string(bean.Secret)) - if err != nil { - messages = append(messages, fmt.Sprintf("two_factor.id=%d, two_factor.uid=%d: base64.StdEncoding.DecodeString: %v", bean.ID, bean.UID, err)) - ids = append(ids, bean.ID) - return nil - } - - secretBytes, err := secret.AesDecrypt(oldEncryptionKey[:], decodedStoredSecret) - if err != nil { - messages = append(messages, fmt.Sprintf("two_factor.id=%d, two_factor.uid=%d: secret.AesDecrypt: %v", bean.ID, bean.UID, err)) - ids = append(ids, bean.ID) - return nil - } - - bean.SetSecret(string(secretBytes)) - _, err = db.GetEngine(ctx).Cols("secret").ID(bean.ID).Update(bean) - return err - }) - if err == nil { - if len(ids) > 0 { - log.Error("Forgejo migration[25]: The following TOTP secrets were found to be corrupted and removed from the database. TOTP is no longer required to login with the associated users. They should be informed because they will need to visit their security settings and configure TOTP again. No other action is required. See https://codeberg.org/forgejo/forgejo/issues/6637 for more context on the various causes for such a corruption.") - for _, message := range messages { - log.Error("Forgejo migration[25]: %s", message) - } - - _, err = db.GetEngine(context.Background()).In("id", ids).NoAutoCondition().NoAutoTime().Delete(&auth.TwoFactor{}) - } - } - - return err -} diff --git a/models/forgejo_migrations/v25_test.go b/models/forgejo_migrations/v25_test.go deleted file mode 100644 index e7402fd021..0000000000 --- a/models/forgejo_migrations/v25_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import ( - "testing" - - "forgejo.org/models/auth" - migration_tests "forgejo.org/models/migrations/test" - "forgejo.org/modules/keying" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_MigrateTwoFactorToKeying(t *testing.T) { - type TwoFactor struct { //revive:disable-line:exported - ID int64 `xorm:"pk autoincr"` - UID int64 `xorm:"UNIQUE"` - Secret string - ScratchSalt string - ScratchHash string - LastUsedPasscode string `xorm:"VARCHAR(10)"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` - } - - // Prepare and load the testing database - x, deferable := migration_tests.PrepareTestEnv(t, 0, new(TwoFactor)) - defer deferable() - if x == nil || t.Failed() { - return - } - - cnt, err := x.Table("two_factor").Count() - require.NoError(t, err) - assert.EqualValues(t, 2, cnt) - - require.NoError(t, MigrateTwoFactorToKeying(x)) - - cnt, err = x.Table("two_factor").Count() - require.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var twofactor auth.TwoFactor - _, err = x.Table("two_factor").ID(1).Get(&twofactor) - require.NoError(t, err) - - secretBytes, err := keying.DeriveKey(keying.ContextTOTP).Decrypt(twofactor.Secret, keying.ColumnAndID("secret", twofactor.ID)) - require.NoError(t, err) - assert.Equal(t, []byte("AVDYS32OPIAYSNBG2NKYV4AHBVEMKKKIGBQ46OXTLMJO664G4TIECOGEANMSNBLS"), secretBytes) -} diff --git a/models/forgejo_migrations/v26.go b/models/forgejo_migrations/v26.go deleted file mode 100644 index 3292d93ffd..0000000000 --- a/models/forgejo_migrations/v26.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -func AddHashBlake2bToPackageBlob(x *xorm.Engine) error { - type PackageBlob struct { - ID int64 `xorm:"pk autoincr"` - HashBlake2b string `xorm:"hash_blake2b char(128) UNIQUE(blake2b) INDEX"` - } - return x.Sync(&PackageBlob{}) -} diff --git a/models/forgejo_migrations/v27.go b/models/forgejo_migrations/v27.go deleted file mode 100644 index 2efa3485a8..0000000000 --- a/models/forgejo_migrations/v27.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations //nolint:revive - -import ( - "forgejo.org/modules/timeutil" - - "xorm.io/xorm" -) - -func AddCreatedUnixToRedirect(x *xorm.Engine) error { - type UserRedirect struct { - ID int64 `xorm:"pk autoincr"` - CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL DEFAULT 0"` - } - return x.Sync(new(UserRedirect)) -} diff --git a/models/forgejo_migrations/v28.go b/models/forgejo_migrations/v28.go deleted file mode 100644 index cba888d2ec..0000000000 --- a/models/forgejo_migrations/v28.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import "xorm.io/xorm" - -func AddHidePronounsOptionToUser(x *xorm.Engine) error { - type User struct { - ID int64 `xorm:"pk autoincr"` - KeepPronounsPrivate bool `xorm:"NOT NULL DEFAULT false"` - } - - return x.Sync(&User{}) -} diff --git a/models/forgejo_migrations/v29.go b/models/forgejo_migrations/v29.go deleted file mode 100644 index d0c2f723ae..0000000000 --- a/models/forgejo_migrations/v29.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import ( - "database/sql" - - "xorm.io/xorm" -) - -func AddPublicKeyInformationForFederation(x *xorm.Engine) error { - type FederationHost struct { - KeyID sql.NullString `xorm:"key_id UNIQUE"` - PublicKey sql.Null[sql.RawBytes] `xorm:"BLOB"` - } - - err := x.Sync(&FederationHost{}) - if err != nil { - return err - } - - type FederatedUser struct { - KeyID sql.NullString `xorm:"key_id UNIQUE"` - PublicKey sql.Null[sql.RawBytes] `xorm:"BLOB"` - } - - return x.Sync(&FederatedUser{}) -} diff --git a/models/forgejo_migrations/v30.go b/models/forgejo_migrations/v30.go deleted file mode 100644 index 6c41a55316..0000000000 --- a/models/forgejo_migrations/v30.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations //nolint:revive - -import ( - "time" - - "forgejo.org/models/migrations/base" - "forgejo.org/modules/forgefed" - "forgejo.org/modules/log" - "forgejo.org/modules/timeutil" - - "xorm.io/xorm" -) - -func MigrateNormalizedFederatedURI(x *xorm.Engine) error { - // Update schema - type FederatedUser struct { - ID int64 `xorm:"pk autoincr"` - UserID int64 `xorm:"NOT NULL"` - ExternalID string `xorm:"UNIQUE(federation_user_mapping) NOT NULL"` - FederationHostID int64 `xorm:"UNIQUE(federation_user_mapping) NOT NULL"` - NormalizedOriginalURL string - } - type User struct { - ID int64 `xorm:"pk autoincr"` - NormalizedFederatedURI string - } - type FederationHost struct { - ID int64 `xorm:"pk autoincr"` - HostFqdn string `xorm:"host_fqdn UNIQUE INDEX VARCHAR(255) NOT NULL"` - NodeInfo NodeInfo `xorm:"extends NOT NULL"` - HostPort uint16 `xorm:"NOT NULL DEFAULT 443"` - HostSchema string `xorm:"NOT NULL DEFAULT 'https'"` - LatestActivity time.Time `xorm:"NOT NULL"` - Created timeutil.TimeStamp `xorm:"created"` - Updated timeutil.TimeStamp `xorm:"updated"` - } - if err := x.Sync(new(User), new(FederatedUser), new(FederationHost)); err != nil { - return err - } - - // Migrate - sessMigration := x.NewSession() - defer sessMigration.Close() - if err := sessMigration.Begin(); err != nil { - return err - } - federatedUsers := make([]*FederatedUser, 0) - err := sessMigration.OrderBy("id").Find(&federatedUsers) - if err != nil { - return err - } - - for _, federatedUser := range federatedUsers { - if federatedUser.NormalizedOriginalURL != "" { - log.Trace("migration[30]: FederatedUser was already migrated %v", federatedUser) - } else { - user := &User{} - has, err := sessMigration.Where("id=?", federatedUser.UserID).Get(user) - if err != nil { - return err - } - - if !has { - log.Debug("migration[30]: User missing for federated user: %v", federatedUser) - _, err := sessMigration.Delete(federatedUser) - if err != nil { - return err - } - } else { - // Migrate User.NormalizedFederatedURI -> FederatedUser.NormalizedOriginalUrl - sql := "UPDATE `federated_user` SET `normalized_original_url` = ? WHERE `id` = ?" - if _, err := sessMigration.Exec(sql, user.NormalizedFederatedURI, federatedUser.FederationHostID); err != nil { - return err - } - - // Migrate (Port, Schema) FederatedUser.NormalizedOriginalUrl -> FederationHost.(Port, Schema) - actorID, err := forgefed.NewActorID(user.NormalizedFederatedURI) - if err != nil { - return err - } - sql = "UPDATE `federation_host` SET `host_port` = ?, `host_schema` = ? WHERE `id` = ?" - if _, err := sessMigration.Exec(sql, actorID.HostPort, actorID.HostSchema, federatedUser.FederationHostID); err != nil { - return err - } - } - } - } - - if err := sessMigration.Commit(); err != nil { - return err - } - - // Drop User.NormalizedFederatedURI field in extra transaction - sessSchema := x.NewSession() - defer sessSchema.Close() - if err := sessSchema.Begin(); err != nil { - return err - } - if err := base.DropTableColumns(sessSchema, "user", "normalized_federated_uri"); err != nil { - return err - } - return sessSchema.Commit() -} diff --git a/models/forgejo_migrations/v30_test.go b/models/forgejo_migrations/v30_test.go deleted file mode 100644 index f826dab815..0000000000 --- a/models/forgejo_migrations/v30_test.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2025 The Forgejo Authors. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations //nolint:revive - -import ( - "testing" - "time" - - migration_tests "forgejo.org/models/migrations/test" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/require" - "xorm.io/xorm/schemas" -) - -func Test_MigrateNormalizedFederatedURI(t *testing.T) { - // Old structs - type User struct { - ID int64 `xorm:"pk autoincr"` - NormalizedFederatedURI string - } - type FederatedUser struct { - ID int64 `xorm:"pk autoincr"` - UserID int64 `xorm:"NOT NULL"` - ExternalID string `xorm:"UNIQUE(federation_user_mapping) NOT NULL"` - FederationHostID int64 `xorm:"UNIQUE(federation_user_mapping) NOT NULL"` - } - type FederationHost struct { - ID int64 `xorm:"pk autoincr"` - HostFqdn string `xorm:"host_fqdn UNIQUE INDEX VARCHAR(255) NOT NULL"` - SoftwareName string `xorm:"NOT NULL"` - LatestActivity time.Time `xorm:"NOT NULL"` - Created timeutil.TimeStamp `xorm:"created"` - Updated timeutil.TimeStamp `xorm:"updated"` - } - - // Prepare TestEnv - x, deferable := migration_tests.PrepareTestEnv(t, 0, - new(User), - new(FederatedUser), - new(FederationHost), - ) - defer deferable() - if x == nil || t.Failed() { - return - } - - // test for expected results - getColumn := func(tn, co string) *schemas.Column { - tables, err := x.DBMetas() - require.NoError(t, err) - var table *schemas.Table - for _, elem := range tables { - if elem.Name == tn { - table = elem - break - } - } - return table.GetColumn(co) - } - - require.NotNil(t, getColumn("user", "normalized_federated_uri")) - require.Nil(t, getColumn("federation_host", "host_port")) - require.Nil(t, getColumn("federation_host", "host_schema")) - cnt1, err := x.Table("federated_user").Count() - require.NoError(t, err) - require.Equal(t, int64(2), cnt1) - - require.NoError(t, MigrateNormalizedFederatedURI(x)) - - require.Nil(t, getColumn("user", "normalized_federated_uri")) - require.NotNil(t, getColumn("federation_host", "host_port")) - require.NotNil(t, getColumn("federation_host", "host_schema")) - cnt2, err := x.Table("federated_user").Count() - require.NoError(t, err) - require.Equal(t, int64(1), cnt2) - - // idempotent - require.NoError(t, MigrateNormalizedFederatedURI(x)) -} diff --git a/models/forgejo_migrations/v31.go b/models/forgejo_migrations/v31.go deleted file mode 100644 index fdcab21b1a..0000000000 --- a/models/forgejo_migrations/v31.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2025 The Forgejo Authors. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations //nolint:revive - -import ( - "xorm.io/xorm" - "xorm.io/xorm/schemas" -) - -func SetTopicsAsEmptySlice(x *xorm.Engine) error { - var err error - switch x.Dialect().URI().DBType { - case schemas.MYSQL: - _, err = x.Exec("UPDATE `repository` SET topics = '[]' WHERE topics IS NULL OR topics = 'null'") - case schemas.SQLITE: - _, err = x.Exec("UPDATE `repository` SET topics = '[]' WHERE topics IS NULL OR topics = 'null'") - case schemas.POSTGRES: - _, err = x.Exec("UPDATE `repository` SET topics = '[]' WHERE topics IS NULL OR topics::text = 'null'") - } - - if err != nil { - return err - } - - if x.Dialect().URI().DBType == schemas.SQLITE { - sessMigration := x.NewSession() - defer sessMigration.Close() - if err := sessMigration.Begin(); err != nil { - return err - } - _, err = sessMigration.Exec("ALTER TABLE `repository` RENAME COLUMN `topics` TO `topics_backup`") - if err != nil { - return err - } - _, err = sessMigration.Exec("ALTER TABLE `repository` ADD COLUMN `topics` TEXT NOT NULL DEFAULT '[]'") - if err != nil { - return err - } - _, err = sessMigration.Exec("UPDATE `repository` SET `topics` = `topics_backup`") - if err != nil { - return err - } - _, err = sessMigration.Exec("ALTER TABLE `repository` DROP COLUMN `topics_backup`") - if err != nil { - return err - } - - return sessMigration.Commit() - } - - type Repository struct { - ID int64 `xorm:"pk autoincr"` - Topics []string `xorm:"TEXT JSON NOT NULL"` - } - - return x.Sync(new(Repository)) -} diff --git a/models/forgejo_migrations/v31_test.go b/models/forgejo_migrations/v31_test.go deleted file mode 100644 index 5b4aac2a60..0000000000 --- a/models/forgejo_migrations/v31_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2025 The Forgejo Authors. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations //nolint:revive - -import ( - "testing" - - migration_tests "forgejo.org/models/migrations/test" - - "github.com/stretchr/testify/require" -) - -func Test_SetTopicsAsEmptySlice(t *testing.T) { - type Repository struct { - ID int64 `xorm:"pk autoincr"` - Topics []string `xorm:"TEXT JSON"` - } - - x, deferable := migration_tests.PrepareTestEnv(t, 0, new(Repository)) - defer deferable() - if x == nil || t.Failed() { - return - } - - require.NoError(t, SetTopicsAsEmptySlice(x)) - - var repos []Repository - require.NoError(t, x.Find(&repos)) - - for _, repo := range repos { - if repo.ID == 2 { - require.Equal(t, []string{"go", "dev"}, repo.Topics, "Valid topics should remain unchanged") - } else { - require.Equal(t, []string{}, repo.Topics, "NULL topics should be set to empty array") - } - } -} diff --git a/models/forgejo_migrations/v32.go b/models/forgejo_migrations/v32.go deleted file mode 100644 index 2460003597..0000000000 --- a/models/forgejo_migrations/v32.go +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations //nolint:revive - -import ( - "encoding/xml" - "fmt" - "regexp" - "slices" - "sort" - "strconv" - "strings" - - "forgejo.org/models/db" - "forgejo.org/models/packages" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/packages/maven" - packages_service "forgejo.org/services/packages" - - "golang.org/x/net/context" - "xorm.io/xorm" -) - -var getPackage = packages_service.GetPackageFileStream - -type Snapshot struct { - baseVersion string - date string - time string - build int -} - -type Metadata struct { - XMLName xml.Name `xml:"metadata"` - ModelVersion string `xml:"modelVersion,attr"` - GroupID string `xml:"groupId"` - ArtifactID string `xml:"artifactId"` - Version string `xml:"version"` -} - -type mavenPackageResult struct { - PackageFile *packages.PackageFile `xorm:"extends"` - PackageVersion *packages.PackageVersion `xorm:"extends"` - Package *packages.Package `xorm:"extends"` - PackageName string `xorm:"-"` - Snapshot *Snapshot `xorm:"-"` - GroupID string `xorm:"-"` - ArtifactID string `xorm:"-"` -} - -// ChangeMavenArtifactConcatenation resolves old dash-concatenated Maven coordinates and regenerates metadata. -// Note: runs per-owner in a single transaction; failures roll back all owners. -func ChangeMavenArtifactConcatenation(x *xorm.Engine) error { - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { - // get unique owner IDs of Maven packages - var ownerIDs []*int64 - if err := db.GetEngine(ctx). - Table("package"). - Select("package.owner_id"). - Where("package.type = 'maven'"). - GroupBy("package.owner_id"). - OrderBy("package.owner_id DESC"). - Find(&ownerIDs); err != nil { - return err - } - - for _, id := range ownerIDs { - if err := fixMavenArtifactPerOwner(ctx, id); err != nil { - log.Error("owner %d migration failed: %v", id, err) - return err // rollback all - } - } - - return nil - }) -} - -func fixMavenArtifactPerOwner(ctx context.Context, ownerID *int64) error { - results, err := getMavenPackageResultsToUpdate(ctx, ownerID) - if err != nil { - return err - } - - if err = resolvePackageCollisions(ctx, results); err != nil { - return err - } - - if err = processPackageVersions(ctx, results); err != nil { - return err - } - - return processPackageFiles(ctx, results) -} - -// processPackageFiles updates Maven package files and versions in the database -// Returns an error if any database or processing operation fails. -func processPackageFiles(ctx context.Context, results []*mavenPackageResult) error { - processedVersion := make(map[string][]*mavenPackageResult) - - for _, r := range results { - if r.Snapshot != nil { - key := fmt.Sprintf("%s:%s", r.PackageName, r.PackageVersion.LowerVersion) - processedVersion[key] = append(processedVersion[key], r) - } - - // Only update version_id when it differs - if r.PackageVersion.ID != r.PackageFile.VersionID { - pattern := strings.TrimSuffix(r.PackageFile.Name, ".pom") + "%" - // Per routers/api/packages/maven/maven.go:338, POM files already have the `IsLead`, so no update needed for this prop - if _, err := db.GetEngine(ctx).Exec("UPDATE package_file SET version_id = ? WHERE version_id = ? and name like ?", r.PackageVersion.ID, r.PackageFile.VersionID, pattern); err != nil { - return err - } - } - } - - // If maven-metadata.xml is missing (snapshot path collision), skip regeneration - // Without this metadata, Maven cannot resolve snapshot details - for _, packageResults := range processedVersion { - sort.Slice(packageResults, func(i, j int) bool { - return packageResults[i].Snapshot.build > packageResults[j].Snapshot.build - }) - - rs := packageResults[0] - - pf, md, err := parseMetadata(ctx, rs) - if err != nil { - return err - } - - if pf != nil && md != nil && md.GroupID == rs.GroupID && md.ArtifactID == rs.ArtifactID { - if pf.VersionID != rs.PackageFile.VersionID { - if _, err := db.GetEngine(ctx).ID(pf.ID).Cols("version_id").Update(pf); err != nil { - return err - } - } - continue - } - - log.Warn("no maven-metadata.xml found for (id: %d) [%s:%s]", rs.PackageVersion.ID, rs.PackageName, rs.PackageVersion.Version) - } - - return nil -} - -// parseMetadata retrieves metadata for a Maven package file from the database and decodes it into a Metadata object. -// Returns the associated PackageFile, Metadata, and any error encountered during processing. -func parseMetadata(ctx context.Context, snapshot *mavenPackageResult) (*packages.PackageFile, *Metadata, error) { - var pf packages.PackageFile - found, err := db.GetEngine(ctx).Table(pf). - Where("version_id = ?", snapshot.PackageFile.VersionID). // still the old id - And("lower_name = ?", "maven-metadata.xml"). - Get(&pf) - if err != nil { - return nil, nil, err - } - - if !found { - return nil, nil, nil - } - - s, _, _, err := getPackage(ctx, &pf) - if err != nil { - return nil, nil, err - } - - defer s.Close() - dec := xml.NewDecoder(s) - var m Metadata - if err := dec.Decode(&m); err != nil { - return nil, nil, err - } - - return &pf, &m, nil -} - -// processPackageVersions processes Maven package versions by updating metadata or inserting new records as necessary. -// It avoids redundant updates by tracking already processed versions using a map. Returns an error on failure. -func processPackageVersions(ctx context.Context, results []*mavenPackageResult) error { - processedVersion := make(map[string]int64) - - for _, r := range results { - key := fmt.Sprintf("%s:%s", r.PackageName, r.PackageVersion.Version) - - if id, ok := processedVersion[key]; ok { - r.PackageVersion.ID = id - continue - } - - // for non collisions, just update the metadata - if r.PackageVersion.PackageID == r.Package.ID { - if _, err := db.GetEngine(ctx).ID(r.PackageVersion.ID).Cols("metadata_json").Update(r.PackageVersion); err != nil { - return err - } - } else { - log.Info("Create new maven package version for %s:%s", r.PackageName, r.PackageVersion.Version) - r.PackageVersion.ID = 0 - r.PackageVersion.PackageID = r.Package.ID - if _, err := db.GetEngine(ctx).Insert(r.PackageVersion); err != nil { - return err - } - } - - processedVersion[key] = r.PackageVersion.ID - } - - return nil -} - -// getMavenPackageResultsToUpdate retrieves Maven package results that need updates based on the owner ID. -// It processes POM metadata, fixes package inconsistencies, and filters corrupted package versions. -func getMavenPackageResultsToUpdate(ctx context.Context, ownerID *int64) ([]*mavenPackageResult, error) { - var candidates []*mavenPackageResult - if err := db.GetEngine(ctx). - Table("package_file"). - Select("package_file.*, package_version.*, package.*"). - Join("INNER", "package_version", "package_version.id = package_file.version_id"). - Join("INNER", "package", "package.id = package_version.package_id"). - Where("package_file.lower_name LIKE ?", "%.pom"). - And("package.type = ?", "maven"). - And("package.owner_id = ?", ownerID). - OrderBy("package_version.id DESC, package_file.id DESC"). - Find(&candidates); err != nil { - return nil, err - } - - var results []*mavenPackageResult - var corruptedVersionIDs []int64 - - // fetch actual metadata from blob as all packages needs to be fixed following the new string concatenation - for _, r := range candidates { - if err := processPomMetadata(ctx, r); err != nil { - // Skip corrupted versions; admin intervention may be needed to repair these files. - log.Warn("Failed to process package file [id: %d] ignoring package version[%d]: %v", r.PackageFile.ID, r.PackageVersion.ID, err) - - corruptedVersionIDs = append(corruptedVersionIDs, r.PackageVersion.ID) - - continue - } - - results = append(results, r) - log.Debug("Resolved id [%d] from [%s:%s] to [%s:%s] [Snapshot: %v]", r.Package.ID, r.Package.Name, r.PackageVersion.Version, r.PackageName, r.PackageVersion.Version, r.Snapshot) - } - - for _, corruptedVersionID := range corruptedVersionIDs { - for i := 0; i < len(results); { - if corruptedVersionID == results[i].PackageVersion.ID { - results = append(results[:i], results[i+1:]...) - } else { - i++ - } - } - } - - return results, nil -} - -// resolvePackageCollisions handles name collisions by keeping the first existing record and inserting new Package records for subsequent collisions. -// Returns a map from PackageName to its resolved Package.ID. -func resolvePackageCollisions(ctx context.Context, results []*mavenPackageResult) error { - // Group new names by lowerName - collisions := make(map[string][]string) - for _, r := range results { - names := collisions[r.Package.LowerName] - if !slices.Contains(names, r.PackageName) { - collisions[r.Package.LowerName] = append(names, r.PackageName) - } - } - - pkgIDByName := make(map[string]int64) - var err error - - for _, r := range results { - list := collisions[r.Package.LowerName] - - // update to the upcoming package name which is colon separated - r.Package.Name = r.PackageName - r.Package.LowerName = r.PackageName - - // exiting entry - if id, ok := pkgIDByName[r.PackageName]; ok { - r.Package.ID = id - // first package kept the current id - } else if list[0] == r.PackageName { - pkgIDByName[r.PackageName] = r.Package.ID - - if _, err = db.GetEngine(ctx).ID(r.Package.ID).Cols("name", "lower_name").Update(r.Package); err != nil { - return err - } - // create a new entry - } else { - log.Info("Create new maven package for %s", r.Package.Name) - - r.Package.ID = 0 - if _, err = db.GetEngine(ctx).Insert(r.Package); err != nil { - return err - } - - pkgIDByName[r.PackageName] = r.Package.ID - } - } - - return nil -} - -// processPomMetadata processes a Maven package file, parses its POM metadata, and updates PackageVersion information. -func processPomMetadata(ctx context.Context, mpr *mavenPackageResult) error { - s, _, _, err := getPackage(ctx, mpr.PackageFile) - if err != nil { - return fmt.Errorf("unable to get package stream: %v", err) - } - defer s.Close() - - actualPom, err := maven.ParsePackageMetaData(s) - if err != nil { - return fmt.Errorf("failed to parse POM metadata: %v", err) - } - - raw, err := json.Marshal(actualPom) - if err != nil { - return fmt.Errorf("failed to marshal metadata: %v", err) - } - - var currentPom *maven.Metadata - if err = json.Unmarshal([]byte(mpr.PackageVersion.MetadataJSON), ¤tPom); err != nil { - return fmt.Errorf("failed to unmarshal metadata: %v", err) - } - - // since the rest api can also be (ab)used to upload artifacts wrong, just ignore them - if isInvalidMatch(currentPom, actualPom) { - return fmt.Errorf("artifact mismatch: actual [%s] expected [%s]", actualPom.ArtifactID, currentPom.ArtifactID) - } - - // this will also fix packages that missed its groupID - // Ref: https://codeberg.org/forgejo/forgejo/pulls/6329 - mpr.PackageVersion.MetadataJSON = string(raw) - - // Since Maven packages are case-sensitive, avoid potential clashes and clean-ups - // by enforcing consistent case handling similar to RPM packages. - mpr.PackageName = fmt.Sprintf("%s:%s", actualPom.GroupID, actualPom.ArtifactID) - - mpr.GroupID = actualPom.GroupID - mpr.ArtifactID = actualPom.ArtifactID - - if strings.HasSuffix(mpr.PackageVersion.Version, "-SNAPSHOT") { - snap, err := extraSnapshotDetails(currentPom, actualPom, mpr) - if err != nil { - return err - } - mpr.Snapshot = snap - } else { - // only snapshots are affected but kept in case of not complete fixtures - expectedFileName := fmt.Sprintf("%s-%s.pom", actualPom.ArtifactID, mpr.PackageVersion.Version) - if mpr.PackageFile.Name != expectedFileName { - log.Warn("invalid package file name - this is a collision which needs to be resolved expected [%s], actual [%s]", expectedFileName, mpr.PackageFile.Name) - } - } - - return nil -} - -// extraSnapshotDetails extracts detailed snapshot information -// Returns a Snapshot object encapsulating the extracted details or an error if the filename is invalid or parsing fails. -func extraSnapshotDetails(currentPom, actualPom *maven.Metadata, mpr *mavenPackageResult) (*Snapshot, error) { - pattern := `^%s-` + - `(?P[\d\.]+)-` + - `(?P\d{8})\.` + - `(?P
`+ @@ -768,7 +754,7 @@ func TestRender_FilePreview(t *testing.T) { `gogits/gogs – `+ `path/to/file.go`+ ``+ - ``+ + ``+ `Lines 2 to 3 in gogits/gogs@190d949`+ ``+ ``+ @@ -794,38 +780,6 @@ func TestRender_FilePreview(t *testing.T) { }, ) }) - t.Run("single-line", func(t *testing.T) { - testRender( - util.URLJoin(markup.TestRepoURL, "src", "commit", "4c1aaf56bcb9f39dcf65f3f250726850aed13cd6", "single-line.txt")+"#L1", - `

`+ - `
`+ - `
`+ - `
`+ - `gogits/gogs – `+ - `single-line.txt`+ - `
`+ - ``+ - `Line 1 in gogits/gogs@4c1aaf5`+ - ``+ - `
`+ - `
`+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - `
A`+`
`+ - `
`+ - `
`+ - `

`, - map[string]string{ - "user": "gogits", - "repo": "gogs2", - }, - ) - }) t.Run("AppSubURL", func(t *testing.T) { urlWithSub := util.URLJoin(markup.TestAppURL, "sub", markup.TestOrgRepo, "src", "commit", sha, "path", "to", "file.go") + "#L2-L3" @@ -847,7 +801,7 @@ func TestRender_FilePreview(t *testing.T) { ``+ - ``+ + ``+ `Lines 2 to 3 in 190d949`+ ``+ ``+ @@ -878,7 +832,7 @@ func TestRender_FilePreview(t *testing.T) { ``+ - ``+ + ``+ `Lines 2 to 3 in 190d949`+ ``+ ``+ @@ -911,7 +865,7 @@ func TestRender_FilePreview(t *testing.T) { ``+ - ``+ + ``+ `Lines 2 to 3 in 190d949`+ ``+ ``+ @@ -936,7 +890,7 @@ func TestRender_FilePreview(t *testing.T) { ``+ - ``+ + ``+ `Lines 2 to 3 in 190d949`+ ``+ ``+ @@ -967,7 +921,7 @@ func TestRender_FilePreview(t *testing.T) { ``+ - ``+ + ``+ `Lines 2 to 3 in 190d949`+ ``+ ``+ @@ -992,7 +946,7 @@ func TestRender_FilePreview(t *testing.T) { ``+ - ``+ + ``+ `Lines 2 to 3 in 190d949`+ ``+ ``+ @@ -1017,7 +971,7 @@ func TestRender_FilePreview(t *testing.T) { ``+ - ``+ + ``+ `Lines 2 to 3 in 190d949`+ ``+ ``+ @@ -1040,138 +994,4 @@ func TestRender_FilePreview(t *testing.T) { localMetas, ) }) - - commitFileURL := util.URLJoin(markup.TestRepoURL, "src", "commit", "c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be", "path", "to", "file.md") - - t.Run("rendered file with ?display=source", func(t *testing.T) { - testRender( - commitFileURL+"?display=source"+"#L1-L2", - `

`+ - `
`+ - `
`+ - `
`+ - `path/to/file.md`+ - `
`+ - ``+ - `Lines 1 to 2 in c991312`+ - ``+ - `
`+ - `
`+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - `
# A`+"\n"+`
B`+"\n"+`
`+ - `
`+ - `
`+ - `

`, - localMetas, - ) - }) - - t.Run("rendered file without ?display=source", func(t *testing.T) { - testRender( - commitFileURL+"#L1-L2", - `

`+ - `
`+ - `
`+ - `
`+ - `path/to/file.md`+ - `
`+ - ``+ - `Lines 1 to 2 in c991312`+ - ``+ - `
`+ - `
`+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - `
# A`+"\n"+`
B`+"\n"+`
`+ - `
`+ - `
`+ - `

`, - localMetas, - ) - }) - - commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "190d9492934af498c3f669d6a2431dc5459e5b20", "path", "to", "file.go") - - t.Run("normal file with ?display=source", func(t *testing.T) { - testRender( - commitFileURL+"?display=source"+"#L2-L3", - `

`+ - `
`+ - `
`+ - `
`+ - `path/to/file.go`+ - `
`+ - ``+ - `Lines 2 to 3 in 190d949`+ - ``+ - `
`+ - `
`+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - `
B`+"\n"+`
C`+"\n"+`
`+ - `
`+ - `
`+ - `

`, - localMetas, - ) - }) - - commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d", "path", "to", "file%20%23.txt") - - t.Run("file with strange characters in name", func(t *testing.T) { - testRender( - commitFileURL+"#L1", - `

`+ - `
`+ - `
`+ - `
`+ - `path/to/file #.txt`+ - `
`+ - ``+ - `Line 1 in eeb243c`+ - ``+ - `
`+ - `
`+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - ``+ - `
A`+"\n"+`
`+ - `
`+ - `
`+ - `

`, - localMetas, - ) - }) } diff --git a/modules/markup/markdown/ast.go b/modules/markup/markdown/ast.go index c2fbbe6692..7f0ac6a92c 100644 --- a/modules/markup/markdown/ast.go +++ b/modules/markup/markdown/ast.go @@ -34,6 +34,13 @@ func NewDetails() *Details { } } +// IsDetails returns true if the given node implements the Details interface, +// otherwise false. +func IsDetails(node ast.Node) bool { + _, ok := node.(*Details) + return ok +} + // Summary is a block that contains the summary of details block type Summary struct { ast.BaseBlock @@ -59,6 +66,13 @@ func NewSummary() *Summary { } } +// IsSummary returns true if the given node implements the Summary interface, +// otherwise false. +func IsSummary(node ast.Node) bool { + _, ok := node.(*Summary) + return ok +} + // TaskCheckBoxListItem is a block that represents a list item of a markdown block with a checkbox type TaskCheckBoxListItem struct { *ast.ListItem @@ -89,6 +103,13 @@ func NewTaskCheckBoxListItem(listItem *ast.ListItem) *TaskCheckBoxListItem { } } +// IsTaskCheckBoxListItem returns true if the given node implements the TaskCheckBoxListItem interface, +// otherwise false. +func IsTaskCheckBoxListItem(node ast.Node) bool { + _, ok := node.(*TaskCheckBoxListItem) + return ok +} + // Icon is an inline for a fomantic icon type Icon struct { ast.BaseInline @@ -118,6 +139,13 @@ func NewIcon(name string) *Icon { } } +// IsIcon returns true if the given node implements the Icon interface, +// otherwise false. +func IsIcon(node ast.Node) bool { + _, ok := node.(*Icon) + return ok +} + // ColorPreview is an inline for a color preview type ColorPreview struct { ast.BaseInline diff --git a/modules/markup/markdown/callout/github.go b/modules/markup/markdown/callout/github.go index 49ad249696..debad42b83 100644 --- a/modules/markup/markdown/callout/github.go +++ b/modules/markup/markdown/callout/github.go @@ -7,7 +7,7 @@ package callout import ( "strings" - "forgejo.org/modules/svg" + "code.gitea.io/gitea/modules/svg" "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/parser" @@ -34,7 +34,8 @@ func (g *GitHubCalloutTransformer) Transform(node *ast.Document, reader text.Rea return ast.WalkContinue, nil } - if v, ok := n.(*ast.Blockquote); ok { + switch v := n.(type) { + case *ast.Blockquote: if v.ChildCount() == 0 { return ast.WalkContinue, nil } @@ -50,7 +51,7 @@ func (g *GitHubCalloutTransformer) Transform(node *ast.Document, reader text.Rea return ast.WalkContinue, nil } firstTextNode, ok := firstParagraph.FirstChild().(*ast.Text) - if !ok || string(firstTextNode.Value(reader.Source())) != "[" { + if !ok || string(firstTextNode.Text(reader.Source())) != "[" { return ast.WalkContinue, nil } secondTextNode, ok := firstTextNode.NextSibling().(*ast.Text) @@ -59,14 +60,14 @@ func (g *GitHubCalloutTransformer) Transform(node *ast.Document, reader text.Rea } // If the second node's text isn't one of the supported attention // types, continue walking. - secondTextNodeText := secondTextNode.Value(reader.Source()) + secondTextNodeText := secondTextNode.Text(reader.Source()) attentionType := strings.ToLower(strings.TrimPrefix(string(secondTextNodeText), "!")) if _, has := supportedAttentionTypes[attentionType]; !has { return ast.WalkContinue, nil } thirdTextNode, ok := secondTextNode.NextSibling().(*ast.Text) - if !ok || string(thirdTextNode.Value(reader.Source())) != "]" { + if !ok || string(thirdTextNode.Text(reader.Source())) != "]" { return ast.WalkContinue, nil } diff --git a/modules/markup/markdown/callout/github_legacy.go b/modules/markup/markdown/callout/github_legacy.go index e77da73dd9..eb15e1e64c 100644 --- a/modules/markup/markdown/callout/github_legacy.go +++ b/modules/markup/markdown/callout/github_legacy.go @@ -7,8 +7,6 @@ package callout import ( "strings" - "forgejo.org/modules/markup/markdown/util" - "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/text" @@ -25,7 +23,8 @@ func (g *GitHubLegacyCalloutTransformer) Transform(node *ast.Document, reader te return ast.WalkContinue, nil } - if v, ok := n.(*ast.Blockquote); ok { + switch v := n.(type) { + case *ast.Blockquote: if v.ChildCount() == 0 { return ast.WalkContinue, nil } @@ -42,7 +41,7 @@ func (g *GitHubLegacyCalloutTransformer) Transform(node *ast.Document, reader te if !ok { return ast.WalkContinue, nil } - calloutText := string(util.Text(calloutNode, reader.Source())) + calloutText := string(calloutNode.Text(reader.Source())) calloutType := strings.ToLower(calloutText) // We only support "Note" and "Warning" callouts in legacy mode, // match only those. @@ -65,14 +64,6 @@ func (g *GitHubLegacyCalloutTransformer) Transform(node *ast.Document, reader te attentionParagraph.AppendChild(attentionParagraph, calloutNode) firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph) firstParagraph.RemoveChild(firstParagraph, calloutNode) - - // Remove softbreak line if there's one. - if firstParagraph.ChildCount() >= 1 { - softBreakNode, ok := firstParagraph.FirstChild().(*ast.Text) - if ok && softBreakNode.SoftLineBreak() { - firstParagraph.RemoveChild(firstParagraph, softBreakNode) - } - } } return ast.WalkContinue, nil diff --git a/modules/markup/markdown/color_util.go b/modules/markup/markdown/color_util.go index efbde6b730..355fef3fc0 100644 --- a/modules/markup/markdown/color_util.go +++ b/modules/markup/markdown/color_util.go @@ -6,7 +6,7 @@ package markdown import "regexp" var ( - hexRGB = regexp.MustCompile(`^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$`) + hexRGB = regexp.MustCompile(`^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$`) hsl = regexp.MustCompile(`^hsl\([ ]*([012]?[0-9]{1,2}|3[0-5][0-9]|360),[ ]*([0-9]{0,2}|100)\%,[ ]*([0-9]{0,2}|100)\%\)$`) hsla = regexp.MustCompile(`^hsla\(([ ]*[012]?[0-9]{1,2}|3[0-5][0-9]|360),[ ]*([0-9]{0,2}|100)\%,[ ]*([0-9]{0,2}|100)\%,[ ]*(1|1\.0|0|(0\.[0-9]+))\)$`) rgb = regexp.MustCompile(`^rgb\(([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))),){2}([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))))\)$`) diff --git a/modules/markup/markdown/color_util_test.go b/modules/markup/markdown/color_util_test.go index 9f6448cf8c..c6e0555a35 100644 --- a/modules/markup/markdown/color_util_test.go +++ b/modules/markup/markdown/color_util_test.go @@ -17,7 +17,6 @@ func TestMatchColor(t *testing.T) { {"#ddeeffa0", true}, {"#ddeefe", true}, {"#abcdef", true}, - {"#fffa", true}, {"#abcdeg", false}, {"#abcdefg0", false}, {"black", false}, diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index d229afa8e3..0290e1312d 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -8,8 +8,8 @@ import ( "regexp" "strings" - "forgejo.org/modules/markup" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/setting" "github.com/yuin/goldmark/ast" east "github.com/yuin/goldmark/extension/ast" @@ -131,7 +131,7 @@ func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast. if entering { _, err = w.WriteString("') @@ -203,7 +203,8 @@ func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node return ast.WalkContinue, nil } - _, err := fmt.Fprintf(w, ``, name) + var err error + _, err = w.WriteString(fmt.Sprintf(``, name)) if err != nil { return ast.WalkStop, err } diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index e811d29994..77c876dfff 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -5,23 +5,24 @@ package markdown import ( - "errors" + "fmt" "html/template" "io" "strings" "sync" - "forgejo.org/modules/log" - "forgejo.org/modules/markup" - "forgejo.org/modules/markup/common" - "forgejo.org/modules/markup/markdown/callout" - "forgejo.org/modules/markup/markdown/math" - "forgejo.org/modules/setting" - giteautil "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/common" + "code.gitea.io/gitea/modules/markup/markdown/callout" + "code.gitea.io/gitea/modules/markup/markdown/math" + "code.gitea.io/gitea/modules/setting" + giteautil "code.gitea.io/gitea/modules/util" chromahtml "github.com/alecthomas/chroma/v2/formatters/html" "github.com/yuin/goldmark" highlighting "github.com/yuin/goldmark-highlighting/v2" + meta "github.com/yuin/goldmark-meta" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer" @@ -54,7 +55,7 @@ func (l *limitWriter) Write(data []byte) (int, error) { if err != nil { return n, err } - return n, errors.New("rendered content too large - truncating render") + return n, fmt.Errorf("rendered content too large - truncating render") } n, err := l.w.Write(data) l.sum += int64(n) @@ -120,6 +121,7 @@ func SpecializedMarkdown() goldmark.Markdown { math.NewExtension( math.Enabled(setting.Markdown.EnableMath), ), + meta.Meta, ), goldmark.WithParserOptions( parser.WithAttribute(), @@ -180,7 +182,7 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer) bufWithMetadataLength := len(buf) rc := &RenderConfig{ - Meta: markup.RenderMetaAsDetails, + Meta: renderMetaModeFromString(string(ctx.RenderMetaAs)), Icon: "table", Lang: "", } @@ -267,13 +269,8 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error // RenderString renders Markdown string to HTML with all specific handling stuff and return string func RenderString(ctx *markup.RenderContext, content string) (template.HTML, error) { - return RenderReader(ctx, strings.NewReader(content)) -} - -// RenderReader renders Markdown io.Reader to HTML with all specific handling stuff and return string -func RenderReader(ctx *markup.RenderContext, input io.Reader) (template.HTML, error) { var buf strings.Builder - if err := Render(ctx, input, &buf); err != nil { + if err := Render(ctx, strings.NewReader(content), &buf); err != nil { return "", err } return template.HTML(buf.String()), nil diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index f7955115e0..d366d288fa 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -10,17 +10,16 @@ import ( "strings" "testing" - "forgejo.org/models/unittest" - "forgejo.org/modules/git" - "forgejo.org/modules/log" - "forgejo.org/modules/markup" - "forgejo.org/modules/markup/markdown" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -58,7 +57,7 @@ func TestRender_StandardLinks(t *testing.T) { Base: FullURL, }, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) buffer, err = markdown.RenderString(&markup.RenderContext{ @@ -68,7 +67,7 @@ func TestRender_StandardLinks(t *testing.T) { }, IsWiki: true, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) } @@ -92,7 +91,7 @@ func TestRender_Images(t *testing.T) { Base: FullURL, }, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) } @@ -104,22 +103,22 @@ func TestRender_Images(t *testing.T) { test( "!["+title+"]("+url+")", - `

`+title+`

`) + `

`+title+`

`) test( "[["+title+"|"+url+"]]", - `

`) + `

`+title+`

`) test( "[!["+title+"]("+url+")]("+href+")", `

`+title+`

`) test( "!["+title+"]("+url+")", - `

`+title+`

`) + `

`+title+`

`) test( "[["+title+"|"+url+"]]", - `

`) + `

`+title+`

`) test( "[!["+title+"]("+url+")]("+href+")", `

`+title+`

`) @@ -135,8 +134,8 @@ func testAnswers(baseURLContent, baseURLImages string) []string {

See commit 65f1bf27bc

Ideas and codes

    -
  • Bezier widget (by @r-lyeh) ocornut/imgui#786
  • -
  • Bezier widget (by @r-lyeh) #786
  • +
  • Bezier widget (by @r-lyeh) ocornut/imgui#786
  • +
  • Bezier widget (by @r-lyeh) #786
  • Node graph editors https://github.com/ocornut/imgui/issues/306
  • Memory Editor
  • Plot var helper
  • @@ -149,13 +148,13 @@ func testAnswers(baseURLContent, baseURLImages string) []string { - + - + @@ -164,9 +163,9 @@ func testAnswers(baseURLContent, baseURLImages string) []string { `

    Excelsior JET allows you to create native executables for Windows, Linux and Mac OS X.

    1. Package your libGDX application
      -
    2. +images/1.png
    3. Perform a test run by hitting the Run! button.
      -
    4. +images/2.png

    More tests

    (from https://www.markdownguide.org/extended-syntax/)

    @@ -301,7 +300,7 @@ func TestTotal_RenderWiki(t *testing.T) { Metas: localMetas, IsWiki: true, }, sameCases[i]) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, template.HTML(answers[i]), line) } @@ -326,7 +325,7 @@ func TestTotal_RenderWiki(t *testing.T) { }, IsWiki: true, }, testCases[i]) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, template.HTML(testCases[i+1]), line) } } @@ -345,7 +344,7 @@ func TestTotal_RenderString(t *testing.T) { }, Metas: localMetas, }, sameCases[i]) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, template.HTML(answers[i]), line) } @@ -358,7 +357,7 @@ func TestTotal_RenderString(t *testing.T) { Base: FullURL, }, }, testCases[i]) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, template.HTML(testCases[i+1]), line) } } @@ -366,17 +365,17 @@ func TestTotal_RenderString(t *testing.T) { func TestRender_RenderParagraphs(t *testing.T) { test := func(t *testing.T, str string, cnt int) { res, err := markdown.RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, str) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, cnt, strings.Count(res, "image1
    -image2

    + expected := `

    image1
    +image2

    ` res, err := markdown.RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, expected, res) } func TestRenderEmojiInLinks_Issue12331(t *testing.T) { testcase := `[Link with emoji :moon: in text](https://gitea.io)` - expected := `

    Link with emoji 🌔 in text

    + expected := `

    Link with emoji 🌔 in text

    ` res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, template.HTML(expected), res) } @@ -459,7 +458,7 @@ func TestColorPreview(t *testing.T) { for _, test := range positiveTests { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) - require.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) + assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) } @@ -471,14 +470,14 @@ func TestColorPreview(t *testing.T) { // no backticks "rgb(166, 32, 64)", // typo - "`hsI(0, 100%, 50%)`", // codespell:ignore + "`hsI(0, 100%, 50%)`", // codespell-ignore // looks like a color but not really "`hsl(40, 60, 80)`", } for _, test := range negativeTests { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test) - require.NoError(t, err, "Unexpected error in testcase: %q", test) + assert.NoError(t, err, "Unexpected error in testcase: %q", test) assert.NotContains(t, res, `a (b) [$c$] {$d$}

    ` + nl, }, - { - "$$a$$ test", - `

    a test

    ` + nl, - }, - { - "test $$a$$", - `

    test a

    ` + nl, - }, } for _, test := range testcases { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) - require.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) + assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) } } @@ -763,7 +754,7 @@ Citation needed[^0].`, } for _, test := range testcases { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) - require.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) + assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) assert.Equal(t, test.expected, string(res), "Unexpected result in testcase %q", test.testcase) } } @@ -800,7 +791,7 @@ foo: bar for _, test := range testcases { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) - require.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) + assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) } } @@ -845,17 +836,17 @@ mail@domain.com remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -872,17 +863,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -901,17 +892,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -930,17 +921,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -959,17 +950,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -988,17 +979,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -1018,17 +1009,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -1048,17 +1039,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -1078,17 +1069,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -1108,17 +1099,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -1139,17 +1130,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -1170,17 +1161,17 @@ space

    remote link
    local link
    remote link
    -local image
    -local image
    -local image
    -remote image
    -
    -
    +local image
    +local image
    +local image
    +remote image
    +local image
    +remote link
    https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
    https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
    com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
    -👍
    +👍
    mail@domain.com
    @mention-user test
    #123
    @@ -1190,8 +1181,8 @@ space

    } for i, c := range cases { - result, err := markdown.RenderString(&markup.RenderContext{Ctx: t.Context(), Links: c.Links, IsWiki: c.IsWiki}, input) - require.NoError(t, err, "Unexpected error in testcase: %v", i) + result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input) + assert.NoError(t, err, "Unexpected error in testcase: %v", i) assert.Equal(t, template.HTML(c.Expected), result, "Unexpected result in testcase %v", i) } } @@ -1208,7 +1199,7 @@ func TestCustomMarkdownURL(t *testing.T) { BranchPath: "branch/main", }, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) } @@ -1220,130 +1211,6 @@ func TestCustomMarkdownURL(t *testing.T) { `

    test

    `) } -func TestYAMLMeta(t *testing.T) { - setting.AppURL = AppURL - - test := func(input, expected string) { - buffer, err := markdown.RenderString(&markup.RenderContext{ - Ctx: git.DefaultContext, - }, input) - require.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) - } - - test(`--- -include_toc: true ---- -## Header`, - `
    images/icon-install.png Installation
    images/icon-usage.png Usage
    - - - - - - - - - - -
    include_toc
    true
    -
    toc -

    Header

    `) - - test(`--- -key: value ----`, - `
    - - - - - - - - - - -
    key
    value
    -
    `) - - test("---\n---\n", - `
    -
    `) - - test(`--- -gitea: - details_icon: smiley - include_toc: true ---- -# Another header`, - `
    - - - - - - - - - - -
    gitea
    - - - - - - - - - - - - -
    details_iconinclude_toc
    smileytrue
    -
    -
    toc -

    Another header

    `) - - test(`--- -gitea: - meta: table -key: value ----`, ` - - - - - - - - - - - - -
    giteakey
    - - - - - - - - - - -
    meta
    table
    -
    value
    `) -} - func TestCallout(t *testing.T) { setting.AppURL = AppURL @@ -1351,15 +1218,9 @@ func TestCallout(t *testing.T) { buffer, err := markdown.RenderString(&markup.RenderContext{ Ctx: git.DefaultContext, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) } test(">\n0", "
    \n
    \n

    0

    ") - test("> **Warning**\n> Bad stuff is brewing here", `

    Warning

    -

    Bad stuff is brewing here

    -
    `) - test("> [!WARNING]\n> Bad stuff is brewing here", `

    Warning

    -

    Bad stuff is brewing here

    -
    `) } diff --git a/modules/markup/markdown/math/block_parser.go b/modules/markup/markdown/math/block_parser.go index 527df84975..f3262c82c0 100644 --- a/modules/markup/markdown/math/block_parser.go +++ b/modules/markup/markdown/math/block_parser.go @@ -47,12 +47,6 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex } idx := bytes.Index(line[pos+2:], endBytes) if idx >= 0 { - // for case $$ ... $$ any other text - for i := pos + idx + 4; i < len(line); i++ { - if line[i] != ' ' && line[i] != '\n' { - return nil, parser.NoChildren - } - } segment.Stop = segment.Start + idx + 2 reader.Advance(segment.Len() - 1) segment.Start += 2 diff --git a/modules/markup/markdown/math/inline_block_node.go b/modules/markup/markdown/math/inline_block_node.go deleted file mode 100644 index c92d0c8d84..0000000000 --- a/modules/markup/markdown/math/inline_block_node.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package math - -import ( - "github.com/yuin/goldmark/ast" -) - -// InlineBlock represents inline math e.g. $$...$$ -type InlineBlock struct { - Inline -} - -// InlineBlock implements InlineBlock. -func (n *InlineBlock) InlineBlock() {} - -// KindInlineBlock is the kind for math inline block -var KindInlineBlock = ast.NewNodeKind("MathInlineBlock") - -// Kind returns KindInlineBlock -func (n *InlineBlock) Kind() ast.NodeKind { - return KindInlineBlock -} - -// NewInlineBlock creates a new ast math inline block node -func NewInlineBlock() *InlineBlock { - return &InlineBlock{ - Inline{}, - } -} diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go index da28d4fd9c..614cf329af 100644 --- a/modules/markup/markdown/math/inline_parser.go +++ b/modules/markup/markdown/math/inline_parser.go @@ -21,20 +21,11 @@ var defaultInlineDollarParser = &inlineParser{ end: []byte{'$'}, } -var defaultDualDollarParser = &inlineParser{ - start: []byte{'$', '$'}, - end: []byte{'$', '$'}, -} - // NewInlineDollarParser returns a new inline parser func NewInlineDollarParser() parser.InlineParser { return defaultInlineDollarParser } -func NewInlineDualDollarParser() parser.InlineParser { - return defaultDualDollarParser -} - var defaultInlineBracketParser = &inlineParser{ start: []byte{'\\', '('}, end: []byte{'\\', ')'}, @@ -47,7 +38,7 @@ func NewInlineBracketParser() parser.InlineParser { // Trigger triggers this parser on $ or \ func (parser *inlineParser) Trigger() []byte { - return parser.start + return parser.start[0:1] } func isPunctuation(b byte) bool { @@ -96,12 +87,8 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. if len(line) <= pos { break } - succeedingCharacter := line[pos] - // check valid ending character - if !isPunctuation(succeedingCharacter) && - (succeedingCharacter != ' ') && - (succeedingCharacter != '\n') && - !isBracket(succeedingCharacter) { + suceedingCharacter := line[pos] + if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') && !isBracket(suceedingCharacter) { return nil } if line[ender-1] != '\\' { @@ -114,21 +101,12 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. block.Advance(opener) _, pos := block.Position() - var node ast.Node - if parser == defaultDualDollarParser { - node = NewInlineBlock() - } else { - node = NewInline() - } + node := NewInline() segment := pos.WithStop(pos.Start + ender - opener) node.AppendChild(node, ast.NewRawTextSegment(segment)) block.Advance(ender - opener + len(parser.end)) - if parser == defaultDualDollarParser { - trimBlock(&(node.(*InlineBlock)).Inline, block) - } else { - trimBlock(node.(*Inline), block) - } + trimBlock(node, block) return node } @@ -139,12 +117,12 @@ func trimBlock(node *Inline, block text.Reader) { // trim first space and last space first := node.FirstChild().(*ast.Text) - if first.Segment.IsEmpty() || block.Source()[first.Segment.Start] != ' ' { + if !(!first.Segment.IsEmpty() && block.Source()[first.Segment.Start] == ' ') { return } last := node.LastChild().(*ast.Text) - if last.Segment.IsEmpty() || block.Source()[last.Segment.Stop-1] != ' ' { + if !(!last.Segment.IsEmpty() && block.Source()[last.Segment.Stop-1] == ' ') { return } diff --git a/modules/markup/markdown/math/inline_renderer.go b/modules/markup/markdown/math/inline_renderer.go index 96848099cc..b4e9ade0ae 100644 --- a/modules/markup/markdown/math/inline_renderer.go +++ b/modules/markup/markdown/math/inline_renderer.go @@ -21,11 +21,7 @@ func NewInlineRenderer() renderer.NodeRenderer { func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { if entering { - extraClass := "" - if _, ok := n.(*InlineBlock); ok { - extraClass = "display " - } - _, _ = w.WriteString(``) + _, _ = w.WriteString(``) for c := n.FirstChild(); c != nil; c = c.NextSibling() { segment := c.(*ast.Text).Segment value := util.EscapeHTML(segment.Value(source)) @@ -47,5 +43,4 @@ func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Nod // RegisterFuncs registers the renderer for inline math nodes func (r *InlineRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { reg.Register(KindInline, r.renderInline) - reg.Register(KindInlineBlock, r.renderInline) } diff --git a/modules/markup/markdown/math/math.go b/modules/markup/markdown/math/math.go index 4126dc9ad6..8a50753574 100644 --- a/modules/markup/markdown/math/math.go +++ b/modules/markup/markdown/math/math.go @@ -39,6 +39,28 @@ func Enabled(enable ...bool) Option { }) } +// WithInlineDollarParser enables or disables the parsing of $...$ +func WithInlineDollarParser(enable ...bool) Option { + value := true + if len(enable) > 0 { + value = enable[0] + } + return extensionFunc(func(e *Extension) { + e.parseDollarInline = value + }) +} + +// WithBlockDollarParser enables or disables the parsing of $$...$$ +func WithBlockDollarParser(enable ...bool) Option { + value := true + if len(enable) > 0 { + value = enable[0] + } + return extensionFunc(func(e *Extension) { + e.parseDollarBlock = value + }) +} + // Math represents a math extension with default rendered delimiters var Math = &Extension{ enabled: true, @@ -74,8 +96,7 @@ func (e *Extension) Extend(m goldmark.Markdown) { util.Prioritized(NewInlineBracketParser(), 501), } if e.parseDollarInline { - inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 503), - util.Prioritized(NewInlineDualDollarParser(), 502)) + inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 501)) } m.Parser().AddOptions(parser.WithInlineParsers(inlines...)) diff --git a/modules/markup/markdown/meta_test.go b/modules/markup/markdown/meta_test.go index aaf116ff20..6949966328 100644 --- a/modules/markup/markdown/meta_test.go +++ b/modules/markup/markdown/meta_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) /* @@ -32,7 +31,7 @@ func TestExtractMetadata(t *testing.T) { t.Run("ValidFrontAndBody", func(t *testing.T) { var meta IssueTemplate body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, bodyTest, body) assert.Equal(t, metaTest, meta) assert.True(t, meta.Valid()) @@ -41,20 +40,20 @@ func TestExtractMetadata(t *testing.T) { t.Run("NoFirstSeparator", func(t *testing.T) { var meta IssueTemplate _, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta) - require.Error(t, err) + assert.Error(t, err) }) t.Run("NoLastSeparator", func(t *testing.T) { var meta IssueTemplate _, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta) - require.Error(t, err) + assert.Error(t, err) }) t.Run("NoBody", func(t *testing.T) { var meta IssueTemplate body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest), &meta) - require.NoError(t, err) - assert.Empty(t, body) + assert.NoError(t, err) + assert.Equal(t, "", body) assert.Equal(t, metaTest, meta) assert.True(t, meta.Valid()) }) @@ -64,7 +63,7 @@ func TestExtractMetadataBytes(t *testing.T) { t.Run("ValidFrontAndBody", func(t *testing.T) { var meta IssueTemplate body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest)), &meta) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, bodyTest, string(body)) assert.Equal(t, metaTest, meta) assert.True(t, meta.Valid()) @@ -73,20 +72,20 @@ func TestExtractMetadataBytes(t *testing.T) { t.Run("NoFirstSeparator", func(t *testing.T) { var meta IssueTemplate _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest)), &meta) - require.Error(t, err) + assert.Error(t, err) }) t.Run("NoLastSeparator", func(t *testing.T) { var meta IssueTemplate _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest)), &meta) - require.Error(t, err) + assert.Error(t, err) }) t.Run("NoBody", func(t *testing.T) { var meta IssueTemplate body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest)), &meta) - require.NoError(t, err) - assert.Empty(t, string(body)) + assert.NoError(t, err) + assert.Equal(t, "", string(body)) assert.Equal(t, metaTest, meta) assert.True(t, meta.Valid()) }) diff --git a/modules/markup/markdown/prefixed_id.go b/modules/markup/markdown/prefixed_id.go index 036481dc05..63d7fadc0a 100644 --- a/modules/markup/markdown/prefixed_id.go +++ b/modules/markup/markdown/prefixed_id.go @@ -7,9 +7,9 @@ import ( "bytes" "fmt" - "forgejo.org/modules/container" - "forgejo.org/modules/markup/common" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/markup/common" + "code.gitea.io/gitea/modules/util" "github.com/yuin/goldmark/ast" ) diff --git a/modules/markup/markdown/renderconfig.go b/modules/markup/markdown/renderconfig.go index 5c3eb1beec..f4c48d1b3d 100644 --- a/modules/markup/markdown/renderconfig.go +++ b/modules/markup/markdown/renderconfig.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - "forgejo.org/modules/markup" + "code.gitea.io/gitea/modules/markup" "github.com/yuin/goldmark/ast" "gopkg.in/yaml.v3" diff --git a/modules/markup/markdown/toc.go b/modules/markup/markdown/toc.go index dbfab3e9dc..38f744a25f 100644 --- a/modules/markup/markdown/toc.go +++ b/modules/markup/markdown/toc.go @@ -7,8 +7,8 @@ import ( "fmt" "net/url" - "forgejo.org/modules/markup" - "forgejo.org/modules/translation" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/translation" "github.com/yuin/goldmark/ast" ) diff --git a/modules/markup/markdown/transform_codespan.go b/modules/markup/markdown/transform_codespan.go index fc88db026b..a2cd4fb5ba 100644 --- a/modules/markup/markdown/transform_codespan.go +++ b/modules/markup/markdown/transform_codespan.go @@ -8,8 +8,7 @@ import ( "fmt" "strings" - "forgejo.org/modules/markup" - mdutil "forgejo.org/modules/markup/markdown/util" + "code.gitea.io/gitea/modules/markup" "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/renderer/html" @@ -40,7 +39,7 @@ func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Nod r.Writer.RawWrite(w, value) } case *ColorPreview: - _, _ = fmt.Fprintf(w, ``, string(v.Color)) + _, _ = w.WriteString(fmt.Sprintf(``, string(v.Color))) } } return ast.WalkSkipChildren, nil @@ -50,7 +49,7 @@ func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Nod } func (g *ASTTransformer) transformCodeSpan(_ *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) { - colorContent := mdutil.Text(v, reader.Source()) + colorContent := v.Text(reader.Source()) if matchColor(strings.ToLower(string(colorContent))) { v.AppendChild(v, NewColorPreview(colorContent)) } diff --git a/modules/markup/markdown/transform_heading.go b/modules/markup/markdown/transform_heading.go index eedaf58556..6d48f34d93 100644 --- a/modules/markup/markdown/transform_heading.go +++ b/modules/markup/markdown/transform_heading.go @@ -6,9 +6,8 @@ package markdown import ( "fmt" - "forgejo.org/modules/markup" - mdutil "forgejo.org/modules/markup/markdown/util" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/util" "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/text" @@ -20,7 +19,7 @@ func (g *ASTTransformer) transformHeading(_ *markup.RenderContext, v *ast.Headin v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value))) } } - txt := mdutil.Text(v, reader.Source()) + txt := v.Text(reader.Source()) header := markup.Header{ Text: util.UnsafeBytesToString(txt), Level: v.Level, diff --git a/modules/markup/markdown/transform_image.go b/modules/markup/markdown/transform_image.go index b86c9e3d41..b34a710fed 100644 --- a/modules/markup/markdown/transform_image.go +++ b/modules/markup/markdown/transform_image.go @@ -6,8 +6,8 @@ package markdown import ( "strings" - "forgejo.org/modules/markup" - giteautil "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/markup" + giteautil "code.gitea.io/gitea/modules/util" "github.com/yuin/goldmark/ast" ) @@ -44,7 +44,6 @@ func (g *ASTTransformer) transformImage(ctx *markup.RenderContext, v *ast.Image) for _, attr := range v.Attributes() { image.SetAttribute(attr.Name, attr.Value) } - image.SetAttributeString("loading", []byte("lazy")) for child := v.FirstChild(); child != nil; { next := child.NextSibling() image.AppendChild(image, child) diff --git a/modules/markup/markdown/transform_link.go b/modules/markup/markdown/transform_link.go index 48e3479563..e6f3836412 100644 --- a/modules/markup/markdown/transform_link.go +++ b/modules/markup/markdown/transform_link.go @@ -7,9 +7,9 @@ import ( "bytes" "slices" - "forgejo.org/modules/markup" - "forgejo.org/modules/setting" - giteautil "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/setting" + giteautil "code.gitea.io/gitea/modules/util" "github.com/yuin/goldmark/ast" ) diff --git a/modules/markup/markdown/transform_list.go b/modules/markup/markdown/transform_list.go index 03b3c4e89c..b982fd4a83 100644 --- a/modules/markup/markdown/transform_list.go +++ b/modules/markup/markdown/transform_list.go @@ -6,7 +6,7 @@ package markdown import ( "fmt" - "forgejo.org/modules/markup" + "code.gitea.io/gitea/modules/markup" "github.com/yuin/goldmark/ast" east "github.com/yuin/goldmark/extension/ast" diff --git a/modules/markup/markdown/util/text.go b/modules/markup/markdown/util/text.go deleted file mode 100644 index 8a42e5835b..0000000000 --- a/modules/markup/markdown/util/text.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package util - -import ( - "bytes" - - "github.com/yuin/goldmark/ast" -) - -func textOfChildren(n ast.Node, src []byte, b *bytes.Buffer) { - for c := n.FirstChild(); c != nil; c = c.NextSibling() { - if t, ok := c.(*ast.Text); ok { - b.Write(t.Value(src)) - } else { - textOfChildren(c, src, b) - } - } -} - -func Text(n ast.Node, src []byte) []byte { - var b bytes.Buffer - textOfChildren(n, src, &b) - return b.Bytes() -} diff --git a/modules/markup/mdstripper/mdstripper.go b/modules/markup/mdstripper/mdstripper.go index 7e5abc2ebe..2a69d95224 100644 --- a/modules/markup/mdstripper/mdstripper.go +++ b/modules/markup/mdstripper/mdstripper.go @@ -10,9 +10,9 @@ import ( "strings" "sync" - "forgejo.org/modules/log" - "forgejo.org/modules/markup/common" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup/common" + "code.gitea.io/gitea/modules/setting" "github.com/yuin/goldmark" "github.com/yuin/goldmark/ast" @@ -46,7 +46,7 @@ func (r *stripRenderer) Render(w io.Writer, source []byte, doc ast.Node) error { coalesce := prevSibIsText r.processString( w, - v.Value(source), + v.Text(source), coalesce) if v.SoftLineBreak() { r.doubleSpace(w) @@ -107,12 +107,11 @@ func (r *stripRenderer) processAutoLink(w io.Writer, link []byte) { } var sep string - switch parts[3] { - case "issues": + if parts[3] == "issues" { sep = "#" - case "pulls": + } else if parts[3] == "pulls" { sep = "!" - default: + } else { // Process out of band r.links = append(r.links, linkStr) return diff --git a/modules/markup/mdstripper/mdstripper_test.go b/modules/markup/mdstripper/mdstripper_test.go index 7fb49c1e01..ea34df0a3b 100644 --- a/modules/markup/mdstripper/mdstripper_test.go +++ b/modules/markup/mdstripper/mdstripper_test.go @@ -79,7 +79,7 @@ A HIDDEN ` + "`" + `GHOST` + "`" + ` IN THIS LINE. lines = append(lines, line) } } - assert.Equal(t, test.expectedText, lines) - assert.Equal(t, test.expectedLinks, links) + assert.EqualValues(t, test.expectedText, lines) + assert.EqualValues(t, test.expectedLinks, links) } } diff --git a/modules/markup/orgmode/orgmode.go b/modules/markup/orgmode/orgmode.go index b9d7b21db0..391ee6c12b 100644 --- a/modules/markup/orgmode/orgmode.go +++ b/modules/markup/orgmode/orgmode.go @@ -9,11 +9,11 @@ import ( "io" "strings" - "forgejo.org/modules/highlight" - "forgejo.org/modules/log" - "forgejo.org/modules/markup" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/highlight" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/alecthomas/chroma/v2" "github.com/alecthomas/chroma/v2/lexers" diff --git a/modules/markup/orgmode/orgmode_test.go b/modules/markup/orgmode/orgmode_test.go index cdaa9f18ce..5ced819984 100644 --- a/modules/markup/orgmode/orgmode_test.go +++ b/modules/markup/orgmode/orgmode_test.go @@ -7,13 +7,12 @@ import ( "strings" "testing" - "forgejo.org/modules/git" - "forgejo.org/modules/markup" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -33,7 +32,7 @@ func TestRender_StandardLinks(t *testing.T) { Base: setting.AppSubURL, }, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) } @@ -61,7 +60,7 @@ func TestRender_BaseLinks(t *testing.T) { BranchPath: "branch/main", }, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) } @@ -74,7 +73,7 @@ func TestRender_BaseLinks(t *testing.T) { TreePath: "deep/nested/folder", }, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) } @@ -100,7 +99,7 @@ func TestRender_Media(t *testing.T) { Base: setting.AppSubURL, }, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) } @@ -141,7 +140,7 @@ func TestRender_Source(t *testing.T) { buffer, err := RenderString(&markup.RenderContext{ Ctx: git.DefaultContext, }, input) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) } @@ -152,8 +151,8 @@ func HelloWorld() { } #+end_src `, `
    -
    // HelloWorld prints "Hello World"
    -func HelloWorld() {
    +
    // HelloWorld prints "Hello World"
    +func HelloWorld() {
     	fmt.Println("Hello World")
     }
    `) diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index 8eec764bbe..f1beee964a 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -14,9 +14,9 @@ import ( "strings" "sync" - "forgejo.org/modules/git" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/yuin/goldmark/ast" ) @@ -67,21 +67,18 @@ type Header struct { // RenderContext represents a render context type RenderContext struct { - Ctx context.Context - RelativePath string // relative path from tree root of the branch - Type string - IsWiki bool - Links Links - Metas map[string]string - DefaultLink string - GitRepo *git.Repository - // reporting the target blob that is to-be-rendered enables - // deeper inspection in the handler for external renderer - // (i.e., more targeted handling of annexed files) - Blob *git.Blob + Ctx context.Context + RelativePath string // relative path from tree root of the branch + Type string + IsWiki bool + Links Links + Metas map[string]string + DefaultLink string + GitRepo *git.Repository ShaExistCache map[string]bool cancelFn func() SidebarTocNode ast.Node + RenderMetaAs RenderMetaMode InStandalonePage bool // used by external render. the router "/org/repo/render/..." will output the rendered content in a standalone page } diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index aacc2536bf..c0b449ea5b 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -10,7 +10,7 @@ import ( "regexp" "sync" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/microcosm-cc/bluemonday" ) @@ -94,10 +94,10 @@ func createDefaultPolicy() *bluemonday.Policy { } // Allow classes for anchors - policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(ref-issue( ref-external-issue)?|mention)$`)).OnElements("a") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`ref-issue( ref-external-issue)?`)).OnElements("a") // Allow classes for task lists - policy.AllowAttrs("class").Matching(regexp.MustCompile(`^task-list-item$`)).OnElements("li") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`task-list-item`)).OnElements("li") // Allow classes for org mode list item status. policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(unchecked|checked|indeterminate)$`)).OnElements("li") @@ -106,17 +106,13 @@ func createDefaultPolicy() *bluemonday.Policy { policy.AllowAttrs("class").Matching(regexp.MustCompile(`^icon(\s+[\p{L}\p{N}_-]+)+$`)).OnElements("i") // Allow classes for emojis - policy.AllowAttrs("class").Matching(regexp.MustCompile(`^emoji$`)).OnElements("img") - - // Allow attributes for images - policy.AllowAttrs("loading").Matching(regexp.MustCompile(`^lazy$`)).OnElements("img") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`emoji`)).OnElements("img") // Allow icons, emojis, chroma syntax and keyword markup on span policy.AllowAttrs("class").Matching(regexp.MustCompile(`^((icon(\s+[\p{L}\p{N}_-]+)+)|(emoji)|(language-math display)|(language-math inline))$|^([a-z][a-z0-9]{0,2})$|^` + keywordClass + `$`)).OnElements("span") - policy.AllowAttrs("data-alias").Matching(regexp.MustCompile(`^[a-zA-Z0-9-_+]+$`)).OnElements("span") - // Allow 'color' and 'background-color' properties for the style attribute on text elements and table cells. - policy.AllowStyles("color", "background-color").OnElements("span", "p", "th", "td") + // Allow 'color' and 'background-color' properties for the style attribute on text elements. + policy.AllowStyles("color", "background-color").OnElements("span", "p") // Allow classes for file preview links... policy.AllowAttrs("class").Matching(regexp.MustCompile("^(lines-num|lines-code chroma)$")).OnElements("td") @@ -125,14 +121,14 @@ func createDefaultPolicy() *bluemonday.Policy { policy.AllowAttrs("class").Matching(regexp.MustCompile("^ui table$")).OnElements("div") policy.AllowAttrs("class").Matching(regexp.MustCompile("^header$")).OnElements("div") policy.AllowAttrs("data-line-number").Matching(regexp.MustCompile("^[0-9]+$")).OnElements("span") - policy.AllowAttrs("class").Matching(regexp.MustCompile("^text grey$")).OnElements("span") - policy.AllowAttrs("class").Matching(regexp.MustCompile("^file-preview$")).OnElements("table") + policy.AllowAttrs("class").Matching(regexp.MustCompile("^text small grey$")).OnElements("span") + policy.AllowAttrs("class").Matching(regexp.MustCompile("^file-preview*")).OnElements("table") policy.AllowAttrs("class").Matching(regexp.MustCompile("^lines-escape$")).OnElements("td") policy.AllowAttrs("class").Matching(regexp.MustCompile("^toggle-escape-button btn interact-bg$")).OnElements("button") policy.AllowAttrs("title").OnElements("button") policy.AllowAttrs("class").Matching(regexp.MustCompile("^ambiguous-code-point$")).OnElements("span") policy.AllowAttrs("data-tooltip-content").OnElements("span") - policy.AllowAttrs("class").Matching(regexp.MustCompile("^muted|(text black)$")).OnElements("a") + policy.AllowAttrs("class").Matching(regexp.MustCompile("muted|(text black)")).OnElements("a") policy.AllowAttrs("class").Matching(regexp.MustCompile("^ui warning message tw-text-left$")).OnElements("div") // Allow generally safe attributes @@ -183,7 +179,6 @@ func createDefaultPolicy() *bluemonday.Policy { // repository descriptions. func createRepoDescriptionPolicy() *bluemonday.Policy { policy := bluemonday.NewPolicy() - policy.AllowStandardURLs() // Allow italics and bold. policy.AllowElements("i", "b", "em", "strong") diff --git a/modules/markup/sanitizer_test.go b/modules/markup/sanitizer_test.go index a0faff0494..b7b8792bd7 100644 --- a/modules/markup/sanitizer_test.go +++ b/modules/markup/sanitizer_test.go @@ -47,10 +47,8 @@ func Test_Sanitizer(t *testing.T) { // Color property `Hello World`, `Hello World`, - `

    Hello World

    `, `

    Hello World

    `, - `
    TH1TH2TH3
    TD1TD2TD3
    `, `
    TH1TH2TH3
    TD1TD2TD3
    `, + `

    Hello World

    `, `

    Hello World

    `, `Hello World`, `Hello World`, - `Hello World`, `Hello World`, `Hello World`, `Hello World`, `

    Hello World

    `, `

    Hello World

    `, `Hello World`, `Hello World`, @@ -68,17 +66,6 @@ func Test_Sanitizer(t *testing.T) { `bad`, `bad`, `bad`, `bad`, `bad`, `bad`, - - // Mention - `@forgejo/UI`, `@forgejo/UI`, - - // Emoji - `THUMBS UP`, `THUMBS UP`, - `THUMBS UP`, `THUMBS UP`, - - // Images lazy loading - `image1`, `image1`, - `image1`, `image1`, } for i := 0; i < len(testCases); i += 2 { @@ -95,15 +82,12 @@ func TestDescriptionSanitizer(t *testing.T) { `THUMBS UP`, `THUMBS UP`, `Hello World`, `Hello World`, `
    `, ``, - `https://example.com`, `https://example.com`, + `https://example.com`, `https://example.com`, `Important!`, `Important!`, `
    Click me! Nothing to see here.
    `, `Click me! Nothing to see here.`, ``, ``, `I have a strong opinion about this.`, `I have a strong opinion about this.`, `Provides alternative wg(8) tool`, `Provides alternative wg(8) tool`, - `Click me.`, `Click me.`, - `Click me.`, `Click me.`, - `Click me.`, `Click me.`, } for i := 0; i < len(testCases); i += 2 { diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/0b/b53b56d70d253ce75c257d3cd6334a41ef2b6c b/modules/markup/tests/repo/repo1_filepreview/objects/0b/b53b56d70d253ce75c257d3cd6334a41ef2b6c deleted file mode 100644 index 1ab268b76c..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/0b/b53b56d70d253ce75c257d3cd6334a41ef2b6c and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/18/9739e1c2a6cdb8ee094ba1ef8a2e40cf65b2ec b/modules/markup/tests/repo/repo1_filepreview/objects/18/9739e1c2a6cdb8ee094ba1ef8a2e40cf65b2ec deleted file mode 100644 index c8b99f906b..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/18/9739e1c2a6cdb8ee094ba1ef8a2e40cf65b2ec and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2a/4032b49cff56d6d4921133e087d9dc0341a2c5 b/modules/markup/tests/repo/repo1_filepreview/objects/2a/4032b49cff56d6d4921133e087d9dc0341a2c5 deleted file mode 100644 index f799e8a988..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/2a/4032b49cff56d6d4921133e087d9dc0341a2c5 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2d/2f8eaa17b17359ee1c73222065575d50d9a157 b/modules/markup/tests/repo/repo1_filepreview/objects/2d/2f8eaa17b17359ee1c73222065575d50d9a157 deleted file mode 100644 index 7f4c451d00..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/2d/2f8eaa17b17359ee1c73222065575d50d9a157 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2f/b9577a8e940a0a84a789cdd4a45d0f172e3fdd b/modules/markup/tests/repo/repo1_filepreview/objects/2f/b9577a8e940a0a84a789cdd4a45d0f172e3fdd deleted file mode 100644 index fc97712911..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/2f/b9577a8e940a0a84a789cdd4a45d0f172e3fdd and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2f/f8eb63aad050c3f20e9cb27090ab7378267ab2 b/modules/markup/tests/repo/repo1_filepreview/objects/2f/f8eb63aad050c3f20e9cb27090ab7378267ab2 deleted file mode 100644 index e230df1343..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/2f/f8eb63aad050c3f20e9cb27090ab7378267ab2 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/35/75ed7948fe86ab56b0a76f796f7995222bec65 b/modules/markup/tests/repo/repo1_filepreview/objects/35/75ed7948fe86ab56b0a76f796f7995222bec65 deleted file mode 100644 index 1493caa3df..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/35/75ed7948fe86ab56b0a76f796f7995222bec65 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/3c/95f14e5a0ab2c5ba9ee9a47ddc261af4968043 b/modules/markup/tests/repo/repo1_filepreview/objects/3c/95f14e5a0ab2c5ba9ee9a47ddc261af4968043 deleted file mode 100644 index 3e9c0c0d8b..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/3c/95f14e5a0ab2c5ba9ee9a47ddc261af4968043 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/3e/2a4f1b9a15ffa15ea7ffdc06acd302442b3eca b/modules/markup/tests/repo/repo1_filepreview/objects/3e/2a4f1b9a15ffa15ea7ffdc06acd302442b3eca deleted file mode 100644 index 78189a52f6..0000000000 --- a/modules/markup/tests/repo/repo1_filepreview/objects/3e/2a4f1b9a15ffa15ea7ffdc06acd302442b3eca +++ /dev/null @@ -1 +0,0 @@ -xAN0EYGB;a U=D9=&r}7ҌB^yY8:A X}RXks";uF9x EdВ%~**Z3\v9Й>n8fxk=[9K%L>{7s;av4hXOHԓՆ`K \ No newline at end of file diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/3f/ed9bce8610a52048747f627b3863374642c85c b/modules/markup/tests/repo/repo1_filepreview/objects/3f/ed9bce8610a52048747f627b3863374642c85c deleted file mode 100644 index ebcf0765a5..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/3f/ed9bce8610a52048747f627b3863374642c85c and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/4c/1aaf56bcb9f39dcf65f3f250726850aed13cd6 b/modules/markup/tests/repo/repo1_filepreview/objects/4c/1aaf56bcb9f39dcf65f3f250726850aed13cd6 deleted file mode 100644 index b0857df8ab..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/4c/1aaf56bcb9f39dcf65f3f250726850aed13cd6 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/72/1f0ce13d83f93d431b849a554a62948b85f573 b/modules/markup/tests/repo/repo1_filepreview/objects/72/1f0ce13d83f93d431b849a554a62948b85f573 deleted file mode 100644 index d781d4d248..0000000000 --- a/modules/markup/tests/repo/repo1_filepreview/objects/72/1f0ce13d83f93d431b849a554a62948b85f573 +++ /dev/null @@ -1 +0,0 @@ -xK1@]$JazJR@w+s۲"@VL&J3%f-GDq2>FjBOEݹ:g\1ꦒkEM6D,Ÿ\Ǹ:\6Olmȩ;ϭ|!GE6ZzYβ mwٛi.x-o"L \ No newline at end of file diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/72/e0a44ea5761c9055995db18019e459576b3b27 b/modules/markup/tests/repo/repo1_filepreview/objects/72/e0a44ea5761c9055995db18019e459576b3b27 deleted file mode 100644 index 7b926dc0d8..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/72/e0a44ea5761c9055995db18019e459576b3b27 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/72/e1c77b65c7baa0e848557089148833fb54705e b/modules/markup/tests/repo/repo1_filepreview/objects/72/e1c77b65c7baa0e848557089148833fb54705e deleted file mode 100644 index 0bbca73af2..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/72/e1c77b65c7baa0e848557089148833fb54705e and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/8a/3b1881b5c4e7dc2be7ee1c0f37f93ffbb5ff77 b/modules/markup/tests/repo/repo1_filepreview/objects/8a/3b1881b5c4e7dc2be7ee1c0f37f93ffbb5ff77 deleted file mode 100644 index 0ea93376dc..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/8a/3b1881b5c4e7dc2be7ee1c0f37f93ffbb5ff77 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/8b/ccd5176c25898b57da2551e076f769054e0d8e b/modules/markup/tests/repo/repo1_filepreview/objects/8b/ccd5176c25898b57da2551e076f769054e0d8e deleted file mode 100644 index 394a7bb50d..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/8b/ccd5176c25898b57da2551e076f769054e0d8e and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/8c/7e5a667f1b771847fe88c01c3de34413a1b220 b/modules/markup/tests/repo/repo1_filepreview/objects/8c/7e5a667f1b771847fe88c01c3de34413a1b220 deleted file mode 100644 index c22450a204..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/8c/7e5a667f1b771847fe88c01c3de34413a1b220 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/95/31b649823095acf5d79ab9e4f8b8d86046352f b/modules/markup/tests/repo/repo1_filepreview/objects/95/31b649823095acf5d79ab9e4f8b8d86046352f deleted file mode 100644 index ab36311f6f..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/95/31b649823095acf5d79ab9e4f8b8d86046352f and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/ac/769ab4baa91060a4c2f828f53e6c3cc2f708f8 b/modules/markup/tests/repo/repo1_filepreview/objects/ac/769ab4baa91060a4c2f828f53e6c3cc2f708f8 deleted file mode 100644 index 59afaebf4a..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/ac/769ab4baa91060a4c2f828f53e6c3cc2f708f8 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/c5/3110b1957cefc56c4b2d879476ddbe905980bf b/modules/markup/tests/repo/repo1_filepreview/objects/c5/3110b1957cefc56c4b2d879476ddbe905980bf deleted file mode 100644 index 3de089bf6a..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/c5/3110b1957cefc56c4b2d879476ddbe905980bf and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/c9/8762531dd068cd818300a5f5c7dca5da79b510 b/modules/markup/tests/repo/repo1_filepreview/objects/c9/8762531dd068cd818300a5f5c7dca5da79b510 deleted file mode 100644 index af5b784773..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/c9/8762531dd068cd818300a5f5c7dca5da79b510 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/c9/913120ed2c1e27c1d7752ecdb7a504dc7cf6be b/modules/markup/tests/repo/repo1_filepreview/objects/c9/913120ed2c1e27c1d7752ecdb7a504dc7cf6be deleted file mode 100644 index 9fc2b7c312..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/c9/913120ed2c1e27c1d7752ecdb7a504dc7cf6be and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/e7/99b34ea867a0364d0df33f382562db9ff39084 b/modules/markup/tests/repo/repo1_filepreview/objects/e7/99b34ea867a0364d0df33f382562db9ff39084 deleted file mode 100644 index ef73ed1791..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/e7/99b34ea867a0364d0df33f382562db9ff39084 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/ee/b243c3395e1921c5d90e73bd739827251fc99d b/modules/markup/tests/repo/repo1_filepreview/objects/ee/b243c3395e1921c5d90e73bd739827251fc99d deleted file mode 100644 index 5515b07d4a..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/ee/b243c3395e1921c5d90e73bd739827251fc99d and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 b/modules/markup/tests/repo/repo1_filepreview/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 deleted file mode 100644 index 2e15b4fb0a..0000000000 Binary files a/modules/markup/tests/repo/repo1_filepreview/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 and /dev/null differ diff --git a/modules/markup/tests/repo/repo1_filepreview/refs/heads/master b/modules/markup/tests/repo/repo1_filepreview/refs/heads/master index 709cffca17..49c348b41c 100644 --- a/modules/markup/tests/repo/repo1_filepreview/refs/heads/master +++ b/modules/markup/tests/repo/repo1_filepreview/refs/heads/master @@ -1 +1 @@ -eeb243c3395e1921c5d90e73bd739827251fc99d +190d9492934af498c3f669d6a2431dc5459e5b20 diff --git a/modules/mcaptcha/mcaptcha.go b/modules/mcaptcha/mcaptcha.go index dbcafce29f..74142aa863 100644 --- a/modules/mcaptcha/mcaptcha.go +++ b/modules/mcaptcha/mcaptcha.go @@ -7,7 +7,7 @@ import ( "context" "fmt" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "codeberg.org/gusted/mcaptcha" ) diff --git a/modules/metrics/collector.go b/modules/metrics/collector.go index 5b6787d2f7..230260ff94 100755 --- a/modules/metrics/collector.go +++ b/modules/metrics/collector.go @@ -6,9 +6,9 @@ package metrics import ( "runtime" - activities_model "forgejo.org/models/activities" - "forgejo.org/models/db" - "forgejo.org/modules/setting" + activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/setting" "github.com/prometheus/client_golang/prometheus" ) diff --git a/modules/migration/downloader.go b/modules/migration/downloader.go index 48bdf0456d..08dbbc29a9 100644 --- a/modules/migration/downloader.go +++ b/modules/migration/downloader.go @@ -7,7 +7,7 @@ package migration import ( "context" - "forgejo.org/modules/structs" + "code.gitea.io/gitea/modules/structs" ) // Downloader downloads the site repo information diff --git a/modules/migration/file_format.go b/modules/migration/file_format.go index 8851ad6de7..e8b6891ca1 100644 --- a/modules/migration/file_format.go +++ b/modules/migration/file_format.go @@ -9,10 +9,10 @@ import ( "strings" "time" - "forgejo.org/modules/json" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" - "github.com/santhosh-tekuri/jsonschema/v6" + "github.com/santhosh-tekuri/jsonschema/v5" "gopkg.in/yaml.v3" ) @@ -43,7 +43,7 @@ func unmarshal(bs []byte, data any, isJSON bool) error { func getSchema(filename string) (*jsonschema.Schema, error) { c := jsonschema.NewCompiler() - c.UseLoader(&SchemaLoader{}) + c.LoadURL = openSchema return c.Compile(filename) } diff --git a/modules/migration/file_format_test.go b/modules/migration/file_format_test.go index f6651cd373..da997f645b 100644 --- a/modules/migration/file_format_test.go +++ b/modules/migration/file_format_test.go @@ -7,17 +7,16 @@ import ( "strings" "testing" - "github.com/santhosh-tekuri/jsonschema/v6" + "github.com/santhosh-tekuri/jsonschema/v5" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMigrationJSON_IssueOK(t *testing.T) { issues := make([]*Issue, 0, 10) err := Load("file_format_testdata/issue_a.json", &issues, true) - require.NoError(t, err) + assert.NoError(t, err) err = Load("file_format_testdata/issue_a.yml", &issues, true) - require.NoError(t, err) + assert.NoError(t, err) } func TestMigrationJSON_IssueFail(t *testing.T) { @@ -35,5 +34,5 @@ func TestMigrationJSON_IssueFail(t *testing.T) { func TestMigrationJSON_MilestoneOK(t *testing.T) { milestones := make([]*Milestone, 0, 10) err := Load("file_format_testdata/milestones.json", &milestones, true) - require.NoError(t, err) + assert.NoError(t, err) } diff --git a/modules/migration/options.go b/modules/migration/options.go index 63bbe60758..234e72c295 100644 --- a/modules/migration/options.go +++ b/modules/migration/options.go @@ -4,7 +4,7 @@ package migration -import "forgejo.org/modules/structs" +import "code.gitea.io/gitea/modules/structs" // MigrateOptions defines the way a repository gets migrated // this is for internal usage by migrations module and func who interact with it diff --git a/modules/migration/pullrequest.go b/modules/migration/pullrequest.go index 0861ab24f1..4e7500f0d6 100644 --- a/modules/migration/pullrequest.go +++ b/modules/migration/pullrequest.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - "forgejo.org/modules/git" + "code.gitea.io/gitea/modules/git" ) // PullRequest defines a standard pull request information @@ -34,11 +34,9 @@ type PullRequest struct { Assignees []string IsLocked bool `yaml:"is_locked"` Reactions []*Reaction - Flow int64 ForeignIndex int64 Context DownloaderContext `yaml:"-"` EnsuredSafe bool `yaml:"ensured_safe"` - IsDraft bool `yaml:"is_draft"` } func (p *PullRequest) GetLocalIndex() int64 { return p.Number } @@ -47,7 +45,7 @@ func (p *PullRequest) GetContext() DownloaderContext { return p.Context } // IsForkPullRequest returns true if the pull request from a forked repository but not the same repository func (p *PullRequest) IsForkPullRequest() bool { - return p.Head.RepoFullName() != p.Base.RepoFullName() + return p.Head.RepoPath() != p.Base.RepoPath() } // GetGitRefName returns pull request relative path to head @@ -64,8 +62,8 @@ type PullRequestBranch struct { OwnerName string `yaml:"owner_name"` } -// RepoFullName returns pull request repo full name -func (p PullRequestBranch) RepoFullName() string { +// RepoPath returns pull request repo path +func (p PullRequestBranch) RepoPath() string { return fmt.Sprintf("%s/%s", p.OwnerName, p.RepoName) } diff --git a/modules/migration/repo.go b/modules/migration/repo.go index a85d38084d..22c2cf6fb3 100644 --- a/modules/migration/repo.go +++ b/modules/migration/repo.go @@ -14,5 +14,4 @@ type Repository struct { CloneURL string `yaml:"clone_url"` // SECURITY: This must be checked to ensure that is safe to be used OriginalURL string `yaml:"original_url"` DefaultBranch string - Website string } diff --git a/modules/migration/schemas_dynamic.go b/modules/migration/schemas_dynamic.go index 37416913e3..dca109d6af 100644 --- a/modules/migration/schemas_dynamic.go +++ b/modules/migration/schemas_dynamic.go @@ -6,17 +6,14 @@ package migration import ( + "io" "net/url" "os" "path" "path/filepath" - - "github.com/santhosh-tekuri/jsonschema/v6" ) -type SchemaLoader struct{} - -func (*SchemaLoader) Load(s string) (any, error) { +func openSchema(s string) (io.ReadCloser, error) { u, err := url.Parse(s) if err != nil { return nil, err @@ -37,11 +34,5 @@ func (*SchemaLoader) Load(s string) (any, error) { filename = filepath.Join("modules/migration/schemas", basename) } } - - f, err := os.Open(filename) - if err != nil { - return nil, err - } - defer f.Close() - return jsonschema.UnmarshalJSON(f) + return os.Open(filename) } diff --git a/modules/migration/schemas_static.go b/modules/migration/schemas_static.go index 832dfd86cf..8a0c340a65 100644 --- a/modules/migration/schemas_static.go +++ b/modules/migration/schemas_static.go @@ -6,18 +6,10 @@ package migration import ( + "io" "path" - - "github.com/santhosh-tekuri/jsonschema/v6" ) -type SchemaLoader struct{} - -func (*SchemaLoader) Load(filename string) (any, error) { - f, err := Assets.Open(path.Base(filename)) - if err != nil { - return nil, err - } - defer f.Close() - return jsonschema.UnmarshalJSON(f) +func openSchema(filename string) (io.ReadCloser, error) { + return Assets.Open(path.Base(filename)) } diff --git a/modules/nosql/manager.go b/modules/nosql/manager.go index 7eea069e09..375c2b5d00 100644 --- a/modules/nosql/manager.go +++ b/modules/nosql/manager.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "forgejo.org/modules/process" + "code.gitea.io/gitea/modules/process" "github.com/redis/go-redis/v9" "github.com/syndtr/goleveldb/leveldb" @@ -27,46 +27,8 @@ type Manager struct { LevelDBConnections map[string]*levelDBHolder } -// RedisClient is a subset of redis.UniversalClient, it exposes less methods -// to avoid generating machine code for unused methods. New method definitions -// should be copied from the definitions in the Redis library github.com/redis/go-redis. -type RedisClient interface { - // redis.GenericCmdable - Del(ctx context.Context, keys ...string) *redis.IntCmd - Exists(ctx context.Context, keys ...string) *redis.IntCmd - - // redis.ListCmdable - RPush(ctx context.Context, key string, values ...any) *redis.IntCmd - LPop(ctx context.Context, key string) *redis.StringCmd - LLen(ctx context.Context, key string) *redis.IntCmd - - // redis.StringCmdable - Decr(ctx context.Context, key string) *redis.IntCmd - Incr(ctx context.Context, key string) *redis.IntCmd - Set(ctx context.Context, key string, value any, expiration time.Duration) *redis.StatusCmd - Get(ctx context.Context, key string) *redis.StringCmd - - // redis.HashCmdable - HSet(ctx context.Context, key string, values ...any) *redis.IntCmd - HDel(ctx context.Context, key string, fields ...string) *redis.IntCmd - HKeys(ctx context.Context, key string) *redis.StringSliceCmd - - // redis.SetCmdable - SAdd(ctx context.Context, key string, members ...any) *redis.IntCmd - SRem(ctx context.Context, key string, members ...any) *redis.IntCmd - SIsMember(ctx context.Context, key string, member any) *redis.BoolCmd - - // redis.Cmdable - DBSize(ctx context.Context) *redis.IntCmd - FlushDB(ctx context.Context) *redis.StatusCmd - Ping(ctx context.Context) *redis.StatusCmd - - // redis.UniversalClient - Close() error -} - type redisClientHolder struct { - RedisClient + redis.UniversalClient name []string count int64 } diff --git a/modules/nosql/manager_leveldb.go b/modules/nosql/manager_leveldb.go index 087aac3e9a..4d2c90debc 100644 --- a/modules/nosql/manager_leveldb.go +++ b/modules/nosql/manager_leveldb.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" diff --git a/modules/nosql/manager_redis.go b/modules/nosql/manager_redis.go index bdaade1b47..3c5502f979 100644 --- a/modules/nosql/manager_redis.go +++ b/modules/nosql/manager_redis.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" "github.com/redis/go-redis/v9" ) @@ -39,11 +39,11 @@ func (m *Manager) CloseRedisClient(connection string) error { for _, name := range client.name { delete(m.RedisConnections, name) } - return client.RedisClient.Close() + return client.UniversalClient.Close() } // GetRedisClient gets a redis client for a particular connection -func (m *Manager) GetRedisClient(connection string) (client RedisClient) { +func (m *Manager) GetRedisClient(connection string) (client redis.UniversalClient) { // Because we want associate any goroutines created by this call to the main nosqldb context we need to // wrap this in a goroutine labelled with the nosqldb context done := make(chan struct{}) @@ -67,7 +67,7 @@ func (m *Manager) GetRedisClient(connection string) (client RedisClient) { return client } -func (m *Manager) getRedisClient(connection string) RedisClient { +func (m *Manager) getRedisClient(connection string) redis.UniversalClient { m.mutex.Lock() defer m.mutex.Unlock() client, ok := m.RedisConnections[connection] @@ -102,24 +102,24 @@ func (m *Manager) getRedisClient(connection string) RedisClient { opts.TLSConfig = tlsConfig fallthrough case "redis+sentinel": - client.RedisClient = redis.NewFailoverClient(opts.Failover()) + client.UniversalClient = redis.NewFailoverClient(opts.Failover()) case "redis+clusters": fallthrough case "rediss+cluster": opts.TLSConfig = tlsConfig fallthrough case "redis+cluster": - client.RedisClient = redis.NewClusterClient(opts.Cluster()) + client.UniversalClient = redis.NewClusterClient(opts.Cluster()) case "redis+socket": simpleOpts := opts.Simple() simpleOpts.Network = "unix" simpleOpts.Addr = path.Join(uri.Host, uri.Path) - client.RedisClient = redis.NewClient(simpleOpts) + client.UniversalClient = redis.NewClient(simpleOpts) case "rediss": opts.TLSConfig = tlsConfig fallthrough case "redis": - client.RedisClient = redis.NewClient(opts.Simple()) + client.UniversalClient = redis.NewClient(opts.Simple()) default: return nil } diff --git a/modules/optional/option.go b/modules/optional/option.go index ccbad259c2..af9e5ac852 100644 --- a/modules/optional/option.go +++ b/modules/optional/option.go @@ -3,8 +3,6 @@ package optional -import "strconv" - type Option[T any] []T func None[T any]() Option[T] { @@ -45,12 +43,3 @@ func (o Option[T]) ValueOrDefault(v T) T { } return v } - -// ParseBool get the corresponding optional.Option[bool] of a string using strconv.ParseBool -func ParseBool(s string) Option[bool] { - v, e := strconv.ParseBool(s) - if e != nil { - return None[bool]() - } - return Some(v) -} diff --git a/modules/optional/option_test.go b/modules/optional/option_test.go index a674caf633..203e9221e3 100644 --- a/modules/optional/option_test.go +++ b/modules/optional/option_test.go @@ -6,7 +6,7 @@ package optional_test import ( "testing" - "forgejo.org/modules/optional" + "code.gitea.io/gitea/modules/optional" "github.com/stretchr/testify/assert" ) @@ -57,16 +57,3 @@ func TestOption(t *testing.T) { assert.True(t, opt3.Has()) assert.Equal(t, int(1), opt3.Value()) } - -func Test_ParseBool(t *testing.T) { - assert.Equal(t, optional.None[bool](), optional.ParseBool("")) - assert.Equal(t, optional.None[bool](), optional.ParseBool("x")) - - assert.Equal(t, optional.Some(false), optional.ParseBool("0")) - assert.Equal(t, optional.Some(false), optional.ParseBool("f")) - assert.Equal(t, optional.Some(false), optional.ParseBool("False")) - - assert.Equal(t, optional.Some(true), optional.ParseBool("1")) - assert.Equal(t, optional.Some(true), optional.ParseBool("t")) - assert.Equal(t, optional.Some(true), optional.ParseBool("True")) -} diff --git a/modules/optional/serialization.go b/modules/optional/serialization.go index 86c1c97341..b120a0edf6 100644 --- a/modules/optional/serialization.go +++ b/modules/optional/serialization.go @@ -4,7 +4,7 @@ package optional import ( - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" "gopkg.in/yaml.v3" ) diff --git a/modules/optional/serialization_test.go b/modules/optional/serialization_test.go index 14bf3b7814..09a4bddea0 100644 --- a/modules/optional/serialization_test.go +++ b/modules/optional/serialization_test.go @@ -7,11 +7,10 @@ import ( std_json "encoding/json" //nolint:depguard "testing" - "forgejo.org/modules/json" - "forgejo.org/modules/optional" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/optional" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) @@ -51,12 +50,12 @@ func TestOptionalToJson(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { b, err := json.Marshal(tc.obj) - require.NoError(t, err) - assert.Equal(t, tc.want, string(b), "gitea json module returned unexpected") + assert.NoError(t, err) + assert.EqualValues(t, tc.want, string(b), "gitea json module returned unexpected") b, err = std_json.Marshal(tc.obj) - require.NoError(t, err) - assert.Equal(t, tc.want, string(b), "std json module returned unexpected") + assert.NoError(t, err) + assert.EqualValues(t, tc.want, string(b), "std json module returned unexpected") }) } } @@ -89,13 +88,13 @@ func TestOptionalFromJson(t *testing.T) { t.Run(tc.name, func(t *testing.T) { var obj1 testSerializationStruct err := json.Unmarshal([]byte(tc.data), &obj1) - require.NoError(t, err) - assert.Equal(t, tc.want, obj1, "gitea json module returned unexpected") + assert.NoError(t, err) + assert.EqualValues(t, tc.want, obj1, "gitea json module returned unexpected") var obj2 testSerializationStruct err = std_json.Unmarshal([]byte(tc.data), &obj2) - require.NoError(t, err) - assert.Equal(t, tc.want, obj2, "std json module returned unexpected") + assert.NoError(t, err) + assert.EqualValues(t, tc.want, obj2, "std json module returned unexpected") }) } } @@ -135,8 +134,8 @@ optional_two_string: null for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { b, err := yaml.Marshal(tc.obj) - require.NoError(t, err) - assert.Equal(t, tc.want, string(b), "yaml module returned unexpected") + assert.NoError(t, err) + assert.EqualValues(t, tc.want, string(b), "yaml module returned unexpected") }) } } @@ -184,8 +183,8 @@ optional_twostring: null t.Run(tc.name, func(t *testing.T) { var obj testSerializationStruct err := yaml.Unmarshal([]byte(tc.data), &obj) - require.NoError(t, err) - assert.Equal(t, tc.want, obj, "yaml module returned unexpected") + assert.NoError(t, err) + assert.EqualValues(t, tc.want, obj, "yaml module returned unexpected") }) } } diff --git a/modules/options/base.go b/modules/options/base.go index 3ae8c56b79..6c6e3839f4 100644 --- a/modules/options/base.go +++ b/modules/options/base.go @@ -4,8 +4,8 @@ package options import ( - "forgejo.org/modules/assetfs" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/setting" ) func CustomAssets() *assetfs.Layer { diff --git a/modules/options/dynamic.go b/modules/options/dynamic.go index 8eed8516ab..085492d11c 100644 --- a/modules/options/dynamic.go +++ b/modules/options/dynamic.go @@ -6,8 +6,8 @@ package options import ( - "forgejo.org/modules/assetfs" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/setting" ) func BuiltinAssets() *assetfs.Layer { diff --git a/modules/options/static.go b/modules/options/static.go index 02091a2b1c..72b28e990e 100644 --- a/modules/options/static.go +++ b/modules/options/static.go @@ -6,7 +6,7 @@ package options import ( - "forgejo.org/modules/assetfs" + "code.gitea.io/gitea/modules/assetfs" ) func BuiltinAssets() *assetfs.Layer { diff --git a/modules/packages/alpine/metadata.go b/modules/packages/alpine/metadata.go index 8562612206..582c42610d 100644 --- a/modules/packages/alpine/metadata.go +++ b/modules/packages/alpine/metadata.go @@ -13,8 +13,8 @@ import ( "strconv" "strings" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" ) var ( diff --git a/modules/packages/alpine/metadata_test.go b/modules/packages/alpine/metadata_test.go index 8167b4902a..2a3c48ffb9 100644 --- a/modules/packages/alpine/metadata_test.go +++ b/modules/packages/alpine/metadata_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -78,7 +77,7 @@ func TestParsePackage(t *testing.T) { pp, err := ParsePackage(data) assert.Nil(t, pp) - require.ErrorIs(t, err, ErrMissingPKGINFOFile) + assert.ErrorIs(t, err, ErrMissingPKGINFOFile) }) t.Run("InvalidPKGINFOFile", func(t *testing.T) { @@ -86,14 +85,14 @@ func TestParsePackage(t *testing.T) { pp, err := ParsePackage(data) assert.Nil(t, pp) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) }) t.Run("Valid", func(t *testing.T) { data := createPackage(".PKGINFO", createPKGINFOContent(packageName, packageVersion)) p, err := ParsePackage(data) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, p) assert.Equal(t, "Q1SRYURM5+uQDqfHSwTnNIOIuuDVQ=", p.FileMetadata.Checksum) @@ -106,7 +105,7 @@ func TestParsePackageInfo(t *testing.T) { p, err := ParsePackageInfo(bytes.NewReader(data)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) }) t.Run("InvalidVersion", func(t *testing.T) { @@ -114,14 +113,14 @@ func TestParsePackageInfo(t *testing.T) { p, err := ParsePackageInfo(bytes.NewReader(data)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) }) t.Run("Valid", func(t *testing.T) { data := createPKGINFOContent(packageName, packageVersion) p, err := ParsePackageInfo(bytes.NewReader(data)) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, p) assert.Equal(t, packageName, p.Name) diff --git a/modules/packages/arch/metadata.go b/modules/packages/arch/metadata.go deleted file mode 100644 index f967bd25a0..0000000000 --- a/modules/packages/arch/metadata.go +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package arch - -import ( - "archive/tar" - "bufio" - "bytes" - "encoding/hex" - "errors" - "fmt" - "io" - "regexp" - "strconv" - "strings" - - "forgejo.org/modules/packages" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" - - "github.com/mholt/archiver/v3" -) - -// Arch Linux Packages -// https://man.archlinux.org/man/PKGBUILD.5 - -const ( - PropertyDescription = "arch.description" - PropertyFiles = "arch.files" - - PropertyArch = "arch.architecture" - PropertyDistribution = "arch.distribution" - - SettingKeyPrivate = "arch.key.private" - SettingKeyPublic = "arch.key.public" - - RepositoryPackage = "_arch" - RepositoryVersion = "_repository" -) - -var ( - reName = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+$`) - reVer = regexp.MustCompile(`^[a-zA-Z0-9:_.+]+-+[0-9]+$`) - reOptDep = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+([<>]?=?([0-9]+:)?[a-zA-Z0-9@._+-]+)?(:.*)?$`) - rePkgVer = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+([<>]?=?([0-9]+:)?[a-zA-Z0-9@._+-]+)?$`) - - magicZSTD = []byte{0x28, 0xB5, 0x2F, 0xFD} - magicXZ = []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A} - magicGZ = []byte{0x1F, 0x8B} -) - -type Package struct { - Name string `json:"name"` - Version string `json:"version"` // Includes version, release and epoch - CompressType string `json:"compress_type"` - VersionMetadata VersionMetadata - FileMetadata FileMetadata -} - -// Arch package metadata related to specific version. -// Version metadata the same across different architectures and distributions. -type VersionMetadata struct { - Base string `json:"base"` - Description string `json:"description"` - ProjectURL string `json:"project_url"` - Groups []string `json:"groups,omitempty"` - Provides []string `json:"provides,omitempty"` - License []string `json:"license,omitempty"` - Depends []string `json:"depends,omitempty"` - OptDepends []string `json:"opt_depends,omitempty"` - MakeDepends []string `json:"make_depends,omitempty"` - CheckDepends []string `json:"check_depends,omitempty"` - Conflicts []string `json:"conflicts,omitempty"` - Replaces []string `json:"replaces,omitempty"` - Backup []string `json:"backup,omitempty"` - XData []string `json:"xdata,omitempty"` -} - -// FileMetadata Metadata related to specific package file. -// This metadata might vary for different architecture and distribution. -type FileMetadata struct { - CompressedSize int64 `json:"compressed_size"` - InstalledSize int64 `json:"installed_size"` - MD5 string `json:"md5"` - SHA256 string `json:"sha256"` - BuildDate int64 `json:"build_date"` - Packager string `json:"packager"` - Arch string `json:"arch"` - PgpSigned string `json:"pgp"` - - Files []string `json:"files,omitempty"` -} - -// ParsePackage Function that receives arch package archive data and returns it's metadata. -func ParsePackage(r *packages.HashedBuffer) (*Package, error) { - md5, _, sha256, _, _ := r.Sums() - _, err := r.Seek(0, io.SeekStart) - if err != nil { - return nil, err - } - header := make([]byte, 5) - _, err = r.Read(header) - if err != nil { - return nil, err - } - _, err = r.Seek(0, io.SeekStart) - if err != nil { - return nil, err - } - - var tarball archiver.Reader - var tarballType string - if bytes.Equal(header[:len(magicZSTD)], magicZSTD) { - tarballType = "zst" - tarball = archiver.NewTarZstd() - } else if bytes.Equal(header[:len(magicXZ)], magicXZ) { - tarballType = "xz" - tarball = archiver.NewTarXz() - } else if bytes.Equal(header[:len(magicGZ)], magicGZ) { - tarballType = "gz" - tarball = archiver.NewTarGz() - } else { - return nil, errors.New("not supported compression") - } - err = tarball.Open(r, 0) - if err != nil { - return nil, err - } - defer tarball.Close() - - var pkg *Package - var mTree bool - - files := make([]string, 0) - - for { - f, err := tarball.Read() - if err == io.EOF { - break - } - if err != nil { - return nil, err - } - // ref:https://gitlab.archlinux.org/pacman/pacman/-/blob/91546004903eea5d5267d59898a6029ba1d64031/lib/libalpm/add.c#L529-L533 - if !strings.HasPrefix(f.Name(), ".") { - files = append(files, (f.Header.(*tar.Header)).Name) - } - - switch f.Name() { - case ".PKGINFO": - pkg, err = ParsePackageInfo(tarballType, f) - if err != nil { - _ = f.Close() - return nil, err - } - case ".MTREE": - mTree = true - } - _ = f.Close() - } - - if pkg == nil { - return nil, util.NewInvalidArgumentErrorf(".PKGINFO file not found") - } - - if !mTree { - return nil, util.NewInvalidArgumentErrorf(".MTREE file not found") - } - pkg.FileMetadata.Files = files - pkg.FileMetadata.CompressedSize = r.Size() - pkg.FileMetadata.MD5 = hex.EncodeToString(md5) - pkg.FileMetadata.SHA256 = hex.EncodeToString(sha256) - - return pkg, nil -} - -// ParsePackageInfo Function that accepts reader for .PKGINFO file from package archive, -// validates all field according to PKGBUILD spec and returns package. -func ParsePackageInfo(compressType string, r io.Reader) (*Package, error) { - p := &Package{ - CompressType: compressType, - } - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - line := scanner.Text() - - if strings.HasPrefix(line, "#") { - continue - } - - key, value, find := strings.Cut(line, "=") - if !find { - continue - } - key = strings.TrimSpace(key) - value = strings.TrimSpace(value) - switch key { - case "pkgname": - p.Name = value - case "pkgbase": - p.VersionMetadata.Base = value - case "pkgver": - p.Version = value - case "pkgdesc": - p.VersionMetadata.Description = value - case "url": - p.VersionMetadata.ProjectURL = value - case "packager": - p.FileMetadata.Packager = value - case "arch": - p.FileMetadata.Arch = value - case "provides": - p.VersionMetadata.Provides = append(p.VersionMetadata.Provides, value) - case "license": - p.VersionMetadata.License = append(p.VersionMetadata.License, value) - case "depend": - p.VersionMetadata.Depends = append(p.VersionMetadata.Depends, value) - case "optdepend": - p.VersionMetadata.OptDepends = append(p.VersionMetadata.OptDepends, value) - case "makedepend": - p.VersionMetadata.MakeDepends = append(p.VersionMetadata.MakeDepends, value) - case "checkdepend": - p.VersionMetadata.CheckDepends = append(p.VersionMetadata.CheckDepends, value) - case "backup": - p.VersionMetadata.Backup = append(p.VersionMetadata.Backup, value) - case "group": - p.VersionMetadata.Groups = append(p.VersionMetadata.Groups, value) - case "conflict": - p.VersionMetadata.Conflicts = append(p.VersionMetadata.Conflicts, value) - case "replaces": - p.VersionMetadata.Replaces = append(p.VersionMetadata.Replaces, value) - case "xdata": - p.VersionMetadata.XData = append(p.VersionMetadata.XData, value) - case "builddate": - bd, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return nil, err - } - p.FileMetadata.BuildDate = bd - case "size": - is, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return nil, err - } - p.FileMetadata.InstalledSize = is - default: - return nil, util.NewInvalidArgumentErrorf("property is not supported %s", key) - } - } - - return p, errors.Join(scanner.Err(), ValidatePackageSpec(p)) -} - -// ValidatePackageSpec Arch package validation according to PKGBUILD specification. -func ValidatePackageSpec(p *Package) error { - if !reName.MatchString(p.Name) { - return util.NewInvalidArgumentErrorf("invalid package name") - } - if !reName.MatchString(p.VersionMetadata.Base) { - return util.NewInvalidArgumentErrorf("invalid package base") - } - if !reVer.MatchString(p.Version) { - return util.NewInvalidArgumentErrorf("invalid package version") - } - if p.FileMetadata.Arch == "" { - return util.NewInvalidArgumentErrorf("architecture should be specified") - } - if p.VersionMetadata.ProjectURL != "" { - if !validation.IsValidURL(p.VersionMetadata.ProjectURL) { - return util.NewInvalidArgumentErrorf("invalid project URL") - } - } - for _, checkDepend := range p.VersionMetadata.CheckDepends { - if !rePkgVer.MatchString(checkDepend) { - return util.NewInvalidArgumentErrorf("invalid check dependency: %s", checkDepend) - } - } - for _, depend := range p.VersionMetadata.Depends { - if !rePkgVer.MatchString(depend) { - return util.NewInvalidArgumentErrorf("invalid dependency: %s", depend) - } - } - for _, makeDepend := range p.VersionMetadata.MakeDepends { - if !rePkgVer.MatchString(makeDepend) { - return util.NewInvalidArgumentErrorf("invalid make dependency: %s", makeDepend) - } - } - for _, provide := range p.VersionMetadata.Provides { - if !rePkgVer.MatchString(provide) { - return util.NewInvalidArgumentErrorf("invalid provides: %s", provide) - } - } - for _, conflict := range p.VersionMetadata.Conflicts { - if !rePkgVer.MatchString(conflict) { - return util.NewInvalidArgumentErrorf("invalid conflicts: %s", conflict) - } - } - for _, replace := range p.VersionMetadata.Replaces { - if !rePkgVer.MatchString(replace) { - return util.NewInvalidArgumentErrorf("invalid replaces: %s", replace) - } - } - for _, optDepend := range p.VersionMetadata.OptDepends { - if !reOptDep.MatchString(optDepend) { - return util.NewInvalidArgumentErrorf("invalid optional dependency: %s", optDepend) - } - } - for _, b := range p.VersionMetadata.Backup { - if strings.HasPrefix(b, "/") { - return util.NewInvalidArgumentErrorf("backup file contains leading forward slash") - } - } - return nil -} - -// Desc Create pacman package description file. -func (p *Package) Desc() string { - entries := []string{ - "FILENAME", fmt.Sprintf("%s-%s-%s.pkg.tar.%s", p.Name, p.Version, p.FileMetadata.Arch, p.CompressType), - "NAME", p.Name, - "BASE", p.VersionMetadata.Base, - "VERSION", p.Version, - "DESC", p.VersionMetadata.Description, - "GROUPS", strings.Join(p.VersionMetadata.Groups, "\n"), - "CSIZE", fmt.Sprintf("%d", p.FileMetadata.CompressedSize), - "ISIZE", fmt.Sprintf("%d", p.FileMetadata.InstalledSize), - "MD5SUM", p.FileMetadata.MD5, - "SHA256SUM", p.FileMetadata.SHA256, - "PGPSIG", p.FileMetadata.PgpSigned, - "URL", p.VersionMetadata.ProjectURL, - "LICENSE", strings.Join(p.VersionMetadata.License, "\n"), - "ARCH", p.FileMetadata.Arch, - "BUILDDATE", fmt.Sprintf("%d", p.FileMetadata.BuildDate), - "PACKAGER", p.FileMetadata.Packager, - "REPLACES", strings.Join(p.VersionMetadata.Replaces, "\n"), - "CONFLICTS", strings.Join(p.VersionMetadata.Conflicts, "\n"), - "PROVIDES", strings.Join(p.VersionMetadata.Provides, "\n"), - "DEPENDS", strings.Join(p.VersionMetadata.Depends, "\n"), - "OPTDEPENDS", strings.Join(p.VersionMetadata.OptDepends, "\n"), - "MAKEDEPENDS", strings.Join(p.VersionMetadata.MakeDepends, "\n"), - "CHECKDEPENDS", strings.Join(p.VersionMetadata.CheckDepends, "\n"), - } - - var buf bytes.Buffer - for i := 0; i < len(entries); i += 2 { - if entries[i+1] != "" { - _, _ = fmt.Fprintf(&buf, "%%%s%%\n%s\n\n", entries[i], entries[i+1]) - } - } - return buf.String() -} - -func (p *Package) Files() string { - var buf bytes.Buffer - buf.WriteString("%FILES%\n") - for _, item := range p.FileMetadata.Files { - _, _ = fmt.Fprintf(&buf, "%s\n", item) - } - return buf.String() -} diff --git a/modules/packages/arch/metadata_test.go b/modules/packages/arch/metadata_test.go deleted file mode 100644 index 16c1c1637d..0000000000 --- a/modules/packages/arch/metadata_test.go +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package arch - -import ( - "bytes" - "errors" - "os" - "strings" - "testing" - "testing/fstest" - "time" - - "forgejo.org/modules/packages" - - "github.com/mholt/archiver/v3" - "github.com/stretchr/testify/require" -) - -func TestParsePackage(t *testing.T) { - // Minimal PKGINFO contents and test FS - const PKGINFO = `pkgname = a -pkgbase = b -pkgver = 1-2 -arch = x86_64 -` - fs := fstest.MapFS{ - "pkginfo": &fstest.MapFile{ - Data: []byte(PKGINFO), - Mode: os.ModePerm, - ModTime: time.Now(), - }, - "mtree": &fstest.MapFile{ - Data: []byte("data"), - Mode: os.ModePerm, - ModTime: time.Now(), - }, - } - - // Test .PKGINFO file - pinf, err := fs.Stat("pkginfo") - require.NoError(t, err) - - pfile, err := fs.Open("pkginfo") - require.NoError(t, err) - - parcname, err := archiver.NameInArchive(pinf, ".PKGINFO", ".PKGINFO") - require.NoError(t, err) - - // Test .MTREE file - minf, err := fs.Stat("mtree") - require.NoError(t, err) - - mfile, err := fs.Open("mtree") - require.NoError(t, err) - - marcname, err := archiver.NameInArchive(minf, ".MTREE", ".MTREE") - require.NoError(t, err) - - t.Run("normal archive", func(t *testing.T) { - var buf bytes.Buffer - - archive := archiver.NewTarZstd() - archive.Create(&buf) - - err = archive.Write(archiver.File{ - FileInfo: archiver.FileInfo{ - FileInfo: pinf, - CustomName: parcname, - }, - ReadCloser: pfile, - }) - require.NoError(t, errors.Join(pfile.Close(), err)) - - err = archive.Write(archiver.File{ - FileInfo: archiver.FileInfo{ - FileInfo: minf, - CustomName: marcname, - }, - ReadCloser: mfile, - }) - require.NoError(t, errors.Join(mfile.Close(), archive.Close(), err)) - - reader, err := packages.CreateHashedBufferFromReader(&buf) - if err != nil { - t.Fatal(err) - } - defer reader.Close() - _, err = ParsePackage(reader) - - require.NoError(t, err) - }) - - t.Run("missing .PKGINFO", func(t *testing.T) { - var buf bytes.Buffer - - archive := archiver.NewTarZstd() - archive.Create(&buf) - require.NoError(t, archive.Close()) - - reader, err := packages.CreateHashedBufferFromReader(&buf) - require.NoError(t, err) - - defer reader.Close() - _, err = ParsePackage(reader) - - require.Error(t, err) - require.Contains(t, err.Error(), ".PKGINFO file not found") - }) - - t.Run("missing .MTREE", func(t *testing.T) { - var buf bytes.Buffer - - pfile, err := fs.Open("pkginfo") - require.NoError(t, err) - - archive := archiver.NewTarZstd() - archive.Create(&buf) - - err = archive.Write(archiver.File{ - FileInfo: archiver.FileInfo{ - FileInfo: pinf, - CustomName: parcname, - }, - ReadCloser: pfile, - }) - require.NoError(t, errors.Join(pfile.Close(), archive.Close(), err)) - reader, err := packages.CreateHashedBufferFromReader(&buf) - require.NoError(t, err) - - defer reader.Close() - _, err = ParsePackage(reader) - - require.Error(t, err) - require.Contains(t, err.Error(), ".MTREE file not found") - }) -} - -func TestParsePackageInfo(t *testing.T) { - const PKGINFO = `# Generated by makepkg 6.0.2 -# using fakeroot version 1.31 -pkgname = a -pkgbase = b -pkgver = 1-2 -pkgdesc = comment -url = https://example.com/ -group = group -builddate = 3 -packager = Name Surname -size = 5 -arch = x86_64 -license = BSD -provides = pvd -depend = smth -optdepend = hex -checkdepend = ola -makedepend = cmake -backup = usr/bin/paket1 -` - p, err := ParsePackageInfo("zst", strings.NewReader(PKGINFO)) - require.NoError(t, err) - require.Equal(t, Package{ - CompressType: "zst", - Name: "a", - Version: "1-2", - VersionMetadata: VersionMetadata{ - Base: "b", - Description: "comment", - ProjectURL: "https://example.com/", - Groups: []string{"group"}, - Provides: []string{"pvd"}, - License: []string{"BSD"}, - Depends: []string{"smth"}, - OptDepends: []string{"hex"}, - MakeDepends: []string{"cmake"}, - CheckDepends: []string{"ola"}, - Backup: []string{"usr/bin/paket1"}, - }, - FileMetadata: FileMetadata{ - InstalledSize: 5, - BuildDate: 3, - Packager: "Name Surname ", - Arch: "x86_64", - }, - }, *p) -} - -func TestValidatePackageSpec(t *testing.T) { - newpkg := func() Package { - return Package{ - Name: "abc", - Version: "1-1", - VersionMetadata: VersionMetadata{ - Base: "ghx", - Description: "whoami", - ProjectURL: "https://example.com/", - Groups: []string{"gnome"}, - Provides: []string{"abc", "def"}, - License: []string{"GPL"}, - Depends: []string{"go", "gpg=1", "curl>=3", "git<=7"}, - OptDepends: []string{"git", "libgcc=1.0", "gzip>1.0", "gz>=1.0", "lz<1.0", "gzip<=1.0", "zstd>1.0:foo bar"}, - MakeDepends: []string{"chrom"}, - CheckDepends: []string{"bariy"}, - Backup: []string{"etc/pacman.d/filo"}, - }, - FileMetadata: FileMetadata{ - CompressedSize: 1, - InstalledSize: 2, - SHA256: "def", - BuildDate: 3, - Packager: "smon", - Arch: "x86_64", - }, - } - } - - t.Run("valid package", func(t *testing.T) { - p := newpkg() - - err := ValidatePackageSpec(&p) - - require.NoError(t, err) - }) - - t.Run("invalid package name", func(t *testing.T) { - p := newpkg() - p.Name = "!$%@^!*&()" - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid package name") - }) - - t.Run("invalid package base", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.Base = "!$%@^!*&()" - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid package base") - }) - - t.Run("invalid package version", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.Base = "una-luna?" - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid package base") - }) - - t.Run("invalid package version", func(t *testing.T) { - p := newpkg() - p.Version = "una-luna" - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid package version") - }) - - t.Run("missing architecture", func(t *testing.T) { - p := newpkg() - p.FileMetadata.Arch = "" - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "architecture should be specified") - }) - - t.Run("invalid URL", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.ProjectURL = "http%%$#" - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid project URL") - }) - - t.Run("invalid check dependency", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.CheckDepends = []string{"Err^_^"} - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid check dependency") - }) - - t.Run("invalid dependency", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.Depends = []string{"^^abc"} - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid dependency") - }) - - t.Run("invalid make dependency", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.MakeDepends = []string{"^m^"} - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid make dependency") - }) - - t.Run("invalid provides", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.Provides = []string{"^m^"} - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid provides") - }) - - t.Run("invalid optional dependency", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.OptDepends = []string{"^m^:MM"} - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "invalid optional dependency") - }) - - t.Run("invalid optional dependency", func(t *testing.T) { - p := newpkg() - p.VersionMetadata.Backup = []string{"/ola/cola"} - - err := ValidatePackageSpec(&p) - - require.Error(t, err) - require.Contains(t, err.Error(), "backup file contains leading forward slash") - }) -} - -func TestDescAndFileString(t *testing.T) { - const pkgDesc = `%FILENAME% -zstd-1.5.5-1-x86_64.pkg.tar.zst - -%NAME% -zstd - -%BASE% -zstd - -%VERSION% -1.5.5-1 - -%DESC% -Zstandard - Fast real-time compression algorithm - -%GROUPS% -dummy1 -dummy2 - -%CSIZE% -401 - -%ISIZE% -1500453 - -%MD5SUM% -5016660ef3d9aa148a7b72a08d3df1b2 - -%SHA256SUM% -9fa4ede47e35f5971e4f26ecadcbfb66ab79f1d638317ac80334a3362dedbabd - -%URL% -https://facebook.github.io/zstd/ - -%LICENSE% -BSD -GPL2 - -%ARCH% -x86_64 - -%BUILDDATE% -1681646714 - -%PACKAGER% -Jelle van der Waa - -%PROVIDES% -libzstd.so=1-64 - -%DEPENDS% -glibc -gcc-libs -zlib -xz -lz4 - -%OPTDEPENDS% -dummy3 -dummy4 - -%MAKEDEPENDS% -cmake -gtest -ninja - -%CHECKDEPENDS% -dummy5 -dummy6 - -` - - const pkgFiles = `%FILES% -usr/ -usr/bin/ -usr/bin/zstd -` - - md := &Package{ - CompressType: "zst", - Name: "zstd", - Version: "1.5.5-1", - VersionMetadata: VersionMetadata{ - Base: "zstd", - Description: "Zstandard - Fast real-time compression algorithm", - ProjectURL: "https://facebook.github.io/zstd/", - Groups: []string{"dummy1", "dummy2"}, - Provides: []string{"libzstd.so=1-64"}, - License: []string{"BSD", "GPL2"}, - Depends: []string{"glibc", "gcc-libs", "zlib", "xz", "lz4"}, - OptDepends: []string{"dummy3", "dummy4"}, - MakeDepends: []string{"cmake", "gtest", "ninja"}, - CheckDepends: []string{"dummy5", "dummy6"}, - }, - FileMetadata: FileMetadata{ - CompressedSize: 401, - InstalledSize: 1500453, - MD5: "5016660ef3d9aa148a7b72a08d3df1b2", - SHA256: "9fa4ede47e35f5971e4f26ecadcbfb66ab79f1d638317ac80334a3362dedbabd", - BuildDate: 1681646714, - Packager: "Jelle van der Waa ", - Arch: "x86_64", - Files: []string{"usr/", "usr/bin/", "usr/bin/zstd"}, - }, - } - require.Equal(t, pkgDesc, md.Desc()) - require.Equal(t, pkgFiles, md.Files()) -} diff --git a/modules/packages/cargo/parser.go b/modules/packages/cargo/parser.go index f2c75538b5..36cd44df84 100644 --- a/modules/packages/cargo/parser.go +++ b/modules/packages/cargo/parser.go @@ -9,8 +9,8 @@ import ( "io" "regexp" - "forgejo.org/modules/json" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" ) @@ -96,7 +96,7 @@ func parsePackage(r io.Reader) (*Package, error) { Target *string `json:"target"` Kind string `json:"kind"` Registry *string `json:"registry"` - ExplicitNameInToml *string `json:"explicit_name_in_toml"` + ExplicitNameInToml string `json:"explicit_name_in_toml"` } `json:"deps"` Features map[string][]string `json:"features"` Authors []string `json:"authors"` @@ -136,16 +136,8 @@ func parsePackage(r io.Reader) (*Package, error) { dependencies := make([]*Dependency, 0, len(meta.Deps)) for _, dep := range meta.Deps { - name := dep.Name - packageName := dep.ExplicitNameInToml - // If the explicit_name_in_toml field is set, the package is renamed and - // should be set accordingly. - if dep.ExplicitNameInToml != nil { - name = *dep.ExplicitNameInToml - packageName = &dep.Name - } dependencies = append(dependencies, &Dependency{ - Name: name, + Name: dep.Name, Req: dep.VersionReq, Features: dep.Features, Optional: dep.Optional, @@ -153,7 +145,6 @@ func parsePackage(r io.Reader) (*Package, error) { Target: dep.Target, Kind: dep.Kind, Registry: dep.Registry, - Package: packageName, }) } diff --git a/modules/packages/cargo/parser_test.go b/modules/packages/cargo/parser_test.go index d2470fab42..2230a5b499 100644 --- a/modules/packages/cargo/parser_test.go +++ b/modules/packages/cargo/parser_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -22,7 +21,7 @@ const ( ) func TestParsePackage(t *testing.T) { - createPackage := func(name, version, dependency string) io.Reader { + createPackage := func(name, version string) io.Reader { metadata := `{ "name":"` + name + `", "vers":"` + version + `", @@ -32,7 +31,7 @@ func TestParsePackage(t *testing.T) { { "name":"dep", "version_req":"1.0" - }` + dependency + ` + } ], "homepage":"` + homepage + `", "license":"` + license + `" @@ -48,30 +47,30 @@ func TestParsePackage(t *testing.T) { t.Run("InvalidName", func(t *testing.T) { for _, name := range []string{"", "0test", "-test", "_test", strings.Repeat("a", 65)} { - data := createPackage(name, "1.0.0", "") + data := createPackage(name, "1.0.0") cp, err := ParsePackage(data) assert.Nil(t, cp) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) } }) t.Run("InvalidVersion", func(t *testing.T) { for _, version := range []string{"", "1.", "-1.0", "1.0.0/1"} { - data := createPackage("test", version, "") + data := createPackage("test", version) cp, err := ParsePackage(data) assert.Nil(t, cp) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) } }) t.Run("Valid", func(t *testing.T) { - data := createPackage("test", "1.0.0", "") + data := createPackage("test", "1.0.0") cp, err := ParsePackage(data) assert.NotNil(t, cp) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "test", cp.Name) assert.Equal(t, "1.0.0", cp.Version) @@ -84,25 +83,4 @@ func TestParsePackage(t *testing.T) { content, _ := io.ReadAll(cp.Content) assert.Equal(t, "test", string(content)) }) - - t.Run("Renamed dependency", func(t *testing.T) { - data := createPackage("test", "1.0.0", `, {"name":"v4l2-sys", "version":"0.3.0", "explicit_name_in_toml":"v4l2-sys-mit"}`) - - cp, err := ParsePackage(data) - assert.NotNil(t, cp) - require.NoError(t, err) - - assert.Equal(t, "test", cp.Name) - assert.Equal(t, "1.0.0", cp.Version) - assert.Equal(t, description, cp.Metadata.Description) - assert.Equal(t, []string{author}, cp.Metadata.Authors) - assert.Len(t, cp.Metadata.Dependencies, 2) - assert.Equal(t, "dep", cp.Metadata.Dependencies[0].Name) - assert.Equal(t, "v4l2-sys-mit", cp.Metadata.Dependencies[1].Name) - assert.Equal(t, "v4l2-sys", *cp.Metadata.Dependencies[1].Package) - assert.Equal(t, homepage, cp.Metadata.ProjectURL) - assert.Equal(t, license, cp.Metadata.License) - content, _ := io.ReadAll(cp.Content) - assert.Equal(t, "test", string(content)) - }) } diff --git a/modules/packages/chef/metadata.go b/modules/packages/chef/metadata.go index 951606bbc5..a1c91870c2 100644 --- a/modules/packages/chef/metadata.go +++ b/modules/packages/chef/metadata.go @@ -10,9 +10,9 @@ import ( "regexp" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" ) const ( diff --git a/modules/packages/chef/metadata_test.go b/modules/packages/chef/metadata_test.go index 8784c629e6..6def4162a9 100644 --- a/modules/packages/chef/metadata_test.go +++ b/modules/packages/chef/metadata_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -32,7 +31,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(&buf) assert.Nil(t, p) - require.ErrorIs(t, err, ErrMissingMetadataFile) + assert.ErrorIs(t, err, ErrMissingMetadataFile) }) t.Run("Valid", func(t *testing.T) { @@ -54,7 +53,7 @@ func TestParsePackage(t *testing.T) { zw.Close() p, err := ParsePackage(&buf) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, p) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) @@ -67,7 +66,7 @@ func TestParseChefMetadata(t *testing.T) { for _, name := range []string{" test", "test "} { p, err := ParseChefMetadata(strings.NewReader(`{"name":"` + name + `","version":"1.0.0"}`)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) } }) @@ -75,14 +74,14 @@ func TestParseChefMetadata(t *testing.T) { for _, version := range []string{"1", "1.2.3.4", "1.0.0 "} { p, err := ParseChefMetadata(strings.NewReader(`{"name":"test","version":"` + version + `"}`)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) } }) t.Run("Valid", func(t *testing.T) { p, err := ParseChefMetadata(strings.NewReader(`{"name":"` + packageName + `","version":"` + packageVersion + `","description":"` + packageDescription + `","maintainer":"` + packageAuthor + `","source_url":"` + packageRepositoryURL + `"}`)) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) diff --git a/modules/packages/composer/metadata.go b/modules/packages/composer/metadata.go index 940309b769..2c2e9ebf27 100644 --- a/modules/packages/composer/metadata.go +++ b/modules/packages/composer/metadata.go @@ -10,9 +10,9 @@ import ( "regexp" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" ) @@ -48,7 +48,6 @@ type Metadata struct { Homepage string `json:"homepage,omitempty"` License Licenses `json:"license,omitempty"` Authors []Author `json:"authors,omitempty"` - Bin []string `json:"bin,omitempty"` Autoload map[string]any `json:"autoload,omitempty"` AutoloadDev map[string]any `json:"autoload-dev,omitempty"` Extra map[string]any `json:"extra,omitempty"` diff --git a/modules/packages/composer/metadata_test.go b/modules/packages/composer/metadata_test.go index e2bbff4e58..a5e317daf1 100644 --- a/modules/packages/composer/metadata_test.go +++ b/modules/packages/composer/metadata_test.go @@ -9,10 +9,9 @@ import ( "strings" "testing" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -50,20 +49,20 @@ const composerContent = `{ func TestLicenseUnmarshal(t *testing.T) { var l Licenses - require.NoError(t, json.NewDecoder(strings.NewReader(`["MIT"]`)).Decode(&l)) + assert.NoError(t, json.NewDecoder(strings.NewReader(`["MIT"]`)).Decode(&l)) assert.Len(t, l, 1) assert.Equal(t, "MIT", l[0]) - require.NoError(t, json.NewDecoder(strings.NewReader(`"MIT"`)).Decode(&l)) + assert.NoError(t, json.NewDecoder(strings.NewReader(`"MIT"`)).Decode(&l)) assert.Len(t, l, 1) assert.Equal(t, "MIT", l[0]) } func TestCommentsUnmarshal(t *testing.T) { var c Comments - require.NoError(t, json.NewDecoder(strings.NewReader(`["comment"]`)).Decode(&c)) + assert.NoError(t, json.NewDecoder(strings.NewReader(`["comment"]`)).Decode(&c)) assert.Len(t, c, 1) assert.Equal(t, "comment", c[0]) - require.NoError(t, json.NewDecoder(strings.NewReader(`"comment"`)).Decode(&c)) + assert.NoError(t, json.NewDecoder(strings.NewReader(`"comment"`)).Decode(&c)) assert.Len(t, c, 1) assert.Equal(t, "comment", c[0]) } @@ -85,7 +84,7 @@ func TestParsePackage(t *testing.T) { cp, err := ParsePackage(bytes.NewReader(data), int64(len(data))) assert.Nil(t, cp) - require.ErrorIs(t, err, ErrMissingComposerFile) + assert.ErrorIs(t, err, ErrMissingComposerFile) }) t.Run("MissingComposerFileInRoot", func(t *testing.T) { @@ -93,7 +92,7 @@ func TestParsePackage(t *testing.T) { cp, err := ParsePackage(bytes.NewReader(data), int64(len(data))) assert.Nil(t, cp) - require.ErrorIs(t, err, ErrMissingComposerFile) + assert.ErrorIs(t, err, ErrMissingComposerFile) }) t.Run("InvalidComposerFile", func(t *testing.T) { @@ -101,7 +100,7 @@ func TestParsePackage(t *testing.T) { cp, err := ParsePackage(bytes.NewReader(data), int64(len(data))) assert.Nil(t, cp) - require.Error(t, err) + assert.Error(t, err) }) t.Run("InvalidPackageName", func(t *testing.T) { @@ -109,7 +108,7 @@ func TestParsePackage(t *testing.T) { cp, err := ParsePackage(bytes.NewReader(data), int64(len(data))) assert.Nil(t, cp) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) }) t.Run("InvalidPackageVersion", func(t *testing.T) { @@ -117,14 +116,14 @@ func TestParsePackage(t *testing.T) { cp, err := ParsePackage(bytes.NewReader(data), int64(len(data))) assert.Nil(t, cp) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) }) t.Run("InvalidReadmePath", func(t *testing.T) { data := createArchive(map[string]string{"composer.json": `{"name": "gitea/composer-package", "readme": "sub/README.md"}`}) cp, err := ParsePackage(bytes.NewReader(data), int64(len(data))) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, cp) assert.Empty(t, cp.Metadata.Readme) @@ -134,7 +133,7 @@ func TestParsePackage(t *testing.T) { data := createArchive(map[string]string{"composer.json": composerContent, "README.md": readme}) cp, err := ParsePackage(bytes.NewReader(data), int64(len(data))) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, cp) assert.Equal(t, name, cp.Name) diff --git a/modules/packages/conan/conanfile_parser_test.go b/modules/packages/conan/conanfile_parser_test.go index fe867fbe76..5801570184 100644 --- a/modules/packages/conan/conanfile_parser_test.go +++ b/modules/packages/conan/conanfile_parser_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -41,7 +40,7 @@ class ConanPackageConan(ConanFile): func TestParseConanfile(t *testing.T) { metadata, err := ParseConanfile(strings.NewReader(contentConanfile)) - require.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, license, metadata.License) assert.Equal(t, author, metadata.Author) assert.Equal(t, homepage, metadata.ProjectURL) diff --git a/modules/packages/conan/conaninfo_parser.go b/modules/packages/conan/conaninfo_parser.go index 6027e51401..de11dbee45 100644 --- a/modules/packages/conan/conaninfo_parser.go +++ b/modules/packages/conan/conaninfo_parser.go @@ -8,7 +8,7 @@ import ( "io" "strings" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) // Conaninfo represents infos of a Conan package diff --git a/modules/packages/conan/conaninfo_parser_test.go b/modules/packages/conan/conaninfo_parser_test.go index dfb1836474..556a4b939e 100644 --- a/modules/packages/conan/conaninfo_parser_test.go +++ b/modules/packages/conan/conaninfo_parser_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -51,7 +50,7 @@ const ( func TestParseConaninfo(t *testing.T) { info, err := ParseConaninfo(strings.NewReader(contentConaninfo)) assert.NotNil(t, info) - require.NoError(t, err) + assert.Nil(t, err) assert.Equal( t, map[string]string{ diff --git a/modules/packages/conan/reference.go b/modules/packages/conan/reference.go index 0b863240cb..58f268bd48 100644 --- a/modules/packages/conan/reference.go +++ b/modules/packages/conan/reference.go @@ -8,8 +8,8 @@ import ( "regexp" "strings" - "forgejo.org/modules/log" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) const ( diff --git a/modules/packages/conan/reference_test.go b/modules/packages/conan/reference_test.go index 7d39bd8238..6ea86eb0dd 100644 --- a/modules/packages/conan/reference_test.go +++ b/modules/packages/conan/reference_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestNewRecipeReference(t *testing.T) { @@ -41,53 +40,53 @@ func TestNewRecipeReference(t *testing.T) { for i, c := range cases { rref, err := NewRecipeReference(c.Name, c.Version, c.User, c.Channel, c.Revision) if c.IsValid { - require.NoError(t, err, "case %d, should be invalid", i) + assert.NoError(t, err, "case %d, should be invalid", i) assert.NotNil(t, rref, "case %d, should not be nil", i) } else { - require.Error(t, err, "case %d, should be valid", i) + assert.Error(t, err, "case %d, should be valid", i) } } } func TestRecipeReferenceRevisionOrDefault(t *testing.T) { rref, err := NewRecipeReference("name", "1.0", "", "", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, DefaultRevision, rref.RevisionOrDefault()) rref, err = NewRecipeReference("name", "1.0", "", "", DefaultRevision) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, DefaultRevision, rref.RevisionOrDefault()) rref, err = NewRecipeReference("name", "1.0", "", "", "Az09") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "Az09", rref.RevisionOrDefault()) } func TestRecipeReferenceString(t *testing.T) { rref, err := NewRecipeReference("name", "1.0", "", "", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "name/1.0", rref.String()) rref, err = NewRecipeReference("name", "1.0", "user", "channel", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "name/1.0@user/channel", rref.String()) rref, err = NewRecipeReference("name", "1.0", "user", "channel", "Az09") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "name/1.0@user/channel#Az09", rref.String()) } func TestRecipeReferenceLinkName(t *testing.T) { rref, err := NewRecipeReference("name", "1.0", "", "", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "name/1.0/_/_/0", rref.LinkName()) rref, err = NewRecipeReference("name", "1.0", "user", "channel", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "name/1.0/user/channel/0", rref.LinkName()) rref, err = NewRecipeReference("name", "1.0", "user", "channel", "Az09") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "name/1.0/user/channel/Az09", rref.LinkName()) } @@ -111,10 +110,10 @@ func TestNewPackageReference(t *testing.T) { for i, c := range cases { pref, err := NewPackageReference(c.Recipe, c.Reference, c.Revision) if c.IsValid { - require.NoError(t, err, "case %d, should be invalid", i) + assert.NoError(t, err, "case %d, should be invalid", i) assert.NotNil(t, pref, "case %d, should not be nil", i) } else { - require.Error(t, err, "case %d, should be valid", i) + assert.Error(t, err, "case %d, should be valid", i) } } } @@ -123,15 +122,15 @@ func TestPackageReferenceRevisionOrDefault(t *testing.T) { rref, _ := NewRecipeReference("name", "1.0", "", "", "") pref, err := NewPackageReference(rref, "ref", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, DefaultRevision, pref.RevisionOrDefault()) pref, err = NewPackageReference(rref, "ref", DefaultRevision) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, DefaultRevision, pref.RevisionOrDefault()) pref, err = NewPackageReference(rref, "ref", "Az09") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "Az09", pref.RevisionOrDefault()) } @@ -139,10 +138,10 @@ func TestPackageReferenceLinkName(t *testing.T) { rref, _ := NewRecipeReference("name", "1.0", "", "", "") pref, err := NewPackageReference(rref, "ref", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "ref/0", pref.LinkName()) pref, err = NewPackageReference(rref, "ref", "Az09") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "ref/Az09", pref.LinkName()) } diff --git a/modules/packages/conda/metadata.go b/modules/packages/conda/metadata.go index f61cc61c2a..5eb72b8e38 100644 --- a/modules/packages/conda/metadata.go +++ b/modules/packages/conda/metadata.go @@ -10,10 +10,11 @@ import ( "io" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" - "forgejo.org/modules/zstd" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" + + "github.com/klauspost/compress/zstd" ) var ( diff --git a/modules/packages/conda/metadata_test.go b/modules/packages/conda/metadata_test.go index 959f9c4727..2bb114f030 100644 --- a/modules/packages/conda/metadata_test.go +++ b/modules/packages/conda/metadata_test.go @@ -10,11 +10,9 @@ import ( "io" "testing" - "forgejo.org/modules/zstd" - "github.com/dsnet/compress/bzip2" + "github.com/klauspost/compress/zstd" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -48,7 +46,7 @@ func TestParsePackage(t *testing.T) { p, err := parsePackageTar(buf) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidStructure) + assert.ErrorIs(t, err, ErrInvalidStructure) }) t.Run("MissingAboutFile", func(t *testing.T) { @@ -56,7 +54,7 @@ func TestParsePackage(t *testing.T) { p, err := parsePackageTar(buf) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "name", p.Name) assert.Equal(t, "1.0", p.Version) @@ -69,7 +67,7 @@ func TestParsePackage(t *testing.T) { p, err := parsePackageTar(buf) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) } }) @@ -79,7 +77,7 @@ func TestParsePackage(t *testing.T) { p, err := parsePackageTar(buf) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) } }) @@ -91,7 +89,7 @@ func TestParsePackage(t *testing.T) { p, err := parsePackageTar(buf) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) @@ -116,7 +114,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackageBZ2(br) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) @@ -143,7 +141,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackageConda(br, int64(br.Len())) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) diff --git a/modules/packages/container/metadata.go b/modules/packages/container/metadata.go index 6cac77b7ff..2a41fb9105 100644 --- a/modules/packages/container/metadata.go +++ b/modules/packages/container/metadata.go @@ -8,9 +8,9 @@ import ( "io" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/packages/container/helm" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/packages/container/helm" + "code.gitea.io/gitea/modules/validation" oci "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -84,13 +84,6 @@ func ParseImageConfig(mt string, r io.Reader) (*Metadata, error) { func parseOCIImageConfig(r io.Reader) (*Metadata, error) { var image oci.Image if err := json.NewDecoder(r).Decode(&image); err != nil { - // Handle empty config blobs (common in OCI artifacts) - if err == io.EOF { - return &Metadata{ - Type: TypeOCI, - Platform: DefaultPlatform, - }, nil - } return nil, err } diff --git a/modules/packages/container/metadata_test.go b/modules/packages/container/metadata_test.go index 5596c95751..665499b2e6 100644 --- a/modules/packages/container/metadata_test.go +++ b/modules/packages/container/metadata_test.go @@ -4,15 +4,13 @@ package container import ( - "io" "strings" "testing" - "forgejo.org/modules/packages/container/helm" + "code.gitea.io/gitea/modules/packages/container/helm" oci "github.com/opencontainers/image-spec/specs-go/v1" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestParseImageConfig(t *testing.T) { @@ -26,7 +24,7 @@ func TestParseImageConfig(t *testing.T) { configOCI := `{"config": {"labels": {"` + labelAuthors + `": "` + author + `", "` + labelLicenses + `": "` + license + `", "` + labelURL + `": "` + projectURL + `", "` + labelSource + `": "` + repositoryURL + `", "` + labelDocumentation + `": "` + documentationURL + `", "` + labelDescription + `": "` + description + `"}}, "history": [{"created_by": "do it 1"}, {"created_by": "dummy #(nop) do it 2"}]}` metadata, err := ParseImageConfig(oci.MediaTypeImageManifest, strings.NewReader(configOCI)) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, TypeOCI, metadata.Type) assert.Equal(t, description, metadata.Description) @@ -53,7 +51,7 @@ func TestParseImageConfig(t *testing.T) { configHelm := `{"description":"` + description + `", "home": "` + projectURL + `", "sources": ["` + repositoryURL + `"], "maintainers":[{"name":"` + author + `"}]}` metadata, err = ParseImageConfig(helm.ConfigMediaType, strings.NewReader(configHelm)) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, TypeHelm, metadata.Type) assert.Equal(t, description, metadata.Description) @@ -61,49 +59,3 @@ func TestParseImageConfig(t *testing.T) { assert.Equal(t, projectURL, metadata.ProjectURL) assert.Equal(t, repositoryURL, metadata.RepositoryURL) } - -func TestParseImageConfigEmptyBlob(t *testing.T) { - t.Run("Empty config blob (EOF)", func(t *testing.T) { - // Test empty reader (simulates empty config blob common in OCI artifacts) - metadata, err := ParseImageConfig(oci.MediaTypeImageManifest, strings.NewReader("")) - require.NoError(t, err) - - assert.Equal(t, TypeOCI, metadata.Type) - assert.Equal(t, DefaultPlatform, metadata.Platform) - assert.Empty(t, metadata.Description) - assert.Empty(t, metadata.Authors) - assert.Empty(t, metadata.Labels) - assert.Empty(t, metadata.Manifests) - }) - - t.Run("Empty JSON object", func(t *testing.T) { - // Test minimal valid JSON config - metadata, err := ParseImageConfig(oci.MediaTypeImageManifest, strings.NewReader("{}")) - require.NoError(t, err) - - assert.Equal(t, TypeOCI, metadata.Type) - assert.Equal(t, DefaultPlatform, metadata.Platform) - assert.Empty(t, metadata.Description) - assert.Empty(t, metadata.Authors) - }) - - t.Run("Invalid JSON still returns error", func(t *testing.T) { - // Test that actual JSON errors (not EOF) are still returned - _, err := ParseImageConfig(oci.MediaTypeImageManifest, strings.NewReader("{invalid json")) - require.Error(t, err) - assert.NotEqual(t, io.EOF, err) - }) - - t.Run("OCI artifact with empty config", func(t *testing.T) { - // Test OCI artifact scenario with minimal config - configOCI := `{"config": {}}` - metadata, err := ParseImageConfig(oci.MediaTypeImageManifest, strings.NewReader(configOCI)) - require.NoError(t, err) - - assert.Equal(t, TypeOCI, metadata.Type) - assert.Equal(t, DefaultPlatform, metadata.Platform) - assert.Empty(t, metadata.Description) - assert.Empty(t, metadata.Authors) - assert.Empty(t, metadata.ImageLayers) - }) -} diff --git a/modules/packages/content_store.go b/modules/packages/content_store.go index f4578d91e0..da93e6cf6b 100644 --- a/modules/packages/content_store.go +++ b/modules/packages/content_store.go @@ -9,9 +9,9 @@ import ( "path" "strings" - "forgejo.org/modules/setting" - "forgejo.org/modules/storage" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" ) // BlobHash256Key is the key to address a blob content @@ -37,8 +37,8 @@ func (s *ContentStore) ShouldServeDirect() bool { return setting.Packages.Storage.MinioConfig.ServeDirect } -func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string, reqParams url.Values) (*url.URL, error) { - return s.store.URL(KeyToRelativePath(key), filename, reqParams) +func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string) (*url.URL, error) { + return s.store.URL(KeyToRelativePath(key), filename) } // FIXME: Workaround to be removed in v1.20 diff --git a/modules/packages/cran/metadata.go b/modules/packages/cran/metadata.go index 547fe87ccb..0b0bfb07c6 100644 --- a/modules/packages/cran/metadata.go +++ b/modules/packages/cran/metadata.go @@ -13,7 +13,7 @@ import ( "regexp" "strings" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) const ( diff --git a/modules/packages/cran/metadata_test.go b/modules/packages/cran/metadata_test.go index 3287380cf0..ff68c34c51 100644 --- a/modules/packages/cran/metadata_test.go +++ b/modules/packages/cran/metadata_test.go @@ -12,7 +12,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -63,7 +62,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(buf, buf.Size()) assert.Nil(t, p) - require.ErrorIs(t, err, ErrMissingDescriptionFile) + assert.ErrorIs(t, err, ErrMissingDescriptionFile) }) t.Run("Valid", func(t *testing.T) { @@ -75,7 +74,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(buf, buf.Size()) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) @@ -100,7 +99,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(buf, buf.Size()) assert.Nil(t, p) - require.ErrorIs(t, err, ErrMissingDescriptionFile) + assert.ErrorIs(t, err, ErrMissingDescriptionFile) }) t.Run("Valid", func(t *testing.T) { @@ -111,7 +110,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(buf, buf.Size()) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) @@ -124,7 +123,7 @@ func TestParseDescription(t *testing.T) { for _, name := range []string{"123abc", "ab-cd", "ab cd", "ab/cd"} { p, err := ParseDescription(createDescription(name, packageVersion)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) } }) @@ -132,13 +131,13 @@ func TestParseDescription(t *testing.T) { for _, version := range []string{"1", "1 0", "1.2.3.4.5", "1-2-3-4-5", "1.", "1.0.", "1-", "1-0-"} { p, err := ParseDescription(createDescription(packageName, version)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) } }) t.Run("Valid", func(t *testing.T) { p, err := ParseDescription(createDescription(packageName, packageVersion)) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, p) assert.Equal(t, packageName, p.Name) diff --git a/modules/packages/debian/metadata.go b/modules/packages/debian/metadata.go index e44801654b..32460a84ae 100644 --- a/modules/packages/debian/metadata.go +++ b/modules/packages/debian/metadata.go @@ -12,11 +12,11 @@ import ( "regexp" "strings" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" - "forgejo.org/modules/zstd" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "github.com/blakesmith/ar" + "github.com/klauspost/compress/zstd" "github.com/ulikunitz/xz" ) diff --git a/modules/packages/debian/metadata_test.go b/modules/packages/debian/metadata_test.go index cfcbc57ee0..26c2a6fc68 100644 --- a/modules/packages/debian/metadata_test.go +++ b/modules/packages/debian/metadata_test.go @@ -10,11 +10,9 @@ import ( "io" "testing" - "forgejo.org/modules/zstd" - "github.com/blakesmith/ar" + "github.com/klauspost/compress/zstd" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/ulikunitz/xz" ) @@ -49,7 +47,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data) assert.Nil(t, p) - require.ErrorIs(t, err, ErrMissingControlFile) + assert.ErrorIs(t, err, ErrMissingControlFile) }) t.Run("Compression", func(t *testing.T) { @@ -58,7 +56,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data) assert.Nil(t, p) - require.ErrorIs(t, err, ErrUnsupportedCompression) + assert.ErrorIs(t, err, ErrUnsupportedCompression) }) var buf bytes.Buffer @@ -114,7 +112,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "gitea", p.Name) t.Run("TrailingSlash", func(t *testing.T) { @@ -122,7 +120,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "gitea", p.Name) }) }) @@ -149,7 +147,7 @@ func TestParseControlFile(t *testing.T) { for _, name := range []string{"", "-cd"} { p, err := ParseControlFile(buildContent(name, packageVersion, packageArchitecture)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) } }) @@ -157,14 +155,14 @@ func TestParseControlFile(t *testing.T) { for _, version := range []string{"", "1-", ":1.0", "1_0"} { p, err := ParseControlFile(buildContent(packageName, version, packageArchitecture)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) } }) t.Run("InvalidArchitecture", func(t *testing.T) { p, err := ParseControlFile(buildContent(packageName, packageVersion, "")) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidArchitecture) + assert.ErrorIs(t, err, ErrInvalidArchitecture) }) t.Run("Valid", func(t *testing.T) { @@ -172,7 +170,7 @@ func TestParseControlFile(t *testing.T) { full := content.String() p, err := ParseControlFile(content) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, p) assert.Equal(t, packageName, p.Name) diff --git a/modules/packages/goproxy/metadata.go b/modules/packages/goproxy/metadata.go index 2dae4100e7..40f7d20508 100644 --- a/modules/packages/goproxy/metadata.go +++ b/modules/packages/goproxy/metadata.go @@ -10,7 +10,7 @@ import ( "path" "strings" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) const ( diff --git a/modules/packages/goproxy/metadata_test.go b/modules/packages/goproxy/metadata_test.go index 3a47f10269..4e7f394f8b 100644 --- a/modules/packages/goproxy/metadata_test.go +++ b/modules/packages/goproxy/metadata_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -34,7 +33,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data, int64(data.Len())) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidStructure) + assert.ErrorIs(t, err, ErrInvalidStructure) }) t.Run("InvalidNameOrVersionStructure", func(t *testing.T) { @@ -44,7 +43,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data, int64(data.Len())) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidStructure) + assert.ErrorIs(t, err, ErrInvalidStructure) }) t.Run("GoModFileInWrongDirectory", func(t *testing.T) { @@ -54,7 +53,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data, int64(data.Len())) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) assert.Equal(t, "module gitea.com/go-gitea/gitea", p.GoMod) @@ -68,7 +67,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data, int64(data.Len())) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) assert.Equal(t, "valid", p.GoMod) diff --git a/modules/packages/hashed_buffer.go b/modules/packages/hashed_buffer.go index 93c693efc9..4ab45edcec 100644 --- a/modules/packages/hashed_buffer.go +++ b/modules/packages/hashed_buffer.go @@ -6,7 +6,7 @@ package packages import ( "io" - "forgejo.org/modules/util/filebuffer" + "code.gitea.io/gitea/modules/util/filebuffer" ) // HashedSizeReader provide methods to read, sum hashes and a Size method @@ -75,7 +75,7 @@ func (b *HashedBuffer) Write(p []byte) (int, error) { return b.combinedWriter.Write(p) } -// Sums gets the MD5, SHA1, SHA256, SHA512 and BLAKE2B checksums of the data -func (b *HashedBuffer) Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512, hashBlake2b []byte) { +// Sums gets the MD5, SHA1, SHA256 and SHA512 checksums of the data +func (b *HashedBuffer) Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512 []byte) { return b.hash.Sums() } diff --git a/modules/packages/hashed_buffer_test.go b/modules/packages/hashed_buffer_test.go index 879038988f..564e782f18 100644 --- a/modules/packages/hashed_buffer_test.go +++ b/modules/packages/hashed_buffer_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestHashedBuffer(t *testing.T) { @@ -21,29 +20,27 @@ func TestHashedBuffer(t *testing.T) { HashSHA1 string HashSHA256 string HashSHA512 string - hashBlake2b string }{ - {5, "test", "098f6bcd4621d373cade4e832627b4f6", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff", "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a483aa9bc33b582f77d30a65e6f29a896c0411f38312e1d66e0bf16386c86a89bea572"}, - {5, "testtest", "05a671c66aefea124cc08b76ea6d30bb", "51abb9636078defbf888d8457a7c76f85c8f114c", "37268335dd6931045bdcdf92623ff819a64244b53d0e746d438797349d4da578", "125d6d03b32c84d492747f79cf0bf6e179d287f341384eb5d6d3197525ad6be8e6df0116032935698f99a09e265073d1d6c32c274591bf1d0a20ad67cba921bc", "372a53b95f46e775b973031e40b844f24389657019f7b7540a9f0496f4ead4a2e4b050909664611fb0f4b7c7e92c3c04c84787be7f6b8edf7bf6bc31856b6c76"}, + {5, "test", "098f6bcd4621d373cade4e832627b4f6", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"}, + {5, "testtest", "05a671c66aefea124cc08b76ea6d30bb", "51abb9636078defbf888d8457a7c76f85c8f114c", "37268335dd6931045bdcdf92623ff819a64244b53d0e746d438797349d4da578", "125d6d03b32c84d492747f79cf0bf6e179d287f341384eb5d6d3197525ad6be8e6df0116032935698f99a09e265073d1d6c32c274591bf1d0a20ad67cba921bc"}, } for _, c := range cases { buf, err := CreateHashedBufferFromReaderWithSize(strings.NewReader(c.Data), c.MaxMemorySize) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, len(c.Data), buf.Size()) data, err := io.ReadAll(buf) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, c.Data, string(data)) - hashMD5, hashSHA1, hashSHA256, hashSHA512, hashBlake2b := buf.Sums() + hashMD5, hashSHA1, hashSHA256, hashSHA512 := buf.Sums() assert.Equal(t, c.HashMD5, hex.EncodeToString(hashMD5)) assert.Equal(t, c.HashSHA1, hex.EncodeToString(hashSHA1)) assert.Equal(t, c.HashSHA256, hex.EncodeToString(hashSHA256)) assert.Equal(t, c.HashSHA512, hex.EncodeToString(hashSHA512)) - assert.Equal(t, c.hashBlake2b, hex.EncodeToString(hashBlake2b)) - require.NoError(t, buf.Close()) + assert.NoError(t, buf.Close()) } } diff --git a/modules/packages/helm/metadata.go b/modules/packages/helm/metadata.go index 19a30c5ffa..421fc5e725 100644 --- a/modules/packages/helm/metadata.go +++ b/modules/packages/helm/metadata.go @@ -9,8 +9,8 @@ import ( "io" "strings" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" "gopkg.in/yaml.v3" diff --git a/modules/packages/maven/metadata.go b/modules/packages/maven/metadata.go index bc0dc0155e..42aa250718 100644 --- a/modules/packages/maven/metadata.go +++ b/modules/packages/maven/metadata.go @@ -7,8 +7,7 @@ import ( "encoding/xml" "io" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/validation" "golang.org/x/net/html/charset" ) @@ -50,16 +49,8 @@ type pomStruct struct { Version string `xml:"version"` Scope string `xml:"scope"` } `xml:"dependencies>dependency"` - Parent struct { - GroupID string `xml:"groupId"` - ArtifactID string `xml:"artifactId"` - Version string `xml:"version"` - RelativePath string `xml:"relativePath"` - } `xml:"parent"` } -var ErrNoGroupID = util.NewInvalidArgumentErrorf("group ID is missing") - // ParsePackageMetaData parses the metadata of a pom file func ParsePackageMetaData(r io.Reader) (*Metadata, error) { var pom pomStruct @@ -74,17 +65,6 @@ func ParsePackageMetaData(r io.Reader) (*Metadata, error) { pom.URL = "" } - groupID := pom.GroupID - - if groupID == "" { - // If a project inherits from a parent project, the groupId element is optional. - // Refer to: https://maven.apache.org/pom.html#Inheritance - if pom.Parent.GroupID == "" { - return nil, ErrNoGroupID - } - groupID = pom.Parent.GroupID - } - licenses := make([]string, 0, len(pom.Licenses)) for _, l := range pom.Licenses { if l.Name != "" { @@ -102,7 +82,7 @@ func ParsePackageMetaData(r io.Reader) (*Metadata, error) { } return &Metadata{ - GroupID: groupID, + GroupID: pom.GroupID, ArtifactID: pom.ArtifactID, Name: pom.Name, Description: pom.Description, diff --git a/modules/packages/maven/metadata_test.go b/modules/packages/maven/metadata_test.go index 3b087989e6..e675467730 100644 --- a/modules/packages/maven/metadata_test.go +++ b/modules/packages/maven/metadata_test.go @@ -8,13 +8,11 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "golang.org/x/text/encoding/charmap" ) const ( groupID = "org.gitea" - parentGroupID = "org.gitea.parent" artifactID = "my-project" version = "1.0.1" name = "My Gitea Project" @@ -28,11 +26,6 @@ const ( const pomContent = ` - - ` + parentGroupID + ` - parent-project - 1.0.0 - ` + groupID + ` ` + artifactID + ` ` + version + ` @@ -53,34 +46,16 @@ const pomContent = ` ` -const pomWithParentGroupID = ` - - - ` + parentGroupID + ` - parent-project - 1.0.0 - - - ` + artifactID + ` - ` + version + ` -` - -const pomWithMissingGroupID = ` - - ` + artifactID + ` - ` + version + ` -` - func TestParsePackageMetaData(t *testing.T) { t.Run("InvalidFile", func(t *testing.T) { m, err := ParsePackageMetaData(strings.NewReader("")) assert.Nil(t, m) - require.Error(t, err) + assert.Error(t, err) }) t.Run("Valid", func(t *testing.T) { m, err := ParsePackageMetaData(strings.NewReader(pomContent)) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, m) assert.Equal(t, groupID, m.GroupID) @@ -105,25 +80,10 @@ func TestParsePackageMetaData(t *testing.T) { ``, ), ) - require.NoError(t, err) + assert.NoError(t, err) m, err := ParsePackageMetaData(strings.NewReader(pomContent8859_1)) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, m) }) - - t.Run("UseParentGroupID", func(t *testing.T) { - m, err := ParsePackageMetaData(strings.NewReader(pomWithParentGroupID)) - require.NoError(t, err) - assert.NotNil(t, m) - - assert.Equal(t, parentGroupID, m.GroupID) - }) - - t.Run("MissingGroupIDThrowsError", func(t *testing.T) { - m, err := ParsePackageMetaData(strings.NewReader(pomWithMissingGroupID)) - assert.Nil(t, m) - require.Error(t, err) - assert.Equal(t, ErrNoGroupID, err) - }) } diff --git a/modules/packages/multi_hasher.go b/modules/packages/multi_hasher.go index d2d9a759a8..83a4b5b7af 100644 --- a/modules/packages/multi_hasher.go +++ b/modules/packages/multi_hasher.go @@ -12,32 +12,28 @@ import ( "errors" "hash" "io" - - "golang.org/x/crypto/blake2b" ) const ( - marshaledSizeMD5 = 92 - marshaledSizeSHA1 = 96 - marshaledSizeSHA256 = 108 - marshaledSizeSHA512 = 204 - marshaledSizeBlake2b = 213 + marshaledSizeMD5 = 92 + marshaledSizeSHA1 = 96 + marshaledSizeSHA256 = 108 + marshaledSizeSHA512 = 204 - marshaledSize = marshaledSizeMD5 + marshaledSizeSHA1 + marshaledSizeSHA256 + marshaledSizeSHA512 + marshaledSizeBlake2b + marshaledSize = marshaledSizeMD5 + marshaledSizeSHA1 + marshaledSizeSHA256 + marshaledSizeSHA512 ) // HashSummer provide a Sums method type HashSummer interface { - Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512, hashBlake2b []byte) + Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512 []byte) } // MultiHasher calculates multiple checksums type MultiHasher struct { - md5 hash.Hash - sha1 hash.Hash - sha256 hash.Hash - sha512 hash.Hash - blake2b hash.Hash + md5 hash.Hash + sha1 hash.Hash + sha256 hash.Hash + sha512 hash.Hash combinedWriter io.Writer } @@ -48,16 +44,14 @@ func NewMultiHasher() *MultiHasher { sha1 := sha1.New() sha256 := sha256.New() sha512 := sha512.New() - blake2b, _ := blake2b.New512(nil) - combinedWriter := io.MultiWriter(md5, sha1, sha256, sha512, blake2b) + combinedWriter := io.MultiWriter(md5, sha1, sha256, sha512) return &MultiHasher{ md5, sha1, sha256, sha512, - blake2b, combinedWriter, } } @@ -80,17 +74,12 @@ func (h *MultiHasher) MarshalBinary() ([]byte, error) { if err != nil { return nil, err } - blake2bBytes, err := h.blake2b.(encoding.BinaryMarshaler).MarshalBinary() - if err != nil { - return nil, err - } b := make([]byte, 0, marshaledSize) b = append(b, md5Bytes...) b = append(b, sha1Bytes...) b = append(b, sha256Bytes...) b = append(b, sha512Bytes...) - b = append(b, blake2bBytes...) return b, nil } @@ -115,12 +104,7 @@ func (h *MultiHasher) UnmarshalBinary(b []byte) error { } b = b[marshaledSizeSHA256:] - if err := h.sha512.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA512]); err != nil { - return err - } - - b = b[marshaledSizeSHA512:] - return h.blake2b.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeBlake2b]) + return h.sha512.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA512]) } // Write implements io.Writer @@ -129,11 +113,10 @@ func (h *MultiHasher) Write(p []byte) (int, error) { } // Sums gets the MD5, SHA1, SHA256 and SHA512 checksums of the data -func (h *MultiHasher) Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512, hashBlake2b []byte) { +func (h *MultiHasher) Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512 []byte) { hashMD5 = h.md5.Sum(nil) hashSHA1 = h.sha1.Sum(nil) hashSHA256 = h.sha256.Sum(nil) hashSHA512 = h.sha512.Sum(nil) - hashBlake2b = h.blake2b.Sum(nil) - return hashMD5, hashSHA1, hashSHA256, hashSHA512, hashBlake2b + return hashMD5, hashSHA1, hashSHA256, hashSHA512 } diff --git a/modules/packages/multi_hasher_test.go b/modules/packages/multi_hasher_test.go index e5a32fc02c..a37debbc95 100644 --- a/modules/packages/multi_hasher_test.go +++ b/modules/packages/multi_hasher_test.go @@ -8,15 +8,13 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( - expectedMD5 = "e3bef03c5f3b7f6b3ab3e3053ed71e9c" - expectedSHA1 = "060b3b99f88e96085b4a68e095bc9e3d1d91e1bc" - expectedSHA256 = "6ccce4863b70f258d691f59609d31b4502e1ba5199942d3bc5d35d17a4ce771d" - expectedSHA512 = "7f70e439ba8c52025c1f06cdf6ae443c4b8ed2e90059cdb9bbbf8adf80846f185a24acca9245b128b226d61753b0d7ed46580a69c8999eeff3bc13a4d0bd816c" - expectedBlake2b = "b3c3ad15c7e6cca543d651add9427727ffb525120eb23264ee35f16f408a369b599d4404a52d29f642fc0d869f9b55581b60e4e8b9b74997182705d3dcb01edb" + expectedMD5 = "e3bef03c5f3b7f6b3ab3e3053ed71e9c" + expectedSHA1 = "060b3b99f88e96085b4a68e095bc9e3d1d91e1bc" + expectedSHA256 = "6ccce4863b70f258d691f59609d31b4502e1ba5199942d3bc5d35d17a4ce771d" + expectedSHA512 = "7f70e439ba8c52025c1f06cdf6ae443c4b8ed2e90059cdb9bbbf8adf80846f185a24acca9245b128b226d61753b0d7ed46580a69c8999eeff3bc13a4d0bd816c" ) func TestMultiHasherSums(t *testing.T) { @@ -24,13 +22,12 @@ func TestMultiHasherSums(t *testing.T) { h := NewMultiHasher() h.Write([]byte("gitea")) - hashMD5, hashSHA1, hashSHA256, hashSHA512, hashBlake2b := h.Sums() + hashMD5, hashSHA1, hashSHA256, hashSHA512 := h.Sums() assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5)) assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1)) assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256)) assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512)) - assert.Equal(t, expectedBlake2b, hex.EncodeToString(hashBlake2b)) }) t.Run("State", func(t *testing.T) { @@ -38,20 +35,19 @@ func TestMultiHasherSums(t *testing.T) { h.Write([]byte("git")) state, err := h.MarshalBinary() - require.NoError(t, err) + assert.NoError(t, err) h2 := NewMultiHasher() err = h2.UnmarshalBinary(state) - require.NoError(t, err) + assert.NoError(t, err) h2.Write([]byte("ea")) - hashMD5, hashSHA1, hashSHA256, hashSHA512, hashBlake2b := h2.Sums() + hashMD5, hashSHA1, hashSHA256, hashSHA512 := h2.Sums() assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5)) assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1)) assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256)) assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512)) - assert.Equal(t, expectedBlake2b, hex.EncodeToString(hashBlake2b)) }) } diff --git a/modules/packages/npm/creator.go b/modules/packages/npm/creator.go index ed163d30ac..7d3d7cd6b5 100644 --- a/modules/packages/npm/creator.go +++ b/modules/packages/npm/creator.go @@ -14,9 +14,9 @@ import ( "strings" "time" - "forgejo.org/modules/json" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" ) diff --git a/modules/packages/npm/creator_test.go b/modules/packages/npm/creator_test.go index 5cbaf0d865..806377a52b 100644 --- a/modules/packages/npm/creator_test.go +++ b/modules/packages/npm/creator_test.go @@ -10,10 +10,9 @@ import ( "strings" "testing" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestParsePackage(t *testing.T) { @@ -35,14 +34,14 @@ func TestParsePackage(t *testing.T) { t.Run("InvalidUpload", func(t *testing.T) { p, err := ParsePackage(bytes.NewReader([]byte{0})) assert.Nil(t, p) - require.Error(t, err) + assert.Error(t, err) }) t.Run("InvalidUploadNoData", func(t *testing.T) { b, _ := json.Marshal(packageUpload{}) p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidPackage) + assert.ErrorIs(t, err, ErrInvalidPackage) }) t.Run("InvalidPackageName", func(t *testing.T) { @@ -61,7 +60,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidPackageName) + assert.ErrorIs(t, err, ErrInvalidPackageName) } test(t, " test ") @@ -100,7 +99,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidPackageVersion) + assert.ErrorIs(t, err, ErrInvalidPackageVersion) } test(t, "test") @@ -132,7 +131,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidPackageVersion) + assert.ErrorIs(t, err, ErrInvalidPackageVersion) }) t.Run("InvalidAttachment", func(t *testing.T) { @@ -154,7 +153,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidAttachment) + assert.ErrorIs(t, err, ErrInvalidAttachment) }) t.Run("InvalidData", func(t *testing.T) { @@ -179,7 +178,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidAttachment) + assert.ErrorIs(t, err, ErrInvalidAttachment) }) t.Run("InvalidIntegrity", func(t *testing.T) { @@ -207,7 +206,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidIntegrity) + assert.ErrorIs(t, err, ErrInvalidIntegrity) }) t.Run("InvalidIntegrity2", func(t *testing.T) { @@ -235,7 +234,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.Nil(t, p) - require.ErrorIs(t, err, ErrInvalidIntegrity) + assert.ErrorIs(t, err, ErrInvalidIntegrity) }) t.Run("Valid", func(t *testing.T) { @@ -278,7 +277,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(bytes.NewReader(b)) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, packageFullName, p.Name) assert.Equal(t, packageVersion, p.Version) diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 126a0ad494..1e98ddffde 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -13,8 +13,8 @@ import ( "regexp" "strings" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" ) @@ -57,21 +57,12 @@ type Package struct { // Metadata represents the metadata of a Nuget package type Metadata struct { - Title string `json:"title,omitempty"` - Language string `json:"language,omitempty"` Description string `json:"description,omitempty"` ReleaseNotes string `json:"release_notes,omitempty"` Readme string `json:"readme,omitempty"` Authors string `json:"authors,omitempty"` - Owners string `json:"owners,omitempty"` - Copyright string `json:"copyright,omitempty"` ProjectURL string `json:"project_url,omitempty"` RepositoryURL string `json:"repository_url,omitempty"` - LicenseURL string `json:"license_url,omitempty"` - IconURL string `json:"icon_url,omitempty"` - MinClientVersion string `json:"min_client_version,omitempty"` - Tags string `json:"tags,omitempty"` - DevelopmentDependency bool `json:"development_dependency,omitempty"` RequireLicenseAcceptance bool `json:"require_license_acceptance"` Dependencies map[string][]Dependency `json:"dependencies,omitempty"` } @@ -86,22 +77,13 @@ type Dependency struct { type nuspecPackage struct { Metadata struct { ID string `xml:"id"` - Title string `xml:"title"` - Language string `xml:"language"` Version string `xml:"version"` Authors string `xml:"authors"` - Owners string `xml:"owners"` - Copyright string `xml:"copyright"` - DevelopmentDependency bool `xml:"developmentDependency"` RequireLicenseAcceptance bool `xml:"requireLicenseAcceptance"` ProjectURL string `xml:"projectUrl"` - LicenseURL string `xml:"licenseUrl"` - IconURL string `xml:"iconUrl"` Description string `xml:"description"` ReleaseNotes string `xml:"releaseNotes"` Readme string `xml:"readme"` - Tags string `xml:"tags"` - MinClientVersion string `xml:"minClientVersion,attr"` PackageTypes struct { PackageType []struct { Name string `xml:"name,attr"` @@ -185,20 +167,11 @@ func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { } m := &Metadata{ - Title: p.Metadata.Title, - Language: p.Metadata.Language, Description: p.Metadata.Description, ReleaseNotes: p.Metadata.ReleaseNotes, Authors: p.Metadata.Authors, - Owners: p.Metadata.Owners, - Copyright: p.Metadata.Copyright, ProjectURL: p.Metadata.ProjectURL, RepositoryURL: p.Metadata.Repository.URL, - LicenseURL: p.Metadata.LicenseURL, - IconURL: p.Metadata.IconURL, - MinClientVersion: p.Metadata.MinClientVersion, - Tags: p.Metadata.Tags, - DevelopmentDependency: p.Metadata.DevelopmentDependency, RequireLicenseAcceptance: p.Metadata.RequireLicenseAcceptance, Dependencies: make(map[string][]Dependency), } diff --git a/modules/packages/nuget/metadata_test.go b/modules/packages/nuget/metadata_test.go index 8a34f1a5ae..f466492f8a 100644 --- a/modules/packages/nuget/metadata_test.go +++ b/modules/packages/nuget/metadata_test.go @@ -9,26 +9,17 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( - id = "System.Forgejo" - title = "Package Title" - language = "Package Language" + id = "System.Gitea" semver = "1.0.1" - authors = "Forgejo Authors" - owners = "Package Owners" - copyright = "Package Copyright" - projectURL = "https://forgejo.org" - licenseURL = "https://forgejo.org/docs/latest/license/" - iconURL = "https://codeberg.org/forgejo/governance/raw/branch/main/branding/logo/forgejo.png" + authors = "Gitea Authors" + projectURL = "https://gitea.io" description = "Package Description" releaseNotes = "Package Release Notes" readme = "Readme" - tags = "tag_1 tag_2 tag_3" - minClientVersion = "1.0.0.0" - repositoryURL = "https://codeberg.org/forgejo" + repositoryURL = "https://gitea.io/gitea/gitea" targetFramework = ".NETStandard2.1" dependencyID = "System.Text.Json" dependencyVersion = "5.0.0" @@ -36,24 +27,16 @@ const ( const nuspecContent = ` - + ` + id + ` - ` + title + ` - ` + language + ` ` + semver + ` ` + authors + ` - ` + owners + ` - ` + copyright + ` - true true ` + projectURL + ` - ` + licenseURL + ` - ` + iconURL + ` ` + description + ` ` + releaseNotes + ` README.md - ` + tags + ` @@ -94,7 +77,7 @@ func TestParsePackageMetaData(t *testing.T) { np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) - require.ErrorIs(t, err, ErrMissingNuspecFile) + assert.ErrorIs(t, err, ErrMissingNuspecFile) }) t.Run("MissingNuspecFileInRoot", func(t *testing.T) { @@ -102,7 +85,7 @@ func TestParsePackageMetaData(t *testing.T) { np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) - require.ErrorIs(t, err, ErrMissingNuspecFile) + assert.ErrorIs(t, err, ErrMissingNuspecFile) }) t.Run("InvalidNuspecFile", func(t *testing.T) { @@ -110,7 +93,7 @@ func TestParsePackageMetaData(t *testing.T) { np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) - require.Error(t, err) + assert.Error(t, err) }) t.Run("InvalidPackageId", func(t *testing.T) { @@ -121,7 +104,7 @@ func TestParsePackageMetaData(t *testing.T) { np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) - require.ErrorIs(t, err, ErrNuspecInvalidID) + assert.ErrorIs(t, err, ErrNuspecInvalidID) }) t.Run("InvalidPackageVersion", func(t *testing.T) { @@ -134,14 +117,14 @@ func TestParsePackageMetaData(t *testing.T) { np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) - require.ErrorIs(t, err, ErrNuspecInvalidVersion) + assert.ErrorIs(t, err, ErrNuspecInvalidVersion) }) t.Run("MissingReadme", func(t *testing.T) { data := createArchive(map[string]string{"package.nuspec": nuspecContent}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, np) assert.Empty(t, np.Metadata.Readme) }) @@ -153,27 +136,17 @@ func TestParsePackageMetaData(t *testing.T) { }) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, DependencyPackage, np.PackageType) assert.Equal(t, id, np.ID) - assert.Equal(t, title, np.Metadata.Title) - assert.Equal(t, language, np.Metadata.Language) assert.Equal(t, semver, np.Version) assert.Equal(t, authors, np.Metadata.Authors) - assert.Equal(t, owners, np.Metadata.Owners) - assert.Equal(t, copyright, np.Metadata.Copyright) - assert.True(t, np.Metadata.DevelopmentDependency) - assert.True(t, np.Metadata.RequireLicenseAcceptance) assert.Equal(t, projectURL, np.Metadata.ProjectURL) - assert.Equal(t, licenseURL, np.Metadata.LicenseURL) - assert.Equal(t, iconURL, np.Metadata.IconURL) assert.Equal(t, description, np.Metadata.Description) assert.Equal(t, releaseNotes, np.Metadata.ReleaseNotes) assert.Equal(t, readme, np.Metadata.Readme) - assert.Equal(t, tags, np.Metadata.Tags) - assert.Equal(t, minClientVersion, np.Metadata.MinClientVersion) assert.Equal(t, repositoryURL, np.Metadata.RepositoryURL) assert.Len(t, np.Metadata.Dependencies, 1) assert.Contains(t, np.Metadata.Dependencies, targetFramework) @@ -192,7 +165,7 @@ func TestParsePackageMetaData(t *testing.T) { `}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, "1.4.5.2-rc.1", np.Version) }) @@ -202,7 +175,7 @@ func TestParsePackageMetaData(t *testing.T) { data := createArchive(map[string]string{"package.nuspec": symbolsNuspecContent}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, SymbolsPackage, np.PackageType) diff --git a/modules/packages/nuget/symbol_extractor.go b/modules/packages/nuget/symbol_extractor.go index 992ade7e8f..81bf0371a0 100644 --- a/modules/packages/nuget/symbol_extractor.go +++ b/modules/packages/nuget/symbol_extractor.go @@ -13,8 +13,8 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/packages" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/util" ) var ( diff --git a/modules/packages/nuget/symbol_extractor_test.go b/modules/packages/nuget/symbol_extractor_test.go index b767ed0387..fa1b80ee82 100644 --- a/modules/packages/nuget/symbol_extractor_test.go +++ b/modules/packages/nuget/symbol_extractor_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const pdbContent = `QlNKQgEAAQAAAAAADAAAAFBEQiB2MS4wAAAAAAAABgB8AAAAWAAAACNQZGIAAAAA1AAAAAgBAAAj @@ -32,7 +31,7 @@ func TestExtractPortablePdb(t *testing.T) { zip.NewWriter(&buf).Close() pdbs, err := ExtractPortablePdb(bytes.NewReader(buf.Bytes()), int64(buf.Len())) - require.ErrorIs(t, err, ErrMissingPdbFiles) + assert.ErrorIs(t, err, ErrMissingPdbFiles) assert.Empty(t, pdbs) }) @@ -40,7 +39,7 @@ func TestExtractPortablePdb(t *testing.T) { data := createArchive("sub/test.bin", []byte{}) pdbs, err := ExtractPortablePdb(bytes.NewReader(data), int64(len(data))) - require.ErrorIs(t, err, ErrInvalidFiles) + assert.ErrorIs(t, err, ErrInvalidFiles) assert.Empty(t, pdbs) }) @@ -49,7 +48,7 @@ func TestExtractPortablePdb(t *testing.T) { data := createArchive("test.pdb", b) pdbs, err := ExtractPortablePdb(bytes.NewReader(data), int64(len(data))) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, pdbs, 1) assert.Equal(t, "test.pdb", pdbs[0].Name) assert.Equal(t, "d910bb6948bd4c6cb40155bcf52c3c94", pdbs[0].ID) @@ -60,7 +59,7 @@ func TestExtractPortablePdb(t *testing.T) { func TestParseDebugHeaderID(t *testing.T) { t.Run("InvalidPdbMagicNumber", func(t *testing.T) { id, err := ParseDebugHeaderID(bytes.NewReader([]byte{0, 0, 0, 0})) - require.ErrorIs(t, err, ErrInvalidPdbMagicNumber) + assert.ErrorIs(t, err, ErrInvalidPdbMagicNumber) assert.Empty(t, id) }) @@ -68,7 +67,7 @@ func TestParseDebugHeaderID(t *testing.T) { b, _ := base64.StdEncoding.DecodeString(`QlNKQgEAAQAAAAAADAAAAFBEQiB2MS4wAAAAAAAAAQB8AAAAWAAAACNVUwA=`) id, err := ParseDebugHeaderID(bytes.NewReader(b)) - require.ErrorIs(t, err, ErrMissingPdbStream) + assert.ErrorIs(t, err, ErrMissingPdbStream) assert.Empty(t, id) }) @@ -76,7 +75,7 @@ func TestParseDebugHeaderID(t *testing.T) { b, _ := base64.StdEncoding.DecodeString(pdbContent) id, err := ParseDebugHeaderID(bytes.NewReader(b)) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "d910bb6948bd4c6cb40155bcf52c3c94", id) }) } diff --git a/modules/packages/pub/metadata.go b/modules/packages/pub/metadata.go index f8afdf7218..afb464e462 100644 --- a/modules/packages/pub/metadata.go +++ b/modules/packages/pub/metadata.go @@ -10,8 +10,8 @@ import ( "regexp" "strings" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" "gopkg.in/yaml.v3" diff --git a/modules/packages/pub/metadata_test.go b/modules/packages/pub/metadata_test.go index 5ed083b952..8f9126e0c9 100644 --- a/modules/packages/pub/metadata_test.go +++ b/modules/packages/pub/metadata_test.go @@ -12,7 +12,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -66,7 +65,7 @@ func TestParsePackage(t *testing.T) { pp, err := ParsePackage(data) assert.Nil(t, pp) - require.ErrorIs(t, err, ErrMissingPubspecFile) + assert.ErrorIs(t, err, ErrMissingPubspecFile) }) t.Run("PubspecFileTooLarge", func(t *testing.T) { @@ -74,7 +73,7 @@ func TestParsePackage(t *testing.T) { pp, err := ParsePackage(data) assert.Nil(t, pp) - require.ErrorIs(t, err, ErrPubspecFileTooLarge) + assert.ErrorIs(t, err, ErrPubspecFileTooLarge) }) t.Run("InvalidPubspecFile", func(t *testing.T) { @@ -82,14 +81,14 @@ func TestParsePackage(t *testing.T) { pp, err := ParsePackage(data) assert.Nil(t, pp) - require.Error(t, err) + assert.Error(t, err) }) t.Run("Valid", func(t *testing.T) { data := createArchive(map[string][]byte{"pubspec.yaml": []byte(pubspecContent)}) pp, err := ParsePackage(data) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, pp) assert.Empty(t, pp.Metadata.Readme) }) @@ -98,7 +97,7 @@ func TestParsePackage(t *testing.T) { data := createArchive(map[string][]byte{"pubspec.yaml": []byte(pubspecContent), "README.md": []byte("readme")}) pp, err := ParsePackage(data) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, pp) assert.Equal(t, "readme", pp.Metadata.Readme) }) @@ -109,7 +108,7 @@ func TestParsePubspecMetadata(t *testing.T) { for _, name := range []string{"123abc", "ab-cd"} { pp, err := ParsePubspecMetadata(strings.NewReader(`name: ` + name)) assert.Nil(t, pp) - require.ErrorIs(t, err, ErrInvalidName) + assert.ErrorIs(t, err, ErrInvalidName) } }) @@ -117,12 +116,12 @@ func TestParsePubspecMetadata(t *testing.T) { pp, err := ParsePubspecMetadata(strings.NewReader(`name: dummy version: invalid`)) assert.Nil(t, pp) - require.ErrorIs(t, err, ErrInvalidVersion) + assert.ErrorIs(t, err, ErrInvalidVersion) }) t.Run("Valid", func(t *testing.T) { pp, err := ParsePubspecMetadata(strings.NewReader(pubspecContent)) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, pp) assert.Equal(t, packageName, pp.Name) diff --git a/modules/packages/rpm/metadata.go b/modules/packages/rpm/metadata.go index 503b7b1a24..f4f78c2cab 100644 --- a/modules/packages/rpm/metadata.go +++ b/modules/packages/rpm/metadata.go @@ -8,10 +8,10 @@ import ( "io" "strings" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/validation" - "code.forgejo.org/forgejo/go-rpmutils" + "github.com/sassoftware/go-rpmutils" ) const ( @@ -78,12 +78,11 @@ type FileMetadata struct { } type Entry struct { - Name string `json:"name" xml:"name,attr"` - Flags string `json:"flags,omitempty" xml:"flags,attr,omitempty"` - AltFlags uint32 `json:"alt_flags,omitempty" xml:"alt_flags,attr,omitempty"` - Version string `json:"version,omitempty" xml:"ver,attr,omitempty"` - Epoch string `json:"epoch,omitempty" xml:"epoch,attr,omitempty"` - Release string `json:"release,omitempty" xml:"rel,attr,omitempty"` + Name string `json:"name" xml:"name,attr"` + Flags string `json:"flags,omitempty" xml:"flags,attr,omitempty"` + Version string `json:"version,omitempty" xml:"ver,attr,omitempty"` + Epoch string `json:"epoch,omitempty" xml:"epoch,attr,omitempty"` + Release string `json:"release,omitempty" xml:"rel,attr,omitempty"` } type File struct { @@ -99,7 +98,7 @@ type Changelog struct { } // ParsePackage parses the RPM package file -func ParsePackage(r io.Reader, repoType string) (*Package, error) { +func ParsePackage(r io.Reader) (*Package, error) { rpm, err := rpmutils.ReadRpm(r) if err != nil { return nil, err @@ -139,10 +138,10 @@ func ParsePackage(r io.Reader, repoType string) (*Package, error) { InstalledSize: getUInt64(rpm.Header, rpmutils.SIZE), ArchiveSize: getUInt64(rpm.Header, rpmutils.SIG_PAYLOADSIZE), - Provides: getEntries(rpm.Header, rpmutils.PROVIDENAME, rpmutils.PROVIDEVERSION, rpmutils.PROVIDEFLAGS, repoType), - Requires: getEntries(rpm.Header, rpmutils.REQUIRENAME, rpmutils.REQUIREVERSION, rpmutils.REQUIREFLAGS, repoType), - Conflicts: getEntries(rpm.Header, rpmutils.CONFLICTNAME, rpmutils.CONFLICTVERSION, rpmutils.CONFLICTFLAGS, repoType), - Obsoletes: getEntries(rpm.Header, rpmutils.OBSOLETENAME, rpmutils.OBSOLETEVERSION, rpmutils.OBSOLETEFLAGS, repoType), + Provides: getEntries(rpm.Header, rpmutils.PROVIDENAME, rpmutils.PROVIDEVERSION, rpmutils.PROVIDEFLAGS), + Requires: getEntries(rpm.Header, rpmutils.REQUIRENAME, rpmutils.REQUIREVERSION, rpmutils.REQUIREFLAGS), + Conflicts: getEntries(rpm.Header, rpmutils.CONFLICTNAME, rpmutils.CONFLICTVERSION, rpmutils.CONFLICTFLAGS), + Obsoletes: getEntries(rpm.Header, rpmutils.OBSOLETENAME, rpmutils.OBSOLETEVERSION, rpmutils.OBSOLETEFLAGS), Files: getFiles(rpm.Header), Changelogs: getChangelogs(rpm.Header), }, @@ -171,7 +170,7 @@ func getUInt64(h *rpmutils.RpmHeader, tag int) uint64 { return values[0] } -func getEntries(h *rpmutils.RpmHeader, namesTag, versionsTag, flagsTag int, repoType string) []*Entry { +func getEntries(h *rpmutils.RpmHeader, namesTag, versionsTag, flagsTag int) []*Entry { names, err := h.GetStrings(namesTag) if err != nil || len(names) == 0 { return nil @@ -189,55 +188,43 @@ func getEntries(h *rpmutils.RpmHeader, namesTag, versionsTag, flagsTag int, repo } entries := make([]*Entry, 0, len(names)) - - switch repoType { - case "rpm": - for i := range names { - e := &Entry{ - Name: names[i], - } - - flags := flags[i] - if (flags&rpmutils.RPMSENSE_GREATER) != 0 && (flags&rpmutils.RPMSENSE_EQUAL) != 0 { - e.Flags = "GE" - } else if (flags&rpmutils.RPMSENSE_LESS) != 0 && (flags&rpmutils.RPMSENSE_EQUAL) != 0 { - e.Flags = "LE" - } else if (flags & rpmutils.RPMSENSE_GREATER) != 0 { - e.Flags = "GT" - } else if (flags & rpmutils.RPMSENSE_LESS) != 0 { - e.Flags = "LT" - } else if (flags & rpmutils.RPMSENSE_EQUAL) != 0 { - e.Flags = "EQ" - } - - version := versions[i] - if version != "" { - parts := strings.Split(version, "-") - - versionParts := strings.Split(parts[0], ":") - if len(versionParts) == 2 { - e.Version = versionParts[1] - e.Epoch = versionParts[0] - } else { - e.Version = versionParts[0] - e.Epoch = "0" - } - - if len(parts) > 1 { - e.Release = parts[1] - } - } - entries = append(entries, e) + for i := range names { + e := &Entry{ + Name: names[i], } - case "alt": - for i := range names { - e := &Entry{ - Name: names[i], - AltFlags: uint32(flags[i]), - Version: versions[i], - } - entries = append(entries, e) + + flags := flags[i] + if (flags&rpmutils.RPMSENSE_GREATER) != 0 && (flags&rpmutils.RPMSENSE_EQUAL) != 0 { + e.Flags = "GE" + } else if (flags&rpmutils.RPMSENSE_LESS) != 0 && (flags&rpmutils.RPMSENSE_EQUAL) != 0 { + e.Flags = "LE" + } else if (flags & rpmutils.RPMSENSE_GREATER) != 0 { + e.Flags = "GT" + } else if (flags & rpmutils.RPMSENSE_LESS) != 0 { + e.Flags = "LT" + } else if (flags & rpmutils.RPMSENSE_EQUAL) != 0 { + e.Flags = "EQ" } + + version := versions[i] + if version != "" { + parts := strings.Split(version, "-") + + versionParts := strings.Split(parts[0], ":") + if len(versionParts) == 2 { + e.Version = versionParts[1] + e.Epoch = versionParts[0] + } else { + e.Version = versionParts[0] + e.Epoch = "0" + } + + if len(parts) > 1 { + e.Release = parts[1] + } + } + + entries = append(entries, e) } return entries } diff --git a/modules/packages/rpm/metadata_test.go b/modules/packages/rpm/metadata_test.go index 05f53ea446..bb538ef9d0 100644 --- a/modules/packages/rpm/metadata_test.go +++ b/modules/packages/rpm/metadata_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestParsePackage(t *testing.T) { @@ -43,14 +42,14 @@ Mu0UFYgZ/bYnuvn/vz4wtCz8qMwsHUvP0PX3tbYFUctAPdrY6tiiDtcCddDECahx7SuVNP5dpmb5 7tpp/pEjDS7cGPZ6BY430+7danDq6f42Nw49b9F7zp6BiKpJb9s5P0AYN2+L159cnrur636rx+v1 7ae1K28QbMMcqI8CqwIrgwg9nTOp8Oj9q81plUY7ZuwXN8Vvs8wbAAA=` rpmPackageContent, err := base64.StdEncoding.DecodeString(base64RpmPackageContent) - require.NoError(t, err) + assert.NoError(t, err) zr, err := gzip.NewReader(bytes.NewReader(rpmPackageContent)) - require.NoError(t, err) + assert.NoError(t, err) - p, err := ParsePackage(zr, "rpm") + p, err := ParsePackage(zr) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "gitea-test", p.Name) assert.Equal(t, "1.0.2-1", p.Version) diff --git a/modules/packages/rubygems/marshal.go b/modules/packages/rubygems/marshal.go index 191efc7c0e..4e6a5fc5f8 100644 --- a/modules/packages/rubygems/marshal.go +++ b/modules/packages/rubygems/marshal.go @@ -9,7 +9,7 @@ import ( "io" "reflect" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) const ( diff --git a/modules/packages/rubygems/marshal_test.go b/modules/packages/rubygems/marshal_test.go index 8aa9160e20..6d2354cd87 100644 --- a/modules/packages/rubygems/marshal_test.go +++ b/modules/packages/rubygems/marshal_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMinimalEncoder(t *testing.T) { @@ -93,7 +92,7 @@ func TestMinimalEncoder(t *testing.T) { for i, c := range cases { var b bytes.Buffer err := NewMarshalEncoder(&b).Encode(c.Value) - require.ErrorIs(t, err, c.Error) + assert.ErrorIs(t, err, c.Error) assert.Equal(t, c.Expected, b.Bytes(), "case %d", i) } } diff --git a/modules/packages/rubygems/metadata.go b/modules/packages/rubygems/metadata.go index 6d021a17ab..8a9794860e 100644 --- a/modules/packages/rubygems/metadata.go +++ b/modules/packages/rubygems/metadata.go @@ -10,8 +10,8 @@ import ( "regexp" "strings" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "gopkg.in/yaml.v3" ) diff --git a/modules/packages/rubygems/metadata_test.go b/modules/packages/rubygems/metadata_test.go index cd3a5bbd10..ec2fa08b6b 100644 --- a/modules/packages/rubygems/metadata_test.go +++ b/modules/packages/rubygems/metadata_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestParsePackageMetaData(t *testing.T) { @@ -33,7 +32,7 @@ func TestParsePackageMetaData(t *testing.T) { data := createArchive("dummy.txt", []byte{0}) rp, err := ParsePackageMetaData(data) - require.ErrorIs(t, err, ErrMissingMetadataFile) + assert.ErrorIs(t, err, ErrMissingMetadataFile) assert.Nil(t, rp) }) @@ -42,7 +41,7 @@ func TestParsePackageMetaData(t *testing.T) { data := createArchive("metadata.gz", content) rp, err := ParsePackageMetaData(data) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, rp) }) } @@ -59,7 +58,7 @@ dVoR6hj07u0HZgAl3SRS8G/fmXcRK20jyq6rDMSYQFgidamqkXbbuspLXE/0k7GphtKqe67GuRC/ yjAbmt9LsOMp8xMamFkSQ38fP5EFjdz8LA4do2C69VvqWXAJgrPbKZb58/xZXrKoW6ttW13Bhvzi 4ftn7/yUxd4YGcglvTmmY8aGY3ZwRn4CqcWcidUGAAA=`) rp, err := parseMetadataFile(bytes.NewReader(content)) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, rp) assert.Equal(t, "gitea", rp.Name) diff --git a/modules/packages/swift/metadata.go b/modules/packages/swift/metadata.go index 34fc4f1784..24c4262ab7 100644 --- a/modules/packages/swift/metadata.go +++ b/modules/packages/swift/metadata.go @@ -11,9 +11,9 @@ import ( "regexp" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" ) diff --git a/modules/packages/swift/metadata_test.go b/modules/packages/swift/metadata_test.go index b223d8c15f..3913c2355b 100644 --- a/modules/packages/swift/metadata_test.go +++ b/modules/packages/swift/metadata_test.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -40,7 +39,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data, data.Size(), nil) assert.Nil(t, p) - require.ErrorIs(t, err, ErrMissingManifestFile) + assert.ErrorIs(t, err, ErrMissingManifestFile) }) t.Run("ManifestFileTooLarge", func(t *testing.T) { @@ -50,7 +49,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data, data.Size(), nil) assert.Nil(t, p) - require.ErrorIs(t, err, ErrManifestFileTooLarge) + assert.ErrorIs(t, err, ErrManifestFileTooLarge) }) t.Run("WithoutMetadata", func(t *testing.T) { @@ -64,7 +63,7 @@ func TestParsePackage(t *testing.T) { p, err := ParsePackage(data, data.Size(), nil) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, p.Metadata) assert.Empty(t, p.RepositoryURLs) @@ -88,7 +87,7 @@ func TestParsePackage(t *testing.T) { strings.NewReader(`{"name":"`+packageName+`","version":"`+packageVersion+`","description":"`+packageDescription+`","keywords":["swift","package"],"license":"`+packageLicense+`","codeRepository":"`+packageRepositoryURL+`","author":{"givenName":"`+packageAuthor+`"},"repositoryURLs":["`+packageRepositoryURL+`"]}`), ) assert.NotNil(t, p) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, p.Metadata) assert.Len(t, p.Metadata.Manifests, 1) diff --git a/modules/packages/vagrant/metadata.go b/modules/packages/vagrant/metadata.go index 24684249b7..6789533339 100644 --- a/modules/packages/vagrant/metadata.go +++ b/modules/packages/vagrant/metadata.go @@ -9,8 +9,8 @@ import ( "io" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/validation" ) const ( diff --git a/modules/packages/vagrant/metadata_test.go b/modules/packages/vagrant/metadata_test.go index f1950685be..d616ffe3d3 100644 --- a/modules/packages/vagrant/metadata_test.go +++ b/modules/packages/vagrant/metadata_test.go @@ -10,10 +10,9 @@ import ( "io" "testing" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -47,7 +46,7 @@ func TestParseMetadataFromBox(t *testing.T) { metadata, err := ParseMetadataFromBox(data) assert.NotNil(t, metadata) - require.NoError(t, err) + assert.NoError(t, err) }) t.Run("Valid", func(t *testing.T) { @@ -57,13 +56,13 @@ func TestParseMetadataFromBox(t *testing.T) { "website": projectURL, "repository": repositoryURL, }) - require.NoError(t, err) + assert.NoError(t, err) data := createArchive(map[string][]byte{"info.json": content}) metadata, err := ParseMetadataFromBox(data) assert.NotNil(t, metadata) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, author, metadata.Author) assert.Equal(t, description, metadata.Description) @@ -78,11 +77,11 @@ func TestParseInfoFile(t *testing.T) { "package": "", "dummy": "", }) - require.NoError(t, err) + assert.NoError(t, err) metadata, err := ParseInfoFile(bytes.NewReader(content)) assert.NotNil(t, metadata) - require.NoError(t, err) + assert.NoError(t, err) assert.Empty(t, metadata.Author) assert.Empty(t, metadata.Description) @@ -97,11 +96,11 @@ func TestParseInfoFile(t *testing.T) { "website": projectURL, "repository": repositoryURL, }) - require.NoError(t, err) + assert.NoError(t, err) metadata, err := ParseInfoFile(bytes.NewReader(content)) assert.NotNil(t, metadata) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, author, metadata.Author) assert.Equal(t, description, metadata.Description) diff --git a/modules/pprof/pprof.go b/modules/pprof/pprof.go index d46790458e..c611c14270 100644 --- a/modules/pprof/pprof.go +++ b/modules/pprof/pprof.go @@ -9,7 +9,7 @@ import ( "runtime" "runtime/pprof" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // DumpMemProfileForUsername dumps a memory profile at pprofDataPath as memprofile__ diff --git a/modules/private/actions.go b/modules/private/actions.go index 8e4b44c226..311a283650 100644 --- a/modules/private/actions.go +++ b/modules/private/actions.go @@ -6,7 +6,7 @@ package private import ( "context" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) type GenerateTokenRequest struct { diff --git a/modules/private/forgejo_actions.go b/modules/private/forgejo_actions.go new file mode 100644 index 0000000000..133d5e253f --- /dev/null +++ b/modules/private/forgejo_actions.go @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT + +package private + +import ( + "context" + + "code.gitea.io/gitea/modules/setting" +) + +type ActionsRunnerRegisterRequest struct { + Token string + Scope string + Labels []string + Name string + Version string +} + +func ActionsRunnerRegister(ctx context.Context, token, scope string, labels []string, name, version string) (string, ResponseExtra) { + reqURL := setting.LocalURL + "api/internal/actions/register" + + req := newInternalRequest(ctx, reqURL, "POST", ActionsRunnerRegisterRequest{ + Token: token, + Scope: scope, + Labels: labels, + Name: name, + Version: version, + }) + + resp, extra := requestJSONResp(req, &ResponseText{}) + return resp.Text, extra +} diff --git a/modules/private/hook.go b/modules/private/hook.go index 2d64c1dec9..93cbcd469d 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -9,10 +9,10 @@ import ( "net/url" "time" - "forgejo.org/modules/git" - "forgejo.org/modules/git/pushoptions" - "forgejo.org/modules/repository" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/git/pushoptions" + "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" ) // Git environment variables diff --git a/modules/private/internal.go b/modules/private/internal.go index 65fddbbe6b..9c330a24a8 100644 --- a/modules/private/internal.go +++ b/modules/private/internal.go @@ -13,11 +13,11 @@ import ( "strings" "time" - "forgejo.org/modules/httplib" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/proxyprotocol" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/httplib" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/proxyprotocol" + "code.gitea.io/gitea/modules/setting" ) // Response is used for internal request response (for user message and error message) diff --git a/modules/private/key.go b/modules/private/key.go index 422ff16d9a..dcd1714856 100644 --- a/modules/private/key.go +++ b/modules/private/key.go @@ -7,7 +7,7 @@ import ( "context" "fmt" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // UpdatePublicKeyInRepo update public key and if necessary deploy key updates diff --git a/modules/private/mail.go b/modules/private/mail.go index f6054f9c74..08de5b7e28 100644 --- a/modules/private/mail.go +++ b/modules/private/mail.go @@ -6,7 +6,7 @@ package private import ( "context" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // Email structure holds a data for sending general emails diff --git a/modules/private/manager.go b/modules/private/manager.go index fa2e0b0d40..6055e553bd 100644 --- a/modules/private/manager.go +++ b/modules/private/manager.go @@ -12,7 +12,7 @@ import ( "strconv" "time" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // Shutdown calls the internal shutdown function diff --git a/modules/private/request.go b/modules/private/request.go index b80167adb6..58cd261239 100644 --- a/modules/private/request.go +++ b/modules/private/request.go @@ -8,8 +8,8 @@ import ( "io" "net/http" - "forgejo.org/modules/httplib" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/httplib" + "code.gitea.io/gitea/modules/json" ) // ResponseText is used to get the response as text, instead of parsing it as JSON. diff --git a/modules/private/restore_repo.go b/modules/private/restore_repo.go index 2192d3048d..496209d3cb 100644 --- a/modules/private/restore_repo.go +++ b/modules/private/restore_repo.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // RestoreParams structure holds a data for restore repository diff --git a/modules/private/serv.go b/modules/private/serv.go index af4a016cb8..6c7c753cf0 100644 --- a/modules/private/serv.go +++ b/modules/private/serv.go @@ -8,10 +8,10 @@ import ( "fmt" "net/url" - asymkey_model "forgejo.org/models/asymkey" - "forgejo.org/models/perm" - user_model "forgejo.org/models/user" - "forgejo.org/modules/setting" + asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/models/perm" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" ) // KeyAndOwner is the response from ServNoCommand diff --git a/modules/process/manager.go b/modules/process/manager.go index 062ee1482f..37098ad92f 100644 --- a/modules/process/manager.go +++ b/modules/process/manager.go @@ -7,7 +7,6 @@ package process import ( "context" "runtime/pprof" - "runtime/trace" "strconv" "sync" "sync/atomic" @@ -127,27 +126,6 @@ func (pm *Manager) AddTypedContext(parent context.Context, description, processT return ctx, cancel, finished } -// AddTypedContextTimeout creates a new context and adds it as a process. Once the process is finished, finished must be called -// to remove the process from the process table. It should not be called until the process is finished but must always be called. -// -// cancel should be used to cancel the returned context, however it will not remove the process from the process table. -// finished will cancel the returned context and remove it from the process table. -// -// Most processes will not need to use the cancel function but there will be cases whereby you want to cancel the process but not immediately remove it from the -// process table. -func (pm *Manager) AddTypedContextTimeout(parent context.Context, timeout time.Duration, description, processType string, currentlyRunning bool) (ctx context.Context, cancel context.CancelFunc, finished FinishedFunc) { - if timeout <= 0 { - // it's meaningless to use timeout <= 0, and it must be a bug! so we must panic here to tell developers to make the timeout correct - panic("the timeout must be greater than zero, otherwise the context will be cancelled immediately") - } - - ctx, cancel = context.WithTimeout(parent, timeout) - - ctx, _, finished = pm.Add(ctx, description, cancel, processType, currentlyRunning) - - return ctx, cancel, finished -} - // AddContextTimeout creates a new context and add it as a process. Once the process is finished, finished must be called // to remove the process from the process table. It should not be called until the process is finished but must always be called. // @@ -157,7 +135,16 @@ func (pm *Manager) AddTypedContextTimeout(parent context.Context, timeout time.D // Most processes will not need to use the cancel function but there will be cases whereby you want to cancel the process but not immediately remove it from the // process table. func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Duration, description string) (ctx context.Context, cancel context.CancelFunc, finished FinishedFunc) { - return pm.AddTypedContextTimeout(parent, timeout, description, NormalProcessType, true) + if timeout <= 0 { + // it's meaningless to use timeout <= 0, and it must be a bug! so we must panic here to tell developers to make the timeout correct + panic("the timeout must be greater than zero, otherwise the context will be cancelled immediately") + } + + ctx, cancel = context.WithTimeout(parent, timeout) + + ctx, _, finished = pm.Add(ctx, description, cancel, NormalProcessType, true) + + return ctx, cancel, finished } // Add create a new process @@ -172,8 +159,6 @@ func (pm *Manager) Add(ctx context.Context, description string, cancel context.C parentPID = "" } - ctx, traceTask := trace.NewTask(ctx, processType) - process := &process{ PID: pid, ParentPID: parentPID, @@ -181,7 +166,6 @@ func (pm *Manager) Add(ctx context.Context, description string, cancel context.C Start: start, Cancel: cancel, Type: processType, - TraceTrask: traceTask, } var finished FinishedFunc @@ -234,7 +218,6 @@ func (pm *Manager) nextPID() (start time.Time, pid IDType) { } func (pm *Manager) remove(process *process) { - process.TraceTrask.End() deleted := false pm.mutex.Lock() diff --git a/modules/process/manager_stacktraces.go b/modules/process/manager_stacktraces.go index a603e6a9f2..e260893113 100644 --- a/modules/process/manager_stacktraces.go +++ b/modules/process/manager_stacktraces.go @@ -4,8 +4,8 @@ package process import ( - "bytes" "fmt" + "io" "runtime/pprof" "sort" "time" @@ -175,12 +175,13 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int // Now from within the lock we need to get the goroutines. // Why? If we release the lock then between between filling the above map and getting // the stacktraces another process could be created which would then look like a dead process below - var buf bytes.Buffer - if err := pprof.Lookup("goroutine").WriteTo(&buf, 0); err != nil { - return nil, 0, 0, err - } - - stacks, err = profile.ParseData(buf.Bytes()) + reader, writer := io.Pipe() + defer reader.Close() + go func() { + err := pprof.Lookup("goroutine").WriteTo(writer, 0) + _ = writer.CloseWithError(err) + }() + stacks, err = profile.Parse(reader) if err != nil { return nil, 0, 0, err } diff --git a/modules/process/manager_stacktraces_test.go b/modules/process/manager_stacktraces_test.go deleted file mode 100644 index 936fab40d8..0000000000 --- a/modules/process/manager_stacktraces_test.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package process - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestProcessStacktraces(t *testing.T) { - _, _, finish := GetManager().AddContext(t.Context(), "Normal process") - defer finish() - parentCtx, _, finish := GetManager().AddContext(t.Context(), "Children normal process") - defer finish() - _, _, finish = GetManager().AddContext(parentCtx, "Children process") - defer finish() - _, _, finish = GetManager().AddTypedContext(t.Context(), "System process", SystemProcessType, true) - defer finish() - - t.Run("No flat with no system process", func(t *testing.T) { - processes, processCount, _, err := GetManager().ProcessStacktraces(false, true) - require.NoError(t, err) - assert.Equal(t, 4, processCount) - assert.Len(t, processes, 2) - - assert.Equal(t, "Children normal process", processes[0].Description) - assert.Equal(t, NormalProcessType, processes[0].Type) - assert.Empty(t, processes[0].ParentPID) - assert.Len(t, processes[0].Children, 1) - - assert.Equal(t, "Children process", processes[0].Children[0].Description) - assert.Equal(t, processes[0].PID, processes[0].Children[0].ParentPID) - - assert.Equal(t, "Normal process", processes[1].Description) - assert.Equal(t, NormalProcessType, processes[1].Type) - assert.Empty(t, processes[1].ParentPID) - assert.Empty(t, processes[1].Children) - }) - - t.Run("Flat with no system process", func(t *testing.T) { - processes, processCount, _, err := GetManager().ProcessStacktraces(true, true) - require.NoError(t, err) - assert.Equal(t, 4, processCount) - assert.Len(t, processes, 3) - - assert.Equal(t, "Children process", processes[0].Description) - assert.Equal(t, NormalProcessType, processes[0].Type) - assert.Equal(t, processes[1].PID, processes[0].ParentPID) - assert.Empty(t, processes[0].Children) - - assert.Equal(t, "Children normal process", processes[1].Description) - assert.Equal(t, NormalProcessType, processes[1].Type) - assert.Empty(t, processes[1].ParentPID) - assert.Empty(t, processes[1].Children) - - assert.Equal(t, "Normal process", processes[2].Description) - assert.Equal(t, NormalProcessType, processes[2].Type) - assert.Empty(t, processes[2].ParentPID) - assert.Empty(t, processes[2].Children) - }) - - t.Run("System process", func(t *testing.T) { - processes, processCount, _, err := GetManager().ProcessStacktraces(false, false) - require.NoError(t, err) - assert.Equal(t, 4, processCount) - assert.Len(t, processes, 4) - - assert.Equal(t, "System process", processes[0].Description) - assert.Equal(t, SystemProcessType, processes[0].Type) - assert.Empty(t, processes[0].ParentPID) - assert.Empty(t, processes[0].Children) - - assert.Equal(t, "Children normal process", processes[1].Description) - assert.Equal(t, NormalProcessType, processes[1].Type) - assert.Empty(t, processes[1].ParentPID) - assert.Len(t, processes[1].Children, 1) - - assert.Equal(t, "Normal process", processes[2].Description) - assert.Equal(t, NormalProcessType, processes[2].Type) - assert.Empty(t, processes[2].ParentPID) - assert.Empty(t, processes[2].Children) - - // This is the "main" pid, testing code always runs in a goroutine. - assert.Equal(t, "(unassociated)", processes[3].Description) - assert.Equal(t, NoneProcessType, processes[3].Type) - assert.Empty(t, processes[3].ParentPID) - assert.Empty(t, processes[3].Children) - }) -} diff --git a/modules/process/manager_test.go b/modules/process/manager_test.go index 0d637c8acc..36b2a912ea 100644 --- a/modules/process/manager_test.go +++ b/modules/process/manager_test.go @@ -23,7 +23,7 @@ func TestGetManager(t *testing.T) { func TestManager_AddContext(t *testing.T) { pm := Manager{processMap: make(map[IDType]*process), next: 1} - ctx, cancel := context.WithCancel(t.Context()) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() p1Ctx, _, finished := pm.AddContext(ctx, "foo") @@ -42,7 +42,7 @@ func TestManager_AddContext(t *testing.T) { func TestManager_Cancel(t *testing.T) { pm := Manager{processMap: make(map[IDType]*process), next: 1} - ctx, _, finished := pm.AddContext(t.Context(), "foo") + ctx, _, finished := pm.AddContext(context.Background(), "foo") defer finished() pm.Cancel(GetPID(ctx)) @@ -54,7 +54,7 @@ func TestManager_Cancel(t *testing.T) { } finished() - ctx, cancel, finished := pm.AddContext(t.Context(), "foo") + ctx, cancel, finished := pm.AddContext(context.Background(), "foo") defer finished() cancel() @@ -70,7 +70,7 @@ func TestManager_Cancel(t *testing.T) { func TestManager_Remove(t *testing.T) { pm := Manager{processMap: make(map[IDType]*process), next: 1} - ctx, cancel := context.WithCancel(t.Context()) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() p1Ctx, _, finished := pm.AddContext(ctx, "foo") diff --git a/modules/process/manager_unix.go b/modules/process/manager_unix.go index 54dd6dc485..c5be906b35 100644 --- a/modules/process/manager_unix.go +++ b/modules/process/manager_unix.go @@ -1,6 +1,8 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT +//go:build !windows + package process import ( diff --git a/modules/process/manager_windows.go b/modules/process/manager_windows.go new file mode 100644 index 0000000000..44a84f2203 --- /dev/null +++ b/modules/process/manager_windows.go @@ -0,0 +1,15 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build windows + +package process + +import ( + "os/exec" +) + +// SetSysProcAttribute sets the common SysProcAttrs for commands +func SetSysProcAttribute(cmd *exec.Cmd) { + // Do nothing +} diff --git a/modules/process/process.go b/modules/process/process.go index 8947eb252f..06a28c4a60 100644 --- a/modules/process/process.go +++ b/modules/process/process.go @@ -5,14 +5,12 @@ package process import ( "context" - "runtime/trace" "time" ) var ( SystemProcessType = "system" RequestProcessType = "request" - GitProcessType = "git" NormalProcessType = "normal" NoneProcessType = "none" ) @@ -25,7 +23,6 @@ type process struct { Start time.Time Cancel context.CancelFunc Type string - TraceTrask *trace.Task } // ToProcess converts a process to a externally usable Process diff --git a/modules/proxy/proxy.go b/modules/proxy/proxy.go index 8c460dba30..1a6bdad7fb 100644 --- a/modules/proxy/proxy.go +++ b/modules/proxy/proxy.go @@ -10,8 +10,8 @@ import ( "strings" "sync" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "github.com/gobwas/glob" ) diff --git a/modules/proxyprotocol/conn.go b/modules/proxyprotocol/conn.go index beac5de120..f437f13683 100644 --- a/modules/proxyprotocol/conn.go +++ b/modules/proxyprotocol/conn.go @@ -14,7 +14,7 @@ import ( "sync" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) var ( diff --git a/modules/public/mime_types.go b/modules/public/mime_types.go index 87ee2854ae..32bdf3bfa2 100644 --- a/modules/public/mime_types.go +++ b/modules/public/mime_types.go @@ -23,11 +23,6 @@ var wellKnownMimeTypesLower = map[string]string{ ".wasm": "application/wasm", ".webp": "image/webp", ".xml": "text/xml; charset=utf-8", - ".glb": "model/gltf-binary", - ".gltf": "model/gltf+json", - ".obj": "model/obj", - ".stl": "model/stl", - ".3mf": "model/3mf", // well, there are some types missing from the builtin list ".txt": "text/plain; charset=utf-8", diff --git a/modules/public/public.go b/modules/public/public.go index a7db5b62e9..abc6b46158 100644 --- a/modules/public/public.go +++ b/modules/public/public.go @@ -6,19 +6,18 @@ package public import ( "bytes" "io" - "io/fs" "net/http" "os" "path" "strings" "time" - "forgejo.org/modules/assetfs" - "forgejo.org/modules/container" - "forgejo.org/modules/httpcache" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/httpcache" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) func CustomAssets() *assetfs.Layer { @@ -60,7 +59,7 @@ func setWellKnownContentType(w http.ResponseWriter, file string) { } } -func handleRequest(w http.ResponseWriter, req *http.Request, fs fs.FS, file string) { +func handleRequest(w http.ResponseWriter, req *http.Request, fs http.FileSystem, file string) { // actually, fs (http.FileSystem) is designed to be a safe interface, relative paths won't bypass its parent directory, it's also fine to do a clean here f, err := fs.Open(util.PathJoinRelX(file)) if err != nil { @@ -87,31 +86,33 @@ func handleRequest(w http.ResponseWriter, req *http.Request, fs fs.FS, file stri return } - serveContent(w, req, fi.Name(), fi.ModTime(), f.(io.ReadSeeker)) + serveContent(w, req, fi, fi.ModTime(), f) } -type ZstdBytesProvider interface { - ZstdBytes() []byte +type GzipBytesProvider interface { + GzipBytes() []byte } // serveContent serve http content -func serveContent(w http.ResponseWriter, req *http.Request, name string, modtime time.Time, content io.ReadSeeker) { - setWellKnownContentType(w, name) +func serveContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modtime time.Time, content io.ReadSeeker) { + setWellKnownContentType(w, fi.Name()) encodings := parseAcceptEncoding(req.Header.Get("Accept-Encoding")) - if encodings.Contains("zstd") { - // If the file was compressed, use the bytes directly. - if compressed, ok := content.(ZstdBytesProvider); ok { - rdZstd := bytes.NewReader(compressed.ZstdBytes()) + if encodings.Contains("gzip") { + // try to provide gzip content directly from bindata (provided by vfsgen۰CompressedFileInfo) + if compressed, ok := fi.(GzipBytesProvider); ok { + rdGzip := bytes.NewReader(compressed.GzipBytes()) + // all gzipped static files (from bindata) are managed by Gitea, so we can make sure every file has the correct ext name + // then we can get the correct Content-Type, we do not need to do http.DetectContentType on the decompressed data if w.Header().Get("Content-Type") == "" { w.Header().Set("Content-Type", "application/octet-stream") } - w.Header().Set("Content-Encoding", "zstd") - httpcache.ServeContentWithCacheControl(w, req, name, modtime, rdZstd) + w.Header().Set("Content-Encoding", "gzip") + httpcache.ServeContentWithCacheControl(w, req, fi.Name(), modtime, rdGzip) return } } - httpcache.ServeContentWithCacheControl(w, req, name, modtime, content) + httpcache.ServeContentWithCacheControl(w, req, fi.Name(), modtime, content) return } diff --git a/modules/public/public_test.go b/modules/public/public_test.go index 4bfbb7ef31..5e4bf5d671 100644 --- a/modules/public/public_test.go +++ b/modules/public/public_test.go @@ -6,7 +6,7 @@ package public import ( "testing" - "forgejo.org/modules/container" + "code.gitea.io/gitea/modules/container" "github.com/stretchr/testify/assert" ) diff --git a/modules/public/serve_dynamic.go b/modules/public/serve_dynamic.go index e5bd89b1cd..a668b17c34 100644 --- a/modules/public/serve_dynamic.go +++ b/modules/public/serve_dynamic.go @@ -6,8 +6,8 @@ package public import ( - "forgejo.org/modules/assetfs" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/setting" ) func BuiltinAssets() *assetfs.Layer { diff --git a/modules/public/serve_static.go b/modules/public/serve_static.go index 148d789bba..e79085021e 100644 --- a/modules/public/serve_static.go +++ b/modules/public/serve_static.go @@ -8,10 +8,12 @@ package public import ( "time" - "forgejo.org/modules/assetfs" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/timeutil" ) +var _ GzipBytesProvider = (*vfsgen۰CompressedFileInfo)(nil) + // GlobalModTime provide a global mod time for embedded asset files func GlobalModTime(filename string) time.Time { return timeutil.GetExecutableModTime() diff --git a/modules/queue/base_channel.go b/modules/queue/base_channel.go index 1be4edf144..d03c72bdae 100644 --- a/modules/queue/base_channel.go +++ b/modules/queue/base_channel.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "forgejo.org/modules/container" + "code.gitea.io/gitea/modules/container" ) var errChannelClosed = errors.New("channel is closed") @@ -120,7 +120,7 @@ func (q *baseChannel) RemoveAll(ctx context.Context) error { q.mu.Lock() defer q.mu.Unlock() - for len(q.c) > 0 { + for q.c != nil && len(q.c) > 0 { <-q.c } diff --git a/modules/queue/base_levelqueue.go b/modules/queue/base_levelqueue.go index 12c805c0be..efc57c9c9c 100644 --- a/modules/queue/base_levelqueue.go +++ b/modules/queue/base_levelqueue.go @@ -7,10 +7,10 @@ import ( "context" "sync/atomic" - "forgejo.org/modules/nosql" - "forgejo.org/modules/queue/lqinternal" + "code.gitea.io/gitea/modules/nosql" + "code.gitea.io/gitea/modules/queue/lqinternal" - "code.forgejo.org/forgejo/levelqueue" + "gitea.com/lunny/levelqueue" "github.com/syndtr/goleveldb/leveldb" ) diff --git a/modules/queue/base_levelqueue_common.go b/modules/queue/base_levelqueue_common.go index 8b4f35c47d..78d3b85a8a 100644 --- a/modules/queue/base_levelqueue_common.go +++ b/modules/queue/base_levelqueue_common.go @@ -11,9 +11,9 @@ import ( "sync" "time" - "forgejo.org/modules/nosql" + "code.gitea.io/gitea/modules/nosql" - "code.forgejo.org/forgejo/levelqueue" + "gitea.com/lunny/levelqueue" "github.com/syndtr/goleveldb/leveldb" ) diff --git a/modules/queue/base_levelqueue_test.go b/modules/queue/base_levelqueue_test.go index 0f02b9f3ee..b881802ca2 100644 --- a/modules/queue/base_levelqueue_test.go +++ b/modules/queue/base_levelqueue_test.go @@ -6,21 +6,20 @@ package queue import ( "testing" - "forgejo.org/modules/queue/lqinternal" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/queue/lqinternal" + "code.gitea.io/gitea/modules/setting" - "code.forgejo.org/forgejo/levelqueue" + "gitea.com/lunny/levelqueue" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/syndtr/goleveldb/leveldb" ) func TestBaseLevelDB(t *testing.T) { _, err := newBaseLevelQueueGeneric(&BaseConfig{ConnStr: "redis://"}, false) - require.ErrorContains(t, err, "invalid leveldb connection string") + assert.ErrorContains(t, err, "invalid leveldb connection string") _, err = newBaseLevelQueueGeneric(&BaseConfig{DataFullDir: "relative"}, false) - require.ErrorContains(t, err, "invalid leveldb data dir") + assert.ErrorContains(t, err, "invalid leveldb data dir") testQueueBasic(t, newBaseLevelQueueSimple, toBaseConfig("baseLevelQueue", setting.QueueSettings{Datadir: t.TempDir() + "/queue-test", Length: 10}), false) testQueueBasic(t, newBaseLevelQueueUnique, toBaseConfig("baseLevelQueueUnique", setting.QueueSettings{ConnStr: "leveldb://" + t.TempDir() + "/queue-test", Length: 10}), true) @@ -30,21 +29,22 @@ func TestCorruptedLevelQueue(t *testing.T) { // sometimes the levelqueue could be in a corrupted state, this test is to make sure it can recover from it dbDir := t.TempDir() + "/levelqueue-test" db, err := leveldb.OpenFile(dbDir, nil) - require.NoError(t, err) - + if !assert.NoError(t, err) { + return + } defer db.Close() - require.NoError(t, db.Put([]byte("other-key"), []byte("other-value"), nil)) + assert.NoError(t, db.Put([]byte("other-key"), []byte("other-value"), nil)) nameQueuePrefix := []byte("queue_name") nameSetPrefix := []byte("set_name") lq, err := levelqueue.NewUniqueQueue(db, nameQueuePrefix, nameSetPrefix, false) - require.NoError(t, err) - require.NoError(t, lq.RPush([]byte("item-1"))) + assert.NoError(t, err) + assert.NoError(t, lq.RPush([]byte("item-1"))) itemKey := lqinternal.QueueItemKeyBytes(nameQueuePrefix, 1) itemValue, err := db.Get(itemKey, nil) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, []byte("item-1"), itemValue) // there should be 5 keys in db: queue low, queue high, 1 queue item, 1 set item, and "other-key" @@ -52,11 +52,11 @@ func TestCorruptedLevelQueue(t *testing.T) { assert.Len(t, keys, 5) // delete the queue item key, to corrupt the queue - require.NoError(t, db.Delete(itemKey, nil)) + assert.NoError(t, db.Delete(itemKey, nil)) // now the queue is corrupted, it never works again _, err = lq.LPop() - require.ErrorIs(t, err, levelqueue.ErrNotFound) - require.NoError(t, lq.Close()) + assert.ErrorIs(t, err, levelqueue.ErrNotFound) + assert.NoError(t, lq.Close()) // remove all the queue related keys to reset the queue lqinternal.RemoveLevelQueueKeys(db, nameQueuePrefix) @@ -68,11 +68,11 @@ func TestCorruptedLevelQueue(t *testing.T) { // re-create a queue from db lq, err = levelqueue.NewUniqueQueue(db, nameQueuePrefix, nameSetPrefix, false) - require.NoError(t, err) - require.NoError(t, lq.RPush([]byte("item-new-1"))) + assert.NoError(t, err) + assert.NoError(t, lq.RPush([]byte("item-new-1"))) // now the queue works again itemValue, err = lq.LPop() - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, []byte("item-new-1"), itemValue) - require.NoError(t, lq.Close()) + assert.NoError(t, lq.Close()) } diff --git a/modules/queue/base_levelqueue_unique.go b/modules/queue/base_levelqueue_unique.go index 91d2e68500..968a4e98d4 100644 --- a/modules/queue/base_levelqueue_unique.go +++ b/modules/queue/base_levelqueue_unique.go @@ -8,10 +8,10 @@ import ( "sync" "sync/atomic" - "forgejo.org/modules/nosql" - "forgejo.org/modules/queue/lqinternal" + "code.gitea.io/gitea/modules/nosql" + "code.gitea.io/gitea/modules/queue/lqinternal" - "code.forgejo.org/forgejo/levelqueue" + "gitea.com/lunny/levelqueue" "github.com/syndtr/goleveldb/leveldb" ) diff --git a/modules/queue/base_redis.go b/modules/queue/base_redis.go index ec3c6dc16d..14931b62cd 100644 --- a/modules/queue/base_redis.go +++ b/modules/queue/base_redis.go @@ -8,15 +8,15 @@ import ( "sync" "time" - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/nosql" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/nosql" "github.com/redis/go-redis/v9" ) type baseRedis struct { - client nosql.RedisClient + client redis.UniversalClient isUnique bool cfg *BaseConfig prefix string @@ -26,7 +26,7 @@ type baseRedis struct { var _ baseQueue = (*baseRedis)(nil) -func newBaseRedisGeneric(cfg *BaseConfig, unique bool, client nosql.RedisClient) (baseQueue, error) { +func newBaseRedisGeneric(cfg *BaseConfig, unique bool, client redis.UniversalClient) (baseQueue, error) { if client == nil { client = nosql.GetManager().GetRedisClient(cfg.ConnStr) } diff --git a/modules/queue/base_redis_test.go b/modules/queue/base_redis_test.go index bf3ad5b97b..04e200c3f7 100644 --- a/modules/queue/base_redis_test.go +++ b/modules/queue/base_redis_test.go @@ -7,8 +7,8 @@ import ( "context" "testing" - "forgejo.org/modules/queue/mock" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/queue/mock" + "code.gitea.io/gitea/modules/setting" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/suite" @@ -72,7 +72,7 @@ func (suite *baseRedisUnitTestSuite) TestBasic() { // Configure expectations. mockRedisStore := mock.NewInMemoryMockRedis() - redisClient := mock.NewMockRedisClient(suite.mockController) + redisClient := mock.NewMockUniversalClient(suite.mockController) redisClient.EXPECT(). Ping(gomock.Any()). diff --git a/modules/queue/base_redis_with_server_test.go b/modules/queue/base_redis_with_server_test.go index e1f552bfb2..b73404f4e5 100644 --- a/modules/queue/base_redis_with_server_test.go +++ b/modules/queue/base_redis_with_server_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "forgejo.org/modules/nosql" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/nosql" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/suite" ) diff --git a/modules/queue/base_test.go b/modules/queue/base_test.go index caa930158c..c5bf526ae6 100644 --- a/modules/queue/base_test.go +++ b/modules/queue/base_test.go @@ -10,90 +10,89 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func testQueueBasic(t *testing.T, newFn func(cfg *BaseConfig) (baseQueue, error), cfg *BaseConfig, isUnique bool) { t.Run(fmt.Sprintf("testQueueBasic-%s-unique:%v", cfg.ManagedName, isUnique), func(t *testing.T) { q, err := newFn(cfg) - require.NoError(t, err) + assert.NoError(t, err) - ctx := t.Context() + ctx := context.Background() _ = q.RemoveAll(ctx) cnt, err := q.Len(ctx) - require.NoError(t, err) - assert.Equal(t, 0, cnt) + assert.NoError(t, err) + assert.EqualValues(t, 0, cnt) // push the first item err = q.PushItem(ctx, []byte("foo")) - require.NoError(t, err) + assert.NoError(t, err) cnt, err = q.Len(ctx) - require.NoError(t, err) - assert.Equal(t, 1, cnt) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) // push a duplicate item err = q.PushItem(ctx, []byte("foo")) if !isUnique { - require.NoError(t, err) + assert.NoError(t, err) } else { - require.ErrorIs(t, err, ErrAlreadyInQueue) + assert.ErrorIs(t, err, ErrAlreadyInQueue) } // check the duplicate item cnt, err = q.Len(ctx) - require.NoError(t, err) + assert.NoError(t, err) has, err := q.HasItem(ctx, []byte("foo")) - require.NoError(t, err) + assert.NoError(t, err) if !isUnique { - assert.Equal(t, 2, cnt) - assert.False(t, has) // non-unique queues don't check for duplicates + assert.EqualValues(t, 2, cnt) + assert.EqualValues(t, false, has) // non-unique queues don't check for duplicates } else { - assert.Equal(t, 1, cnt) - assert.True(t, has) + assert.EqualValues(t, 1, cnt) + assert.EqualValues(t, true, has) } // push another item err = q.PushItem(ctx, []byte("bar")) - require.NoError(t, err) + assert.NoError(t, err) // pop the first item (and the duplicate if non-unique) it, err := q.PopItem(ctx) - require.NoError(t, err) - assert.Equal(t, "foo", string(it)) + assert.NoError(t, err) + assert.EqualValues(t, "foo", string(it)) if !isUnique { it, err = q.PopItem(ctx) - require.NoError(t, err) - assert.Equal(t, "foo", string(it)) + assert.NoError(t, err) + assert.EqualValues(t, "foo", string(it)) } // pop another item it, err = q.PopItem(ctx) - require.NoError(t, err) - assert.Equal(t, "bar", string(it)) + assert.NoError(t, err) + assert.EqualValues(t, "bar", string(it)) // pop an empty queue (timeout, cancel) ctxTimed, cancel := context.WithTimeout(ctx, 10*time.Millisecond) it, err = q.PopItem(ctxTimed) - require.ErrorIs(t, err, context.DeadlineExceeded) + assert.ErrorIs(t, err, context.DeadlineExceeded) assert.Nil(t, it) cancel() ctxTimed, cancel = context.WithTimeout(ctx, 10*time.Millisecond) cancel() it, err = q.PopItem(ctxTimed) - require.ErrorIs(t, err, context.Canceled) + assert.ErrorIs(t, err, context.Canceled) assert.Nil(t, it) // test blocking push if queue is full for i := 0; i < cfg.Length; i++ { err = q.PushItem(ctx, []byte(fmt.Sprintf("item-%d", i))) - require.NoError(t, err) + assert.NoError(t, err) } ctxTimed, cancel = context.WithTimeout(ctx, 10*time.Millisecond) err = q.PushItem(ctxTimed, []byte("item-full")) - require.ErrorIs(t, err, context.DeadlineExceeded) + assert.ErrorIs(t, err, context.DeadlineExceeded) cancel() // test blocking push if queue is full (with custom pushBlockTime) @@ -101,41 +100,41 @@ func testQueueBasic(t *testing.T, newFn func(cfg *BaseConfig) (baseQueue, error) timeStart := time.Now() pushBlockTime = 30 * time.Millisecond err = q.PushItem(ctx, []byte("item-full")) - require.ErrorIs(t, err, context.DeadlineExceeded) - assert.GreaterOrEqual(t, time.Since(timeStart), pushBlockTime*2/3) + assert.ErrorIs(t, err, context.DeadlineExceeded) + assert.True(t, time.Since(timeStart) >= pushBlockTime*2/3) pushBlockTime = oldPushBlockTime // remove all cnt, err = q.Len(ctx) - require.NoError(t, err) - assert.Equal(t, cfg.Length, cnt) + assert.NoError(t, err) + assert.EqualValues(t, cfg.Length, cnt) _ = q.RemoveAll(ctx) cnt, err = q.Len(ctx) - require.NoError(t, err) - assert.Equal(t, 0, cnt) + assert.NoError(t, err) + assert.EqualValues(t, 0, cnt) }) } func TestBaseDummy(t *testing.T) { q, err := newBaseDummy(&BaseConfig{}, true) - require.NoError(t, err) + assert.NoError(t, err) - ctx := t.Context() - require.NoError(t, q.PushItem(ctx, []byte("foo"))) + ctx := context.Background() + assert.NoError(t, q.PushItem(ctx, []byte("foo"))) cnt, err := q.Len(ctx) - require.NoError(t, err) - assert.Equal(t, 0, cnt) + assert.NoError(t, err) + assert.EqualValues(t, 0, cnt) has, err := q.HasItem(ctx, []byte("foo")) - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, has) it, err := q.PopItem(ctx) - require.NoError(t, err) + assert.NoError(t, err) assert.Nil(t, it) - require.NoError(t, q.RemoveAll(ctx)) + assert.NoError(t, q.RemoveAll(ctx)) } diff --git a/modules/queue/config.go b/modules/queue/config.go index f736a5aa12..c5bc16b6f0 100644 --- a/modules/queue/config.go +++ b/modules/queue/config.go @@ -4,7 +4,7 @@ package queue import ( - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) type BaseConfig struct { diff --git a/modules/queue/manager.go b/modules/queue/manager.go index 8f1a93f273..8b964c0c28 100644 --- a/modules/queue/manager.go +++ b/modules/queue/manager.go @@ -8,8 +8,8 @@ import ( "sync" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) // Manager is a manager for the queues created by "CreateXxxQueue" functions, these queues are called "managed queues". diff --git a/modules/queue/manager_test.go b/modules/queue/manager_test.go index fd5d21570c..15dd1b4f2f 100644 --- a/modules/queue/manager_test.go +++ b/modules/queue/manager_test.go @@ -4,18 +4,21 @@ package queue import ( + "context" "path/filepath" "testing" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestManager(t *testing.T) { - defer test.MockVariableValue(&setting.AppDataPath, t.TempDir())() + oldAppDataPath := setting.AppDataPath + setting.AppDataPath = t.TempDir() + defer func() { + setting.AppDataPath = oldAppDataPath + }() newQueueFromConfig := func(name, cfg string) (*WorkerPoolQueue[int], error) { cfgProvider, err := setting.NewConfigProviderFromData(cfg) @@ -35,17 +38,17 @@ func TestManager(t *testing.T) { DATADIR = temp-dir CONN_STR = redis:// `) - require.ErrorContains(t, err, "invalid leveldb connection string") + assert.ErrorContains(t, err, "invalid leveldb connection string") // test default config q, err := newQueueFromConfig("default", "") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "default", q.GetName()) assert.Equal(t, "level", q.GetType()) assert.Equal(t, filepath.Join(setting.AppDataPath, "queues/common"), q.baseConfig.DataFullDir) assert.Equal(t, 100000, q.baseConfig.Length) assert.Equal(t, 20, q.batchLength) - assert.Empty(t, q.baseConfig.ConnStr) + assert.Equal(t, "", q.baseConfig.ConnStr) assert.Equal(t, "default_queue", q.baseConfig.QueueFullName) assert.Equal(t, "default_queue_unique", q.baseConfig.SetFullName) assert.NotZero(t, q.GetWorkerMaxNumber()) @@ -75,9 +78,9 @@ SET_NAME = _u2 MAX_WORKERS = 123 `) - require.NoError(t, err) + assert.NoError(t, err) - q1 := createWorkerPoolQueue[string](t.Context(), "no-such", cfgProvider, nil, false) + q1 := createWorkerPoolQueue[string](context.Background(), "no-such", cfgProvider, nil, false) assert.Equal(t, "no-such", q1.GetName()) assert.Equal(t, "dummy", q1.GetType()) // no handler, so it becomes dummy assert.Equal(t, filepath.Join(setting.AppDataPath, "queues/dir1"), q1.baseConfig.DataFullDir) @@ -93,13 +96,13 @@ MAX_WORKERS = 123 assert.Equal(t, "string", q1.GetItemTypeName()) qid1 := GetManager().qidCounter - q2 := createWorkerPoolQueue(t.Context(), "sub", cfgProvider, func(s ...int) (unhandled []int) { return nil }, false) + q2 := createWorkerPoolQueue(context.Background(), "sub", cfgProvider, func(s ...int) (unhandled []int) { return nil }, false) assert.Equal(t, "sub", q2.GetName()) assert.Equal(t, "level", q2.GetType()) assert.Equal(t, filepath.Join(setting.AppDataPath, "queues/dir2"), q2.baseConfig.DataFullDir) assert.Equal(t, 102, q2.baseConfig.Length) assert.Equal(t, 22, q2.batchLength) - assert.Empty(t, q2.baseConfig.ConnStr) + assert.Equal(t, "", q2.baseConfig.ConnStr) assert.Equal(t, "sub_q2", q2.baseConfig.QueueFullName) assert.Equal(t, "sub_q2_u2", q2.baseConfig.SetFullName) assert.Equal(t, 123, q2.GetWorkerMaxNumber()) @@ -115,7 +118,7 @@ MAX_WORKERS = 123 assert.Equal(t, 120, q1.workerMaxNum) stop := runWorkerPoolQueue(q2) - require.NoError(t, GetManager().GetManagedQueue(qid2).FlushWithContext(t.Context(), 0)) - require.NoError(t, GetManager().FlushAll(t.Context(), 0)) + assert.NoError(t, GetManager().GetManagedQueue(qid2).FlushWithContext(context.Background(), 0)) + assert.NoError(t, GetManager().FlushAll(context.Background(), 0)) stop() } diff --git a/modules/queue/mock/redisuniversalclient.go b/modules/queue/mock/redisuniversalclient.go index a19e639ac1..95e6f6d5a8 100644 --- a/modules/queue/mock/redisuniversalclient.go +++ b/modules/queue/mock/redisuniversalclient.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: forgejo.org/modules/nosql (interfaces: RedisClient) +// Source: github.com/redis/go-redis/v9 (interfaces: UniversalClient) // // Generated by this command: // -// mockgen -package mock -destination ./modules/queue/mock/redisuniversalclient.go forgejo.org/modules/nosql RedisClient +// mockgen -package mock -destination ./modules/queue/mock/redisuniversalclient.go github.com/redis/go-redis/v9 UniversalClient // // Package mock is a generated GoMock package. @@ -18,32 +18,1208 @@ import ( gomock "go.uber.org/mock/gomock" ) -// MockRedisClient is a mock of RedisClient interface. -type MockRedisClient struct { +// MockUniversalClient is a mock of UniversalClient interface. +type MockUniversalClient struct { ctrl *gomock.Controller - recorder *MockRedisClientMockRecorder - isgomock struct{} + recorder *MockUniversalClientMockRecorder } -// MockRedisClientMockRecorder is the mock recorder for MockRedisClient. -type MockRedisClientMockRecorder struct { - mock *MockRedisClient +// MockUniversalClientMockRecorder is the mock recorder for MockUniversalClient. +type MockUniversalClientMockRecorder struct { + mock *MockUniversalClient } -// NewMockRedisClient creates a new mock instance. -func NewMockRedisClient(ctrl *gomock.Controller) *MockRedisClient { - mock := &MockRedisClient{ctrl: ctrl} - mock.recorder = &MockRedisClientMockRecorder{mock} +// NewMockUniversalClient creates a new mock instance. +func NewMockUniversalClient(ctrl *gomock.Controller) *MockUniversalClient { + mock := &MockUniversalClient{ctrl: ctrl} + mock.recorder = &MockUniversalClientMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockRedisClient) EXPECT() *MockRedisClientMockRecorder { +func (m *MockUniversalClient) EXPECT() *MockUniversalClientMockRecorder { return m.recorder } +// ACLDryRun mocks base method. +func (m *MockUniversalClient) ACLDryRun(arg0 context.Context, arg1 string, arg2 ...any) *redis.StringCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ACLDryRun", varargs...) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ACLDryRun indicates an expected call of ACLDryRun. +func (mr *MockUniversalClientMockRecorder) ACLDryRun(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLDryRun", reflect.TypeOf((*MockUniversalClient)(nil).ACLDryRun), varargs...) +} + +// ACLLog mocks base method. +func (m *MockUniversalClient) ACLLog(arg0 context.Context, arg1 int64) *redis.ACLLogCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ACLLog", arg0, arg1) + ret0, _ := ret[0].(*redis.ACLLogCmd) + return ret0 +} + +// ACLLog indicates an expected call of ACLLog. +func (mr *MockUniversalClientMockRecorder) ACLLog(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLLog", reflect.TypeOf((*MockUniversalClient)(nil).ACLLog), arg0, arg1) +} + +// ACLLogReset mocks base method. +func (m *MockUniversalClient) ACLLogReset(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ACLLogReset", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ACLLogReset indicates an expected call of ACLLogReset. +func (mr *MockUniversalClientMockRecorder) ACLLogReset(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLLogReset", reflect.TypeOf((*MockUniversalClient)(nil).ACLLogReset), arg0) +} + +// AddHook mocks base method. +func (m *MockUniversalClient) AddHook(arg0 redis.Hook) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "AddHook", arg0) +} + +// AddHook indicates an expected call of AddHook. +func (mr *MockUniversalClientMockRecorder) AddHook(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddHook", reflect.TypeOf((*MockUniversalClient)(nil).AddHook), arg0) +} + +// Append mocks base method. +func (m *MockUniversalClient) Append(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Append", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// Append indicates an expected call of Append. +func (mr *MockUniversalClientMockRecorder) Append(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Append", reflect.TypeOf((*MockUniversalClient)(nil).Append), arg0, arg1, arg2) +} + +// BFAdd mocks base method. +func (m *MockUniversalClient) BFAdd(arg0 context.Context, arg1 string, arg2 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFAdd", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// BFAdd indicates an expected call of BFAdd. +func (mr *MockUniversalClientMockRecorder) BFAdd(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFAdd", reflect.TypeOf((*MockUniversalClient)(nil).BFAdd), arg0, arg1, arg2) +} + +// BFCard mocks base method. +func (m *MockUniversalClient) BFCard(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFCard", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BFCard indicates an expected call of BFCard. +func (mr *MockUniversalClientMockRecorder) BFCard(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFCard", reflect.TypeOf((*MockUniversalClient)(nil).BFCard), arg0, arg1) +} + +// BFExists mocks base method. +func (m *MockUniversalClient) BFExists(arg0 context.Context, arg1 string, arg2 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFExists", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// BFExists indicates an expected call of BFExists. +func (mr *MockUniversalClientMockRecorder) BFExists(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFExists", reflect.TypeOf((*MockUniversalClient)(nil).BFExists), arg0, arg1, arg2) +} + +// BFInfo mocks base method. +func (m *MockUniversalClient) BFInfo(arg0 context.Context, arg1 string) *redis.BFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFInfo", arg0, arg1) + ret0, _ := ret[0].(*redis.BFInfoCmd) + return ret0 +} + +// BFInfo indicates an expected call of BFInfo. +func (mr *MockUniversalClientMockRecorder) BFInfo(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInfo", reflect.TypeOf((*MockUniversalClient)(nil).BFInfo), arg0, arg1) +} + +// BFInfoArg mocks base method. +func (m *MockUniversalClient) BFInfoArg(arg0 context.Context, arg1, arg2 string) *redis.BFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFInfoArg", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BFInfoCmd) + return ret0 +} + +// BFInfoArg indicates an expected call of BFInfoArg. +func (mr *MockUniversalClientMockRecorder) BFInfoArg(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInfoArg", reflect.TypeOf((*MockUniversalClient)(nil).BFInfoArg), arg0, arg1, arg2) +} + +// BFInfoCapacity mocks base method. +func (m *MockUniversalClient) BFInfoCapacity(arg0 context.Context, arg1 string) *redis.BFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFInfoCapacity", arg0, arg1) + ret0, _ := ret[0].(*redis.BFInfoCmd) + return ret0 +} + +// BFInfoCapacity indicates an expected call of BFInfoCapacity. +func (mr *MockUniversalClientMockRecorder) BFInfoCapacity(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInfoCapacity", reflect.TypeOf((*MockUniversalClient)(nil).BFInfoCapacity), arg0, arg1) +} + +// BFInfoExpansion mocks base method. +func (m *MockUniversalClient) BFInfoExpansion(arg0 context.Context, arg1 string) *redis.BFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFInfoExpansion", arg0, arg1) + ret0, _ := ret[0].(*redis.BFInfoCmd) + return ret0 +} + +// BFInfoExpansion indicates an expected call of BFInfoExpansion. +func (mr *MockUniversalClientMockRecorder) BFInfoExpansion(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInfoExpansion", reflect.TypeOf((*MockUniversalClient)(nil).BFInfoExpansion), arg0, arg1) +} + +// BFInfoFilters mocks base method. +func (m *MockUniversalClient) BFInfoFilters(arg0 context.Context, arg1 string) *redis.BFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFInfoFilters", arg0, arg1) + ret0, _ := ret[0].(*redis.BFInfoCmd) + return ret0 +} + +// BFInfoFilters indicates an expected call of BFInfoFilters. +func (mr *MockUniversalClientMockRecorder) BFInfoFilters(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInfoFilters", reflect.TypeOf((*MockUniversalClient)(nil).BFInfoFilters), arg0, arg1) +} + +// BFInfoItems mocks base method. +func (m *MockUniversalClient) BFInfoItems(arg0 context.Context, arg1 string) *redis.BFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFInfoItems", arg0, arg1) + ret0, _ := ret[0].(*redis.BFInfoCmd) + return ret0 +} + +// BFInfoItems indicates an expected call of BFInfoItems. +func (mr *MockUniversalClientMockRecorder) BFInfoItems(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInfoItems", reflect.TypeOf((*MockUniversalClient)(nil).BFInfoItems), arg0, arg1) +} + +// BFInfoSize mocks base method. +func (m *MockUniversalClient) BFInfoSize(arg0 context.Context, arg1 string) *redis.BFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFInfoSize", arg0, arg1) + ret0, _ := ret[0].(*redis.BFInfoCmd) + return ret0 +} + +// BFInfoSize indicates an expected call of BFInfoSize. +func (mr *MockUniversalClientMockRecorder) BFInfoSize(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInfoSize", reflect.TypeOf((*MockUniversalClient)(nil).BFInfoSize), arg0, arg1) +} + +// BFInsert mocks base method. +func (m *MockUniversalClient) BFInsert(arg0 context.Context, arg1 string, arg2 *redis.BFInsertOptions, arg3 ...any) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BFInsert", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// BFInsert indicates an expected call of BFInsert. +func (mr *MockUniversalClientMockRecorder) BFInsert(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFInsert", reflect.TypeOf((*MockUniversalClient)(nil).BFInsert), varargs...) +} + +// BFLoadChunk mocks base method. +func (m *MockUniversalClient) BFLoadChunk(arg0 context.Context, arg1 string, arg2 int64, arg3 any) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFLoadChunk", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// BFLoadChunk indicates an expected call of BFLoadChunk. +func (mr *MockUniversalClientMockRecorder) BFLoadChunk(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFLoadChunk", reflect.TypeOf((*MockUniversalClient)(nil).BFLoadChunk), arg0, arg1, arg2, arg3) +} + +// BFMAdd mocks base method. +func (m *MockUniversalClient) BFMAdd(arg0 context.Context, arg1 string, arg2 ...any) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BFMAdd", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// BFMAdd indicates an expected call of BFMAdd. +func (mr *MockUniversalClientMockRecorder) BFMAdd(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFMAdd", reflect.TypeOf((*MockUniversalClient)(nil).BFMAdd), varargs...) +} + +// BFMExists mocks base method. +func (m *MockUniversalClient) BFMExists(arg0 context.Context, arg1 string, arg2 ...any) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BFMExists", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// BFMExists indicates an expected call of BFMExists. +func (mr *MockUniversalClientMockRecorder) BFMExists(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFMExists", reflect.TypeOf((*MockUniversalClient)(nil).BFMExists), varargs...) +} + +// BFReserve mocks base method. +func (m *MockUniversalClient) BFReserve(arg0 context.Context, arg1 string, arg2 float64, arg3 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFReserve", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// BFReserve indicates an expected call of BFReserve. +func (mr *MockUniversalClientMockRecorder) BFReserve(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFReserve", reflect.TypeOf((*MockUniversalClient)(nil).BFReserve), arg0, arg1, arg2, arg3) +} + +// BFReserveExpansion mocks base method. +func (m *MockUniversalClient) BFReserveExpansion(arg0 context.Context, arg1 string, arg2 float64, arg3, arg4 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFReserveExpansion", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// BFReserveExpansion indicates an expected call of BFReserveExpansion. +func (mr *MockUniversalClientMockRecorder) BFReserveExpansion(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFReserveExpansion", reflect.TypeOf((*MockUniversalClient)(nil).BFReserveExpansion), arg0, arg1, arg2, arg3, arg4) +} + +// BFReserveNonScaling mocks base method. +func (m *MockUniversalClient) BFReserveNonScaling(arg0 context.Context, arg1 string, arg2 float64, arg3 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFReserveNonScaling", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// BFReserveNonScaling indicates an expected call of BFReserveNonScaling. +func (mr *MockUniversalClientMockRecorder) BFReserveNonScaling(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFReserveNonScaling", reflect.TypeOf((*MockUniversalClient)(nil).BFReserveNonScaling), arg0, arg1, arg2, arg3) +} + +// BFReserveWithArgs mocks base method. +func (m *MockUniversalClient) BFReserveWithArgs(arg0 context.Context, arg1 string, arg2 *redis.BFReserveOptions) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFReserveWithArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// BFReserveWithArgs indicates an expected call of BFReserveWithArgs. +func (mr *MockUniversalClientMockRecorder) BFReserveWithArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFReserveWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).BFReserveWithArgs), arg0, arg1, arg2) +} + +// BFScanDump mocks base method. +func (m *MockUniversalClient) BFScanDump(arg0 context.Context, arg1 string, arg2 int64) *redis.ScanDumpCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BFScanDump", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.ScanDumpCmd) + return ret0 +} + +// BFScanDump indicates an expected call of BFScanDump. +func (mr *MockUniversalClientMockRecorder) BFScanDump(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFScanDump", reflect.TypeOf((*MockUniversalClient)(nil).BFScanDump), arg0, arg1, arg2) +} + +// BLMPop mocks base method. +func (m *MockUniversalClient) BLMPop(arg0 context.Context, arg1 time.Duration, arg2 string, arg3 int64, arg4 ...string) *redis.KeyValuesCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BLMPop", varargs...) + ret0, _ := ret[0].(*redis.KeyValuesCmd) + return ret0 +} + +// BLMPop indicates an expected call of BLMPop. +func (mr *MockUniversalClientMockRecorder) BLMPop(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BLMPop", reflect.TypeOf((*MockUniversalClient)(nil).BLMPop), varargs...) +} + +// BLMove mocks base method. +func (m *MockUniversalClient) BLMove(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 time.Duration) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BLMove", arg0, arg1, arg2, arg3, arg4, arg5) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// BLMove indicates an expected call of BLMove. +func (mr *MockUniversalClientMockRecorder) BLMove(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BLMove", reflect.TypeOf((*MockUniversalClient)(nil).BLMove), arg0, arg1, arg2, arg3, arg4, arg5) +} + +// BLPop mocks base method. +func (m *MockUniversalClient) BLPop(arg0 context.Context, arg1 time.Duration, arg2 ...string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BLPop", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// BLPop indicates an expected call of BLPop. +func (mr *MockUniversalClientMockRecorder) BLPop(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BLPop", reflect.TypeOf((*MockUniversalClient)(nil).BLPop), varargs...) +} + +// BRPop mocks base method. +func (m *MockUniversalClient) BRPop(arg0 context.Context, arg1 time.Duration, arg2 ...string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BRPop", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// BRPop indicates an expected call of BRPop. +func (mr *MockUniversalClientMockRecorder) BRPop(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BRPop", reflect.TypeOf((*MockUniversalClient)(nil).BRPop), varargs...) +} + +// BRPopLPush mocks base method. +func (m *MockUniversalClient) BRPopLPush(arg0 context.Context, arg1, arg2 string, arg3 time.Duration) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BRPopLPush", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// BRPopLPush indicates an expected call of BRPopLPush. +func (mr *MockUniversalClientMockRecorder) BRPopLPush(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BRPopLPush", reflect.TypeOf((*MockUniversalClient)(nil).BRPopLPush), arg0, arg1, arg2, arg3) +} + +// BZMPop mocks base method. +func (m *MockUniversalClient) BZMPop(arg0 context.Context, arg1 time.Duration, arg2 string, arg3 int64, arg4 ...string) *redis.ZSliceWithKeyCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BZMPop", varargs...) + ret0, _ := ret[0].(*redis.ZSliceWithKeyCmd) + return ret0 +} + +// BZMPop indicates an expected call of BZMPop. +func (mr *MockUniversalClientMockRecorder) BZMPop(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BZMPop", reflect.TypeOf((*MockUniversalClient)(nil).BZMPop), varargs...) +} + +// BZPopMax mocks base method. +func (m *MockUniversalClient) BZPopMax(arg0 context.Context, arg1 time.Duration, arg2 ...string) *redis.ZWithKeyCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BZPopMax", varargs...) + ret0, _ := ret[0].(*redis.ZWithKeyCmd) + return ret0 +} + +// BZPopMax indicates an expected call of BZPopMax. +func (mr *MockUniversalClientMockRecorder) BZPopMax(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BZPopMax", reflect.TypeOf((*MockUniversalClient)(nil).BZPopMax), varargs...) +} + +// BZPopMin mocks base method. +func (m *MockUniversalClient) BZPopMin(arg0 context.Context, arg1 time.Duration, arg2 ...string) *redis.ZWithKeyCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BZPopMin", varargs...) + ret0, _ := ret[0].(*redis.ZWithKeyCmd) + return ret0 +} + +// BZPopMin indicates an expected call of BZPopMin. +func (mr *MockUniversalClientMockRecorder) BZPopMin(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BZPopMin", reflect.TypeOf((*MockUniversalClient)(nil).BZPopMin), varargs...) +} + +// BgRewriteAOF mocks base method. +func (m *MockUniversalClient) BgRewriteAOF(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BgRewriteAOF", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// BgRewriteAOF indicates an expected call of BgRewriteAOF. +func (mr *MockUniversalClientMockRecorder) BgRewriteAOF(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BgRewriteAOF", reflect.TypeOf((*MockUniversalClient)(nil).BgRewriteAOF), arg0) +} + +// BgSave mocks base method. +func (m *MockUniversalClient) BgSave(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BgSave", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// BgSave indicates an expected call of BgSave. +func (mr *MockUniversalClientMockRecorder) BgSave(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BgSave", reflect.TypeOf((*MockUniversalClient)(nil).BgSave), arg0) +} + +// BitCount mocks base method. +func (m *MockUniversalClient) BitCount(arg0 context.Context, arg1 string, arg2 *redis.BitCount) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BitCount", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BitCount indicates an expected call of BitCount. +func (mr *MockUniversalClientMockRecorder) BitCount(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitCount", reflect.TypeOf((*MockUniversalClient)(nil).BitCount), arg0, arg1, arg2) +} + +// BitField mocks base method. +func (m *MockUniversalClient) BitField(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BitField", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// BitField indicates an expected call of BitField. +func (mr *MockUniversalClientMockRecorder) BitField(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitField", reflect.TypeOf((*MockUniversalClient)(nil).BitField), varargs...) +} + +// BitFieldRO mocks base method. +func (m *MockUniversalClient) BitFieldRO(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BitFieldRO", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// BitFieldRO indicates an expected call of BitFieldRO. +func (mr *MockUniversalClientMockRecorder) BitFieldRO(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitFieldRO", reflect.TypeOf((*MockUniversalClient)(nil).BitFieldRO), varargs...) +} + +// BitOpAnd mocks base method. +func (m *MockUniversalClient) BitOpAnd(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BitOpAnd", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BitOpAnd indicates an expected call of BitOpAnd. +func (mr *MockUniversalClientMockRecorder) BitOpAnd(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitOpAnd", reflect.TypeOf((*MockUniversalClient)(nil).BitOpAnd), varargs...) +} + +// BitOpNot mocks base method. +func (m *MockUniversalClient) BitOpNot(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BitOpNot", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BitOpNot indicates an expected call of BitOpNot. +func (mr *MockUniversalClientMockRecorder) BitOpNot(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitOpNot", reflect.TypeOf((*MockUniversalClient)(nil).BitOpNot), arg0, arg1, arg2) +} + +// BitOpOr mocks base method. +func (m *MockUniversalClient) BitOpOr(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BitOpOr", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BitOpOr indicates an expected call of BitOpOr. +func (mr *MockUniversalClientMockRecorder) BitOpOr(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitOpOr", reflect.TypeOf((*MockUniversalClient)(nil).BitOpOr), varargs...) +} + +// BitOpXor mocks base method. +func (m *MockUniversalClient) BitOpXor(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BitOpXor", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BitOpXor indicates an expected call of BitOpXor. +func (mr *MockUniversalClientMockRecorder) BitOpXor(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitOpXor", reflect.TypeOf((*MockUniversalClient)(nil).BitOpXor), varargs...) +} + +// BitPos mocks base method. +func (m *MockUniversalClient) BitPos(arg0 context.Context, arg1 string, arg2 int64, arg3 ...int64) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BitPos", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BitPos indicates an expected call of BitPos. +func (mr *MockUniversalClientMockRecorder) BitPos(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitPos", reflect.TypeOf((*MockUniversalClient)(nil).BitPos), varargs...) +} + +// BitPosSpan mocks base method. +func (m *MockUniversalClient) BitPosSpan(arg0 context.Context, arg1 string, arg2 int8, arg3, arg4 int64, arg5 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BitPosSpan", arg0, arg1, arg2, arg3, arg4, arg5) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// BitPosSpan indicates an expected call of BitPosSpan. +func (mr *MockUniversalClientMockRecorder) BitPosSpan(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BitPosSpan", reflect.TypeOf((*MockUniversalClient)(nil).BitPosSpan), arg0, arg1, arg2, arg3, arg4, arg5) +} + +// CFAdd mocks base method. +func (m *MockUniversalClient) CFAdd(arg0 context.Context, arg1 string, arg2 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFAdd", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// CFAdd indicates an expected call of CFAdd. +func (mr *MockUniversalClientMockRecorder) CFAdd(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFAdd", reflect.TypeOf((*MockUniversalClient)(nil).CFAdd), arg0, arg1, arg2) +} + +// CFAddNX mocks base method. +func (m *MockUniversalClient) CFAddNX(arg0 context.Context, arg1 string, arg2 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFAddNX", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// CFAddNX indicates an expected call of CFAddNX. +func (mr *MockUniversalClientMockRecorder) CFAddNX(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFAddNX", reflect.TypeOf((*MockUniversalClient)(nil).CFAddNX), arg0, arg1, arg2) +} + +// CFCount mocks base method. +func (m *MockUniversalClient) CFCount(arg0 context.Context, arg1 string, arg2 any) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFCount", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// CFCount indicates an expected call of CFCount. +func (mr *MockUniversalClientMockRecorder) CFCount(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFCount", reflect.TypeOf((*MockUniversalClient)(nil).CFCount), arg0, arg1, arg2) +} + +// CFDel mocks base method. +func (m *MockUniversalClient) CFDel(arg0 context.Context, arg1 string, arg2 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFDel", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// CFDel indicates an expected call of CFDel. +func (mr *MockUniversalClientMockRecorder) CFDel(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFDel", reflect.TypeOf((*MockUniversalClient)(nil).CFDel), arg0, arg1, arg2) +} + +// CFExists mocks base method. +func (m *MockUniversalClient) CFExists(arg0 context.Context, arg1 string, arg2 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFExists", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// CFExists indicates an expected call of CFExists. +func (mr *MockUniversalClientMockRecorder) CFExists(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFExists", reflect.TypeOf((*MockUniversalClient)(nil).CFExists), arg0, arg1, arg2) +} + +// CFInfo mocks base method. +func (m *MockUniversalClient) CFInfo(arg0 context.Context, arg1 string) *redis.CFInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFInfo", arg0, arg1) + ret0, _ := ret[0].(*redis.CFInfoCmd) + return ret0 +} + +// CFInfo indicates an expected call of CFInfo. +func (mr *MockUniversalClientMockRecorder) CFInfo(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFInfo", reflect.TypeOf((*MockUniversalClient)(nil).CFInfo), arg0, arg1) +} + +// CFInsert mocks base method. +func (m *MockUniversalClient) CFInsert(arg0 context.Context, arg1 string, arg2 *redis.CFInsertOptions, arg3 ...any) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CFInsert", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// CFInsert indicates an expected call of CFInsert. +func (mr *MockUniversalClientMockRecorder) CFInsert(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFInsert", reflect.TypeOf((*MockUniversalClient)(nil).CFInsert), varargs...) +} + +// CFInsertNX mocks base method. +func (m *MockUniversalClient) CFInsertNX(arg0 context.Context, arg1 string, arg2 *redis.CFInsertOptions, arg3 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CFInsertNX", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// CFInsertNX indicates an expected call of CFInsertNX. +func (mr *MockUniversalClientMockRecorder) CFInsertNX(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFInsertNX", reflect.TypeOf((*MockUniversalClient)(nil).CFInsertNX), varargs...) +} + +// CFLoadChunk mocks base method. +func (m *MockUniversalClient) CFLoadChunk(arg0 context.Context, arg1 string, arg2 int64, arg3 any) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFLoadChunk", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CFLoadChunk indicates an expected call of CFLoadChunk. +func (mr *MockUniversalClientMockRecorder) CFLoadChunk(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFLoadChunk", reflect.TypeOf((*MockUniversalClient)(nil).CFLoadChunk), arg0, arg1, arg2, arg3) +} + +// CFMExists mocks base method. +func (m *MockUniversalClient) CFMExists(arg0 context.Context, arg1 string, arg2 ...any) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CFMExists", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// CFMExists indicates an expected call of CFMExists. +func (mr *MockUniversalClientMockRecorder) CFMExists(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFMExists", reflect.TypeOf((*MockUniversalClient)(nil).CFMExists), varargs...) +} + +// CFReserve mocks base method. +func (m *MockUniversalClient) CFReserve(arg0 context.Context, arg1 string, arg2 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFReserve", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CFReserve indicates an expected call of CFReserve. +func (mr *MockUniversalClientMockRecorder) CFReserve(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFReserve", reflect.TypeOf((*MockUniversalClient)(nil).CFReserve), arg0, arg1, arg2) +} + +// CFReserveBucketSize mocks base method. +func (m *MockUniversalClient) CFReserveBucketSize(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFReserveBucketSize", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CFReserveBucketSize indicates an expected call of CFReserveBucketSize. +func (mr *MockUniversalClientMockRecorder) CFReserveBucketSize(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFReserveBucketSize", reflect.TypeOf((*MockUniversalClient)(nil).CFReserveBucketSize), arg0, arg1, arg2, arg3) +} + +// CFReserveExpansion mocks base method. +func (m *MockUniversalClient) CFReserveExpansion(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFReserveExpansion", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CFReserveExpansion indicates an expected call of CFReserveExpansion. +func (mr *MockUniversalClientMockRecorder) CFReserveExpansion(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFReserveExpansion", reflect.TypeOf((*MockUniversalClient)(nil).CFReserveExpansion), arg0, arg1, arg2, arg3) +} + +// CFReserveMaxIterations mocks base method. +func (m *MockUniversalClient) CFReserveMaxIterations(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFReserveMaxIterations", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CFReserveMaxIterations indicates an expected call of CFReserveMaxIterations. +func (mr *MockUniversalClientMockRecorder) CFReserveMaxIterations(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFReserveMaxIterations", reflect.TypeOf((*MockUniversalClient)(nil).CFReserveMaxIterations), arg0, arg1, arg2, arg3) +} + +// CFReserveWithArgs mocks base method. +func (m *MockUniversalClient) CFReserveWithArgs(arg0 context.Context, arg1 string, arg2 *redis.CFReserveOptions) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFReserveWithArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CFReserveWithArgs indicates an expected call of CFReserveWithArgs. +func (mr *MockUniversalClientMockRecorder) CFReserveWithArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFReserveWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).CFReserveWithArgs), arg0, arg1, arg2) +} + +// CFScanDump mocks base method. +func (m *MockUniversalClient) CFScanDump(arg0 context.Context, arg1 string, arg2 int64) *redis.ScanDumpCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CFScanDump", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.ScanDumpCmd) + return ret0 +} + +// CFScanDump indicates an expected call of CFScanDump. +func (mr *MockUniversalClientMockRecorder) CFScanDump(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CFScanDump", reflect.TypeOf((*MockUniversalClient)(nil).CFScanDump), arg0, arg1, arg2) +} + +// CMSIncrBy mocks base method. +func (m *MockUniversalClient) CMSIncrBy(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CMSIncrBy", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// CMSIncrBy indicates an expected call of CMSIncrBy. +func (mr *MockUniversalClientMockRecorder) CMSIncrBy(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CMSIncrBy", reflect.TypeOf((*MockUniversalClient)(nil).CMSIncrBy), varargs...) +} + +// CMSInfo mocks base method. +func (m *MockUniversalClient) CMSInfo(arg0 context.Context, arg1 string) *redis.CMSInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CMSInfo", arg0, arg1) + ret0, _ := ret[0].(*redis.CMSInfoCmd) + return ret0 +} + +// CMSInfo indicates an expected call of CMSInfo. +func (mr *MockUniversalClientMockRecorder) CMSInfo(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CMSInfo", reflect.TypeOf((*MockUniversalClient)(nil).CMSInfo), arg0, arg1) +} + +// CMSInitByDim mocks base method. +func (m *MockUniversalClient) CMSInitByDim(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CMSInitByDim", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CMSInitByDim indicates an expected call of CMSInitByDim. +func (mr *MockUniversalClientMockRecorder) CMSInitByDim(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CMSInitByDim", reflect.TypeOf((*MockUniversalClient)(nil).CMSInitByDim), arg0, arg1, arg2, arg3) +} + +// CMSInitByProb mocks base method. +func (m *MockUniversalClient) CMSInitByProb(arg0 context.Context, arg1 string, arg2, arg3 float64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CMSInitByProb", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CMSInitByProb indicates an expected call of CMSInitByProb. +func (mr *MockUniversalClientMockRecorder) CMSInitByProb(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CMSInitByProb", reflect.TypeOf((*MockUniversalClient)(nil).CMSInitByProb), arg0, arg1, arg2, arg3) +} + +// CMSMerge mocks base method. +func (m *MockUniversalClient) CMSMerge(arg0 context.Context, arg1 string, arg2 ...string) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CMSMerge", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CMSMerge indicates an expected call of CMSMerge. +func (mr *MockUniversalClientMockRecorder) CMSMerge(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CMSMerge", reflect.TypeOf((*MockUniversalClient)(nil).CMSMerge), varargs...) +} + +// CMSMergeWithWeight mocks base method. +func (m *MockUniversalClient) CMSMergeWithWeight(arg0 context.Context, arg1 string, arg2 map[string]int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CMSMergeWithWeight", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// CMSMergeWithWeight indicates an expected call of CMSMergeWithWeight. +func (mr *MockUniversalClientMockRecorder) CMSMergeWithWeight(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CMSMergeWithWeight", reflect.TypeOf((*MockUniversalClient)(nil).CMSMergeWithWeight), arg0, arg1, arg2) +} + +// CMSQuery mocks base method. +func (m *MockUniversalClient) CMSQuery(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CMSQuery", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// CMSQuery indicates an expected call of CMSQuery. +func (mr *MockUniversalClientMockRecorder) CMSQuery(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CMSQuery", reflect.TypeOf((*MockUniversalClient)(nil).CMSQuery), varargs...) +} + +// ClientGetName mocks base method. +func (m *MockUniversalClient) ClientGetName(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientGetName", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ClientGetName indicates an expected call of ClientGetName. +func (mr *MockUniversalClientMockRecorder) ClientGetName(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientGetName", reflect.TypeOf((*MockUniversalClient)(nil).ClientGetName), arg0) +} + +// ClientID mocks base method. +func (m *MockUniversalClient) ClientID(arg0 context.Context) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientID", arg0) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ClientID indicates an expected call of ClientID. +func (mr *MockUniversalClientMockRecorder) ClientID(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientID", reflect.TypeOf((*MockUniversalClient)(nil).ClientID), arg0) +} + +// ClientInfo mocks base method. +func (m *MockUniversalClient) ClientInfo(arg0 context.Context) *redis.ClientInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientInfo", arg0) + ret0, _ := ret[0].(*redis.ClientInfoCmd) + return ret0 +} + +// ClientInfo indicates an expected call of ClientInfo. +func (mr *MockUniversalClientMockRecorder) ClientInfo(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientInfo", reflect.TypeOf((*MockUniversalClient)(nil).ClientInfo), arg0) +} + +// ClientKill mocks base method. +func (m *MockUniversalClient) ClientKill(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientKill", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClientKill indicates an expected call of ClientKill. +func (mr *MockUniversalClientMockRecorder) ClientKill(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientKill", reflect.TypeOf((*MockUniversalClient)(nil).ClientKill), arg0, arg1) +} + +// ClientKillByFilter mocks base method. +func (m *MockUniversalClient) ClientKillByFilter(arg0 context.Context, arg1 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ClientKillByFilter", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ClientKillByFilter indicates an expected call of ClientKillByFilter. +func (mr *MockUniversalClientMockRecorder) ClientKillByFilter(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientKillByFilter", reflect.TypeOf((*MockUniversalClient)(nil).ClientKillByFilter), varargs...) +} + +// ClientList mocks base method. +func (m *MockUniversalClient) ClientList(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientList", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ClientList indicates an expected call of ClientList. +func (mr *MockUniversalClientMockRecorder) ClientList(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientList", reflect.TypeOf((*MockUniversalClient)(nil).ClientList), arg0) +} + +// ClientPause mocks base method. +func (m *MockUniversalClient) ClientPause(arg0 context.Context, arg1 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientPause", arg0, arg1) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// ClientPause indicates an expected call of ClientPause. +func (mr *MockUniversalClientMockRecorder) ClientPause(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientPause", reflect.TypeOf((*MockUniversalClient)(nil).ClientPause), arg0, arg1) +} + +// ClientUnblock mocks base method. +func (m *MockUniversalClient) ClientUnblock(arg0 context.Context, arg1 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientUnblock", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ClientUnblock indicates an expected call of ClientUnblock. +func (mr *MockUniversalClientMockRecorder) ClientUnblock(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientUnblock", reflect.TypeOf((*MockUniversalClient)(nil).ClientUnblock), arg0, arg1) +} + +// ClientUnblockWithError mocks base method. +func (m *MockUniversalClient) ClientUnblockWithError(arg0 context.Context, arg1 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientUnblockWithError", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ClientUnblockWithError indicates an expected call of ClientUnblockWithError. +func (mr *MockUniversalClientMockRecorder) ClientUnblockWithError(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientUnblockWithError", reflect.TypeOf((*MockUniversalClient)(nil).ClientUnblockWithError), arg0, arg1) +} + +// ClientUnpause mocks base method. +func (m *MockUniversalClient) ClientUnpause(arg0 context.Context) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientUnpause", arg0) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// ClientUnpause indicates an expected call of ClientUnpause. +func (mr *MockUniversalClientMockRecorder) ClientUnpause(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientUnpause", reflect.TypeOf((*MockUniversalClient)(nil).ClientUnpause), arg0) +} + // Close mocks base method. -func (m *MockRedisClient) Close() error { +func (m *MockUniversalClient) Close() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Close") ret0, _ := ret[0].(error) @@ -51,44 +1227,526 @@ func (m *MockRedisClient) Close() error { } // Close indicates an expected call of Close. -func (mr *MockRedisClientMockRecorder) Close() *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockRedisClient)(nil).Close)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockUniversalClient)(nil).Close)) +} + +// ClusterAddSlots mocks base method. +func (m *MockUniversalClient) ClusterAddSlots(arg0 context.Context, arg1 ...int) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ClusterAddSlots", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterAddSlots indicates an expected call of ClusterAddSlots. +func (mr *MockUniversalClientMockRecorder) ClusterAddSlots(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterAddSlots", reflect.TypeOf((*MockUniversalClient)(nil).ClusterAddSlots), varargs...) +} + +// ClusterAddSlotsRange mocks base method. +func (m *MockUniversalClient) ClusterAddSlotsRange(arg0 context.Context, arg1, arg2 int) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterAddSlotsRange", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterAddSlotsRange indicates an expected call of ClusterAddSlotsRange. +func (mr *MockUniversalClientMockRecorder) ClusterAddSlotsRange(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterAddSlotsRange", reflect.TypeOf((*MockUniversalClient)(nil).ClusterAddSlotsRange), arg0, arg1, arg2) +} + +// ClusterCountFailureReports mocks base method. +func (m *MockUniversalClient) ClusterCountFailureReports(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterCountFailureReports", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ClusterCountFailureReports indicates an expected call of ClusterCountFailureReports. +func (mr *MockUniversalClientMockRecorder) ClusterCountFailureReports(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterCountFailureReports", reflect.TypeOf((*MockUniversalClient)(nil).ClusterCountFailureReports), arg0, arg1) +} + +// ClusterCountKeysInSlot mocks base method. +func (m *MockUniversalClient) ClusterCountKeysInSlot(arg0 context.Context, arg1 int) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterCountKeysInSlot", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ClusterCountKeysInSlot indicates an expected call of ClusterCountKeysInSlot. +func (mr *MockUniversalClientMockRecorder) ClusterCountKeysInSlot(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterCountKeysInSlot", reflect.TypeOf((*MockUniversalClient)(nil).ClusterCountKeysInSlot), arg0, arg1) +} + +// ClusterDelSlots mocks base method. +func (m *MockUniversalClient) ClusterDelSlots(arg0 context.Context, arg1 ...int) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ClusterDelSlots", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterDelSlots indicates an expected call of ClusterDelSlots. +func (mr *MockUniversalClientMockRecorder) ClusterDelSlots(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterDelSlots", reflect.TypeOf((*MockUniversalClient)(nil).ClusterDelSlots), varargs...) +} + +// ClusterDelSlotsRange mocks base method. +func (m *MockUniversalClient) ClusterDelSlotsRange(arg0 context.Context, arg1, arg2 int) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterDelSlotsRange", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterDelSlotsRange indicates an expected call of ClusterDelSlotsRange. +func (mr *MockUniversalClientMockRecorder) ClusterDelSlotsRange(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterDelSlotsRange", reflect.TypeOf((*MockUniversalClient)(nil).ClusterDelSlotsRange), arg0, arg1, arg2) +} + +// ClusterFailover mocks base method. +func (m *MockUniversalClient) ClusterFailover(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterFailover", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterFailover indicates an expected call of ClusterFailover. +func (mr *MockUniversalClientMockRecorder) ClusterFailover(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterFailover", reflect.TypeOf((*MockUniversalClient)(nil).ClusterFailover), arg0) +} + +// ClusterForget mocks base method. +func (m *MockUniversalClient) ClusterForget(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterForget", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterForget indicates an expected call of ClusterForget. +func (mr *MockUniversalClientMockRecorder) ClusterForget(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterForget", reflect.TypeOf((*MockUniversalClient)(nil).ClusterForget), arg0, arg1) +} + +// ClusterGetKeysInSlot mocks base method. +func (m *MockUniversalClient) ClusterGetKeysInSlot(arg0 context.Context, arg1, arg2 int) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterGetKeysInSlot", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ClusterGetKeysInSlot indicates an expected call of ClusterGetKeysInSlot. +func (mr *MockUniversalClientMockRecorder) ClusterGetKeysInSlot(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterGetKeysInSlot", reflect.TypeOf((*MockUniversalClient)(nil).ClusterGetKeysInSlot), arg0, arg1, arg2) +} + +// ClusterInfo mocks base method. +func (m *MockUniversalClient) ClusterInfo(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterInfo", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ClusterInfo indicates an expected call of ClusterInfo. +func (mr *MockUniversalClientMockRecorder) ClusterInfo(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterInfo", reflect.TypeOf((*MockUniversalClient)(nil).ClusterInfo), arg0) +} + +// ClusterKeySlot mocks base method. +func (m *MockUniversalClient) ClusterKeySlot(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterKeySlot", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ClusterKeySlot indicates an expected call of ClusterKeySlot. +func (mr *MockUniversalClientMockRecorder) ClusterKeySlot(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterKeySlot", reflect.TypeOf((*MockUniversalClient)(nil).ClusterKeySlot), arg0, arg1) +} + +// ClusterLinks mocks base method. +func (m *MockUniversalClient) ClusterLinks(arg0 context.Context) *redis.ClusterLinksCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterLinks", arg0) + ret0, _ := ret[0].(*redis.ClusterLinksCmd) + return ret0 +} + +// ClusterLinks indicates an expected call of ClusterLinks. +func (mr *MockUniversalClientMockRecorder) ClusterLinks(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterLinks", reflect.TypeOf((*MockUniversalClient)(nil).ClusterLinks), arg0) +} + +// ClusterMeet mocks base method. +func (m *MockUniversalClient) ClusterMeet(arg0 context.Context, arg1, arg2 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterMeet", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterMeet indicates an expected call of ClusterMeet. +func (mr *MockUniversalClientMockRecorder) ClusterMeet(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterMeet", reflect.TypeOf((*MockUniversalClient)(nil).ClusterMeet), arg0, arg1, arg2) +} + +// ClusterMyShardID mocks base method. +func (m *MockUniversalClient) ClusterMyShardID(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterMyShardID", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ClusterMyShardID indicates an expected call of ClusterMyShardID. +func (mr *MockUniversalClientMockRecorder) ClusterMyShardID(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterMyShardID", reflect.TypeOf((*MockUniversalClient)(nil).ClusterMyShardID), arg0) +} + +// ClusterNodes mocks base method. +func (m *MockUniversalClient) ClusterNodes(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterNodes", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ClusterNodes indicates an expected call of ClusterNodes. +func (mr *MockUniversalClientMockRecorder) ClusterNodes(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterNodes", reflect.TypeOf((*MockUniversalClient)(nil).ClusterNodes), arg0) +} + +// ClusterReplicate mocks base method. +func (m *MockUniversalClient) ClusterReplicate(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterReplicate", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterReplicate indicates an expected call of ClusterReplicate. +func (mr *MockUniversalClientMockRecorder) ClusterReplicate(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterReplicate", reflect.TypeOf((*MockUniversalClient)(nil).ClusterReplicate), arg0, arg1) +} + +// ClusterResetHard mocks base method. +func (m *MockUniversalClient) ClusterResetHard(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterResetHard", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterResetHard indicates an expected call of ClusterResetHard. +func (mr *MockUniversalClientMockRecorder) ClusterResetHard(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterResetHard", reflect.TypeOf((*MockUniversalClient)(nil).ClusterResetHard), arg0) +} + +// ClusterResetSoft mocks base method. +func (m *MockUniversalClient) ClusterResetSoft(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterResetSoft", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterResetSoft indicates an expected call of ClusterResetSoft. +func (mr *MockUniversalClientMockRecorder) ClusterResetSoft(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterResetSoft", reflect.TypeOf((*MockUniversalClient)(nil).ClusterResetSoft), arg0) +} + +// ClusterSaveConfig mocks base method. +func (m *MockUniversalClient) ClusterSaveConfig(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterSaveConfig", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ClusterSaveConfig indicates an expected call of ClusterSaveConfig. +func (mr *MockUniversalClientMockRecorder) ClusterSaveConfig(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterSaveConfig", reflect.TypeOf((*MockUniversalClient)(nil).ClusterSaveConfig), arg0) +} + +// ClusterShards mocks base method. +func (m *MockUniversalClient) ClusterShards(arg0 context.Context) *redis.ClusterShardsCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterShards", arg0) + ret0, _ := ret[0].(*redis.ClusterShardsCmd) + return ret0 +} + +// ClusterShards indicates an expected call of ClusterShards. +func (mr *MockUniversalClientMockRecorder) ClusterShards(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterShards", reflect.TypeOf((*MockUniversalClient)(nil).ClusterShards), arg0) +} + +// ClusterSlaves mocks base method. +func (m *MockUniversalClient) ClusterSlaves(arg0 context.Context, arg1 string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterSlaves", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ClusterSlaves indicates an expected call of ClusterSlaves. +func (mr *MockUniversalClientMockRecorder) ClusterSlaves(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterSlaves", reflect.TypeOf((*MockUniversalClient)(nil).ClusterSlaves), arg0, arg1) +} + +// ClusterSlots mocks base method. +func (m *MockUniversalClient) ClusterSlots(arg0 context.Context) *redis.ClusterSlotsCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClusterSlots", arg0) + ret0, _ := ret[0].(*redis.ClusterSlotsCmd) + return ret0 +} + +// ClusterSlots indicates an expected call of ClusterSlots. +func (mr *MockUniversalClientMockRecorder) ClusterSlots(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterSlots", reflect.TypeOf((*MockUniversalClient)(nil).ClusterSlots), arg0) +} + +// Command mocks base method. +func (m *MockUniversalClient) Command(arg0 context.Context) *redis.CommandsInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Command", arg0) + ret0, _ := ret[0].(*redis.CommandsInfoCmd) + return ret0 +} + +// Command indicates an expected call of Command. +func (mr *MockUniversalClientMockRecorder) Command(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Command", reflect.TypeOf((*MockUniversalClient)(nil).Command), arg0) +} + +// CommandGetKeys mocks base method. +func (m *MockUniversalClient) CommandGetKeys(arg0 context.Context, arg1 ...any) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CommandGetKeys", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// CommandGetKeys indicates an expected call of CommandGetKeys. +func (mr *MockUniversalClientMockRecorder) CommandGetKeys(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommandGetKeys", reflect.TypeOf((*MockUniversalClient)(nil).CommandGetKeys), varargs...) +} + +// CommandGetKeysAndFlags mocks base method. +func (m *MockUniversalClient) CommandGetKeysAndFlags(arg0 context.Context, arg1 ...any) *redis.KeyFlagsCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CommandGetKeysAndFlags", varargs...) + ret0, _ := ret[0].(*redis.KeyFlagsCmd) + return ret0 +} + +// CommandGetKeysAndFlags indicates an expected call of CommandGetKeysAndFlags. +func (mr *MockUniversalClientMockRecorder) CommandGetKeysAndFlags(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommandGetKeysAndFlags", reflect.TypeOf((*MockUniversalClient)(nil).CommandGetKeysAndFlags), varargs...) +} + +// CommandList mocks base method. +func (m *MockUniversalClient) CommandList(arg0 context.Context, arg1 *redis.FilterBy) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CommandList", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// CommandList indicates an expected call of CommandList. +func (mr *MockUniversalClientMockRecorder) CommandList(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommandList", reflect.TypeOf((*MockUniversalClient)(nil).CommandList), arg0, arg1) +} + +// ConfigGet mocks base method. +func (m *MockUniversalClient) ConfigGet(arg0 context.Context, arg1 string) *redis.MapStringStringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigGet", arg0, arg1) + ret0, _ := ret[0].(*redis.MapStringStringCmd) + return ret0 +} + +// ConfigGet indicates an expected call of ConfigGet. +func (mr *MockUniversalClientMockRecorder) ConfigGet(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigGet", reflect.TypeOf((*MockUniversalClient)(nil).ConfigGet), arg0, arg1) +} + +// ConfigResetStat mocks base method. +func (m *MockUniversalClient) ConfigResetStat(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigResetStat", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ConfigResetStat indicates an expected call of ConfigResetStat. +func (mr *MockUniversalClientMockRecorder) ConfigResetStat(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigResetStat", reflect.TypeOf((*MockUniversalClient)(nil).ConfigResetStat), arg0) +} + +// ConfigRewrite mocks base method. +func (m *MockUniversalClient) ConfigRewrite(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigRewrite", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ConfigRewrite indicates an expected call of ConfigRewrite. +func (mr *MockUniversalClientMockRecorder) ConfigRewrite(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigRewrite", reflect.TypeOf((*MockUniversalClient)(nil).ConfigRewrite), arg0) +} + +// ConfigSet mocks base method. +func (m *MockUniversalClient) ConfigSet(arg0 context.Context, arg1, arg2 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigSet", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ConfigSet indicates an expected call of ConfigSet. +func (mr *MockUniversalClientMockRecorder) ConfigSet(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigSet", reflect.TypeOf((*MockUniversalClient)(nil).ConfigSet), arg0, arg1, arg2) +} + +// Copy mocks base method. +func (m *MockUniversalClient) Copy(arg0 context.Context, arg1, arg2 string, arg3 int, arg4 bool) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Copy", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// Copy indicates an expected call of Copy. +func (mr *MockUniversalClientMockRecorder) Copy(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Copy", reflect.TypeOf((*MockUniversalClient)(nil).Copy), arg0, arg1, arg2, arg3, arg4) } // DBSize mocks base method. -func (m *MockRedisClient) DBSize(ctx context.Context) *redis.IntCmd { +func (m *MockUniversalClient) DBSize(arg0 context.Context) *redis.IntCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DBSize", ctx) + ret := m.ctrl.Call(m, "DBSize", arg0) ret0, _ := ret[0].(*redis.IntCmd) return ret0 } // DBSize indicates an expected call of DBSize. -func (mr *MockRedisClientMockRecorder) DBSize(ctx any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) DBSize(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DBSize", reflect.TypeOf((*MockRedisClient)(nil).DBSize), ctx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DBSize", reflect.TypeOf((*MockUniversalClient)(nil).DBSize), arg0) +} + +// DebugObject mocks base method. +func (m *MockUniversalClient) DebugObject(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DebugObject", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// DebugObject indicates an expected call of DebugObject. +func (mr *MockUniversalClientMockRecorder) DebugObject(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugObject", reflect.TypeOf((*MockUniversalClient)(nil).DebugObject), arg0, arg1) } // Decr mocks base method. -func (m *MockRedisClient) Decr(ctx context.Context, key string) *redis.IntCmd { +func (m *MockUniversalClient) Decr(arg0 context.Context, arg1 string) *redis.IntCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Decr", ctx, key) + ret := m.ctrl.Call(m, "Decr", arg0, arg1) ret0, _ := ret[0].(*redis.IntCmd) return ret0 } // Decr indicates an expected call of Decr. -func (mr *MockRedisClientMockRecorder) Decr(ctx, key any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Decr(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Decr", reflect.TypeOf((*MockRedisClient)(nil).Decr), ctx, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Decr", reflect.TypeOf((*MockUniversalClient)(nil).Decr), arg0, arg1) +} + +// DecrBy mocks base method. +func (m *MockUniversalClient) DecrBy(arg0 context.Context, arg1 string, arg2 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DecrBy", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// DecrBy indicates an expected call of DecrBy. +func (mr *MockUniversalClientMockRecorder) DecrBy(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecrBy", reflect.TypeOf((*MockUniversalClient)(nil).DecrBy), arg0, arg1, arg2) } // Del mocks base method. -func (m *MockRedisClient) Del(ctx context.Context, keys ...string) *redis.IntCmd { +func (m *MockUniversalClient) Del(arg0 context.Context, arg1 ...string) *redis.IntCmd { m.ctrl.T.Helper() - varargs := []any{ctx} - for _, a := range keys { + varargs := []any{arg0} + for _, a := range arg1 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "Del", varargs...) @@ -97,17 +1755,140 @@ func (m *MockRedisClient) Del(ctx context.Context, keys ...string) *redis.IntCmd } // Del indicates an expected call of Del. -func (mr *MockRedisClientMockRecorder) Del(ctx any, keys ...any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Del(arg0 any, arg1 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx}, keys...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Del", reflect.TypeOf((*MockRedisClient)(nil).Del), varargs...) + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Del", reflect.TypeOf((*MockUniversalClient)(nil).Del), varargs...) +} + +// Do mocks base method. +func (m *MockUniversalClient) Do(arg0 context.Context, arg1 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Do", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// Do indicates an expected call of Do. +func (mr *MockUniversalClientMockRecorder) Do(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Do", reflect.TypeOf((*MockUniversalClient)(nil).Do), varargs...) +} + +// Dump mocks base method. +func (m *MockUniversalClient) Dump(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Dump", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// Dump indicates an expected call of Dump. +func (mr *MockUniversalClientMockRecorder) Dump(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Dump", reflect.TypeOf((*MockUniversalClient)(nil).Dump), arg0, arg1) +} + +// Echo mocks base method. +func (m *MockUniversalClient) Echo(arg0 context.Context, arg1 any) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Echo", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// Echo indicates an expected call of Echo. +func (mr *MockUniversalClientMockRecorder) Echo(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Echo", reflect.TypeOf((*MockUniversalClient)(nil).Echo), arg0, arg1) +} + +// Eval mocks base method. +func (m *MockUniversalClient) Eval(arg0 context.Context, arg1 string, arg2 []string, arg3 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Eval", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// Eval indicates an expected call of Eval. +func (mr *MockUniversalClientMockRecorder) Eval(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Eval", reflect.TypeOf((*MockUniversalClient)(nil).Eval), varargs...) +} + +// EvalRO mocks base method. +func (m *MockUniversalClient) EvalRO(arg0 context.Context, arg1 string, arg2 []string, arg3 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "EvalRO", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// EvalRO indicates an expected call of EvalRO. +func (mr *MockUniversalClientMockRecorder) EvalRO(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvalRO", reflect.TypeOf((*MockUniversalClient)(nil).EvalRO), varargs...) +} + +// EvalSha mocks base method. +func (m *MockUniversalClient) EvalSha(arg0 context.Context, arg1 string, arg2 []string, arg3 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "EvalSha", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// EvalSha indicates an expected call of EvalSha. +func (mr *MockUniversalClientMockRecorder) EvalSha(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvalSha", reflect.TypeOf((*MockUniversalClient)(nil).EvalSha), varargs...) +} + +// EvalShaRO mocks base method. +func (m *MockUniversalClient) EvalShaRO(arg0 context.Context, arg1 string, arg2 []string, arg3 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "EvalShaRO", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// EvalShaRO indicates an expected call of EvalShaRO. +func (mr *MockUniversalClientMockRecorder) EvalShaRO(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvalShaRO", reflect.TypeOf((*MockUniversalClient)(nil).EvalShaRO), varargs...) } // Exists mocks base method. -func (m *MockRedisClient) Exists(ctx context.Context, keys ...string) *redis.IntCmd { +func (m *MockUniversalClient) Exists(arg0 context.Context, arg1 ...string) *redis.IntCmd { m.ctrl.T.Helper() - varargs := []any{ctx} - for _, a := range keys { + varargs := []any{arg0} + for _, a := range arg1 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "Exists", varargs...) @@ -116,45 +1897,621 @@ func (m *MockRedisClient) Exists(ctx context.Context, keys ...string) *redis.Int } // Exists indicates an expected call of Exists. -func (mr *MockRedisClientMockRecorder) Exists(ctx any, keys ...any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Exists(arg0 any, arg1 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx}, keys...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockRedisClient)(nil).Exists), varargs...) + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockUniversalClient)(nil).Exists), varargs...) +} + +// Expire mocks base method. +func (m *MockUniversalClient) Expire(arg0 context.Context, arg1 string, arg2 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Expire", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// Expire indicates an expected call of Expire. +func (mr *MockUniversalClientMockRecorder) Expire(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Expire", reflect.TypeOf((*MockUniversalClient)(nil).Expire), arg0, arg1, arg2) +} + +// ExpireAt mocks base method. +func (m *MockUniversalClient) ExpireAt(arg0 context.Context, arg1 string, arg2 time.Time) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExpireAt", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// ExpireAt indicates an expected call of ExpireAt. +func (mr *MockUniversalClientMockRecorder) ExpireAt(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpireAt", reflect.TypeOf((*MockUniversalClient)(nil).ExpireAt), arg0, arg1, arg2) +} + +// ExpireGT mocks base method. +func (m *MockUniversalClient) ExpireGT(arg0 context.Context, arg1 string, arg2 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExpireGT", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// ExpireGT indicates an expected call of ExpireGT. +func (mr *MockUniversalClientMockRecorder) ExpireGT(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpireGT", reflect.TypeOf((*MockUniversalClient)(nil).ExpireGT), arg0, arg1, arg2) +} + +// ExpireLT mocks base method. +func (m *MockUniversalClient) ExpireLT(arg0 context.Context, arg1 string, arg2 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExpireLT", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// ExpireLT indicates an expected call of ExpireLT. +func (mr *MockUniversalClientMockRecorder) ExpireLT(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpireLT", reflect.TypeOf((*MockUniversalClient)(nil).ExpireLT), arg0, arg1, arg2) +} + +// ExpireNX mocks base method. +func (m *MockUniversalClient) ExpireNX(arg0 context.Context, arg1 string, arg2 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExpireNX", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// ExpireNX indicates an expected call of ExpireNX. +func (mr *MockUniversalClientMockRecorder) ExpireNX(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpireNX", reflect.TypeOf((*MockUniversalClient)(nil).ExpireNX), arg0, arg1, arg2) +} + +// ExpireTime mocks base method. +func (m *MockUniversalClient) ExpireTime(arg0 context.Context, arg1 string) *redis.DurationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExpireTime", arg0, arg1) + ret0, _ := ret[0].(*redis.DurationCmd) + return ret0 +} + +// ExpireTime indicates an expected call of ExpireTime. +func (mr *MockUniversalClientMockRecorder) ExpireTime(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpireTime", reflect.TypeOf((*MockUniversalClient)(nil).ExpireTime), arg0, arg1) +} + +// ExpireXX mocks base method. +func (m *MockUniversalClient) ExpireXX(arg0 context.Context, arg1 string, arg2 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExpireXX", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// ExpireXX indicates an expected call of ExpireXX. +func (mr *MockUniversalClientMockRecorder) ExpireXX(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpireXX", reflect.TypeOf((*MockUniversalClient)(nil).ExpireXX), arg0, arg1, arg2) +} + +// FCall mocks base method. +func (m *MockUniversalClient) FCall(arg0 context.Context, arg1 string, arg2 []string, arg3 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "FCall", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// FCall indicates an expected call of FCall. +func (mr *MockUniversalClientMockRecorder) FCall(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FCall", reflect.TypeOf((*MockUniversalClient)(nil).FCall), varargs...) +} + +// FCallRO mocks base method. +func (m *MockUniversalClient) FCallRO(arg0 context.Context, arg1 string, arg2 []string, arg3 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "FCallRO", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// FCallRO indicates an expected call of FCallRO. +func (mr *MockUniversalClientMockRecorder) FCallRO(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FCallRO", reflect.TypeOf((*MockUniversalClient)(nil).FCallRO), varargs...) +} + +// FCallRo mocks base method. +func (m *MockUniversalClient) FCallRo(arg0 context.Context, arg1 string, arg2 []string, arg3 ...any) *redis.Cmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "FCallRo", varargs...) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// FCallRo indicates an expected call of FCallRo. +func (mr *MockUniversalClientMockRecorder) FCallRo(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FCallRo", reflect.TypeOf((*MockUniversalClient)(nil).FCallRo), varargs...) +} + +// FlushAll mocks base method. +func (m *MockUniversalClient) FlushAll(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FlushAll", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// FlushAll indicates an expected call of FlushAll. +func (mr *MockUniversalClientMockRecorder) FlushAll(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FlushAll", reflect.TypeOf((*MockUniversalClient)(nil).FlushAll), arg0) +} + +// FlushAllAsync mocks base method. +func (m *MockUniversalClient) FlushAllAsync(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FlushAllAsync", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// FlushAllAsync indicates an expected call of FlushAllAsync. +func (mr *MockUniversalClientMockRecorder) FlushAllAsync(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FlushAllAsync", reflect.TypeOf((*MockUniversalClient)(nil).FlushAllAsync), arg0) } // FlushDB mocks base method. -func (m *MockRedisClient) FlushDB(ctx context.Context) *redis.StatusCmd { +func (m *MockUniversalClient) FlushDB(arg0 context.Context) *redis.StatusCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FlushDB", ctx) + ret := m.ctrl.Call(m, "FlushDB", arg0) ret0, _ := ret[0].(*redis.StatusCmd) return ret0 } // FlushDB indicates an expected call of FlushDB. -func (mr *MockRedisClientMockRecorder) FlushDB(ctx any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) FlushDB(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FlushDB", reflect.TypeOf((*MockRedisClient)(nil).FlushDB), ctx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FlushDB", reflect.TypeOf((*MockUniversalClient)(nil).FlushDB), arg0) +} + +// FlushDBAsync mocks base method. +func (m *MockUniversalClient) FlushDBAsync(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FlushDBAsync", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// FlushDBAsync indicates an expected call of FlushDBAsync. +func (mr *MockUniversalClientMockRecorder) FlushDBAsync(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FlushDBAsync", reflect.TypeOf((*MockUniversalClient)(nil).FlushDBAsync), arg0) +} + +// FunctionDelete mocks base method. +func (m *MockUniversalClient) FunctionDelete(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionDelete", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionDelete indicates an expected call of FunctionDelete. +func (mr *MockUniversalClientMockRecorder) FunctionDelete(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionDelete", reflect.TypeOf((*MockUniversalClient)(nil).FunctionDelete), arg0, arg1) +} + +// FunctionDump mocks base method. +func (m *MockUniversalClient) FunctionDump(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionDump", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionDump indicates an expected call of FunctionDump. +func (mr *MockUniversalClientMockRecorder) FunctionDump(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionDump", reflect.TypeOf((*MockUniversalClient)(nil).FunctionDump), arg0) +} + +// FunctionFlush mocks base method. +func (m *MockUniversalClient) FunctionFlush(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionFlush", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionFlush indicates an expected call of FunctionFlush. +func (mr *MockUniversalClientMockRecorder) FunctionFlush(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionFlush", reflect.TypeOf((*MockUniversalClient)(nil).FunctionFlush), arg0) +} + +// FunctionFlushAsync mocks base method. +func (m *MockUniversalClient) FunctionFlushAsync(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionFlushAsync", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionFlushAsync indicates an expected call of FunctionFlushAsync. +func (mr *MockUniversalClientMockRecorder) FunctionFlushAsync(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionFlushAsync", reflect.TypeOf((*MockUniversalClient)(nil).FunctionFlushAsync), arg0) +} + +// FunctionKill mocks base method. +func (m *MockUniversalClient) FunctionKill(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionKill", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionKill indicates an expected call of FunctionKill. +func (mr *MockUniversalClientMockRecorder) FunctionKill(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionKill", reflect.TypeOf((*MockUniversalClient)(nil).FunctionKill), arg0) +} + +// FunctionList mocks base method. +func (m *MockUniversalClient) FunctionList(arg0 context.Context, arg1 redis.FunctionListQuery) *redis.FunctionListCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionList", arg0, arg1) + ret0, _ := ret[0].(*redis.FunctionListCmd) + return ret0 +} + +// FunctionList indicates an expected call of FunctionList. +func (mr *MockUniversalClientMockRecorder) FunctionList(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionList", reflect.TypeOf((*MockUniversalClient)(nil).FunctionList), arg0, arg1) +} + +// FunctionLoad mocks base method. +func (m *MockUniversalClient) FunctionLoad(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionLoad", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionLoad indicates an expected call of FunctionLoad. +func (mr *MockUniversalClientMockRecorder) FunctionLoad(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionLoad", reflect.TypeOf((*MockUniversalClient)(nil).FunctionLoad), arg0, arg1) +} + +// FunctionLoadReplace mocks base method. +func (m *MockUniversalClient) FunctionLoadReplace(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionLoadReplace", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionLoadReplace indicates an expected call of FunctionLoadReplace. +func (mr *MockUniversalClientMockRecorder) FunctionLoadReplace(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionLoadReplace", reflect.TypeOf((*MockUniversalClient)(nil).FunctionLoadReplace), arg0, arg1) +} + +// FunctionRestore mocks base method. +func (m *MockUniversalClient) FunctionRestore(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionRestore", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// FunctionRestore indicates an expected call of FunctionRestore. +func (mr *MockUniversalClientMockRecorder) FunctionRestore(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionRestore", reflect.TypeOf((*MockUniversalClient)(nil).FunctionRestore), arg0, arg1) +} + +// FunctionStats mocks base method. +func (m *MockUniversalClient) FunctionStats(arg0 context.Context) *redis.FunctionStatsCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FunctionStats", arg0) + ret0, _ := ret[0].(*redis.FunctionStatsCmd) + return ret0 +} + +// FunctionStats indicates an expected call of FunctionStats. +func (mr *MockUniversalClientMockRecorder) FunctionStats(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FunctionStats", reflect.TypeOf((*MockUniversalClient)(nil).FunctionStats), arg0) +} + +// GeoAdd mocks base method. +func (m *MockUniversalClient) GeoAdd(arg0 context.Context, arg1 string, arg2 ...*redis.GeoLocation) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GeoAdd", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// GeoAdd indicates an expected call of GeoAdd. +func (mr *MockUniversalClientMockRecorder) GeoAdd(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoAdd", reflect.TypeOf((*MockUniversalClient)(nil).GeoAdd), varargs...) +} + +// GeoDist mocks base method. +func (m *MockUniversalClient) GeoDist(arg0 context.Context, arg1, arg2, arg3, arg4 string) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoDist", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// GeoDist indicates an expected call of GeoDist. +func (mr *MockUniversalClientMockRecorder) GeoDist(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoDist", reflect.TypeOf((*MockUniversalClient)(nil).GeoDist), arg0, arg1, arg2, arg3, arg4) +} + +// GeoHash mocks base method. +func (m *MockUniversalClient) GeoHash(arg0 context.Context, arg1 string, arg2 ...string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GeoHash", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// GeoHash indicates an expected call of GeoHash. +func (mr *MockUniversalClientMockRecorder) GeoHash(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoHash", reflect.TypeOf((*MockUniversalClient)(nil).GeoHash), varargs...) +} + +// GeoPos mocks base method. +func (m *MockUniversalClient) GeoPos(arg0 context.Context, arg1 string, arg2 ...string) *redis.GeoPosCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GeoPos", varargs...) + ret0, _ := ret[0].(*redis.GeoPosCmd) + return ret0 +} + +// GeoPos indicates an expected call of GeoPos. +func (mr *MockUniversalClientMockRecorder) GeoPos(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoPos", reflect.TypeOf((*MockUniversalClient)(nil).GeoPos), varargs...) +} + +// GeoRadius mocks base method. +func (m *MockUniversalClient) GeoRadius(arg0 context.Context, arg1 string, arg2, arg3 float64, arg4 *redis.GeoRadiusQuery) *redis.GeoLocationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoRadius", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.GeoLocationCmd) + return ret0 +} + +// GeoRadius indicates an expected call of GeoRadius. +func (mr *MockUniversalClientMockRecorder) GeoRadius(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoRadius", reflect.TypeOf((*MockUniversalClient)(nil).GeoRadius), arg0, arg1, arg2, arg3, arg4) +} + +// GeoRadiusByMember mocks base method. +func (m *MockUniversalClient) GeoRadiusByMember(arg0 context.Context, arg1, arg2 string, arg3 *redis.GeoRadiusQuery) *redis.GeoLocationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoRadiusByMember", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.GeoLocationCmd) + return ret0 +} + +// GeoRadiusByMember indicates an expected call of GeoRadiusByMember. +func (mr *MockUniversalClientMockRecorder) GeoRadiusByMember(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoRadiusByMember", reflect.TypeOf((*MockUniversalClient)(nil).GeoRadiusByMember), arg0, arg1, arg2, arg3) +} + +// GeoRadiusByMemberStore mocks base method. +func (m *MockUniversalClient) GeoRadiusByMemberStore(arg0 context.Context, arg1, arg2 string, arg3 *redis.GeoRadiusQuery) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoRadiusByMemberStore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// GeoRadiusByMemberStore indicates an expected call of GeoRadiusByMemberStore. +func (mr *MockUniversalClientMockRecorder) GeoRadiusByMemberStore(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoRadiusByMemberStore", reflect.TypeOf((*MockUniversalClient)(nil).GeoRadiusByMemberStore), arg0, arg1, arg2, arg3) +} + +// GeoRadiusStore mocks base method. +func (m *MockUniversalClient) GeoRadiusStore(arg0 context.Context, arg1 string, arg2, arg3 float64, arg4 *redis.GeoRadiusQuery) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoRadiusStore", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// GeoRadiusStore indicates an expected call of GeoRadiusStore. +func (mr *MockUniversalClientMockRecorder) GeoRadiusStore(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoRadiusStore", reflect.TypeOf((*MockUniversalClient)(nil).GeoRadiusStore), arg0, arg1, arg2, arg3, arg4) +} + +// GeoSearch mocks base method. +func (m *MockUniversalClient) GeoSearch(arg0 context.Context, arg1 string, arg2 *redis.GeoSearchQuery) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoSearch", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// GeoSearch indicates an expected call of GeoSearch. +func (mr *MockUniversalClientMockRecorder) GeoSearch(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoSearch", reflect.TypeOf((*MockUniversalClient)(nil).GeoSearch), arg0, arg1, arg2) +} + +// GeoSearchLocation mocks base method. +func (m *MockUniversalClient) GeoSearchLocation(arg0 context.Context, arg1 string, arg2 *redis.GeoSearchLocationQuery) *redis.GeoSearchLocationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoSearchLocation", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.GeoSearchLocationCmd) + return ret0 +} + +// GeoSearchLocation indicates an expected call of GeoSearchLocation. +func (mr *MockUniversalClientMockRecorder) GeoSearchLocation(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoSearchLocation", reflect.TypeOf((*MockUniversalClient)(nil).GeoSearchLocation), arg0, arg1, arg2) +} + +// GeoSearchStore mocks base method. +func (m *MockUniversalClient) GeoSearchStore(arg0 context.Context, arg1, arg2 string, arg3 *redis.GeoSearchStoreQuery) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeoSearchStore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// GeoSearchStore indicates an expected call of GeoSearchStore. +func (mr *MockUniversalClientMockRecorder) GeoSearchStore(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeoSearchStore", reflect.TypeOf((*MockUniversalClient)(nil).GeoSearchStore), arg0, arg1, arg2, arg3) } // Get mocks base method. -func (m *MockRedisClient) Get(ctx context.Context, key string) *redis.StringCmd { +func (m *MockUniversalClient) Get(arg0 context.Context, arg1 string) *redis.StringCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", ctx, key) + ret := m.ctrl.Call(m, "Get", arg0, arg1) ret0, _ := ret[0].(*redis.StringCmd) return ret0 } // Get indicates an expected call of Get. -func (mr *MockRedisClientMockRecorder) Get(ctx, key any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Get(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRedisClient)(nil).Get), ctx, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockUniversalClient)(nil).Get), arg0, arg1) +} + +// GetBit mocks base method. +func (m *MockUniversalClient) GetBit(arg0 context.Context, arg1 string, arg2 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBit", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// GetBit indicates an expected call of GetBit. +func (mr *MockUniversalClientMockRecorder) GetBit(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBit", reflect.TypeOf((*MockUniversalClient)(nil).GetBit), arg0, arg1, arg2) +} + +// GetDel mocks base method. +func (m *MockUniversalClient) GetDel(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDel", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// GetDel indicates an expected call of GetDel. +func (mr *MockUniversalClientMockRecorder) GetDel(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDel", reflect.TypeOf((*MockUniversalClient)(nil).GetDel), arg0, arg1) +} + +// GetEx mocks base method. +func (m *MockUniversalClient) GetEx(arg0 context.Context, arg1 string, arg2 time.Duration) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEx", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// GetEx indicates an expected call of GetEx. +func (mr *MockUniversalClientMockRecorder) GetEx(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEx", reflect.TypeOf((*MockUniversalClient)(nil).GetEx), arg0, arg1, arg2) +} + +// GetRange mocks base method. +func (m *MockUniversalClient) GetRange(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// GetRange indicates an expected call of GetRange. +func (mr *MockUniversalClientMockRecorder) GetRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRange", reflect.TypeOf((*MockUniversalClient)(nil).GetRange), arg0, arg1, arg2, arg3) +} + +// GetSet mocks base method. +func (m *MockUniversalClient) GetSet(arg0 context.Context, arg1 string, arg2 any) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSet", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// GetSet indicates an expected call of GetSet. +func (mr *MockUniversalClientMockRecorder) GetSet(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSet", reflect.TypeOf((*MockUniversalClient)(nil).GetSet), arg0, arg1, arg2) } // HDel mocks base method. -func (m *MockRedisClient) HDel(ctx context.Context, key string, fields ...string) *redis.IntCmd { +func (m *MockUniversalClient) HDel(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { m.ctrl.T.Helper() - varargs := []any{ctx, key} - for _, a := range fields { + varargs := []any{arg0, arg1} + for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "HDel", varargs...) @@ -163,31 +2520,195 @@ func (m *MockRedisClient) HDel(ctx context.Context, key string, fields ...string } // HDel indicates an expected call of HDel. -func (mr *MockRedisClientMockRecorder) HDel(ctx, key any, fields ...any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) HDel(arg0, arg1 any, arg2 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, key}, fields...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HDel", reflect.TypeOf((*MockRedisClient)(nil).HDel), varargs...) + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HDel", reflect.TypeOf((*MockUniversalClient)(nil).HDel), varargs...) +} + +// HExists mocks base method. +func (m *MockUniversalClient) HExists(arg0 context.Context, arg1, arg2 string) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HExists", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// HExists indicates an expected call of HExists. +func (mr *MockUniversalClientMockRecorder) HExists(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExists", reflect.TypeOf((*MockUniversalClient)(nil).HExists), arg0, arg1, arg2) +} + +// HGet mocks base method. +func (m *MockUniversalClient) HGet(arg0 context.Context, arg1, arg2 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HGet", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// HGet indicates an expected call of HGet. +func (mr *MockUniversalClientMockRecorder) HGet(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HGet", reflect.TypeOf((*MockUniversalClient)(nil).HGet), arg0, arg1, arg2) +} + +// HGetAll mocks base method. +func (m *MockUniversalClient) HGetAll(arg0 context.Context, arg1 string) *redis.MapStringStringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HGetAll", arg0, arg1) + ret0, _ := ret[0].(*redis.MapStringStringCmd) + return ret0 +} + +// HGetAll indicates an expected call of HGetAll. +func (mr *MockUniversalClientMockRecorder) HGetAll(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HGetAll", reflect.TypeOf((*MockUniversalClient)(nil).HGetAll), arg0, arg1) +} + +// HIncrBy mocks base method. +func (m *MockUniversalClient) HIncrBy(arg0 context.Context, arg1, arg2 string, arg3 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HIncrBy", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// HIncrBy indicates an expected call of HIncrBy. +func (mr *MockUniversalClientMockRecorder) HIncrBy(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HIncrBy", reflect.TypeOf((*MockUniversalClient)(nil).HIncrBy), arg0, arg1, arg2, arg3) +} + +// HIncrByFloat mocks base method. +func (m *MockUniversalClient) HIncrByFloat(arg0 context.Context, arg1, arg2 string, arg3 float64) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HIncrByFloat", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// HIncrByFloat indicates an expected call of HIncrByFloat. +func (mr *MockUniversalClientMockRecorder) HIncrByFloat(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HIncrByFloat", reflect.TypeOf((*MockUniversalClient)(nil).HIncrByFloat), arg0, arg1, arg2, arg3) } // HKeys mocks base method. -func (m *MockRedisClient) HKeys(ctx context.Context, key string) *redis.StringSliceCmd { +func (m *MockUniversalClient) HKeys(arg0 context.Context, arg1 string) *redis.StringSliceCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HKeys", ctx, key) + ret := m.ctrl.Call(m, "HKeys", arg0, arg1) ret0, _ := ret[0].(*redis.StringSliceCmd) return ret0 } // HKeys indicates an expected call of HKeys. -func (mr *MockRedisClientMockRecorder) HKeys(ctx, key any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) HKeys(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HKeys", reflect.TypeOf((*MockRedisClient)(nil).HKeys), ctx, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HKeys", reflect.TypeOf((*MockUniversalClient)(nil).HKeys), arg0, arg1) +} + +// HLen mocks base method. +func (m *MockUniversalClient) HLen(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HLen", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// HLen indicates an expected call of HLen. +func (mr *MockUniversalClientMockRecorder) HLen(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HLen", reflect.TypeOf((*MockUniversalClient)(nil).HLen), arg0, arg1) +} + +// HMGet mocks base method. +func (m *MockUniversalClient) HMGet(arg0 context.Context, arg1 string, arg2 ...string) *redis.SliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HMGet", varargs...) + ret0, _ := ret[0].(*redis.SliceCmd) + return ret0 +} + +// HMGet indicates an expected call of HMGet. +func (mr *MockUniversalClientMockRecorder) HMGet(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HMGet", reflect.TypeOf((*MockUniversalClient)(nil).HMGet), varargs...) +} + +// HMSet mocks base method. +func (m *MockUniversalClient) HMSet(arg0 context.Context, arg1 string, arg2 ...any) *redis.BoolCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HMSet", varargs...) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// HMSet indicates an expected call of HMSet. +func (mr *MockUniversalClientMockRecorder) HMSet(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HMSet", reflect.TypeOf((*MockUniversalClient)(nil).HMSet), varargs...) +} + +// HRandField mocks base method. +func (m *MockUniversalClient) HRandField(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HRandField", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// HRandField indicates an expected call of HRandField. +func (mr *MockUniversalClientMockRecorder) HRandField(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HRandField", reflect.TypeOf((*MockUniversalClient)(nil).HRandField), arg0, arg1, arg2) +} + +// HRandFieldWithValues mocks base method. +func (m *MockUniversalClient) HRandFieldWithValues(arg0 context.Context, arg1 string, arg2 int) *redis.KeyValueSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HRandFieldWithValues", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.KeyValueSliceCmd) + return ret0 +} + +// HRandFieldWithValues indicates an expected call of HRandFieldWithValues. +func (mr *MockUniversalClientMockRecorder) HRandFieldWithValues(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HRandFieldWithValues", reflect.TypeOf((*MockUniversalClient)(nil).HRandFieldWithValues), arg0, arg1, arg2) +} + +// HScan mocks base method. +func (m *MockUniversalClient) HScan(arg0 context.Context, arg1 string, arg2 uint64, arg3 string, arg4 int64) *redis.ScanCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HScan", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.ScanCmd) + return ret0 +} + +// HScan indicates an expected call of HScan. +func (mr *MockUniversalClientMockRecorder) HScan(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HScan", reflect.TypeOf((*MockUniversalClient)(nil).HScan), arg0, arg1, arg2, arg3, arg4) } // HSet mocks base method. -func (m *MockRedisClient) HSet(ctx context.Context, key string, values ...any) *redis.IntCmd { +func (m *MockUniversalClient) HSet(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { m.ctrl.T.Helper() - varargs := []any{ctx, key} - for _, a := range values { + varargs := []any{arg0, arg1} + for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "HSet", varargs...) @@ -196,73 +2717,1360 @@ func (m *MockRedisClient) HSet(ctx context.Context, key string, values ...any) * } // HSet indicates an expected call of HSet. -func (mr *MockRedisClientMockRecorder) HSet(ctx, key any, values ...any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) HSet(arg0, arg1 any, arg2 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, key}, values...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HSet", reflect.TypeOf((*MockRedisClient)(nil).HSet), varargs...) + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HSet", reflect.TypeOf((*MockUniversalClient)(nil).HSet), varargs...) +} + +// HSetNX mocks base method. +func (m *MockUniversalClient) HSetNX(arg0 context.Context, arg1, arg2 string, arg3 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HSetNX", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// HSetNX indicates an expected call of HSetNX. +func (mr *MockUniversalClientMockRecorder) HSetNX(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HSetNX", reflect.TypeOf((*MockUniversalClient)(nil).HSetNX), arg0, arg1, arg2, arg3) +} + +// HVals mocks base method. +func (m *MockUniversalClient) HVals(arg0 context.Context, arg1 string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HVals", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// HVals indicates an expected call of HVals. +func (mr *MockUniversalClientMockRecorder) HVals(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HVals", reflect.TypeOf((*MockUniversalClient)(nil).HVals), arg0, arg1) } // Incr mocks base method. -func (m *MockRedisClient) Incr(ctx context.Context, key string) *redis.IntCmd { +func (m *MockUniversalClient) Incr(arg0 context.Context, arg1 string) *redis.IntCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Incr", ctx, key) + ret := m.ctrl.Call(m, "Incr", arg0, arg1) ret0, _ := ret[0].(*redis.IntCmd) return ret0 } // Incr indicates an expected call of Incr. -func (mr *MockRedisClientMockRecorder) Incr(ctx, key any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Incr(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Incr", reflect.TypeOf((*MockRedisClient)(nil).Incr), ctx, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Incr", reflect.TypeOf((*MockUniversalClient)(nil).Incr), arg0, arg1) +} + +// IncrBy mocks base method. +func (m *MockUniversalClient) IncrBy(arg0 context.Context, arg1 string, arg2 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IncrBy", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// IncrBy indicates an expected call of IncrBy. +func (mr *MockUniversalClientMockRecorder) IncrBy(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrBy", reflect.TypeOf((*MockUniversalClient)(nil).IncrBy), arg0, arg1, arg2) +} + +// IncrByFloat mocks base method. +func (m *MockUniversalClient) IncrByFloat(arg0 context.Context, arg1 string, arg2 float64) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IncrByFloat", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// IncrByFloat indicates an expected call of IncrByFloat. +func (mr *MockUniversalClientMockRecorder) IncrByFloat(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrByFloat", reflect.TypeOf((*MockUniversalClient)(nil).IncrByFloat), arg0, arg1, arg2) +} + +// Info mocks base method. +func (m *MockUniversalClient) Info(arg0 context.Context, arg1 ...string) *redis.StringCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Info", varargs...) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// Info indicates an expected call of Info. +func (mr *MockUniversalClientMockRecorder) Info(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockUniversalClient)(nil).Info), varargs...) +} + +// JSONArrAppend mocks base method. +func (m *MockUniversalClient) JSONArrAppend(arg0 context.Context, arg1, arg2 string, arg3 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONArrAppend", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// JSONArrAppend indicates an expected call of JSONArrAppend. +func (mr *MockUniversalClientMockRecorder) JSONArrAppend(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrAppend", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrAppend), varargs...) +} + +// JSONArrIndex mocks base method. +func (m *MockUniversalClient) JSONArrIndex(arg0 context.Context, arg1, arg2 string, arg3 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONArrIndex", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// JSONArrIndex indicates an expected call of JSONArrIndex. +func (mr *MockUniversalClientMockRecorder) JSONArrIndex(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrIndex", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrIndex), varargs...) +} + +// JSONArrIndexWithArgs mocks base method. +func (m *MockUniversalClient) JSONArrIndexWithArgs(arg0 context.Context, arg1, arg2 string, arg3 *redis.JSONArrIndexArgs, arg4 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONArrIndexWithArgs", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// JSONArrIndexWithArgs indicates an expected call of JSONArrIndexWithArgs. +func (mr *MockUniversalClientMockRecorder) JSONArrIndexWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrIndexWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrIndexWithArgs), varargs...) +} + +// JSONArrInsert mocks base method. +func (m *MockUniversalClient) JSONArrInsert(arg0 context.Context, arg1, arg2 string, arg3 int64, arg4 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONArrInsert", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// JSONArrInsert indicates an expected call of JSONArrInsert. +func (mr *MockUniversalClientMockRecorder) JSONArrInsert(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrInsert", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrInsert), varargs...) +} + +// JSONArrLen mocks base method. +func (m *MockUniversalClient) JSONArrLen(arg0 context.Context, arg1, arg2 string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONArrLen", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// JSONArrLen indicates an expected call of JSONArrLen. +func (mr *MockUniversalClientMockRecorder) JSONArrLen(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrLen", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrLen), arg0, arg1, arg2) +} + +// JSONArrPop mocks base method. +func (m *MockUniversalClient) JSONArrPop(arg0 context.Context, arg1, arg2 string, arg3 int) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONArrPop", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// JSONArrPop indicates an expected call of JSONArrPop. +func (mr *MockUniversalClientMockRecorder) JSONArrPop(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrPop", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrPop), arg0, arg1, arg2, arg3) +} + +// JSONArrTrim mocks base method. +func (m *MockUniversalClient) JSONArrTrim(arg0 context.Context, arg1, arg2 string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONArrTrim", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// JSONArrTrim indicates an expected call of JSONArrTrim. +func (mr *MockUniversalClientMockRecorder) JSONArrTrim(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrTrim", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrTrim), arg0, arg1, arg2) +} + +// JSONArrTrimWithArgs mocks base method. +func (m *MockUniversalClient) JSONArrTrimWithArgs(arg0 context.Context, arg1, arg2 string, arg3 *redis.JSONArrTrimArgs) *redis.IntSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONArrTrimWithArgs", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// JSONArrTrimWithArgs indicates an expected call of JSONArrTrimWithArgs. +func (mr *MockUniversalClientMockRecorder) JSONArrTrimWithArgs(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONArrTrimWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).JSONArrTrimWithArgs), arg0, arg1, arg2, arg3) +} + +// JSONClear mocks base method. +func (m *MockUniversalClient) JSONClear(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONClear", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// JSONClear indicates an expected call of JSONClear. +func (mr *MockUniversalClientMockRecorder) JSONClear(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONClear", reflect.TypeOf((*MockUniversalClient)(nil).JSONClear), arg0, arg1, arg2) +} + +// JSONDebugMemory mocks base method. +func (m *MockUniversalClient) JSONDebugMemory(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONDebugMemory", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// JSONDebugMemory indicates an expected call of JSONDebugMemory. +func (mr *MockUniversalClientMockRecorder) JSONDebugMemory(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONDebugMemory", reflect.TypeOf((*MockUniversalClient)(nil).JSONDebugMemory), arg0, arg1, arg2) +} + +// JSONDel mocks base method. +func (m *MockUniversalClient) JSONDel(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONDel", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// JSONDel indicates an expected call of JSONDel. +func (mr *MockUniversalClientMockRecorder) JSONDel(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONDel", reflect.TypeOf((*MockUniversalClient)(nil).JSONDel), arg0, arg1, arg2) +} + +// JSONForget mocks base method. +func (m *MockUniversalClient) JSONForget(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONForget", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// JSONForget indicates an expected call of JSONForget. +func (mr *MockUniversalClientMockRecorder) JSONForget(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONForget", reflect.TypeOf((*MockUniversalClient)(nil).JSONForget), arg0, arg1, arg2) +} + +// JSONGet mocks base method. +func (m *MockUniversalClient) JSONGet(arg0 context.Context, arg1 string, arg2 ...string) *redis.JSONCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONGet", varargs...) + ret0, _ := ret[0].(*redis.JSONCmd) + return ret0 +} + +// JSONGet indicates an expected call of JSONGet. +func (mr *MockUniversalClientMockRecorder) JSONGet(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONGet", reflect.TypeOf((*MockUniversalClient)(nil).JSONGet), varargs...) +} + +// JSONGetWithArgs mocks base method. +func (m *MockUniversalClient) JSONGetWithArgs(arg0 context.Context, arg1 string, arg2 *redis.JSONGetArgs, arg3 ...string) *redis.JSONCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONGetWithArgs", varargs...) + ret0, _ := ret[0].(*redis.JSONCmd) + return ret0 +} + +// JSONGetWithArgs indicates an expected call of JSONGetWithArgs. +func (mr *MockUniversalClientMockRecorder) JSONGetWithArgs(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONGetWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).JSONGetWithArgs), varargs...) +} + +// JSONMGet mocks base method. +func (m *MockUniversalClient) JSONMGet(arg0 context.Context, arg1 string, arg2 ...string) *redis.JSONSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONMGet", varargs...) + ret0, _ := ret[0].(*redis.JSONSliceCmd) + return ret0 +} + +// JSONMGet indicates an expected call of JSONMGet. +func (mr *MockUniversalClientMockRecorder) JSONMGet(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONMGet", reflect.TypeOf((*MockUniversalClient)(nil).JSONMGet), varargs...) +} + +// JSONMSet mocks base method. +func (m *MockUniversalClient) JSONMSet(arg0 context.Context, arg1 ...any) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "JSONMSet", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// JSONMSet indicates an expected call of JSONMSet. +func (mr *MockUniversalClientMockRecorder) JSONMSet(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONMSet", reflect.TypeOf((*MockUniversalClient)(nil).JSONMSet), varargs...) +} + +// JSONMSetArgs mocks base method. +func (m *MockUniversalClient) JSONMSetArgs(arg0 context.Context, arg1 []redis.JSONSetArgs) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONMSetArgs", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// JSONMSetArgs indicates an expected call of JSONMSetArgs. +func (mr *MockUniversalClientMockRecorder) JSONMSetArgs(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONMSetArgs", reflect.TypeOf((*MockUniversalClient)(nil).JSONMSetArgs), arg0, arg1) +} + +// JSONMerge mocks base method. +func (m *MockUniversalClient) JSONMerge(arg0 context.Context, arg1, arg2, arg3 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONMerge", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// JSONMerge indicates an expected call of JSONMerge. +func (mr *MockUniversalClientMockRecorder) JSONMerge(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONMerge", reflect.TypeOf((*MockUniversalClient)(nil).JSONMerge), arg0, arg1, arg2, arg3) +} + +// JSONNumIncrBy mocks base method. +func (m *MockUniversalClient) JSONNumIncrBy(arg0 context.Context, arg1, arg2 string, arg3 float64) *redis.JSONCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONNumIncrBy", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.JSONCmd) + return ret0 +} + +// JSONNumIncrBy indicates an expected call of JSONNumIncrBy. +func (mr *MockUniversalClientMockRecorder) JSONNumIncrBy(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONNumIncrBy", reflect.TypeOf((*MockUniversalClient)(nil).JSONNumIncrBy), arg0, arg1, arg2, arg3) +} + +// JSONObjKeys mocks base method. +func (m *MockUniversalClient) JSONObjKeys(arg0 context.Context, arg1, arg2 string) *redis.SliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONObjKeys", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.SliceCmd) + return ret0 +} + +// JSONObjKeys indicates an expected call of JSONObjKeys. +func (mr *MockUniversalClientMockRecorder) JSONObjKeys(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONObjKeys", reflect.TypeOf((*MockUniversalClient)(nil).JSONObjKeys), arg0, arg1, arg2) +} + +// JSONObjLen mocks base method. +func (m *MockUniversalClient) JSONObjLen(arg0 context.Context, arg1, arg2 string) *redis.IntPointerSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONObjLen", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntPointerSliceCmd) + return ret0 +} + +// JSONObjLen indicates an expected call of JSONObjLen. +func (mr *MockUniversalClientMockRecorder) JSONObjLen(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONObjLen", reflect.TypeOf((*MockUniversalClient)(nil).JSONObjLen), arg0, arg1, arg2) +} + +// JSONSet mocks base method. +func (m *MockUniversalClient) JSONSet(arg0 context.Context, arg1, arg2 string, arg3 any) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONSet", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// JSONSet indicates an expected call of JSONSet. +func (mr *MockUniversalClientMockRecorder) JSONSet(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONSet", reflect.TypeOf((*MockUniversalClient)(nil).JSONSet), arg0, arg1, arg2, arg3) +} + +// JSONSetMode mocks base method. +func (m *MockUniversalClient) JSONSetMode(arg0 context.Context, arg1, arg2 string, arg3 any, arg4 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONSetMode", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// JSONSetMode indicates an expected call of JSONSetMode. +func (mr *MockUniversalClientMockRecorder) JSONSetMode(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONSetMode", reflect.TypeOf((*MockUniversalClient)(nil).JSONSetMode), arg0, arg1, arg2, arg3, arg4) +} + +// JSONStrAppend mocks base method. +func (m *MockUniversalClient) JSONStrAppend(arg0 context.Context, arg1, arg2, arg3 string) *redis.IntPointerSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONStrAppend", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntPointerSliceCmd) + return ret0 +} + +// JSONStrAppend indicates an expected call of JSONStrAppend. +func (mr *MockUniversalClientMockRecorder) JSONStrAppend(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONStrAppend", reflect.TypeOf((*MockUniversalClient)(nil).JSONStrAppend), arg0, arg1, arg2, arg3) +} + +// JSONStrLen mocks base method. +func (m *MockUniversalClient) JSONStrLen(arg0 context.Context, arg1, arg2 string) *redis.IntPointerSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONStrLen", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntPointerSliceCmd) + return ret0 +} + +// JSONStrLen indicates an expected call of JSONStrLen. +func (mr *MockUniversalClientMockRecorder) JSONStrLen(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONStrLen", reflect.TypeOf((*MockUniversalClient)(nil).JSONStrLen), arg0, arg1, arg2) +} + +// JSONToggle mocks base method. +func (m *MockUniversalClient) JSONToggle(arg0 context.Context, arg1, arg2 string) *redis.IntPointerSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONToggle", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntPointerSliceCmd) + return ret0 +} + +// JSONToggle indicates an expected call of JSONToggle. +func (mr *MockUniversalClientMockRecorder) JSONToggle(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONToggle", reflect.TypeOf((*MockUniversalClient)(nil).JSONToggle), arg0, arg1, arg2) +} + +// JSONType mocks base method. +func (m *MockUniversalClient) JSONType(arg0 context.Context, arg1, arg2 string) *redis.JSONSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "JSONType", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.JSONSliceCmd) + return ret0 +} + +// JSONType indicates an expected call of JSONType. +func (mr *MockUniversalClientMockRecorder) JSONType(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSONType", reflect.TypeOf((*MockUniversalClient)(nil).JSONType), arg0, arg1, arg2) +} + +// Keys mocks base method. +func (m *MockUniversalClient) Keys(arg0 context.Context, arg1 string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Keys", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// Keys indicates an expected call of Keys. +func (mr *MockUniversalClientMockRecorder) Keys(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keys", reflect.TypeOf((*MockUniversalClient)(nil).Keys), arg0, arg1) +} + +// LCS mocks base method. +func (m *MockUniversalClient) LCS(arg0 context.Context, arg1 *redis.LCSQuery) *redis.LCSCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LCS", arg0, arg1) + ret0, _ := ret[0].(*redis.LCSCmd) + return ret0 +} + +// LCS indicates an expected call of LCS. +func (mr *MockUniversalClientMockRecorder) LCS(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LCS", reflect.TypeOf((*MockUniversalClient)(nil).LCS), arg0, arg1) +} + +// LIndex mocks base method. +func (m *MockUniversalClient) LIndex(arg0 context.Context, arg1 string, arg2 int64) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LIndex", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// LIndex indicates an expected call of LIndex. +func (mr *MockUniversalClientMockRecorder) LIndex(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LIndex", reflect.TypeOf((*MockUniversalClient)(nil).LIndex), arg0, arg1, arg2) +} + +// LInsert mocks base method. +func (m *MockUniversalClient) LInsert(arg0 context.Context, arg1, arg2 string, arg3, arg4 any) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LInsert", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LInsert indicates an expected call of LInsert. +func (mr *MockUniversalClientMockRecorder) LInsert(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LInsert", reflect.TypeOf((*MockUniversalClient)(nil).LInsert), arg0, arg1, arg2, arg3, arg4) +} + +// LInsertAfter mocks base method. +func (m *MockUniversalClient) LInsertAfter(arg0 context.Context, arg1 string, arg2, arg3 any) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LInsertAfter", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LInsertAfter indicates an expected call of LInsertAfter. +func (mr *MockUniversalClientMockRecorder) LInsertAfter(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LInsertAfter", reflect.TypeOf((*MockUniversalClient)(nil).LInsertAfter), arg0, arg1, arg2, arg3) +} + +// LInsertBefore mocks base method. +func (m *MockUniversalClient) LInsertBefore(arg0 context.Context, arg1 string, arg2, arg3 any) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LInsertBefore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LInsertBefore indicates an expected call of LInsertBefore. +func (mr *MockUniversalClientMockRecorder) LInsertBefore(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LInsertBefore", reflect.TypeOf((*MockUniversalClient)(nil).LInsertBefore), arg0, arg1, arg2, arg3) } // LLen mocks base method. -func (m *MockRedisClient) LLen(ctx context.Context, key string) *redis.IntCmd { +func (m *MockUniversalClient) LLen(arg0 context.Context, arg1 string) *redis.IntCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LLen", ctx, key) + ret := m.ctrl.Call(m, "LLen", arg0, arg1) ret0, _ := ret[0].(*redis.IntCmd) return ret0 } // LLen indicates an expected call of LLen. -func (mr *MockRedisClientMockRecorder) LLen(ctx, key any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) LLen(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LLen", reflect.TypeOf((*MockRedisClient)(nil).LLen), ctx, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LLen", reflect.TypeOf((*MockUniversalClient)(nil).LLen), arg0, arg1) +} + +// LMPop mocks base method. +func (m *MockUniversalClient) LMPop(arg0 context.Context, arg1 string, arg2 int64, arg3 ...string) *redis.KeyValuesCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "LMPop", varargs...) + ret0, _ := ret[0].(*redis.KeyValuesCmd) + return ret0 +} + +// LMPop indicates an expected call of LMPop. +func (mr *MockUniversalClientMockRecorder) LMPop(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LMPop", reflect.TypeOf((*MockUniversalClient)(nil).LMPop), varargs...) +} + +// LMove mocks base method. +func (m *MockUniversalClient) LMove(arg0 context.Context, arg1, arg2, arg3, arg4 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LMove", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// LMove indicates an expected call of LMove. +func (mr *MockUniversalClientMockRecorder) LMove(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LMove", reflect.TypeOf((*MockUniversalClient)(nil).LMove), arg0, arg1, arg2, arg3, arg4) } // LPop mocks base method. -func (m *MockRedisClient) LPop(ctx context.Context, key string) *redis.StringCmd { +func (m *MockUniversalClient) LPop(arg0 context.Context, arg1 string) *redis.StringCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LPop", ctx, key) + ret := m.ctrl.Call(m, "LPop", arg0, arg1) ret0, _ := ret[0].(*redis.StringCmd) return ret0 } // LPop indicates an expected call of LPop. -func (mr *MockRedisClientMockRecorder) LPop(ctx, key any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) LPop(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LPop", reflect.TypeOf((*MockRedisClient)(nil).LPop), ctx, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LPop", reflect.TypeOf((*MockUniversalClient)(nil).LPop), arg0, arg1) +} + +// LPopCount mocks base method. +func (m *MockUniversalClient) LPopCount(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LPopCount", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// LPopCount indicates an expected call of LPopCount. +func (mr *MockUniversalClientMockRecorder) LPopCount(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LPopCount", reflect.TypeOf((*MockUniversalClient)(nil).LPopCount), arg0, arg1, arg2) +} + +// LPos mocks base method. +func (m *MockUniversalClient) LPos(arg0 context.Context, arg1, arg2 string, arg3 redis.LPosArgs) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LPos", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LPos indicates an expected call of LPos. +func (mr *MockUniversalClientMockRecorder) LPos(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LPos", reflect.TypeOf((*MockUniversalClient)(nil).LPos), arg0, arg1, arg2, arg3) +} + +// LPosCount mocks base method. +func (m *MockUniversalClient) LPosCount(arg0 context.Context, arg1, arg2 string, arg3 int64, arg4 redis.LPosArgs) *redis.IntSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LPosCount", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// LPosCount indicates an expected call of LPosCount. +func (mr *MockUniversalClientMockRecorder) LPosCount(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LPosCount", reflect.TypeOf((*MockUniversalClient)(nil).LPosCount), arg0, arg1, arg2, arg3, arg4) +} + +// LPush mocks base method. +func (m *MockUniversalClient) LPush(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "LPush", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LPush indicates an expected call of LPush. +func (mr *MockUniversalClientMockRecorder) LPush(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LPush", reflect.TypeOf((*MockUniversalClient)(nil).LPush), varargs...) +} + +// LPushX mocks base method. +func (m *MockUniversalClient) LPushX(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "LPushX", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LPushX indicates an expected call of LPushX. +func (mr *MockUniversalClientMockRecorder) LPushX(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LPushX", reflect.TypeOf((*MockUniversalClient)(nil).LPushX), varargs...) +} + +// LRange mocks base method. +func (m *MockUniversalClient) LRange(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// LRange indicates an expected call of LRange. +func (mr *MockUniversalClientMockRecorder) LRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LRange", reflect.TypeOf((*MockUniversalClient)(nil).LRange), arg0, arg1, arg2, arg3) +} + +// LRem mocks base method. +func (m *MockUniversalClient) LRem(arg0 context.Context, arg1 string, arg2 int64, arg3 any) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LRem", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LRem indicates an expected call of LRem. +func (mr *MockUniversalClientMockRecorder) LRem(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LRem", reflect.TypeOf((*MockUniversalClient)(nil).LRem), arg0, arg1, arg2, arg3) +} + +// LSet mocks base method. +func (m *MockUniversalClient) LSet(arg0 context.Context, arg1 string, arg2 int64, arg3 any) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LSet", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// LSet indicates an expected call of LSet. +func (mr *MockUniversalClientMockRecorder) LSet(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LSet", reflect.TypeOf((*MockUniversalClient)(nil).LSet), arg0, arg1, arg2, arg3) +} + +// LTrim mocks base method. +func (m *MockUniversalClient) LTrim(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LTrim", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// LTrim indicates an expected call of LTrim. +func (mr *MockUniversalClientMockRecorder) LTrim(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LTrim", reflect.TypeOf((*MockUniversalClient)(nil).LTrim), arg0, arg1, arg2, arg3) +} + +// LastSave mocks base method. +func (m *MockUniversalClient) LastSave(arg0 context.Context) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LastSave", arg0) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// LastSave indicates an expected call of LastSave. +func (mr *MockUniversalClientMockRecorder) LastSave(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastSave", reflect.TypeOf((*MockUniversalClient)(nil).LastSave), arg0) +} + +// MGet mocks base method. +func (m *MockUniversalClient) MGet(arg0 context.Context, arg1 ...string) *redis.SliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MGet", varargs...) + ret0, _ := ret[0].(*redis.SliceCmd) + return ret0 +} + +// MGet indicates an expected call of MGet. +func (mr *MockUniversalClientMockRecorder) MGet(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MGet", reflect.TypeOf((*MockUniversalClient)(nil).MGet), varargs...) +} + +// MSet mocks base method. +func (m *MockUniversalClient) MSet(arg0 context.Context, arg1 ...any) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MSet", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// MSet indicates an expected call of MSet. +func (mr *MockUniversalClientMockRecorder) MSet(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MSet", reflect.TypeOf((*MockUniversalClient)(nil).MSet), varargs...) +} + +// MSetNX mocks base method. +func (m *MockUniversalClient) MSetNX(arg0 context.Context, arg1 ...any) *redis.BoolCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MSetNX", varargs...) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// MSetNX indicates an expected call of MSetNX. +func (mr *MockUniversalClientMockRecorder) MSetNX(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MSetNX", reflect.TypeOf((*MockUniversalClient)(nil).MSetNX), varargs...) +} + +// MemoryUsage mocks base method. +func (m *MockUniversalClient) MemoryUsage(arg0 context.Context, arg1 string, arg2 ...int) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MemoryUsage", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// MemoryUsage indicates an expected call of MemoryUsage. +func (mr *MockUniversalClientMockRecorder) MemoryUsage(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MemoryUsage", reflect.TypeOf((*MockUniversalClient)(nil).MemoryUsage), varargs...) +} + +// Migrate mocks base method. +func (m *MockUniversalClient) Migrate(arg0 context.Context, arg1, arg2, arg3 string, arg4 int, arg5 time.Duration) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Migrate", arg0, arg1, arg2, arg3, arg4, arg5) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// Migrate indicates an expected call of Migrate. +func (mr *MockUniversalClientMockRecorder) Migrate(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Migrate", reflect.TypeOf((*MockUniversalClient)(nil).Migrate), arg0, arg1, arg2, arg3, arg4, arg5) +} + +// ModuleLoadex mocks base method. +func (m *MockUniversalClient) ModuleLoadex(arg0 context.Context, arg1 *redis.ModuleLoadexConfig) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ModuleLoadex", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ModuleLoadex indicates an expected call of ModuleLoadex. +func (mr *MockUniversalClientMockRecorder) ModuleLoadex(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModuleLoadex", reflect.TypeOf((*MockUniversalClient)(nil).ModuleLoadex), arg0, arg1) +} + +// Move mocks base method. +func (m *MockUniversalClient) Move(arg0 context.Context, arg1 string, arg2 int) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Move", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// Move indicates an expected call of Move. +func (mr *MockUniversalClientMockRecorder) Move(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Move", reflect.TypeOf((*MockUniversalClient)(nil).Move), arg0, arg1, arg2) +} + +// ObjectEncoding mocks base method. +func (m *MockUniversalClient) ObjectEncoding(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ObjectEncoding", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ObjectEncoding indicates an expected call of ObjectEncoding. +func (mr *MockUniversalClientMockRecorder) ObjectEncoding(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObjectEncoding", reflect.TypeOf((*MockUniversalClient)(nil).ObjectEncoding), arg0, arg1) +} + +// ObjectFreq mocks base method. +func (m *MockUniversalClient) ObjectFreq(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ObjectFreq", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ObjectFreq indicates an expected call of ObjectFreq. +func (mr *MockUniversalClientMockRecorder) ObjectFreq(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObjectFreq", reflect.TypeOf((*MockUniversalClient)(nil).ObjectFreq), arg0, arg1) +} + +// ObjectIdleTime mocks base method. +func (m *MockUniversalClient) ObjectIdleTime(arg0 context.Context, arg1 string) *redis.DurationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ObjectIdleTime", arg0, arg1) + ret0, _ := ret[0].(*redis.DurationCmd) + return ret0 +} + +// ObjectIdleTime indicates an expected call of ObjectIdleTime. +func (mr *MockUniversalClientMockRecorder) ObjectIdleTime(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObjectIdleTime", reflect.TypeOf((*MockUniversalClient)(nil).ObjectIdleTime), arg0, arg1) +} + +// ObjectRefCount mocks base method. +func (m *MockUniversalClient) ObjectRefCount(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ObjectRefCount", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ObjectRefCount indicates an expected call of ObjectRefCount. +func (mr *MockUniversalClientMockRecorder) ObjectRefCount(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObjectRefCount", reflect.TypeOf((*MockUniversalClient)(nil).ObjectRefCount), arg0, arg1) +} + +// PExpire mocks base method. +func (m *MockUniversalClient) PExpire(arg0 context.Context, arg1 string, arg2 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PExpire", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// PExpire indicates an expected call of PExpire. +func (mr *MockUniversalClientMockRecorder) PExpire(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PExpire", reflect.TypeOf((*MockUniversalClient)(nil).PExpire), arg0, arg1, arg2) +} + +// PExpireAt mocks base method. +func (m *MockUniversalClient) PExpireAt(arg0 context.Context, arg1 string, arg2 time.Time) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PExpireAt", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// PExpireAt indicates an expected call of PExpireAt. +func (mr *MockUniversalClientMockRecorder) PExpireAt(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PExpireAt", reflect.TypeOf((*MockUniversalClient)(nil).PExpireAt), arg0, arg1, arg2) +} + +// PExpireTime mocks base method. +func (m *MockUniversalClient) PExpireTime(arg0 context.Context, arg1 string) *redis.DurationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PExpireTime", arg0, arg1) + ret0, _ := ret[0].(*redis.DurationCmd) + return ret0 +} + +// PExpireTime indicates an expected call of PExpireTime. +func (mr *MockUniversalClientMockRecorder) PExpireTime(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PExpireTime", reflect.TypeOf((*MockUniversalClient)(nil).PExpireTime), arg0, arg1) +} + +// PFAdd mocks base method. +func (m *MockUniversalClient) PFAdd(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PFAdd", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// PFAdd indicates an expected call of PFAdd. +func (mr *MockUniversalClientMockRecorder) PFAdd(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PFAdd", reflect.TypeOf((*MockUniversalClient)(nil).PFAdd), varargs...) +} + +// PFCount mocks base method. +func (m *MockUniversalClient) PFCount(arg0 context.Context, arg1 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PFCount", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// PFCount indicates an expected call of PFCount. +func (mr *MockUniversalClientMockRecorder) PFCount(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PFCount", reflect.TypeOf((*MockUniversalClient)(nil).PFCount), varargs...) +} + +// PFMerge mocks base method. +func (m *MockUniversalClient) PFMerge(arg0 context.Context, arg1 string, arg2 ...string) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PFMerge", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// PFMerge indicates an expected call of PFMerge. +func (mr *MockUniversalClientMockRecorder) PFMerge(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PFMerge", reflect.TypeOf((*MockUniversalClient)(nil).PFMerge), varargs...) +} + +// PSubscribe mocks base method. +func (m *MockUniversalClient) PSubscribe(arg0 context.Context, arg1 ...string) *redis.PubSub { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PSubscribe", varargs...) + ret0, _ := ret[0].(*redis.PubSub) + return ret0 +} + +// PSubscribe indicates an expected call of PSubscribe. +func (mr *MockUniversalClientMockRecorder) PSubscribe(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PSubscribe", reflect.TypeOf((*MockUniversalClient)(nil).PSubscribe), varargs...) +} + +// PTTL mocks base method. +func (m *MockUniversalClient) PTTL(arg0 context.Context, arg1 string) *redis.DurationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PTTL", arg0, arg1) + ret0, _ := ret[0].(*redis.DurationCmd) + return ret0 +} + +// PTTL indicates an expected call of PTTL. +func (mr *MockUniversalClientMockRecorder) PTTL(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PTTL", reflect.TypeOf((*MockUniversalClient)(nil).PTTL), arg0, arg1) +} + +// Persist mocks base method. +func (m *MockUniversalClient) Persist(arg0 context.Context, arg1 string) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Persist", arg0, arg1) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// Persist indicates an expected call of Persist. +func (mr *MockUniversalClientMockRecorder) Persist(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Persist", reflect.TypeOf((*MockUniversalClient)(nil).Persist), arg0, arg1) } // Ping mocks base method. -func (m *MockRedisClient) Ping(ctx context.Context) *redis.StatusCmd { +func (m *MockUniversalClient) Ping(arg0 context.Context) *redis.StatusCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Ping", ctx) + ret := m.ctrl.Call(m, "Ping", arg0) ret0, _ := ret[0].(*redis.StatusCmd) return ret0 } // Ping indicates an expected call of Ping. -func (mr *MockRedisClientMockRecorder) Ping(ctx any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Ping(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockRedisClient)(nil).Ping), ctx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockUniversalClient)(nil).Ping), arg0) +} + +// Pipeline mocks base method. +func (m *MockUniversalClient) Pipeline() redis.Pipeliner { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Pipeline") + ret0, _ := ret[0].(redis.Pipeliner) + return ret0 +} + +// Pipeline indicates an expected call of Pipeline. +func (mr *MockUniversalClientMockRecorder) Pipeline() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pipeline", reflect.TypeOf((*MockUniversalClient)(nil).Pipeline)) +} + +// Pipelined mocks base method. +func (m *MockUniversalClient) Pipelined(arg0 context.Context, arg1 func(redis.Pipeliner) error) ([]redis.Cmder, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Pipelined", arg0, arg1) + ret0, _ := ret[0].([]redis.Cmder) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Pipelined indicates an expected call of Pipelined. +func (mr *MockUniversalClientMockRecorder) Pipelined(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pipelined", reflect.TypeOf((*MockUniversalClient)(nil).Pipelined), arg0, arg1) +} + +// PoolStats mocks base method. +func (m *MockUniversalClient) PoolStats() *redis.PoolStats { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PoolStats") + ret0, _ := ret[0].(*redis.PoolStats) + return ret0 +} + +// PoolStats indicates an expected call of PoolStats. +func (mr *MockUniversalClientMockRecorder) PoolStats() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PoolStats", reflect.TypeOf((*MockUniversalClient)(nil).PoolStats)) +} + +// Process mocks base method. +func (m *MockUniversalClient) Process(arg0 context.Context, arg1 redis.Cmder) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Process", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Process indicates an expected call of Process. +func (mr *MockUniversalClientMockRecorder) Process(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Process", reflect.TypeOf((*MockUniversalClient)(nil).Process), arg0, arg1) +} + +// PubSubChannels mocks base method. +func (m *MockUniversalClient) PubSubChannels(arg0 context.Context, arg1 string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PubSubChannels", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// PubSubChannels indicates an expected call of PubSubChannels. +func (mr *MockUniversalClientMockRecorder) PubSubChannels(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PubSubChannels", reflect.TypeOf((*MockUniversalClient)(nil).PubSubChannels), arg0, arg1) +} + +// PubSubNumPat mocks base method. +func (m *MockUniversalClient) PubSubNumPat(arg0 context.Context) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PubSubNumPat", arg0) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// PubSubNumPat indicates an expected call of PubSubNumPat. +func (mr *MockUniversalClientMockRecorder) PubSubNumPat(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PubSubNumPat", reflect.TypeOf((*MockUniversalClient)(nil).PubSubNumPat), arg0) +} + +// PubSubNumSub mocks base method. +func (m *MockUniversalClient) PubSubNumSub(arg0 context.Context, arg1 ...string) *redis.MapStringIntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PubSubNumSub", varargs...) + ret0, _ := ret[0].(*redis.MapStringIntCmd) + return ret0 +} + +// PubSubNumSub indicates an expected call of PubSubNumSub. +func (mr *MockUniversalClientMockRecorder) PubSubNumSub(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PubSubNumSub", reflect.TypeOf((*MockUniversalClient)(nil).PubSubNumSub), varargs...) +} + +// PubSubShardChannels mocks base method. +func (m *MockUniversalClient) PubSubShardChannels(arg0 context.Context, arg1 string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PubSubShardChannels", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// PubSubShardChannels indicates an expected call of PubSubShardChannels. +func (mr *MockUniversalClientMockRecorder) PubSubShardChannels(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PubSubShardChannels", reflect.TypeOf((*MockUniversalClient)(nil).PubSubShardChannels), arg0, arg1) +} + +// PubSubShardNumSub mocks base method. +func (m *MockUniversalClient) PubSubShardNumSub(arg0 context.Context, arg1 ...string) *redis.MapStringIntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PubSubShardNumSub", varargs...) + ret0, _ := ret[0].(*redis.MapStringIntCmd) + return ret0 +} + +// PubSubShardNumSub indicates an expected call of PubSubShardNumSub. +func (mr *MockUniversalClientMockRecorder) PubSubShardNumSub(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PubSubShardNumSub", reflect.TypeOf((*MockUniversalClient)(nil).PubSubShardNumSub), varargs...) +} + +// Publish mocks base method. +func (m *MockUniversalClient) Publish(arg0 context.Context, arg1 string, arg2 any) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Publish", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// Publish indicates an expected call of Publish. +func (mr *MockUniversalClientMockRecorder) Publish(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Publish", reflect.TypeOf((*MockUniversalClient)(nil).Publish), arg0, arg1, arg2) +} + +// Quit mocks base method. +func (m *MockUniversalClient) Quit(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Quit", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// Quit indicates an expected call of Quit. +func (mr *MockUniversalClientMockRecorder) Quit(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Quit", reflect.TypeOf((*MockUniversalClient)(nil).Quit), arg0) +} + +// RPop mocks base method. +func (m *MockUniversalClient) RPop(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RPop", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// RPop indicates an expected call of RPop. +func (mr *MockUniversalClientMockRecorder) RPop(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RPop", reflect.TypeOf((*MockUniversalClient)(nil).RPop), arg0, arg1) +} + +// RPopCount mocks base method. +func (m *MockUniversalClient) RPopCount(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RPopCount", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// RPopCount indicates an expected call of RPopCount. +func (mr *MockUniversalClientMockRecorder) RPopCount(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RPopCount", reflect.TypeOf((*MockUniversalClient)(nil).RPopCount), arg0, arg1, arg2) +} + +// RPopLPush mocks base method. +func (m *MockUniversalClient) RPopLPush(arg0 context.Context, arg1, arg2 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RPopLPush", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// RPopLPush indicates an expected call of RPopLPush. +func (mr *MockUniversalClientMockRecorder) RPopLPush(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RPopLPush", reflect.TypeOf((*MockUniversalClient)(nil).RPopLPush), arg0, arg1, arg2) } // RPush mocks base method. -func (m *MockRedisClient) RPush(ctx context.Context, key string, values ...any) *redis.IntCmd { +func (m *MockUniversalClient) RPush(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { m.ctrl.T.Helper() - varargs := []any{ctx, key} - for _, a := range values { + varargs := []any{arg0, arg1} + for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "RPush", varargs...) @@ -271,17 +4079,134 @@ func (m *MockRedisClient) RPush(ctx context.Context, key string, values ...any) } // RPush indicates an expected call of RPush. -func (mr *MockRedisClientMockRecorder) RPush(ctx, key any, values ...any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) RPush(arg0, arg1 any, arg2 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, key}, values...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RPush", reflect.TypeOf((*MockRedisClient)(nil).RPush), varargs...) + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RPush", reflect.TypeOf((*MockUniversalClient)(nil).RPush), varargs...) +} + +// RPushX mocks base method. +func (m *MockUniversalClient) RPushX(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "RPushX", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// RPushX indicates an expected call of RPushX. +func (mr *MockUniversalClientMockRecorder) RPushX(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RPushX", reflect.TypeOf((*MockUniversalClient)(nil).RPushX), varargs...) +} + +// RandomKey mocks base method. +func (m *MockUniversalClient) RandomKey(arg0 context.Context) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RandomKey", arg0) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// RandomKey indicates an expected call of RandomKey. +func (mr *MockUniversalClientMockRecorder) RandomKey(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RandomKey", reflect.TypeOf((*MockUniversalClient)(nil).RandomKey), arg0) +} + +// ReadOnly mocks base method. +func (m *MockUniversalClient) ReadOnly(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadOnly", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ReadOnly indicates an expected call of ReadOnly. +func (mr *MockUniversalClientMockRecorder) ReadOnly(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadOnly", reflect.TypeOf((*MockUniversalClient)(nil).ReadOnly), arg0) +} + +// ReadWrite mocks base method. +func (m *MockUniversalClient) ReadWrite(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadWrite", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ReadWrite indicates an expected call of ReadWrite. +func (mr *MockUniversalClientMockRecorder) ReadWrite(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadWrite", reflect.TypeOf((*MockUniversalClient)(nil).ReadWrite), arg0) +} + +// Rename mocks base method. +func (m *MockUniversalClient) Rename(arg0 context.Context, arg1, arg2 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Rename", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// Rename indicates an expected call of Rename. +func (mr *MockUniversalClientMockRecorder) Rename(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rename", reflect.TypeOf((*MockUniversalClient)(nil).Rename), arg0, arg1, arg2) +} + +// RenameNX mocks base method. +func (m *MockUniversalClient) RenameNX(arg0 context.Context, arg1, arg2 string) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RenameNX", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// RenameNX indicates an expected call of RenameNX. +func (mr *MockUniversalClientMockRecorder) RenameNX(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RenameNX", reflect.TypeOf((*MockUniversalClient)(nil).RenameNX), arg0, arg1, arg2) +} + +// Restore mocks base method. +func (m *MockUniversalClient) Restore(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Restore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// Restore indicates an expected call of Restore. +func (mr *MockUniversalClientMockRecorder) Restore(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Restore", reflect.TypeOf((*MockUniversalClient)(nil).Restore), arg0, arg1, arg2, arg3) +} + +// RestoreReplace mocks base method. +func (m *MockUniversalClient) RestoreReplace(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RestoreReplace", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// RestoreReplace indicates an expected call of RestoreReplace. +func (mr *MockUniversalClientMockRecorder) RestoreReplace(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RestoreReplace", reflect.TypeOf((*MockUniversalClient)(nil).RestoreReplace), arg0, arg1, arg2, arg3) } // SAdd mocks base method. -func (m *MockRedisClient) SAdd(ctx context.Context, key string, members ...any) *redis.IntCmd { +func (m *MockUniversalClient) SAdd(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { m.ctrl.T.Helper() - varargs := []any{ctx, key} - for _, a := range members { + varargs := []any{arg0, arg1} + for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "SAdd", varargs...) @@ -290,31 +4215,271 @@ func (m *MockRedisClient) SAdd(ctx context.Context, key string, members ...any) } // SAdd indicates an expected call of SAdd. -func (mr *MockRedisClientMockRecorder) SAdd(ctx, key any, members ...any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) SAdd(arg0, arg1 any, arg2 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, key}, members...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SAdd", reflect.TypeOf((*MockRedisClient)(nil).SAdd), varargs...) + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SAdd", reflect.TypeOf((*MockUniversalClient)(nil).SAdd), varargs...) +} + +// SCard mocks base method. +func (m *MockUniversalClient) SCard(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SCard", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SCard indicates an expected call of SCard. +func (mr *MockUniversalClientMockRecorder) SCard(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SCard", reflect.TypeOf((*MockUniversalClient)(nil).SCard), arg0, arg1) +} + +// SDiff mocks base method. +func (m *MockUniversalClient) SDiff(arg0 context.Context, arg1 ...string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SDiff", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// SDiff indicates an expected call of SDiff. +func (mr *MockUniversalClientMockRecorder) SDiff(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SDiff", reflect.TypeOf((*MockUniversalClient)(nil).SDiff), varargs...) +} + +// SDiffStore mocks base method. +func (m *MockUniversalClient) SDiffStore(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SDiffStore", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SDiffStore indicates an expected call of SDiffStore. +func (mr *MockUniversalClientMockRecorder) SDiffStore(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SDiffStore", reflect.TypeOf((*MockUniversalClient)(nil).SDiffStore), varargs...) +} + +// SInter mocks base method. +func (m *MockUniversalClient) SInter(arg0 context.Context, arg1 ...string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SInter", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// SInter indicates an expected call of SInter. +func (mr *MockUniversalClientMockRecorder) SInter(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SInter", reflect.TypeOf((*MockUniversalClient)(nil).SInter), varargs...) +} + +// SInterCard mocks base method. +func (m *MockUniversalClient) SInterCard(arg0 context.Context, arg1 int64, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SInterCard", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SInterCard indicates an expected call of SInterCard. +func (mr *MockUniversalClientMockRecorder) SInterCard(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SInterCard", reflect.TypeOf((*MockUniversalClient)(nil).SInterCard), varargs...) +} + +// SInterStore mocks base method. +func (m *MockUniversalClient) SInterStore(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SInterStore", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SInterStore indicates an expected call of SInterStore. +func (mr *MockUniversalClientMockRecorder) SInterStore(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SInterStore", reflect.TypeOf((*MockUniversalClient)(nil).SInterStore), varargs...) } // SIsMember mocks base method. -func (m *MockRedisClient) SIsMember(ctx context.Context, key string, member any) *redis.BoolCmd { +func (m *MockUniversalClient) SIsMember(arg0 context.Context, arg1 string, arg2 any) *redis.BoolCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SIsMember", ctx, key, member) + ret := m.ctrl.Call(m, "SIsMember", arg0, arg1, arg2) ret0, _ := ret[0].(*redis.BoolCmd) return ret0 } // SIsMember indicates an expected call of SIsMember. -func (mr *MockRedisClientMockRecorder) SIsMember(ctx, key, member any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) SIsMember(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SIsMember", reflect.TypeOf((*MockRedisClient)(nil).SIsMember), ctx, key, member) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SIsMember", reflect.TypeOf((*MockUniversalClient)(nil).SIsMember), arg0, arg1, arg2) +} + +// SMIsMember mocks base method. +func (m *MockUniversalClient) SMIsMember(arg0 context.Context, arg1 string, arg2 ...any) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SMIsMember", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// SMIsMember indicates an expected call of SMIsMember. +func (mr *MockUniversalClientMockRecorder) SMIsMember(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMIsMember", reflect.TypeOf((*MockUniversalClient)(nil).SMIsMember), varargs...) +} + +// SMembers mocks base method. +func (m *MockUniversalClient) SMembers(arg0 context.Context, arg1 string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SMembers", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// SMembers indicates an expected call of SMembers. +func (mr *MockUniversalClientMockRecorder) SMembers(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMembers", reflect.TypeOf((*MockUniversalClient)(nil).SMembers), arg0, arg1) +} + +// SMembersMap mocks base method. +func (m *MockUniversalClient) SMembersMap(arg0 context.Context, arg1 string) *redis.StringStructMapCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SMembersMap", arg0, arg1) + ret0, _ := ret[0].(*redis.StringStructMapCmd) + return ret0 +} + +// SMembersMap indicates an expected call of SMembersMap. +func (mr *MockUniversalClientMockRecorder) SMembersMap(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMembersMap", reflect.TypeOf((*MockUniversalClient)(nil).SMembersMap), arg0, arg1) +} + +// SMove mocks base method. +func (m *MockUniversalClient) SMove(arg0 context.Context, arg1, arg2 string, arg3 any) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SMove", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// SMove indicates an expected call of SMove. +func (mr *MockUniversalClientMockRecorder) SMove(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMove", reflect.TypeOf((*MockUniversalClient)(nil).SMove), arg0, arg1, arg2, arg3) +} + +// SPop mocks base method. +func (m *MockUniversalClient) SPop(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SPop", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// SPop indicates an expected call of SPop. +func (mr *MockUniversalClientMockRecorder) SPop(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SPop", reflect.TypeOf((*MockUniversalClient)(nil).SPop), arg0, arg1) +} + +// SPopN mocks base method. +func (m *MockUniversalClient) SPopN(arg0 context.Context, arg1 string, arg2 int64) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SPopN", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// SPopN indicates an expected call of SPopN. +func (mr *MockUniversalClientMockRecorder) SPopN(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SPopN", reflect.TypeOf((*MockUniversalClient)(nil).SPopN), arg0, arg1, arg2) +} + +// SPublish mocks base method. +func (m *MockUniversalClient) SPublish(arg0 context.Context, arg1 string, arg2 any) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SPublish", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SPublish indicates an expected call of SPublish. +func (mr *MockUniversalClientMockRecorder) SPublish(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SPublish", reflect.TypeOf((*MockUniversalClient)(nil).SPublish), arg0, arg1, arg2) +} + +// SRandMember mocks base method. +func (m *MockUniversalClient) SRandMember(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SRandMember", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// SRandMember indicates an expected call of SRandMember. +func (mr *MockUniversalClientMockRecorder) SRandMember(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SRandMember", reflect.TypeOf((*MockUniversalClient)(nil).SRandMember), arg0, arg1) +} + +// SRandMemberN mocks base method. +func (m *MockUniversalClient) SRandMemberN(arg0 context.Context, arg1 string, arg2 int64) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SRandMemberN", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// SRandMemberN indicates an expected call of SRandMemberN. +func (mr *MockUniversalClientMockRecorder) SRandMemberN(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SRandMemberN", reflect.TypeOf((*MockUniversalClient)(nil).SRandMemberN), arg0, arg1, arg2) } // SRem mocks base method. -func (m *MockRedisClient) SRem(ctx context.Context, key string, members ...any) *redis.IntCmd { +func (m *MockUniversalClient) SRem(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { m.ctrl.T.Helper() - varargs := []any{ctx, key} - for _, a := range members { + varargs := []any{arg0, arg1} + for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "SRem", varargs...) @@ -323,22 +4488,2714 @@ func (m *MockRedisClient) SRem(ctx context.Context, key string, members ...any) } // SRem indicates an expected call of SRem. -func (mr *MockRedisClientMockRecorder) SRem(ctx, key any, members ...any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) SRem(arg0, arg1 any, arg2 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, key}, members...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SRem", reflect.TypeOf((*MockRedisClient)(nil).SRem), varargs...) + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SRem", reflect.TypeOf((*MockUniversalClient)(nil).SRem), varargs...) +} + +// SScan mocks base method. +func (m *MockUniversalClient) SScan(arg0 context.Context, arg1 string, arg2 uint64, arg3 string, arg4 int64) *redis.ScanCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SScan", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.ScanCmd) + return ret0 +} + +// SScan indicates an expected call of SScan. +func (mr *MockUniversalClientMockRecorder) SScan(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SScan", reflect.TypeOf((*MockUniversalClient)(nil).SScan), arg0, arg1, arg2, arg3, arg4) +} + +// SSubscribe mocks base method. +func (m *MockUniversalClient) SSubscribe(arg0 context.Context, arg1 ...string) *redis.PubSub { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SSubscribe", varargs...) + ret0, _ := ret[0].(*redis.PubSub) + return ret0 +} + +// SSubscribe indicates an expected call of SSubscribe. +func (mr *MockUniversalClientMockRecorder) SSubscribe(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SSubscribe", reflect.TypeOf((*MockUniversalClient)(nil).SSubscribe), varargs...) +} + +// SUnion mocks base method. +func (m *MockUniversalClient) SUnion(arg0 context.Context, arg1 ...string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SUnion", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// SUnion indicates an expected call of SUnion. +func (mr *MockUniversalClientMockRecorder) SUnion(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SUnion", reflect.TypeOf((*MockUniversalClient)(nil).SUnion), varargs...) +} + +// SUnionStore mocks base method. +func (m *MockUniversalClient) SUnionStore(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SUnionStore", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SUnionStore indicates an expected call of SUnionStore. +func (mr *MockUniversalClientMockRecorder) SUnionStore(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SUnionStore", reflect.TypeOf((*MockUniversalClient)(nil).SUnionStore), varargs...) +} + +// Save mocks base method. +func (m *MockUniversalClient) Save(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Save", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// Save indicates an expected call of Save. +func (mr *MockUniversalClientMockRecorder) Save(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockUniversalClient)(nil).Save), arg0) +} + +// Scan mocks base method. +func (m *MockUniversalClient) Scan(arg0 context.Context, arg1 uint64, arg2 string, arg3 int64) *redis.ScanCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Scan", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.ScanCmd) + return ret0 +} + +// Scan indicates an expected call of Scan. +func (mr *MockUniversalClientMockRecorder) Scan(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Scan", reflect.TypeOf((*MockUniversalClient)(nil).Scan), arg0, arg1, arg2, arg3) +} + +// ScanType mocks base method. +func (m *MockUniversalClient) ScanType(arg0 context.Context, arg1 uint64, arg2 string, arg3 int64, arg4 string) *redis.ScanCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ScanType", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.ScanCmd) + return ret0 +} + +// ScanType indicates an expected call of ScanType. +func (mr *MockUniversalClientMockRecorder) ScanType(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScanType", reflect.TypeOf((*MockUniversalClient)(nil).ScanType), arg0, arg1, arg2, arg3, arg4) +} + +// ScriptExists mocks base method. +func (m *MockUniversalClient) ScriptExists(arg0 context.Context, arg1 ...string) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ScriptExists", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// ScriptExists indicates an expected call of ScriptExists. +func (mr *MockUniversalClientMockRecorder) ScriptExists(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptExists", reflect.TypeOf((*MockUniversalClient)(nil).ScriptExists), varargs...) +} + +// ScriptFlush mocks base method. +func (m *MockUniversalClient) ScriptFlush(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ScriptFlush", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ScriptFlush indicates an expected call of ScriptFlush. +func (mr *MockUniversalClientMockRecorder) ScriptFlush(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptFlush", reflect.TypeOf((*MockUniversalClient)(nil).ScriptFlush), arg0) +} + +// ScriptKill mocks base method. +func (m *MockUniversalClient) ScriptKill(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ScriptKill", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ScriptKill indicates an expected call of ScriptKill. +func (mr *MockUniversalClientMockRecorder) ScriptKill(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptKill", reflect.TypeOf((*MockUniversalClient)(nil).ScriptKill), arg0) +} + +// ScriptLoad mocks base method. +func (m *MockUniversalClient) ScriptLoad(arg0 context.Context, arg1 string) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ScriptLoad", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// ScriptLoad indicates an expected call of ScriptLoad. +func (mr *MockUniversalClientMockRecorder) ScriptLoad(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptLoad", reflect.TypeOf((*MockUniversalClient)(nil).ScriptLoad), arg0, arg1) } // Set mocks base method. -func (m *MockRedisClient) Set(ctx context.Context, key string, value any, expiration time.Duration) *redis.StatusCmd { +func (m *MockUniversalClient) Set(arg0 context.Context, arg1 string, arg2 any, arg3 time.Duration) *redis.StatusCmd { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Set", ctx, key, value, expiration) + ret := m.ctrl.Call(m, "Set", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(*redis.StatusCmd) return ret0 } // Set indicates an expected call of Set. -func (mr *MockRedisClientMockRecorder) Set(ctx, key, value, expiration any) *gomock.Call { +func (mr *MockUniversalClientMockRecorder) Set(arg0, arg1, arg2, arg3 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockRedisClient)(nil).Set), ctx, key, value, expiration) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockUniversalClient)(nil).Set), arg0, arg1, arg2, arg3) +} + +// SetArgs mocks base method. +func (m *MockUniversalClient) SetArgs(arg0 context.Context, arg1 string, arg2 any, arg3 redis.SetArgs) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetArgs", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// SetArgs indicates an expected call of SetArgs. +func (mr *MockUniversalClientMockRecorder) SetArgs(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetArgs", reflect.TypeOf((*MockUniversalClient)(nil).SetArgs), arg0, arg1, arg2, arg3) +} + +// SetBit mocks base method. +func (m *MockUniversalClient) SetBit(arg0 context.Context, arg1 string, arg2 int64, arg3 int) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetBit", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SetBit indicates an expected call of SetBit. +func (mr *MockUniversalClientMockRecorder) SetBit(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBit", reflect.TypeOf((*MockUniversalClient)(nil).SetBit), arg0, arg1, arg2, arg3) +} + +// SetEx mocks base method. +func (m *MockUniversalClient) SetEx(arg0 context.Context, arg1 string, arg2 any, arg3 time.Duration) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetEx", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// SetEx indicates an expected call of SetEx. +func (mr *MockUniversalClientMockRecorder) SetEx(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetEx", reflect.TypeOf((*MockUniversalClient)(nil).SetEx), arg0, arg1, arg2, arg3) +} + +// SetNX mocks base method. +func (m *MockUniversalClient) SetNX(arg0 context.Context, arg1 string, arg2 any, arg3 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetNX", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// SetNX indicates an expected call of SetNX. +func (mr *MockUniversalClientMockRecorder) SetNX(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetNX", reflect.TypeOf((*MockUniversalClient)(nil).SetNX), arg0, arg1, arg2, arg3) +} + +// SetRange mocks base method. +func (m *MockUniversalClient) SetRange(arg0 context.Context, arg1 string, arg2 int64, arg3 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SetRange indicates an expected call of SetRange. +func (mr *MockUniversalClientMockRecorder) SetRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRange", reflect.TypeOf((*MockUniversalClient)(nil).SetRange), arg0, arg1, arg2, arg3) +} + +// SetXX mocks base method. +func (m *MockUniversalClient) SetXX(arg0 context.Context, arg1 string, arg2 any, arg3 time.Duration) *redis.BoolCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetXX", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.BoolCmd) + return ret0 +} + +// SetXX indicates an expected call of SetXX. +func (mr *MockUniversalClientMockRecorder) SetXX(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetXX", reflect.TypeOf((*MockUniversalClient)(nil).SetXX), arg0, arg1, arg2, arg3) +} + +// Shutdown mocks base method. +func (m *MockUniversalClient) Shutdown(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Shutdown", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// Shutdown indicates an expected call of Shutdown. +func (mr *MockUniversalClientMockRecorder) Shutdown(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Shutdown", reflect.TypeOf((*MockUniversalClient)(nil).Shutdown), arg0) +} + +// ShutdownNoSave mocks base method. +func (m *MockUniversalClient) ShutdownNoSave(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ShutdownNoSave", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ShutdownNoSave indicates an expected call of ShutdownNoSave. +func (mr *MockUniversalClientMockRecorder) ShutdownNoSave(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShutdownNoSave", reflect.TypeOf((*MockUniversalClient)(nil).ShutdownNoSave), arg0) +} + +// ShutdownSave mocks base method. +func (m *MockUniversalClient) ShutdownSave(arg0 context.Context) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ShutdownSave", arg0) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// ShutdownSave indicates an expected call of ShutdownSave. +func (mr *MockUniversalClientMockRecorder) ShutdownSave(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShutdownSave", reflect.TypeOf((*MockUniversalClient)(nil).ShutdownSave), arg0) +} + +// SlaveOf mocks base method. +func (m *MockUniversalClient) SlaveOf(arg0 context.Context, arg1, arg2 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SlaveOf", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// SlaveOf indicates an expected call of SlaveOf. +func (mr *MockUniversalClientMockRecorder) SlaveOf(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlaveOf", reflect.TypeOf((*MockUniversalClient)(nil).SlaveOf), arg0, arg1, arg2) +} + +// SlowLogGet mocks base method. +func (m *MockUniversalClient) SlowLogGet(arg0 context.Context, arg1 int64) *redis.SlowLogCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SlowLogGet", arg0, arg1) + ret0, _ := ret[0].(*redis.SlowLogCmd) + return ret0 +} + +// SlowLogGet indicates an expected call of SlowLogGet. +func (mr *MockUniversalClientMockRecorder) SlowLogGet(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlowLogGet", reflect.TypeOf((*MockUniversalClient)(nil).SlowLogGet), arg0, arg1) +} + +// Sort mocks base method. +func (m *MockUniversalClient) Sort(arg0 context.Context, arg1 string, arg2 *redis.Sort) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Sort", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// Sort indicates an expected call of Sort. +func (mr *MockUniversalClientMockRecorder) Sort(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sort", reflect.TypeOf((*MockUniversalClient)(nil).Sort), arg0, arg1, arg2) +} + +// SortInterfaces mocks base method. +func (m *MockUniversalClient) SortInterfaces(arg0 context.Context, arg1 string, arg2 *redis.Sort) *redis.SliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SortInterfaces", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.SliceCmd) + return ret0 +} + +// SortInterfaces indicates an expected call of SortInterfaces. +func (mr *MockUniversalClientMockRecorder) SortInterfaces(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SortInterfaces", reflect.TypeOf((*MockUniversalClient)(nil).SortInterfaces), arg0, arg1, arg2) +} + +// SortRO mocks base method. +func (m *MockUniversalClient) SortRO(arg0 context.Context, arg1 string, arg2 *redis.Sort) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SortRO", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// SortRO indicates an expected call of SortRO. +func (mr *MockUniversalClientMockRecorder) SortRO(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SortRO", reflect.TypeOf((*MockUniversalClient)(nil).SortRO), arg0, arg1, arg2) +} + +// SortStore mocks base method. +func (m *MockUniversalClient) SortStore(arg0 context.Context, arg1, arg2 string, arg3 *redis.Sort) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SortStore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// SortStore indicates an expected call of SortStore. +func (mr *MockUniversalClientMockRecorder) SortStore(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SortStore", reflect.TypeOf((*MockUniversalClient)(nil).SortStore), arg0, arg1, arg2, arg3) +} + +// StrLen mocks base method. +func (m *MockUniversalClient) StrLen(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StrLen", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// StrLen indicates an expected call of StrLen. +func (mr *MockUniversalClientMockRecorder) StrLen(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StrLen", reflect.TypeOf((*MockUniversalClient)(nil).StrLen), arg0, arg1) +} + +// Subscribe mocks base method. +func (m *MockUniversalClient) Subscribe(arg0 context.Context, arg1 ...string) *redis.PubSub { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Subscribe", varargs...) + ret0, _ := ret[0].(*redis.PubSub) + return ret0 +} + +// Subscribe indicates an expected call of Subscribe. +func (mr *MockUniversalClientMockRecorder) Subscribe(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockUniversalClient)(nil).Subscribe), varargs...) +} + +// TDigestAdd mocks base method. +func (m *MockUniversalClient) TDigestAdd(arg0 context.Context, arg1 string, arg2 ...float64) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestAdd", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TDigestAdd indicates an expected call of TDigestAdd. +func (mr *MockUniversalClientMockRecorder) TDigestAdd(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestAdd", reflect.TypeOf((*MockUniversalClient)(nil).TDigestAdd), varargs...) +} + +// TDigestByRank mocks base method. +func (m *MockUniversalClient) TDigestByRank(arg0 context.Context, arg1 string, arg2 ...uint64) *redis.FloatSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestByRank", varargs...) + ret0, _ := ret[0].(*redis.FloatSliceCmd) + return ret0 +} + +// TDigestByRank indicates an expected call of TDigestByRank. +func (mr *MockUniversalClientMockRecorder) TDigestByRank(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestByRank", reflect.TypeOf((*MockUniversalClient)(nil).TDigestByRank), varargs...) +} + +// TDigestByRevRank mocks base method. +func (m *MockUniversalClient) TDigestByRevRank(arg0 context.Context, arg1 string, arg2 ...uint64) *redis.FloatSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestByRevRank", varargs...) + ret0, _ := ret[0].(*redis.FloatSliceCmd) + return ret0 +} + +// TDigestByRevRank indicates an expected call of TDigestByRevRank. +func (mr *MockUniversalClientMockRecorder) TDigestByRevRank(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestByRevRank", reflect.TypeOf((*MockUniversalClient)(nil).TDigestByRevRank), varargs...) +} + +// TDigestCDF mocks base method. +func (m *MockUniversalClient) TDigestCDF(arg0 context.Context, arg1 string, arg2 ...float64) *redis.FloatSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestCDF", varargs...) + ret0, _ := ret[0].(*redis.FloatSliceCmd) + return ret0 +} + +// TDigestCDF indicates an expected call of TDigestCDF. +func (mr *MockUniversalClientMockRecorder) TDigestCDF(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestCDF", reflect.TypeOf((*MockUniversalClient)(nil).TDigestCDF), varargs...) +} + +// TDigestCreate mocks base method. +func (m *MockUniversalClient) TDigestCreate(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TDigestCreate", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TDigestCreate indicates an expected call of TDigestCreate. +func (mr *MockUniversalClientMockRecorder) TDigestCreate(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestCreate", reflect.TypeOf((*MockUniversalClient)(nil).TDigestCreate), arg0, arg1) +} + +// TDigestCreateWithCompression mocks base method. +func (m *MockUniversalClient) TDigestCreateWithCompression(arg0 context.Context, arg1 string, arg2 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TDigestCreateWithCompression", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TDigestCreateWithCompression indicates an expected call of TDigestCreateWithCompression. +func (mr *MockUniversalClientMockRecorder) TDigestCreateWithCompression(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestCreateWithCompression", reflect.TypeOf((*MockUniversalClient)(nil).TDigestCreateWithCompression), arg0, arg1, arg2) +} + +// TDigestInfo mocks base method. +func (m *MockUniversalClient) TDigestInfo(arg0 context.Context, arg1 string) *redis.TDigestInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TDigestInfo", arg0, arg1) + ret0, _ := ret[0].(*redis.TDigestInfoCmd) + return ret0 +} + +// TDigestInfo indicates an expected call of TDigestInfo. +func (mr *MockUniversalClientMockRecorder) TDigestInfo(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestInfo", reflect.TypeOf((*MockUniversalClient)(nil).TDigestInfo), arg0, arg1) +} + +// TDigestMax mocks base method. +func (m *MockUniversalClient) TDigestMax(arg0 context.Context, arg1 string) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TDigestMax", arg0, arg1) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// TDigestMax indicates an expected call of TDigestMax. +func (mr *MockUniversalClientMockRecorder) TDigestMax(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestMax", reflect.TypeOf((*MockUniversalClient)(nil).TDigestMax), arg0, arg1) +} + +// TDigestMerge mocks base method. +func (m *MockUniversalClient) TDigestMerge(arg0 context.Context, arg1 string, arg2 *redis.TDigestMergeOptions, arg3 ...string) *redis.StatusCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestMerge", varargs...) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TDigestMerge indicates an expected call of TDigestMerge. +func (mr *MockUniversalClientMockRecorder) TDigestMerge(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestMerge", reflect.TypeOf((*MockUniversalClient)(nil).TDigestMerge), varargs...) +} + +// TDigestMin mocks base method. +func (m *MockUniversalClient) TDigestMin(arg0 context.Context, arg1 string) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TDigestMin", arg0, arg1) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// TDigestMin indicates an expected call of TDigestMin. +func (mr *MockUniversalClientMockRecorder) TDigestMin(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestMin", reflect.TypeOf((*MockUniversalClient)(nil).TDigestMin), arg0, arg1) +} + +// TDigestQuantile mocks base method. +func (m *MockUniversalClient) TDigestQuantile(arg0 context.Context, arg1 string, arg2 ...float64) *redis.FloatSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestQuantile", varargs...) + ret0, _ := ret[0].(*redis.FloatSliceCmd) + return ret0 +} + +// TDigestQuantile indicates an expected call of TDigestQuantile. +func (mr *MockUniversalClientMockRecorder) TDigestQuantile(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestQuantile", reflect.TypeOf((*MockUniversalClient)(nil).TDigestQuantile), varargs...) +} + +// TDigestRank mocks base method. +func (m *MockUniversalClient) TDigestRank(arg0 context.Context, arg1 string, arg2 ...float64) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestRank", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// TDigestRank indicates an expected call of TDigestRank. +func (mr *MockUniversalClientMockRecorder) TDigestRank(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestRank", reflect.TypeOf((*MockUniversalClient)(nil).TDigestRank), varargs...) +} + +// TDigestReset mocks base method. +func (m *MockUniversalClient) TDigestReset(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TDigestReset", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TDigestReset indicates an expected call of TDigestReset. +func (mr *MockUniversalClientMockRecorder) TDigestReset(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestReset", reflect.TypeOf((*MockUniversalClient)(nil).TDigestReset), arg0, arg1) +} + +// TDigestRevRank mocks base method. +func (m *MockUniversalClient) TDigestRevRank(arg0 context.Context, arg1 string, arg2 ...float64) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TDigestRevRank", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// TDigestRevRank indicates an expected call of TDigestRevRank. +func (mr *MockUniversalClientMockRecorder) TDigestRevRank(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestRevRank", reflect.TypeOf((*MockUniversalClient)(nil).TDigestRevRank), varargs...) +} + +// TDigestTrimmedMean mocks base method. +func (m *MockUniversalClient) TDigestTrimmedMean(arg0 context.Context, arg1 string, arg2, arg3 float64) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TDigestTrimmedMean", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// TDigestTrimmedMean indicates an expected call of TDigestTrimmedMean. +func (mr *MockUniversalClientMockRecorder) TDigestTrimmedMean(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TDigestTrimmedMean", reflect.TypeOf((*MockUniversalClient)(nil).TDigestTrimmedMean), arg0, arg1, arg2, arg3) +} + +// TFCall mocks base method. +func (m *MockUniversalClient) TFCall(arg0 context.Context, arg1, arg2 string, arg3 int) *redis.Cmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFCall", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// TFCall indicates an expected call of TFCall. +func (mr *MockUniversalClientMockRecorder) TFCall(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFCall", reflect.TypeOf((*MockUniversalClient)(nil).TFCall), arg0, arg1, arg2, arg3) +} + +// TFCallASYNC mocks base method. +func (m *MockUniversalClient) TFCallASYNC(arg0 context.Context, arg1, arg2 string, arg3 int) *redis.Cmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFCallASYNC", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// TFCallASYNC indicates an expected call of TFCallASYNC. +func (mr *MockUniversalClientMockRecorder) TFCallASYNC(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFCallASYNC", reflect.TypeOf((*MockUniversalClient)(nil).TFCallASYNC), arg0, arg1, arg2, arg3) +} + +// TFCallASYNCArgs mocks base method. +func (m *MockUniversalClient) TFCallASYNCArgs(arg0 context.Context, arg1, arg2 string, arg3 int, arg4 *redis.TFCallOptions) *redis.Cmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFCallASYNCArgs", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// TFCallASYNCArgs indicates an expected call of TFCallASYNCArgs. +func (mr *MockUniversalClientMockRecorder) TFCallASYNCArgs(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFCallASYNCArgs", reflect.TypeOf((*MockUniversalClient)(nil).TFCallASYNCArgs), arg0, arg1, arg2, arg3, arg4) +} + +// TFCallArgs mocks base method. +func (m *MockUniversalClient) TFCallArgs(arg0 context.Context, arg1, arg2 string, arg3 int, arg4 *redis.TFCallOptions) *redis.Cmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFCallArgs", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.Cmd) + return ret0 +} + +// TFCallArgs indicates an expected call of TFCallArgs. +func (mr *MockUniversalClientMockRecorder) TFCallArgs(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFCallArgs", reflect.TypeOf((*MockUniversalClient)(nil).TFCallArgs), arg0, arg1, arg2, arg3, arg4) +} + +// TFunctionDelete mocks base method. +func (m *MockUniversalClient) TFunctionDelete(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFunctionDelete", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TFunctionDelete indicates an expected call of TFunctionDelete. +func (mr *MockUniversalClientMockRecorder) TFunctionDelete(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFunctionDelete", reflect.TypeOf((*MockUniversalClient)(nil).TFunctionDelete), arg0, arg1) +} + +// TFunctionList mocks base method. +func (m *MockUniversalClient) TFunctionList(arg0 context.Context) *redis.MapStringInterfaceSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFunctionList", arg0) + ret0, _ := ret[0].(*redis.MapStringInterfaceSliceCmd) + return ret0 +} + +// TFunctionList indicates an expected call of TFunctionList. +func (mr *MockUniversalClientMockRecorder) TFunctionList(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFunctionList", reflect.TypeOf((*MockUniversalClient)(nil).TFunctionList), arg0) +} + +// TFunctionListArgs mocks base method. +func (m *MockUniversalClient) TFunctionListArgs(arg0 context.Context, arg1 *redis.TFunctionListOptions) *redis.MapStringInterfaceSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFunctionListArgs", arg0, arg1) + ret0, _ := ret[0].(*redis.MapStringInterfaceSliceCmd) + return ret0 +} + +// TFunctionListArgs indicates an expected call of TFunctionListArgs. +func (mr *MockUniversalClientMockRecorder) TFunctionListArgs(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFunctionListArgs", reflect.TypeOf((*MockUniversalClient)(nil).TFunctionListArgs), arg0, arg1) +} + +// TFunctionLoad mocks base method. +func (m *MockUniversalClient) TFunctionLoad(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFunctionLoad", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TFunctionLoad indicates an expected call of TFunctionLoad. +func (mr *MockUniversalClientMockRecorder) TFunctionLoad(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFunctionLoad", reflect.TypeOf((*MockUniversalClient)(nil).TFunctionLoad), arg0, arg1) +} + +// TFunctionLoadArgs mocks base method. +func (m *MockUniversalClient) TFunctionLoadArgs(arg0 context.Context, arg1 string, arg2 *redis.TFunctionLoadOptions) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TFunctionLoadArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TFunctionLoadArgs indicates an expected call of TFunctionLoadArgs. +func (mr *MockUniversalClientMockRecorder) TFunctionLoadArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TFunctionLoadArgs", reflect.TypeOf((*MockUniversalClient)(nil).TFunctionLoadArgs), arg0, arg1, arg2) +} + +// TSAdd mocks base method. +func (m *MockUniversalClient) TSAdd(arg0 context.Context, arg1 string, arg2 any, arg3 float64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSAdd", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// TSAdd indicates an expected call of TSAdd. +func (mr *MockUniversalClientMockRecorder) TSAdd(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSAdd", reflect.TypeOf((*MockUniversalClient)(nil).TSAdd), arg0, arg1, arg2, arg3) +} + +// TSAddWithArgs mocks base method. +func (m *MockUniversalClient) TSAddWithArgs(arg0 context.Context, arg1 string, arg2 any, arg3 float64, arg4 *redis.TSOptions) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSAddWithArgs", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// TSAddWithArgs indicates an expected call of TSAddWithArgs. +func (mr *MockUniversalClientMockRecorder) TSAddWithArgs(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSAddWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSAddWithArgs), arg0, arg1, arg2, arg3, arg4) +} + +// TSAlter mocks base method. +func (m *MockUniversalClient) TSAlter(arg0 context.Context, arg1 string, arg2 *redis.TSAlterOptions) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSAlter", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TSAlter indicates an expected call of TSAlter. +func (mr *MockUniversalClientMockRecorder) TSAlter(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSAlter", reflect.TypeOf((*MockUniversalClient)(nil).TSAlter), arg0, arg1, arg2) +} + +// TSCreate mocks base method. +func (m *MockUniversalClient) TSCreate(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSCreate", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TSCreate indicates an expected call of TSCreate. +func (mr *MockUniversalClientMockRecorder) TSCreate(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSCreate", reflect.TypeOf((*MockUniversalClient)(nil).TSCreate), arg0, arg1) +} + +// TSCreateRule mocks base method. +func (m *MockUniversalClient) TSCreateRule(arg0 context.Context, arg1, arg2 string, arg3 redis.Aggregator, arg4 int) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSCreateRule", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TSCreateRule indicates an expected call of TSCreateRule. +func (mr *MockUniversalClientMockRecorder) TSCreateRule(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSCreateRule", reflect.TypeOf((*MockUniversalClient)(nil).TSCreateRule), arg0, arg1, arg2, arg3, arg4) +} + +// TSCreateRuleWithArgs mocks base method. +func (m *MockUniversalClient) TSCreateRuleWithArgs(arg0 context.Context, arg1, arg2 string, arg3 redis.Aggregator, arg4 int, arg5 *redis.TSCreateRuleOptions) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSCreateRuleWithArgs", arg0, arg1, arg2, arg3, arg4, arg5) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TSCreateRuleWithArgs indicates an expected call of TSCreateRuleWithArgs. +func (mr *MockUniversalClientMockRecorder) TSCreateRuleWithArgs(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSCreateRuleWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSCreateRuleWithArgs), arg0, arg1, arg2, arg3, arg4, arg5) +} + +// TSCreateWithArgs mocks base method. +func (m *MockUniversalClient) TSCreateWithArgs(arg0 context.Context, arg1 string, arg2 *redis.TSOptions) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSCreateWithArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TSCreateWithArgs indicates an expected call of TSCreateWithArgs. +func (mr *MockUniversalClientMockRecorder) TSCreateWithArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSCreateWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSCreateWithArgs), arg0, arg1, arg2) +} + +// TSDecrBy mocks base method. +func (m *MockUniversalClient) TSDecrBy(arg0 context.Context, arg1 string, arg2 float64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSDecrBy", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// TSDecrBy indicates an expected call of TSDecrBy. +func (mr *MockUniversalClientMockRecorder) TSDecrBy(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSDecrBy", reflect.TypeOf((*MockUniversalClient)(nil).TSDecrBy), arg0, arg1, arg2) +} + +// TSDecrByWithArgs mocks base method. +func (m *MockUniversalClient) TSDecrByWithArgs(arg0 context.Context, arg1 string, arg2 float64, arg3 *redis.TSIncrDecrOptions) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSDecrByWithArgs", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// TSDecrByWithArgs indicates an expected call of TSDecrByWithArgs. +func (mr *MockUniversalClientMockRecorder) TSDecrByWithArgs(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSDecrByWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSDecrByWithArgs), arg0, arg1, arg2, arg3) +} + +// TSDel mocks base method. +func (m *MockUniversalClient) TSDel(arg0 context.Context, arg1 string, arg2, arg3 int) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSDel", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// TSDel indicates an expected call of TSDel. +func (mr *MockUniversalClientMockRecorder) TSDel(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSDel", reflect.TypeOf((*MockUniversalClient)(nil).TSDel), arg0, arg1, arg2, arg3) +} + +// TSDeleteRule mocks base method. +func (m *MockUniversalClient) TSDeleteRule(arg0 context.Context, arg1, arg2 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSDeleteRule", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TSDeleteRule indicates an expected call of TSDeleteRule. +func (mr *MockUniversalClientMockRecorder) TSDeleteRule(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSDeleteRule", reflect.TypeOf((*MockUniversalClient)(nil).TSDeleteRule), arg0, arg1, arg2) +} + +// TSGet mocks base method. +func (m *MockUniversalClient) TSGet(arg0 context.Context, arg1 string) *redis.TSTimestampValueCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSGet", arg0, arg1) + ret0, _ := ret[0].(*redis.TSTimestampValueCmd) + return ret0 +} + +// TSGet indicates an expected call of TSGet. +func (mr *MockUniversalClientMockRecorder) TSGet(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSGet", reflect.TypeOf((*MockUniversalClient)(nil).TSGet), arg0, arg1) +} + +// TSGetWithArgs mocks base method. +func (m *MockUniversalClient) TSGetWithArgs(arg0 context.Context, arg1 string, arg2 *redis.TSGetOptions) *redis.TSTimestampValueCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSGetWithArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.TSTimestampValueCmd) + return ret0 +} + +// TSGetWithArgs indicates an expected call of TSGetWithArgs. +func (mr *MockUniversalClientMockRecorder) TSGetWithArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSGetWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSGetWithArgs), arg0, arg1, arg2) +} + +// TSIncrBy mocks base method. +func (m *MockUniversalClient) TSIncrBy(arg0 context.Context, arg1 string, arg2 float64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSIncrBy", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// TSIncrBy indicates an expected call of TSIncrBy. +func (mr *MockUniversalClientMockRecorder) TSIncrBy(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSIncrBy", reflect.TypeOf((*MockUniversalClient)(nil).TSIncrBy), arg0, arg1, arg2) +} + +// TSIncrByWithArgs mocks base method. +func (m *MockUniversalClient) TSIncrByWithArgs(arg0 context.Context, arg1 string, arg2 float64, arg3 *redis.TSIncrDecrOptions) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSIncrByWithArgs", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// TSIncrByWithArgs indicates an expected call of TSIncrByWithArgs. +func (mr *MockUniversalClientMockRecorder) TSIncrByWithArgs(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSIncrByWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSIncrByWithArgs), arg0, arg1, arg2, arg3) +} + +// TSInfo mocks base method. +func (m *MockUniversalClient) TSInfo(arg0 context.Context, arg1 string) *redis.MapStringInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSInfo", arg0, arg1) + ret0, _ := ret[0].(*redis.MapStringInterfaceCmd) + return ret0 +} + +// TSInfo indicates an expected call of TSInfo. +func (mr *MockUniversalClientMockRecorder) TSInfo(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSInfo", reflect.TypeOf((*MockUniversalClient)(nil).TSInfo), arg0, arg1) +} + +// TSInfoWithArgs mocks base method. +func (m *MockUniversalClient) TSInfoWithArgs(arg0 context.Context, arg1 string, arg2 *redis.TSInfoOptions) *redis.MapStringInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSInfoWithArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.MapStringInterfaceCmd) + return ret0 +} + +// TSInfoWithArgs indicates an expected call of TSInfoWithArgs. +func (mr *MockUniversalClientMockRecorder) TSInfoWithArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSInfoWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSInfoWithArgs), arg0, arg1, arg2) +} + +// TSMAdd mocks base method. +func (m *MockUniversalClient) TSMAdd(arg0 context.Context, arg1 [][]any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSMAdd", arg0, arg1) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// TSMAdd indicates an expected call of TSMAdd. +func (mr *MockUniversalClientMockRecorder) TSMAdd(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSMAdd", reflect.TypeOf((*MockUniversalClient)(nil).TSMAdd), arg0, arg1) +} + +// TSMGet mocks base method. +func (m *MockUniversalClient) TSMGet(arg0 context.Context, arg1 []string) *redis.MapStringSliceInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSMGet", arg0, arg1) + ret0, _ := ret[0].(*redis.MapStringSliceInterfaceCmd) + return ret0 +} + +// TSMGet indicates an expected call of TSMGet. +func (mr *MockUniversalClientMockRecorder) TSMGet(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSMGet", reflect.TypeOf((*MockUniversalClient)(nil).TSMGet), arg0, arg1) +} + +// TSMGetWithArgs mocks base method. +func (m *MockUniversalClient) TSMGetWithArgs(arg0 context.Context, arg1 []string, arg2 *redis.TSMGetOptions) *redis.MapStringSliceInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSMGetWithArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.MapStringSliceInterfaceCmd) + return ret0 +} + +// TSMGetWithArgs indicates an expected call of TSMGetWithArgs. +func (mr *MockUniversalClientMockRecorder) TSMGetWithArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSMGetWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSMGetWithArgs), arg0, arg1, arg2) +} + +// TSMRange mocks base method. +func (m *MockUniversalClient) TSMRange(arg0 context.Context, arg1, arg2 int, arg3 []string) *redis.MapStringSliceInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSMRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.MapStringSliceInterfaceCmd) + return ret0 +} + +// TSMRange indicates an expected call of TSMRange. +func (mr *MockUniversalClientMockRecorder) TSMRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSMRange", reflect.TypeOf((*MockUniversalClient)(nil).TSMRange), arg0, arg1, arg2, arg3) +} + +// TSMRangeWithArgs mocks base method. +func (m *MockUniversalClient) TSMRangeWithArgs(arg0 context.Context, arg1, arg2 int, arg3 []string, arg4 *redis.TSMRangeOptions) *redis.MapStringSliceInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSMRangeWithArgs", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.MapStringSliceInterfaceCmd) + return ret0 +} + +// TSMRangeWithArgs indicates an expected call of TSMRangeWithArgs. +func (mr *MockUniversalClientMockRecorder) TSMRangeWithArgs(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSMRangeWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSMRangeWithArgs), arg0, arg1, arg2, arg3, arg4) +} + +// TSMRevRange mocks base method. +func (m *MockUniversalClient) TSMRevRange(arg0 context.Context, arg1, arg2 int, arg3 []string) *redis.MapStringSliceInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSMRevRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.MapStringSliceInterfaceCmd) + return ret0 +} + +// TSMRevRange indicates an expected call of TSMRevRange. +func (mr *MockUniversalClientMockRecorder) TSMRevRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSMRevRange", reflect.TypeOf((*MockUniversalClient)(nil).TSMRevRange), arg0, arg1, arg2, arg3) +} + +// TSMRevRangeWithArgs mocks base method. +func (m *MockUniversalClient) TSMRevRangeWithArgs(arg0 context.Context, arg1, arg2 int, arg3 []string, arg4 *redis.TSMRevRangeOptions) *redis.MapStringSliceInterfaceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSMRevRangeWithArgs", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.MapStringSliceInterfaceCmd) + return ret0 +} + +// TSMRevRangeWithArgs indicates an expected call of TSMRevRangeWithArgs. +func (mr *MockUniversalClientMockRecorder) TSMRevRangeWithArgs(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSMRevRangeWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSMRevRangeWithArgs), arg0, arg1, arg2, arg3, arg4) +} + +// TSQueryIndex mocks base method. +func (m *MockUniversalClient) TSQueryIndex(arg0 context.Context, arg1 []string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSQueryIndex", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// TSQueryIndex indicates an expected call of TSQueryIndex. +func (mr *MockUniversalClientMockRecorder) TSQueryIndex(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSQueryIndex", reflect.TypeOf((*MockUniversalClient)(nil).TSQueryIndex), arg0, arg1) +} + +// TSRange mocks base method. +func (m *MockUniversalClient) TSRange(arg0 context.Context, arg1 string, arg2, arg3 int) *redis.TSTimestampValueSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.TSTimestampValueSliceCmd) + return ret0 +} + +// TSRange indicates an expected call of TSRange. +func (mr *MockUniversalClientMockRecorder) TSRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSRange", reflect.TypeOf((*MockUniversalClient)(nil).TSRange), arg0, arg1, arg2, arg3) +} + +// TSRangeWithArgs mocks base method. +func (m *MockUniversalClient) TSRangeWithArgs(arg0 context.Context, arg1 string, arg2, arg3 int, arg4 *redis.TSRangeOptions) *redis.TSTimestampValueSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSRangeWithArgs", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.TSTimestampValueSliceCmd) + return ret0 +} + +// TSRangeWithArgs indicates an expected call of TSRangeWithArgs. +func (mr *MockUniversalClientMockRecorder) TSRangeWithArgs(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSRangeWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSRangeWithArgs), arg0, arg1, arg2, arg3, arg4) +} + +// TSRevRange mocks base method. +func (m *MockUniversalClient) TSRevRange(arg0 context.Context, arg1 string, arg2, arg3 int) *redis.TSTimestampValueSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSRevRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.TSTimestampValueSliceCmd) + return ret0 +} + +// TSRevRange indicates an expected call of TSRevRange. +func (mr *MockUniversalClientMockRecorder) TSRevRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSRevRange", reflect.TypeOf((*MockUniversalClient)(nil).TSRevRange), arg0, arg1, arg2, arg3) +} + +// TSRevRangeWithArgs mocks base method. +func (m *MockUniversalClient) TSRevRangeWithArgs(arg0 context.Context, arg1 string, arg2, arg3 int, arg4 *redis.TSRevRangeOptions) *redis.TSTimestampValueSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TSRevRangeWithArgs", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.TSTimestampValueSliceCmd) + return ret0 +} + +// TSRevRangeWithArgs indicates an expected call of TSRevRangeWithArgs. +func (mr *MockUniversalClientMockRecorder) TSRevRangeWithArgs(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TSRevRangeWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).TSRevRangeWithArgs), arg0, arg1, arg2, arg3, arg4) +} + +// TTL mocks base method. +func (m *MockUniversalClient) TTL(arg0 context.Context, arg1 string) *redis.DurationCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TTL", arg0, arg1) + ret0, _ := ret[0].(*redis.DurationCmd) + return ret0 +} + +// TTL indicates an expected call of TTL. +func (mr *MockUniversalClientMockRecorder) TTL(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TTL", reflect.TypeOf((*MockUniversalClient)(nil).TTL), arg0, arg1) +} + +// Time mocks base method. +func (m *MockUniversalClient) Time(arg0 context.Context) *redis.TimeCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Time", arg0) + ret0, _ := ret[0].(*redis.TimeCmd) + return ret0 +} + +// Time indicates an expected call of Time. +func (mr *MockUniversalClientMockRecorder) Time(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Time", reflect.TypeOf((*MockUniversalClient)(nil).Time), arg0) +} + +// TopKAdd mocks base method. +func (m *MockUniversalClient) TopKAdd(arg0 context.Context, arg1 string, arg2 ...any) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TopKAdd", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// TopKAdd indicates an expected call of TopKAdd. +func (mr *MockUniversalClientMockRecorder) TopKAdd(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKAdd", reflect.TypeOf((*MockUniversalClient)(nil).TopKAdd), varargs...) +} + +// TopKCount mocks base method. +func (m *MockUniversalClient) TopKCount(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TopKCount", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// TopKCount indicates an expected call of TopKCount. +func (mr *MockUniversalClientMockRecorder) TopKCount(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKCount", reflect.TypeOf((*MockUniversalClient)(nil).TopKCount), varargs...) +} + +// TopKIncrBy mocks base method. +func (m *MockUniversalClient) TopKIncrBy(arg0 context.Context, arg1 string, arg2 ...any) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TopKIncrBy", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// TopKIncrBy indicates an expected call of TopKIncrBy. +func (mr *MockUniversalClientMockRecorder) TopKIncrBy(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKIncrBy", reflect.TypeOf((*MockUniversalClient)(nil).TopKIncrBy), varargs...) +} + +// TopKInfo mocks base method. +func (m *MockUniversalClient) TopKInfo(arg0 context.Context, arg1 string) *redis.TopKInfoCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TopKInfo", arg0, arg1) + ret0, _ := ret[0].(*redis.TopKInfoCmd) + return ret0 +} + +// TopKInfo indicates an expected call of TopKInfo. +func (mr *MockUniversalClientMockRecorder) TopKInfo(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKInfo", reflect.TypeOf((*MockUniversalClient)(nil).TopKInfo), arg0, arg1) +} + +// TopKList mocks base method. +func (m *MockUniversalClient) TopKList(arg0 context.Context, arg1 string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TopKList", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// TopKList indicates an expected call of TopKList. +func (mr *MockUniversalClientMockRecorder) TopKList(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKList", reflect.TypeOf((*MockUniversalClient)(nil).TopKList), arg0, arg1) +} + +// TopKListWithCount mocks base method. +func (m *MockUniversalClient) TopKListWithCount(arg0 context.Context, arg1 string) *redis.MapStringIntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TopKListWithCount", arg0, arg1) + ret0, _ := ret[0].(*redis.MapStringIntCmd) + return ret0 +} + +// TopKListWithCount indicates an expected call of TopKListWithCount. +func (mr *MockUniversalClientMockRecorder) TopKListWithCount(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKListWithCount", reflect.TypeOf((*MockUniversalClient)(nil).TopKListWithCount), arg0, arg1) +} + +// TopKQuery mocks base method. +func (m *MockUniversalClient) TopKQuery(arg0 context.Context, arg1 string, arg2 ...any) *redis.BoolSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "TopKQuery", varargs...) + ret0, _ := ret[0].(*redis.BoolSliceCmd) + return ret0 +} + +// TopKQuery indicates an expected call of TopKQuery. +func (mr *MockUniversalClientMockRecorder) TopKQuery(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKQuery", reflect.TypeOf((*MockUniversalClient)(nil).TopKQuery), varargs...) +} + +// TopKReserve mocks base method. +func (m *MockUniversalClient) TopKReserve(arg0 context.Context, arg1 string, arg2 int64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TopKReserve", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TopKReserve indicates an expected call of TopKReserve. +func (mr *MockUniversalClientMockRecorder) TopKReserve(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKReserve", reflect.TypeOf((*MockUniversalClient)(nil).TopKReserve), arg0, arg1, arg2) +} + +// TopKReserveWithOptions mocks base method. +func (m *MockUniversalClient) TopKReserveWithOptions(arg0 context.Context, arg1 string, arg2, arg3, arg4 int64, arg5 float64) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TopKReserveWithOptions", arg0, arg1, arg2, arg3, arg4, arg5) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// TopKReserveWithOptions indicates an expected call of TopKReserveWithOptions. +func (mr *MockUniversalClientMockRecorder) TopKReserveWithOptions(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopKReserveWithOptions", reflect.TypeOf((*MockUniversalClient)(nil).TopKReserveWithOptions), arg0, arg1, arg2, arg3, arg4, arg5) +} + +// Touch mocks base method. +func (m *MockUniversalClient) Touch(arg0 context.Context, arg1 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Touch", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// Touch indicates an expected call of Touch. +func (mr *MockUniversalClientMockRecorder) Touch(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Touch", reflect.TypeOf((*MockUniversalClient)(nil).Touch), varargs...) +} + +// TxPipeline mocks base method. +func (m *MockUniversalClient) TxPipeline() redis.Pipeliner { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TxPipeline") + ret0, _ := ret[0].(redis.Pipeliner) + return ret0 +} + +// TxPipeline indicates an expected call of TxPipeline. +func (mr *MockUniversalClientMockRecorder) TxPipeline() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxPipeline", reflect.TypeOf((*MockUniversalClient)(nil).TxPipeline)) +} + +// TxPipelined mocks base method. +func (m *MockUniversalClient) TxPipelined(arg0 context.Context, arg1 func(redis.Pipeliner) error) ([]redis.Cmder, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TxPipelined", arg0, arg1) + ret0, _ := ret[0].([]redis.Cmder) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TxPipelined indicates an expected call of TxPipelined. +func (mr *MockUniversalClientMockRecorder) TxPipelined(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxPipelined", reflect.TypeOf((*MockUniversalClient)(nil).TxPipelined), arg0, arg1) +} + +// Type mocks base method. +func (m *MockUniversalClient) Type(arg0 context.Context, arg1 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Type", arg0, arg1) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// Type indicates an expected call of Type. +func (mr *MockUniversalClientMockRecorder) Type(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Type", reflect.TypeOf((*MockUniversalClient)(nil).Type), arg0, arg1) +} + +// Unlink mocks base method. +func (m *MockUniversalClient) Unlink(arg0 context.Context, arg1 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Unlink", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// Unlink indicates an expected call of Unlink. +func (mr *MockUniversalClientMockRecorder) Unlink(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlink", reflect.TypeOf((*MockUniversalClient)(nil).Unlink), varargs...) +} + +// Watch mocks base method. +func (m *MockUniversalClient) Watch(arg0 context.Context, arg1 func(*redis.Tx) error, arg2 ...string) error { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Watch", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// Watch indicates an expected call of Watch. +func (mr *MockUniversalClientMockRecorder) Watch(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Watch", reflect.TypeOf((*MockUniversalClient)(nil).Watch), varargs...) +} + +// XAck mocks base method. +func (m *MockUniversalClient) XAck(arg0 context.Context, arg1, arg2 string, arg3 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "XAck", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XAck indicates an expected call of XAck. +func (mr *MockUniversalClientMockRecorder) XAck(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XAck", reflect.TypeOf((*MockUniversalClient)(nil).XAck), varargs...) +} + +// XAdd mocks base method. +func (m *MockUniversalClient) XAdd(arg0 context.Context, arg1 *redis.XAddArgs) *redis.StringCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XAdd", arg0, arg1) + ret0, _ := ret[0].(*redis.StringCmd) + return ret0 +} + +// XAdd indicates an expected call of XAdd. +func (mr *MockUniversalClientMockRecorder) XAdd(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XAdd", reflect.TypeOf((*MockUniversalClient)(nil).XAdd), arg0, arg1) +} + +// XAutoClaim mocks base method. +func (m *MockUniversalClient) XAutoClaim(arg0 context.Context, arg1 *redis.XAutoClaimArgs) *redis.XAutoClaimCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XAutoClaim", arg0, arg1) + ret0, _ := ret[0].(*redis.XAutoClaimCmd) + return ret0 +} + +// XAutoClaim indicates an expected call of XAutoClaim. +func (mr *MockUniversalClientMockRecorder) XAutoClaim(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XAutoClaim", reflect.TypeOf((*MockUniversalClient)(nil).XAutoClaim), arg0, arg1) +} + +// XAutoClaimJustID mocks base method. +func (m *MockUniversalClient) XAutoClaimJustID(arg0 context.Context, arg1 *redis.XAutoClaimArgs) *redis.XAutoClaimJustIDCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XAutoClaimJustID", arg0, arg1) + ret0, _ := ret[0].(*redis.XAutoClaimJustIDCmd) + return ret0 +} + +// XAutoClaimJustID indicates an expected call of XAutoClaimJustID. +func (mr *MockUniversalClientMockRecorder) XAutoClaimJustID(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XAutoClaimJustID", reflect.TypeOf((*MockUniversalClient)(nil).XAutoClaimJustID), arg0, arg1) +} + +// XClaim mocks base method. +func (m *MockUniversalClient) XClaim(arg0 context.Context, arg1 *redis.XClaimArgs) *redis.XMessageSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XClaim", arg0, arg1) + ret0, _ := ret[0].(*redis.XMessageSliceCmd) + return ret0 +} + +// XClaim indicates an expected call of XClaim. +func (mr *MockUniversalClientMockRecorder) XClaim(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XClaim", reflect.TypeOf((*MockUniversalClient)(nil).XClaim), arg0, arg1) +} + +// XClaimJustID mocks base method. +func (m *MockUniversalClient) XClaimJustID(arg0 context.Context, arg1 *redis.XClaimArgs) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XClaimJustID", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// XClaimJustID indicates an expected call of XClaimJustID. +func (mr *MockUniversalClientMockRecorder) XClaimJustID(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XClaimJustID", reflect.TypeOf((*MockUniversalClient)(nil).XClaimJustID), arg0, arg1) +} + +// XDel mocks base method. +func (m *MockUniversalClient) XDel(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "XDel", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XDel indicates an expected call of XDel. +func (mr *MockUniversalClientMockRecorder) XDel(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XDel", reflect.TypeOf((*MockUniversalClient)(nil).XDel), varargs...) +} + +// XGroupCreate mocks base method. +func (m *MockUniversalClient) XGroupCreate(arg0 context.Context, arg1, arg2, arg3 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XGroupCreate", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// XGroupCreate indicates an expected call of XGroupCreate. +func (mr *MockUniversalClientMockRecorder) XGroupCreate(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XGroupCreate", reflect.TypeOf((*MockUniversalClient)(nil).XGroupCreate), arg0, arg1, arg2, arg3) +} + +// XGroupCreateConsumer mocks base method. +func (m *MockUniversalClient) XGroupCreateConsumer(arg0 context.Context, arg1, arg2, arg3 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XGroupCreateConsumer", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XGroupCreateConsumer indicates an expected call of XGroupCreateConsumer. +func (mr *MockUniversalClientMockRecorder) XGroupCreateConsumer(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XGroupCreateConsumer", reflect.TypeOf((*MockUniversalClient)(nil).XGroupCreateConsumer), arg0, arg1, arg2, arg3) +} + +// XGroupCreateMkStream mocks base method. +func (m *MockUniversalClient) XGroupCreateMkStream(arg0 context.Context, arg1, arg2, arg3 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XGroupCreateMkStream", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// XGroupCreateMkStream indicates an expected call of XGroupCreateMkStream. +func (mr *MockUniversalClientMockRecorder) XGroupCreateMkStream(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XGroupCreateMkStream", reflect.TypeOf((*MockUniversalClient)(nil).XGroupCreateMkStream), arg0, arg1, arg2, arg3) +} + +// XGroupDelConsumer mocks base method. +func (m *MockUniversalClient) XGroupDelConsumer(arg0 context.Context, arg1, arg2, arg3 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XGroupDelConsumer", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XGroupDelConsumer indicates an expected call of XGroupDelConsumer. +func (mr *MockUniversalClientMockRecorder) XGroupDelConsumer(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XGroupDelConsumer", reflect.TypeOf((*MockUniversalClient)(nil).XGroupDelConsumer), arg0, arg1, arg2, arg3) +} + +// XGroupDestroy mocks base method. +func (m *MockUniversalClient) XGroupDestroy(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XGroupDestroy", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XGroupDestroy indicates an expected call of XGroupDestroy. +func (mr *MockUniversalClientMockRecorder) XGroupDestroy(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XGroupDestroy", reflect.TypeOf((*MockUniversalClient)(nil).XGroupDestroy), arg0, arg1, arg2) +} + +// XGroupSetID mocks base method. +func (m *MockUniversalClient) XGroupSetID(arg0 context.Context, arg1, arg2, arg3 string) *redis.StatusCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XGroupSetID", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StatusCmd) + return ret0 +} + +// XGroupSetID indicates an expected call of XGroupSetID. +func (mr *MockUniversalClientMockRecorder) XGroupSetID(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XGroupSetID", reflect.TypeOf((*MockUniversalClient)(nil).XGroupSetID), arg0, arg1, arg2, arg3) +} + +// XInfoConsumers mocks base method. +func (m *MockUniversalClient) XInfoConsumers(arg0 context.Context, arg1, arg2 string) *redis.XInfoConsumersCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XInfoConsumers", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.XInfoConsumersCmd) + return ret0 +} + +// XInfoConsumers indicates an expected call of XInfoConsumers. +func (mr *MockUniversalClientMockRecorder) XInfoConsumers(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XInfoConsumers", reflect.TypeOf((*MockUniversalClient)(nil).XInfoConsumers), arg0, arg1, arg2) +} + +// XInfoGroups mocks base method. +func (m *MockUniversalClient) XInfoGroups(arg0 context.Context, arg1 string) *redis.XInfoGroupsCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XInfoGroups", arg0, arg1) + ret0, _ := ret[0].(*redis.XInfoGroupsCmd) + return ret0 +} + +// XInfoGroups indicates an expected call of XInfoGroups. +func (mr *MockUniversalClientMockRecorder) XInfoGroups(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XInfoGroups", reflect.TypeOf((*MockUniversalClient)(nil).XInfoGroups), arg0, arg1) +} + +// XInfoStream mocks base method. +func (m *MockUniversalClient) XInfoStream(arg0 context.Context, arg1 string) *redis.XInfoStreamCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XInfoStream", arg0, arg1) + ret0, _ := ret[0].(*redis.XInfoStreamCmd) + return ret0 +} + +// XInfoStream indicates an expected call of XInfoStream. +func (mr *MockUniversalClientMockRecorder) XInfoStream(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XInfoStream", reflect.TypeOf((*MockUniversalClient)(nil).XInfoStream), arg0, arg1) +} + +// XInfoStreamFull mocks base method. +func (m *MockUniversalClient) XInfoStreamFull(arg0 context.Context, arg1 string, arg2 int) *redis.XInfoStreamFullCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XInfoStreamFull", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.XInfoStreamFullCmd) + return ret0 +} + +// XInfoStreamFull indicates an expected call of XInfoStreamFull. +func (mr *MockUniversalClientMockRecorder) XInfoStreamFull(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XInfoStreamFull", reflect.TypeOf((*MockUniversalClient)(nil).XInfoStreamFull), arg0, arg1, arg2) +} + +// XLen mocks base method. +func (m *MockUniversalClient) XLen(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XLen", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XLen indicates an expected call of XLen. +func (mr *MockUniversalClientMockRecorder) XLen(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XLen", reflect.TypeOf((*MockUniversalClient)(nil).XLen), arg0, arg1) +} + +// XPending mocks base method. +func (m *MockUniversalClient) XPending(arg0 context.Context, arg1, arg2 string) *redis.XPendingCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XPending", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.XPendingCmd) + return ret0 +} + +// XPending indicates an expected call of XPending. +func (mr *MockUniversalClientMockRecorder) XPending(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XPending", reflect.TypeOf((*MockUniversalClient)(nil).XPending), arg0, arg1, arg2) +} + +// XPendingExt mocks base method. +func (m *MockUniversalClient) XPendingExt(arg0 context.Context, arg1 *redis.XPendingExtArgs) *redis.XPendingExtCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XPendingExt", arg0, arg1) + ret0, _ := ret[0].(*redis.XPendingExtCmd) + return ret0 +} + +// XPendingExt indicates an expected call of XPendingExt. +func (mr *MockUniversalClientMockRecorder) XPendingExt(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XPendingExt", reflect.TypeOf((*MockUniversalClient)(nil).XPendingExt), arg0, arg1) +} + +// XRange mocks base method. +func (m *MockUniversalClient) XRange(arg0 context.Context, arg1, arg2, arg3 string) *redis.XMessageSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.XMessageSliceCmd) + return ret0 +} + +// XRange indicates an expected call of XRange. +func (mr *MockUniversalClientMockRecorder) XRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XRange", reflect.TypeOf((*MockUniversalClient)(nil).XRange), arg0, arg1, arg2, arg3) +} + +// XRangeN mocks base method. +func (m *MockUniversalClient) XRangeN(arg0 context.Context, arg1, arg2, arg3 string, arg4 int64) *redis.XMessageSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XRangeN", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.XMessageSliceCmd) + return ret0 +} + +// XRangeN indicates an expected call of XRangeN. +func (mr *MockUniversalClientMockRecorder) XRangeN(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XRangeN", reflect.TypeOf((*MockUniversalClient)(nil).XRangeN), arg0, arg1, arg2, arg3, arg4) +} + +// XRead mocks base method. +func (m *MockUniversalClient) XRead(arg0 context.Context, arg1 *redis.XReadArgs) *redis.XStreamSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XRead", arg0, arg1) + ret0, _ := ret[0].(*redis.XStreamSliceCmd) + return ret0 +} + +// XRead indicates an expected call of XRead. +func (mr *MockUniversalClientMockRecorder) XRead(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XRead", reflect.TypeOf((*MockUniversalClient)(nil).XRead), arg0, arg1) +} + +// XReadGroup mocks base method. +func (m *MockUniversalClient) XReadGroup(arg0 context.Context, arg1 *redis.XReadGroupArgs) *redis.XStreamSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XReadGroup", arg0, arg1) + ret0, _ := ret[0].(*redis.XStreamSliceCmd) + return ret0 +} + +// XReadGroup indicates an expected call of XReadGroup. +func (mr *MockUniversalClientMockRecorder) XReadGroup(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XReadGroup", reflect.TypeOf((*MockUniversalClient)(nil).XReadGroup), arg0, arg1) +} + +// XReadStreams mocks base method. +func (m *MockUniversalClient) XReadStreams(arg0 context.Context, arg1 ...string) *redis.XStreamSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "XReadStreams", varargs...) + ret0, _ := ret[0].(*redis.XStreamSliceCmd) + return ret0 +} + +// XReadStreams indicates an expected call of XReadStreams. +func (mr *MockUniversalClientMockRecorder) XReadStreams(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XReadStreams", reflect.TypeOf((*MockUniversalClient)(nil).XReadStreams), varargs...) +} + +// XRevRange mocks base method. +func (m *MockUniversalClient) XRevRange(arg0 context.Context, arg1, arg2, arg3 string) *redis.XMessageSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XRevRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.XMessageSliceCmd) + return ret0 +} + +// XRevRange indicates an expected call of XRevRange. +func (mr *MockUniversalClientMockRecorder) XRevRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XRevRange", reflect.TypeOf((*MockUniversalClient)(nil).XRevRange), arg0, arg1, arg2, arg3) +} + +// XRevRangeN mocks base method. +func (m *MockUniversalClient) XRevRangeN(arg0 context.Context, arg1, arg2, arg3 string, arg4 int64) *redis.XMessageSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XRevRangeN", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.XMessageSliceCmd) + return ret0 +} + +// XRevRangeN indicates an expected call of XRevRangeN. +func (mr *MockUniversalClientMockRecorder) XRevRangeN(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XRevRangeN", reflect.TypeOf((*MockUniversalClient)(nil).XRevRangeN), arg0, arg1, arg2, arg3, arg4) +} + +// XTrimMaxLen mocks base method. +func (m *MockUniversalClient) XTrimMaxLen(arg0 context.Context, arg1 string, arg2 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XTrimMaxLen", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XTrimMaxLen indicates an expected call of XTrimMaxLen. +func (mr *MockUniversalClientMockRecorder) XTrimMaxLen(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XTrimMaxLen", reflect.TypeOf((*MockUniversalClient)(nil).XTrimMaxLen), arg0, arg1, arg2) +} + +// XTrimMaxLenApprox mocks base method. +func (m *MockUniversalClient) XTrimMaxLenApprox(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XTrimMaxLenApprox", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XTrimMaxLenApprox indicates an expected call of XTrimMaxLenApprox. +func (mr *MockUniversalClientMockRecorder) XTrimMaxLenApprox(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XTrimMaxLenApprox", reflect.TypeOf((*MockUniversalClient)(nil).XTrimMaxLenApprox), arg0, arg1, arg2, arg3) +} + +// XTrimMinID mocks base method. +func (m *MockUniversalClient) XTrimMinID(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XTrimMinID", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XTrimMinID indicates an expected call of XTrimMinID. +func (mr *MockUniversalClientMockRecorder) XTrimMinID(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XTrimMinID", reflect.TypeOf((*MockUniversalClient)(nil).XTrimMinID), arg0, arg1, arg2) +} + +// XTrimMinIDApprox mocks base method. +func (m *MockUniversalClient) XTrimMinIDApprox(arg0 context.Context, arg1, arg2 string, arg3 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "XTrimMinIDApprox", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// XTrimMinIDApprox indicates an expected call of XTrimMinIDApprox. +func (mr *MockUniversalClientMockRecorder) XTrimMinIDApprox(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "XTrimMinIDApprox", reflect.TypeOf((*MockUniversalClient)(nil).XTrimMinIDApprox), arg0, arg1, arg2, arg3) +} + +// ZAdd mocks base method. +func (m *MockUniversalClient) ZAdd(arg0 context.Context, arg1 string, arg2 ...redis.Z) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZAdd", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZAdd indicates an expected call of ZAdd. +func (mr *MockUniversalClientMockRecorder) ZAdd(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZAdd", reflect.TypeOf((*MockUniversalClient)(nil).ZAdd), varargs...) +} + +// ZAddArgs mocks base method. +func (m *MockUniversalClient) ZAddArgs(arg0 context.Context, arg1 string, arg2 redis.ZAddArgs) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZAddArgs", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZAddArgs indicates an expected call of ZAddArgs. +func (mr *MockUniversalClientMockRecorder) ZAddArgs(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZAddArgs", reflect.TypeOf((*MockUniversalClient)(nil).ZAddArgs), arg0, arg1, arg2) +} + +// ZAddArgsIncr mocks base method. +func (m *MockUniversalClient) ZAddArgsIncr(arg0 context.Context, arg1 string, arg2 redis.ZAddArgs) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZAddArgsIncr", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// ZAddArgsIncr indicates an expected call of ZAddArgsIncr. +func (mr *MockUniversalClientMockRecorder) ZAddArgsIncr(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZAddArgsIncr", reflect.TypeOf((*MockUniversalClient)(nil).ZAddArgsIncr), arg0, arg1, arg2) +} + +// ZAddGT mocks base method. +func (m *MockUniversalClient) ZAddGT(arg0 context.Context, arg1 string, arg2 ...redis.Z) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZAddGT", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZAddGT indicates an expected call of ZAddGT. +func (mr *MockUniversalClientMockRecorder) ZAddGT(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZAddGT", reflect.TypeOf((*MockUniversalClient)(nil).ZAddGT), varargs...) +} + +// ZAddLT mocks base method. +func (m *MockUniversalClient) ZAddLT(arg0 context.Context, arg1 string, arg2 ...redis.Z) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZAddLT", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZAddLT indicates an expected call of ZAddLT. +func (mr *MockUniversalClientMockRecorder) ZAddLT(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZAddLT", reflect.TypeOf((*MockUniversalClient)(nil).ZAddLT), varargs...) +} + +// ZAddNX mocks base method. +func (m *MockUniversalClient) ZAddNX(arg0 context.Context, arg1 string, arg2 ...redis.Z) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZAddNX", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZAddNX indicates an expected call of ZAddNX. +func (mr *MockUniversalClientMockRecorder) ZAddNX(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZAddNX", reflect.TypeOf((*MockUniversalClient)(nil).ZAddNX), varargs...) +} + +// ZAddXX mocks base method. +func (m *MockUniversalClient) ZAddXX(arg0 context.Context, arg1 string, arg2 ...redis.Z) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZAddXX", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZAddXX indicates an expected call of ZAddXX. +func (mr *MockUniversalClientMockRecorder) ZAddXX(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZAddXX", reflect.TypeOf((*MockUniversalClient)(nil).ZAddXX), varargs...) +} + +// ZCard mocks base method. +func (m *MockUniversalClient) ZCard(arg0 context.Context, arg1 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZCard", arg0, arg1) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZCard indicates an expected call of ZCard. +func (mr *MockUniversalClientMockRecorder) ZCard(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZCard", reflect.TypeOf((*MockUniversalClient)(nil).ZCard), arg0, arg1) +} + +// ZCount mocks base method. +func (m *MockUniversalClient) ZCount(arg0 context.Context, arg1, arg2, arg3 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZCount", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZCount indicates an expected call of ZCount. +func (mr *MockUniversalClientMockRecorder) ZCount(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZCount", reflect.TypeOf((*MockUniversalClient)(nil).ZCount), arg0, arg1, arg2, arg3) +} + +// ZDiff mocks base method. +func (m *MockUniversalClient) ZDiff(arg0 context.Context, arg1 ...string) *redis.StringSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZDiff", varargs...) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZDiff indicates an expected call of ZDiff. +func (mr *MockUniversalClientMockRecorder) ZDiff(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZDiff", reflect.TypeOf((*MockUniversalClient)(nil).ZDiff), varargs...) +} + +// ZDiffStore mocks base method. +func (m *MockUniversalClient) ZDiffStore(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZDiffStore", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZDiffStore indicates an expected call of ZDiffStore. +func (mr *MockUniversalClientMockRecorder) ZDiffStore(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZDiffStore", reflect.TypeOf((*MockUniversalClient)(nil).ZDiffStore), varargs...) +} + +// ZDiffWithScores mocks base method. +func (m *MockUniversalClient) ZDiffWithScores(arg0 context.Context, arg1 ...string) *redis.ZSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZDiffWithScores", varargs...) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZDiffWithScores indicates an expected call of ZDiffWithScores. +func (mr *MockUniversalClientMockRecorder) ZDiffWithScores(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZDiffWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZDiffWithScores), varargs...) +} + +// ZIncrBy mocks base method. +func (m *MockUniversalClient) ZIncrBy(arg0 context.Context, arg1 string, arg2 float64, arg3 string) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZIncrBy", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// ZIncrBy indicates an expected call of ZIncrBy. +func (mr *MockUniversalClientMockRecorder) ZIncrBy(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZIncrBy", reflect.TypeOf((*MockUniversalClient)(nil).ZIncrBy), arg0, arg1, arg2, arg3) +} + +// ZInter mocks base method. +func (m *MockUniversalClient) ZInter(arg0 context.Context, arg1 *redis.ZStore) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZInter", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZInter indicates an expected call of ZInter. +func (mr *MockUniversalClientMockRecorder) ZInter(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZInter", reflect.TypeOf((*MockUniversalClient)(nil).ZInter), arg0, arg1) +} + +// ZInterCard mocks base method. +func (m *MockUniversalClient) ZInterCard(arg0 context.Context, arg1 int64, arg2 ...string) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZInterCard", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZInterCard indicates an expected call of ZInterCard. +func (mr *MockUniversalClientMockRecorder) ZInterCard(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZInterCard", reflect.TypeOf((*MockUniversalClient)(nil).ZInterCard), varargs...) +} + +// ZInterStore mocks base method. +func (m *MockUniversalClient) ZInterStore(arg0 context.Context, arg1 string, arg2 *redis.ZStore) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZInterStore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZInterStore indicates an expected call of ZInterStore. +func (mr *MockUniversalClientMockRecorder) ZInterStore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZInterStore", reflect.TypeOf((*MockUniversalClient)(nil).ZInterStore), arg0, arg1, arg2) +} + +// ZInterWithScores mocks base method. +func (m *MockUniversalClient) ZInterWithScores(arg0 context.Context, arg1 *redis.ZStore) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZInterWithScores", arg0, arg1) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZInterWithScores indicates an expected call of ZInterWithScores. +func (mr *MockUniversalClientMockRecorder) ZInterWithScores(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZInterWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZInterWithScores), arg0, arg1) +} + +// ZLexCount mocks base method. +func (m *MockUniversalClient) ZLexCount(arg0 context.Context, arg1, arg2, arg3 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZLexCount", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZLexCount indicates an expected call of ZLexCount. +func (mr *MockUniversalClientMockRecorder) ZLexCount(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZLexCount", reflect.TypeOf((*MockUniversalClient)(nil).ZLexCount), arg0, arg1, arg2, arg3) +} + +// ZMPop mocks base method. +func (m *MockUniversalClient) ZMPop(arg0 context.Context, arg1 string, arg2 int64, arg3 ...string) *redis.ZSliceWithKeyCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZMPop", varargs...) + ret0, _ := ret[0].(*redis.ZSliceWithKeyCmd) + return ret0 +} + +// ZMPop indicates an expected call of ZMPop. +func (mr *MockUniversalClientMockRecorder) ZMPop(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZMPop", reflect.TypeOf((*MockUniversalClient)(nil).ZMPop), varargs...) +} + +// ZMScore mocks base method. +func (m *MockUniversalClient) ZMScore(arg0 context.Context, arg1 string, arg2 ...string) *redis.FloatSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZMScore", varargs...) + ret0, _ := ret[0].(*redis.FloatSliceCmd) + return ret0 +} + +// ZMScore indicates an expected call of ZMScore. +func (mr *MockUniversalClientMockRecorder) ZMScore(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZMScore", reflect.TypeOf((*MockUniversalClient)(nil).ZMScore), varargs...) +} + +// ZPopMax mocks base method. +func (m *MockUniversalClient) ZPopMax(arg0 context.Context, arg1 string, arg2 ...int64) *redis.ZSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZPopMax", varargs...) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZPopMax indicates an expected call of ZPopMax. +func (mr *MockUniversalClientMockRecorder) ZPopMax(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZPopMax", reflect.TypeOf((*MockUniversalClient)(nil).ZPopMax), varargs...) +} + +// ZPopMin mocks base method. +func (m *MockUniversalClient) ZPopMin(arg0 context.Context, arg1 string, arg2 ...int64) *redis.ZSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZPopMin", varargs...) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZPopMin indicates an expected call of ZPopMin. +func (mr *MockUniversalClientMockRecorder) ZPopMin(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZPopMin", reflect.TypeOf((*MockUniversalClient)(nil).ZPopMin), varargs...) +} + +// ZRandMember mocks base method. +func (m *MockUniversalClient) ZRandMember(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRandMember", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRandMember indicates an expected call of ZRandMember. +func (mr *MockUniversalClientMockRecorder) ZRandMember(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRandMember", reflect.TypeOf((*MockUniversalClient)(nil).ZRandMember), arg0, arg1, arg2) +} + +// ZRandMemberWithScores mocks base method. +func (m *MockUniversalClient) ZRandMemberWithScores(arg0 context.Context, arg1 string, arg2 int) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRandMemberWithScores", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZRandMemberWithScores indicates an expected call of ZRandMemberWithScores. +func (mr *MockUniversalClientMockRecorder) ZRandMemberWithScores(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRandMemberWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZRandMemberWithScores), arg0, arg1, arg2) +} + +// ZRange mocks base method. +func (m *MockUniversalClient) ZRange(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRange indicates an expected call of ZRange. +func (mr *MockUniversalClientMockRecorder) ZRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRange", reflect.TypeOf((*MockUniversalClient)(nil).ZRange), arg0, arg1, arg2, arg3) +} + +// ZRangeArgs mocks base method. +func (m *MockUniversalClient) ZRangeArgs(arg0 context.Context, arg1 redis.ZRangeArgs) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRangeArgs", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRangeArgs indicates an expected call of ZRangeArgs. +func (mr *MockUniversalClientMockRecorder) ZRangeArgs(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRangeArgs", reflect.TypeOf((*MockUniversalClient)(nil).ZRangeArgs), arg0, arg1) +} + +// ZRangeArgsWithScores mocks base method. +func (m *MockUniversalClient) ZRangeArgsWithScores(arg0 context.Context, arg1 redis.ZRangeArgs) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRangeArgsWithScores", arg0, arg1) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZRangeArgsWithScores indicates an expected call of ZRangeArgsWithScores. +func (mr *MockUniversalClientMockRecorder) ZRangeArgsWithScores(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRangeArgsWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZRangeArgsWithScores), arg0, arg1) +} + +// ZRangeByLex mocks base method. +func (m *MockUniversalClient) ZRangeByLex(arg0 context.Context, arg1 string, arg2 *redis.ZRangeBy) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRangeByLex", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRangeByLex indicates an expected call of ZRangeByLex. +func (mr *MockUniversalClientMockRecorder) ZRangeByLex(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRangeByLex", reflect.TypeOf((*MockUniversalClient)(nil).ZRangeByLex), arg0, arg1, arg2) +} + +// ZRangeByScore mocks base method. +func (m *MockUniversalClient) ZRangeByScore(arg0 context.Context, arg1 string, arg2 *redis.ZRangeBy) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRangeByScore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRangeByScore indicates an expected call of ZRangeByScore. +func (mr *MockUniversalClientMockRecorder) ZRangeByScore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRangeByScore", reflect.TypeOf((*MockUniversalClient)(nil).ZRangeByScore), arg0, arg1, arg2) +} + +// ZRangeByScoreWithScores mocks base method. +func (m *MockUniversalClient) ZRangeByScoreWithScores(arg0 context.Context, arg1 string, arg2 *redis.ZRangeBy) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRangeByScoreWithScores", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZRangeByScoreWithScores indicates an expected call of ZRangeByScoreWithScores. +func (mr *MockUniversalClientMockRecorder) ZRangeByScoreWithScores(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRangeByScoreWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZRangeByScoreWithScores), arg0, arg1, arg2) +} + +// ZRangeStore mocks base method. +func (m *MockUniversalClient) ZRangeStore(arg0 context.Context, arg1 string, arg2 redis.ZRangeArgs) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRangeStore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZRangeStore indicates an expected call of ZRangeStore. +func (mr *MockUniversalClientMockRecorder) ZRangeStore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRangeStore", reflect.TypeOf((*MockUniversalClient)(nil).ZRangeStore), arg0, arg1, arg2) +} + +// ZRangeWithScores mocks base method. +func (m *MockUniversalClient) ZRangeWithScores(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRangeWithScores", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZRangeWithScores indicates an expected call of ZRangeWithScores. +func (mr *MockUniversalClientMockRecorder) ZRangeWithScores(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRangeWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZRangeWithScores), arg0, arg1, arg2, arg3) +} + +// ZRank mocks base method. +func (m *MockUniversalClient) ZRank(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRank", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZRank indicates an expected call of ZRank. +func (mr *MockUniversalClientMockRecorder) ZRank(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRank", reflect.TypeOf((*MockUniversalClient)(nil).ZRank), arg0, arg1, arg2) +} + +// ZRankWithScore mocks base method. +func (m *MockUniversalClient) ZRankWithScore(arg0 context.Context, arg1, arg2 string) *redis.RankWithScoreCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRankWithScore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.RankWithScoreCmd) + return ret0 +} + +// ZRankWithScore indicates an expected call of ZRankWithScore. +func (mr *MockUniversalClientMockRecorder) ZRankWithScore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRankWithScore", reflect.TypeOf((*MockUniversalClient)(nil).ZRankWithScore), arg0, arg1, arg2) +} + +// ZRem mocks base method. +func (m *MockUniversalClient) ZRem(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZRem", varargs...) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZRem indicates an expected call of ZRem. +func (mr *MockUniversalClientMockRecorder) ZRem(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRem", reflect.TypeOf((*MockUniversalClient)(nil).ZRem), varargs...) +} + +// ZRemRangeByLex mocks base method. +func (m *MockUniversalClient) ZRemRangeByLex(arg0 context.Context, arg1, arg2, arg3 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRemRangeByLex", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZRemRangeByLex indicates an expected call of ZRemRangeByLex. +func (mr *MockUniversalClientMockRecorder) ZRemRangeByLex(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRemRangeByLex", reflect.TypeOf((*MockUniversalClient)(nil).ZRemRangeByLex), arg0, arg1, arg2, arg3) +} + +// ZRemRangeByRank mocks base method. +func (m *MockUniversalClient) ZRemRangeByRank(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRemRangeByRank", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZRemRangeByRank indicates an expected call of ZRemRangeByRank. +func (mr *MockUniversalClientMockRecorder) ZRemRangeByRank(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRemRangeByRank", reflect.TypeOf((*MockUniversalClient)(nil).ZRemRangeByRank), arg0, arg1, arg2, arg3) +} + +// ZRemRangeByScore mocks base method. +func (m *MockUniversalClient) ZRemRangeByScore(arg0 context.Context, arg1, arg2, arg3 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRemRangeByScore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZRemRangeByScore indicates an expected call of ZRemRangeByScore. +func (mr *MockUniversalClientMockRecorder) ZRemRangeByScore(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRemRangeByScore", reflect.TypeOf((*MockUniversalClient)(nil).ZRemRangeByScore), arg0, arg1, arg2, arg3) +} + +// ZRevRange mocks base method. +func (m *MockUniversalClient) ZRevRange(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRevRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRevRange indicates an expected call of ZRevRange. +func (mr *MockUniversalClientMockRecorder) ZRevRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRevRange", reflect.TypeOf((*MockUniversalClient)(nil).ZRevRange), arg0, arg1, arg2, arg3) +} + +// ZRevRangeByLex mocks base method. +func (m *MockUniversalClient) ZRevRangeByLex(arg0 context.Context, arg1 string, arg2 *redis.ZRangeBy) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRevRangeByLex", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRevRangeByLex indicates an expected call of ZRevRangeByLex. +func (mr *MockUniversalClientMockRecorder) ZRevRangeByLex(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRevRangeByLex", reflect.TypeOf((*MockUniversalClient)(nil).ZRevRangeByLex), arg0, arg1, arg2) +} + +// ZRevRangeByScore mocks base method. +func (m *MockUniversalClient) ZRevRangeByScore(arg0 context.Context, arg1 string, arg2 *redis.ZRangeBy) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRevRangeByScore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZRevRangeByScore indicates an expected call of ZRevRangeByScore. +func (mr *MockUniversalClientMockRecorder) ZRevRangeByScore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRevRangeByScore", reflect.TypeOf((*MockUniversalClient)(nil).ZRevRangeByScore), arg0, arg1, arg2) +} + +// ZRevRangeByScoreWithScores mocks base method. +func (m *MockUniversalClient) ZRevRangeByScoreWithScores(arg0 context.Context, arg1 string, arg2 *redis.ZRangeBy) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRevRangeByScoreWithScores", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZRevRangeByScoreWithScores indicates an expected call of ZRevRangeByScoreWithScores. +func (mr *MockUniversalClientMockRecorder) ZRevRangeByScoreWithScores(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRevRangeByScoreWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZRevRangeByScoreWithScores), arg0, arg1, arg2) +} + +// ZRevRangeWithScores mocks base method. +func (m *MockUniversalClient) ZRevRangeWithScores(arg0 context.Context, arg1 string, arg2, arg3 int64) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRevRangeWithScores", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZRevRangeWithScores indicates an expected call of ZRevRangeWithScores. +func (mr *MockUniversalClientMockRecorder) ZRevRangeWithScores(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRevRangeWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZRevRangeWithScores), arg0, arg1, arg2, arg3) +} + +// ZRevRank mocks base method. +func (m *MockUniversalClient) ZRevRank(arg0 context.Context, arg1, arg2 string) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRevRank", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZRevRank indicates an expected call of ZRevRank. +func (mr *MockUniversalClientMockRecorder) ZRevRank(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRevRank", reflect.TypeOf((*MockUniversalClient)(nil).ZRevRank), arg0, arg1, arg2) +} + +// ZRevRankWithScore mocks base method. +func (m *MockUniversalClient) ZRevRankWithScore(arg0 context.Context, arg1, arg2 string) *redis.RankWithScoreCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZRevRankWithScore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.RankWithScoreCmd) + return ret0 +} + +// ZRevRankWithScore indicates an expected call of ZRevRankWithScore. +func (mr *MockUniversalClientMockRecorder) ZRevRankWithScore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZRevRankWithScore", reflect.TypeOf((*MockUniversalClient)(nil).ZRevRankWithScore), arg0, arg1, arg2) +} + +// ZScan mocks base method. +func (m *MockUniversalClient) ZScan(arg0 context.Context, arg1 string, arg2 uint64, arg3 string, arg4 int64) *redis.ScanCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZScan", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.ScanCmd) + return ret0 +} + +// ZScan indicates an expected call of ZScan. +func (mr *MockUniversalClientMockRecorder) ZScan(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZScan", reflect.TypeOf((*MockUniversalClient)(nil).ZScan), arg0, arg1, arg2, arg3, arg4) +} + +// ZScore mocks base method. +func (m *MockUniversalClient) ZScore(arg0 context.Context, arg1, arg2 string) *redis.FloatCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZScore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.FloatCmd) + return ret0 +} + +// ZScore indicates an expected call of ZScore. +func (mr *MockUniversalClientMockRecorder) ZScore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZScore", reflect.TypeOf((*MockUniversalClient)(nil).ZScore), arg0, arg1, arg2) +} + +// ZUnion mocks base method. +func (m *MockUniversalClient) ZUnion(arg0 context.Context, arg1 redis.ZStore) *redis.StringSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZUnion", arg0, arg1) + ret0, _ := ret[0].(*redis.StringSliceCmd) + return ret0 +} + +// ZUnion indicates an expected call of ZUnion. +func (mr *MockUniversalClientMockRecorder) ZUnion(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZUnion", reflect.TypeOf((*MockUniversalClient)(nil).ZUnion), arg0, arg1) +} + +// ZUnionStore mocks base method. +func (m *MockUniversalClient) ZUnionStore(arg0 context.Context, arg1 string, arg2 *redis.ZStore) *redis.IntCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZUnionStore", arg0, arg1, arg2) + ret0, _ := ret[0].(*redis.IntCmd) + return ret0 +} + +// ZUnionStore indicates an expected call of ZUnionStore. +func (mr *MockUniversalClientMockRecorder) ZUnionStore(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZUnionStore", reflect.TypeOf((*MockUniversalClient)(nil).ZUnionStore), arg0, arg1, arg2) +} + +// ZUnionWithScores mocks base method. +func (m *MockUniversalClient) ZUnionWithScores(arg0 context.Context, arg1 redis.ZStore) *redis.ZSliceCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZUnionWithScores", arg0, arg1) + ret0, _ := ret[0].(*redis.ZSliceCmd) + return ret0 +} + +// ZUnionWithScores indicates an expected call of ZUnionWithScores. +func (mr *MockUniversalClientMockRecorder) ZUnionWithScores(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZUnionWithScores", reflect.TypeOf((*MockUniversalClient)(nil).ZUnionWithScores), arg0, arg1) } diff --git a/modules/queue/queue.go b/modules/queue/queue.go index f16b3c1f34..56835014a5 100644 --- a/modules/queue/queue.go +++ b/modules/queue/queue.go @@ -61,7 +61,7 @@ // func handler(items ...*mypkg.QueueItem) []*mypkg.QueueItem { ... } package queue -import "forgejo.org/modules/util" +import "code.gitea.io/gitea/modules/util" type HandlerFuncT[T any] func(...T) (unhandled []T) diff --git a/modules/queue/workergroup.go b/modules/queue/workergroup.go index 3fb821ce69..ea4c0020c5 100644 --- a/modules/queue/workergroup.go +++ b/modules/queue/workergroup.go @@ -10,7 +10,7 @@ import ( "sync/atomic" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) var ( diff --git a/modules/queue/workerqueue.go b/modules/queue/workerqueue.go index 6a71fc4fb4..041ce9a3f2 100644 --- a/modules/queue/workerqueue.go +++ b/modules/queue/workerqueue.go @@ -10,10 +10,10 @@ import ( "sync/atomic" "time" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/process" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" ) // WorkerPoolQueue is a queue that uses a pool of workers to process items diff --git a/modules/queue/workerqueue_test.go b/modules/queue/workerqueue_test.go index 8d907ed8cd..9898ceb873 100644 --- a/modules/queue/workerqueue_test.go +++ b/modules/queue/workerqueue_test.go @@ -5,14 +5,15 @@ package queue import ( "bytes" + "context" "runtime" "strconv" "sync" "testing" "time" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -56,17 +57,17 @@ func TestWorkerPoolQueueUnhandled(t *testing.T) { stop := runWorkerPoolQueue(q) for i := 0; i < queueSetting.Length; i++ { testRecorder.Record("push:%v", i) - require.NoError(t, q.Push(i)) + assert.NoError(t, q.Push(i)) } - require.NoError(t, q.FlushWithContext(t.Context(), 0)) + assert.NoError(t, q.FlushWithContext(context.Background(), 0)) stop() ok := true for i := 0; i < queueSetting.Length; i++ { if i%2 == 0 { - ok = ok && assert.Equal(t, 2, m[i], "test %s: item %d", t.Name(), i) + ok = ok && assert.EqualValues(t, 2, m[i], "test %s: item %d", t.Name(), i) } else { - ok = ok && assert.Equal(t, 1, m[i], "test %s: item %d", t.Name(), i) + ok = ok && assert.EqualValues(t, 1, m[i], "test %s: item %d", t.Name(), i) } } if !ok { @@ -166,15 +167,15 @@ func testWorkerPoolQueuePersistence(t *testing.T, queueSetting setting.QueueSett q, _ := newWorkerPoolQueueForTest("pr_patch_checker_test", queueSetting, testHandler, true) stop := runWorkerPoolQueue(q) - require.NoError(t, q.FlushWithContext(t.Context(), 0)) + assert.NoError(t, q.FlushWithContext(context.Background(), 0)) stop() } q2() // restart the queue to continue to execute the tasks in it - assert.NotEmpty(t, tasksQ1) - assert.NotEmpty(t, tasksQ2) - assert.Equal(t, testCount, len(tasksQ1)+len(tasksQ2)) + assert.NotZero(t, len(tasksQ1)) + assert.NotZero(t, len(tasksQ2)) + assert.EqualValues(t, testCount, len(tasksQ1)+len(tasksQ2)) } func TestWorkerPoolQueueActiveWorkers(t *testing.T) { @@ -188,33 +189,33 @@ func TestWorkerPoolQueueActiveWorkers(t *testing.T) { q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 1, Length: 100}, handler, false) stop := runWorkerPoolQueue(q) for i := 0; i < 5; i++ { - require.NoError(t, q.Push(i)) + assert.NoError(t, q.Push(i)) } time.Sleep(50 * time.Millisecond) - assert.Equal(t, 1, q.GetWorkerNumber()) - assert.Equal(t, 1, q.GetWorkerActiveNumber()) + assert.EqualValues(t, 1, q.GetWorkerNumber()) + assert.EqualValues(t, 1, q.GetWorkerActiveNumber()) time.Sleep(500 * time.Millisecond) - assert.Equal(t, 1, q.GetWorkerNumber()) - assert.Equal(t, 0, q.GetWorkerActiveNumber()) + assert.EqualValues(t, 1, q.GetWorkerNumber()) + assert.EqualValues(t, 0, q.GetWorkerActiveNumber()) time.Sleep(workerIdleDuration) - assert.Equal(t, 1, q.GetWorkerNumber()) // there is at least one worker after the queue begins working + assert.EqualValues(t, 1, q.GetWorkerNumber()) // there is at least one worker after the queue begins working stop() q, _ = newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 3, Length: 100}, handler, false) stop = runWorkerPoolQueue(q) for i := 0; i < 15; i++ { - require.NoError(t, q.Push(i)) + assert.NoError(t, q.Push(i)) } time.Sleep(50 * time.Millisecond) - assert.Equal(t, 3, q.GetWorkerNumber()) - assert.Equal(t, 3, q.GetWorkerActiveNumber()) + assert.EqualValues(t, 3, q.GetWorkerNumber()) + assert.EqualValues(t, 3, q.GetWorkerActiveNumber()) time.Sleep(500 * time.Millisecond) - assert.Equal(t, 3, q.GetWorkerNumber()) - assert.Equal(t, 0, q.GetWorkerActiveNumber()) + assert.EqualValues(t, 3, q.GetWorkerNumber()) + assert.EqualValues(t, 0, q.GetWorkerActiveNumber()) time.Sleep(workerIdleDuration) - assert.Equal(t, 1, q.GetWorkerNumber()) // there is at least one worker after the queue begins working + assert.EqualValues(t, 1, q.GetWorkerNumber()) // there is at least one worker after the queue begins working stop() } @@ -237,17 +238,17 @@ func TestWorkerPoolQueueShutdown(t *testing.T) { q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", qs, handler, false) stop := runWorkerPoolQueue(q) for i := 0; i < qs.Length; i++ { - require.NoError(t, q.Push(i)) + assert.NoError(t, q.Push(i)) } <-handlerCalled time.Sleep(200 * time.Millisecond) // wait for a while to make sure all workers are active - assert.Equal(t, 4, q.GetWorkerActiveNumber()) + assert.EqualValues(t, 4, q.GetWorkerActiveNumber()) stop() // stop triggers shutdown - assert.Equal(t, 0, q.GetWorkerActiveNumber()) + assert.EqualValues(t, 0, q.GetWorkerActiveNumber()) // no item was ever handled, so we still get all of them again q, _ = newWorkerPoolQueueForTest("test-workpoolqueue", qs, handler, false) - assert.Equal(t, 20, q.GetQueueItemNumber()) + assert.EqualValues(t, 20, q.GetQueueItemNumber()) } func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) { @@ -265,7 +266,7 @@ func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) { const workloadSize = 12 for i := 0; i < workloadSize; i++ { - require.NoError(t, q.Push(i)) + assert.NoError(t, q.Push(i)) } workerIDs := make(map[string]struct{}) diff --git a/modules/recaptcha/recaptcha.go b/modules/recaptcha/recaptcha.go index 95b0a77a43..1777d169c1 100644 --- a/modules/recaptcha/recaptcha.go +++ b/modules/recaptcha/recaptcha.go @@ -11,9 +11,9 @@ import ( "net/url" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) // Response is the structure of JSON returned from API diff --git a/modules/references/references.go b/modules/references/references.go index 7df5119393..c61d06d5dc 100644 --- a/modules/references/references.go +++ b/modules/references/references.go @@ -11,10 +11,10 @@ import ( "strings" "sync" - "forgejo.org/modules/log" - "forgejo.org/modules/markup/mdstripper" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup/mdstripper" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) var ( @@ -32,7 +32,7 @@ var ( // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`) // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 - issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\'|,)`) + issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\')`) // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository // e.g. org/repo#12345 crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) @@ -460,17 +460,15 @@ func findAllIssueReferencesBytes(content []byte, links []string) []*rawReference } parts := strings.Split(u.EscapedPath(), "/") // /user/repo/issues/3 - // /user/repo/pulls/7/files/... - if len(parts) < 5 || parts[0] != "" { + if len(parts) != 5 || parts[0] != "" { continue } var sep string - switch parts[3] { - case "issues": + if parts[3] == "issues" { sep = "#" - case "pulls": + } else if parts[3] == "pulls" { sep = "!" - default: + } else { continue } // Note: closing/reopening keywords not supported with URLs diff --git a/modules/references/references_test.go b/modules/references/references_test.go index bb22c0bd59..498374b2a7 100644 --- a/modules/references/references_test.go +++ b/modules/references/references_test.go @@ -7,7 +7,7 @@ import ( "regexp" "testing" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) @@ -46,7 +46,7 @@ owner/repo!123456789 contentBytes := []byte(test) convertFullHTMLReferencesToShortRefs(re, &contentBytes) result := string(contentBytes) - assert.Equal(t, expect, result) + assert.EqualValues(t, expect, result) } func TestFindAllIssueReferences(t *testing.T) { @@ -132,30 +132,6 @@ func TestFindAllIssueReferences(t *testing.T) { {203, "user4", "repo5", "203", true, XRefActionNone, nil, nil, ""}, }, }, - { - "This http://gitea.com:3000/user4/repo5/pulls/202#x yes.", - []testResult{ - {202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""}, - }, - }, - { - "This http://gitea.com:3000/user4/repo5/pulls/202/commits yes.", - []testResult{ - {202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""}, - }, - }, - { - "This http://gitea.com:3000/user4/repo5/pulls/202/files yes.", - []testResult{ - {202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""}, - }, - }, - { - "This http://gitea.com:3000/user4/repo5/pulls/202/files#diff- yes.", - []testResult{ - {202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""}, - }, - }, { "This http://GiTeA.COM:3000/user4/repo6/pulls/205 yes.", []testResult{ @@ -308,9 +284,9 @@ func testFixtures(t *testing.T, fixtures []testFixture, context string) { } expref := rawToIssueReferenceList(expraw) refs := FindAllIssueReferencesMarkdown(fixture.input) - assert.Equal(t, expref, refs, "[%s] Failed to parse: {%s}", context, fixture.input) + assert.EqualValues(t, expref, refs, "[%s] Failed to parse: {%s}", context, fixture.input) rawrefs := findAllIssueReferencesMarkdown(fixture.input) - assert.Equal(t, expraw, rawrefs, "[%s] Failed to parse: {%s}", context, fixture.input) + assert.EqualValues(t, expraw, rawrefs, "[%s] Failed to parse: {%s}", context, fixture.input) } // Restore for other tests that may rely on the original value @@ -319,7 +295,7 @@ func testFixtures(t *testing.T, fixtures []testFixture, context string) { func TestFindAllMentions(t *testing.T) { res := FindAllMentionsBytes([]byte("@tasha, @mike; @lucy: @john")) - assert.Equal(t, []RefSpan{ + assert.EqualValues(t, []RefSpan{ {Start: 0, End: 6}, {Start: 8, End: 13}, {Start: 15, End: 20}, @@ -490,7 +466,6 @@ func TestRegExp_issueAlphanumericPattern(t *testing.T) { "ABC-123:", "\"ABC-123\"", "'ABC-123'", - "ABC-123, unknown PR", } falseTestCases := []string{ "RC-08", @@ -554,7 +529,7 @@ func TestCustomizeCloseKeywords(t *testing.T) { func TestParseCloseKeywords(t *testing.T) { // Test parsing of CloseKeywords and ReopenKeywords - assert.Empty(t, parseKeywords([]string{""})) + assert.Len(t, parseKeywords([]string{""}), 0) assert.Len(t, parseKeywords([]string{" aa ", " bb ", "99", "#", "", "this is", "cc"}), 3) for _, test := range []struct { @@ -582,7 +557,7 @@ func TestParseCloseKeywords(t *testing.T) { res := pat.FindAllStringSubmatch(test.match, -1) assert.Len(t, res, 1) assert.Len(t, res[0], 2) - assert.Equal(t, test.expected, res[0][1]) + assert.EqualValues(t, test.expected, res[0][1]) } } } diff --git a/modules/regexplru/regexplru.go b/modules/regexplru/regexplru.go index b452094c16..8f66dcf3f7 100644 --- a/modules/regexplru/regexplru.go +++ b/modules/regexplru/regexplru.go @@ -6,7 +6,7 @@ package regexplru import ( "regexp" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" lru "github.com/hashicorp/golang-lru/v2" ) diff --git a/modules/regexplru/regexplru_test.go b/modules/regexplru/regexplru_test.go index 6e15e88e14..9c24b23fa9 100644 --- a/modules/regexplru/regexplru_test.go +++ b/modules/regexplru/regexplru_test.go @@ -7,21 +7,20 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestRegexpLru(t *testing.T) { r, err := GetCompiled("a") - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, r.MatchString("a")) r, err = GetCompiled("a") - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, r.MatchString("a")) - assert.Equal(t, 1, lruCache.Len()) + assert.EqualValues(t, 1, lruCache.Len()) _, err = GetCompiled("(") - require.Error(t, err) - assert.Equal(t, 2, lruCache.Len()) + assert.Error(t, err) + assert.EqualValues(t, 2, lruCache.Len()) } diff --git a/modules/repository/branch.go b/modules/repository/branch.go index 59b5f9e7d5..2bf9930f19 100644 --- a/modules/repository/branch.go +++ b/modules/repository/branch.go @@ -7,14 +7,14 @@ import ( "context" "fmt" - "forgejo.org/models/db" - git_model "forgejo.org/models/git" - repo_model "forgejo.org/models/repo" - "forgejo.org/modules/container" - "forgejo.org/modules/git" - "forgejo.org/modules/gitrepo" - "forgejo.org/modules/log" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/timeutil" ) // SyncRepoBranches synchronizes branch table with repository branches diff --git a/modules/repository/branch_test.go b/modules/repository/branch_test.go index 31e27f222f..acf75a1ac0 100644 --- a/modules/repository/branch_test.go +++ b/modules/repository/branch_test.go @@ -6,27 +6,26 @@ package repository import ( "testing" - "forgejo.org/models/db" - git_model "forgejo.org/models/git" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestSyncRepoBranches(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) _, err := db.GetEngine(db.DefaultContext).ID(1).Update(&repo_model.Repository{ObjectFormatName: "bad-fmt"}) - require.NoError(t, db.TruncateBeans(db.DefaultContext, &git_model.Branch{})) - require.NoError(t, err) + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &git_model.Branch{})) + assert.NoError(t, err) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.Equal(t, "bad-fmt", repo.ObjectFormatName) _, err = SyncRepoBranches(db.DefaultContext, 1, 0) - require.NoError(t, err) + assert.NoError(t, err) repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.Equal(t, "sha1", repo.ObjectFormatName) branch, err := git_model.GetBranch(db.DefaultContext, 1, "master") - require.NoError(t, err) - assert.Equal(t, "master", branch.Name) + assert.NoError(t, err) + assert.EqualValues(t, "master", branch.Name) } diff --git a/modules/repository/collaborator.go b/modules/repository/collaborator.go index 5a0c4451b7..17915d34b7 100644 --- a/modules/repository/collaborator.go +++ b/modules/repository/collaborator.go @@ -6,11 +6,11 @@ package repository import ( "context" - "forgejo.org/models/db" - "forgejo.org/models/perm" - access_model "forgejo.org/models/perm/access" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" "xorm.io/builder" ) diff --git a/modules/repository/collaborator_test.go b/modules/repository/collaborator_test.go index dae173506b..e623dbdaa4 100644 --- a/modules/repository/collaborator_test.go +++ b/modules/repository/collaborator_test.go @@ -6,27 +6,26 @@ package repository import ( "testing" - "forgejo.org/models/db" - "forgejo.org/models/organization" - perm_model "forgejo.org/models/perm" - access_model "forgejo.org/models/perm/access" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unit" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/organization" + perm_model "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestRepository_AddCollaborator(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(repoID, userID int64) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) - require.NoError(t, repo.LoadOwner(db.DefaultContext)) + assert.NoError(t, repo.LoadOwner(db.DefaultContext)) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) - require.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) } testSuccess(1, 4) @@ -35,23 +34,23 @@ func TestRepository_AddCollaborator(t *testing.T) { } func TestRepository_AddCollaborator_IsBlocked(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(repoID, userID int64) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) - require.NoError(t, repo.LoadOwner(db.DefaultContext)) + assert.NoError(t, repo.LoadOwner(db.DefaultContext)) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) // Owner blocked user. unittest.AssertSuccessfulInsert(t, &user_model.BlockedUser{UserID: repo.OwnerID, BlockID: userID}) - require.ErrorIs(t, AddCollaborator(db.DefaultContext, repo, user), user_model.ErrBlockedByUser) + assert.ErrorIs(t, AddCollaborator(db.DefaultContext, repo, user), user_model.ErrBlockedByUser) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) _, err := db.DeleteByBean(db.DefaultContext, &user_model.BlockedUser{UserID: repo.OwnerID, BlockID: userID}) - require.NoError(t, err) + assert.NoError(t, err) // User has owner blocked. unittest.AssertSuccessfulInsert(t, &user_model.BlockedUser{UserID: userID, BlockID: repo.OwnerID}) - require.ErrorIs(t, AddCollaborator(db.DefaultContext, repo, user), user_model.ErrBlockedByUser) + assert.ErrorIs(t, AddCollaborator(db.DefaultContext, repo, user), user_model.ErrBlockedByUser) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) } // Ensure idempotency (public repository). @@ -62,25 +61,25 @@ func TestRepository_AddCollaborator_IsBlocked(t *testing.T) { } func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) // public non-organization repo repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) - require.NoError(t, repo.LoadUnits(db.DefaultContext)) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.False(t, perm.CanWrite(unit.Type)) } // change to collaborator - require.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -89,7 +88,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // collaborator collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, collaborator) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -98,7 +97,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -107,7 +106,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -115,33 +114,33 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { } func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) // private non-organization repo repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - require.NoError(t, repo.LoadUnits(db.DefaultContext)) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.False(t, perm.CanRead(unit.Type)) assert.False(t, perm.CanWrite(unit.Type)) } // change to collaborator to default write access - require.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) } - require.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.False(t, perm.CanWrite(unit.Type)) @@ -150,7 +149,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -159,7 +158,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -167,33 +166,33 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { } func TestRepoPermissionPublicOrgRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) // public organization repo repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32}) - require.NoError(t, repo.LoadUnits(db.DefaultContext)) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.False(t, perm.CanWrite(unit.Type)) } // change to collaborator to default write access - require.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) } - require.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.False(t, perm.CanWrite(unit.Type)) @@ -202,7 +201,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // org member team owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -211,7 +210,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // org member team tester member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, member) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) } @@ -221,7 +220,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -229,33 +228,33 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { } func TestRepoPermissionPrivateOrgRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) // private organization repo repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}) - require.NoError(t, repo.LoadUnits(db.DefaultContext)) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.False(t, perm.CanRead(unit.Type)) assert.False(t, perm.CanWrite(unit.Type)) } // change to collaborator to default write access - require.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) } - require.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.False(t, perm.CanWrite(unit.Type)) @@ -264,7 +263,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -272,9 +271,10 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // update team information and then check permission team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}) - unittest.AssertSuccessfulDelete(t, &organization.TeamUnit{TeamID: team.ID}) + err = organization.UpdateTeamUnits(db.DefaultContext, team, nil) + assert.NoError(t, err) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) @@ -283,7 +283,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team tester tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, tester) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, perm.CanWrite(unit.TypeIssues)) assert.False(t, perm.CanWrite(unit.TypeCode)) assert.False(t, perm.CanRead(unit.TypeCode)) @@ -291,7 +291,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team reviewer reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, reviewer) - require.NoError(t, err) + assert.NoError(t, err) assert.False(t, perm.CanRead(unit.TypeIssues)) assert.False(t, perm.CanWrite(unit.TypeCode)) assert.True(t, perm.CanRead(unit.TypeCode)) @@ -299,7 +299,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) - require.NoError(t, err) + assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) diff --git a/modules/repository/commits.go b/modules/repository/commits.go index 261b6f7a22..ede60429a1 100644 --- a/modules/repository/commits.go +++ b/modules/repository/commits.go @@ -1,5 +1,4 @@ // Copyright 2019 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package repository @@ -10,14 +9,13 @@ import ( "net/url" "time" - asymkey_model "forgejo.org/models/asymkey" - "forgejo.org/models/avatars" - user_model "forgejo.org/models/user" - "forgejo.org/modules/cache" - "forgejo.org/modules/git" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - api "forgejo.org/modules/structs" + "code.gitea.io/gitea/models/avatars" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" ) // PushCommit represents a commit in a push operation. @@ -28,8 +26,6 @@ type PushCommit struct { AuthorName string CommitterEmail string CommitterName string - Signature *git.ObjectSignature - Verification *asymkey_model.ObjectVerification Timestamp time.Time } @@ -149,32 +145,6 @@ func (pc *PushCommits) AvatarLink(ctx context.Context, email string) string { return v } -// PushCommitToCommit transforms a PushCommit to a git.Commit type on a best effort basis. -// -// Attention: Converting a Commit to a PushCommit and converting back to a Commit will not result in an identical object! -func PushCommitToCommit(commit *PushCommit) (*git.Commit, error) { - id, err := git.NewIDFromString(commit.Sha1) - if err != nil { - return nil, err - } - return &git.Commit{ - ID: id, - Author: &git.Signature{ - Name: commit.AuthorName, - Email: commit.AuthorEmail, - When: commit.Timestamp, - }, - Committer: &git.Signature{ - Name: commit.CommitterName, - Email: commit.CommitterEmail, - When: commit.Timestamp, - }, - CommitMessage: commit.Message, - Signature: commit.Signature, - Parents: []git.ObjectID{}, - }, nil -} - // CommitToPushCommit transforms a git.Commit to PushCommit type. func CommitToPushCommit(commit *git.Commit) *PushCommit { return &PushCommit{ @@ -184,7 +154,6 @@ func CommitToPushCommit(commit *git.Commit) *PushCommit { AuthorName: commit.Author.Name, CommitterEmail: commit.Committer.Email, CommitterName: commit.Committer.Name, - Signature: commit.Signature, Timestamp: commit.Author.When, } } diff --git a/modules/repository/commits_test.go b/modules/repository/commits_test.go index 4b6d4bfe51..248673a907 100644 --- a/modules/repository/commits_test.go +++ b/modules/repository/commits_test.go @@ -1,26 +1,26 @@ // Copyright 2019 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package repository import ( + "crypto/md5" + "fmt" "strconv" "testing" "time" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" - "forgejo.org/modules/git" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) pushCommits := NewPushCommits() pushCommits.Commits = []*PushCommit{ @@ -53,7 +53,7 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) payloadCommits, headCommit, err := pushCommits.ToAPIPayloadCommits(git.DefaultContext, repo.RepoPath(), "/user2/repo16") - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, payloadCommits, 3) assert.NotNil(t, headCommit) @@ -64,9 +64,9 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { assert.Equal(t, "user2", payloadCommits[0].Committer.UserName) assert.Equal(t, "User2", payloadCommits[0].Author.Name) assert.Equal(t, "user2", payloadCommits[0].Author.UserName) - assert.Equal(t, []string{}, payloadCommits[0].Added) - assert.Equal(t, []string{}, payloadCommits[0].Removed) - assert.Equal(t, []string{"readme.md"}, payloadCommits[0].Modified) + assert.EqualValues(t, []string{}, payloadCommits[0].Added) + assert.EqualValues(t, []string{}, payloadCommits[0].Removed) + assert.EqualValues(t, []string{"readme.md"}, payloadCommits[0].Modified) assert.Equal(t, "27566bd", payloadCommits[1].ID) assert.Equal(t, "good signed commit (with not yet validated email)", payloadCommits[1].Message) @@ -75,9 +75,9 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { assert.Equal(t, "user2", payloadCommits[1].Committer.UserName) assert.Equal(t, "User2", payloadCommits[1].Author.Name) assert.Equal(t, "user2", payloadCommits[1].Author.UserName) - assert.Equal(t, []string{}, payloadCommits[1].Added) - assert.Equal(t, []string{}, payloadCommits[1].Removed) - assert.Equal(t, []string{"readme.md"}, payloadCommits[1].Modified) + assert.EqualValues(t, []string{}, payloadCommits[1].Added) + assert.EqualValues(t, []string{}, payloadCommits[1].Removed) + assert.EqualValues(t, []string{"readme.md"}, payloadCommits[1].Modified) assert.Equal(t, "5099b81", payloadCommits[2].ID) assert.Equal(t, "good signed commit", payloadCommits[2].Message) @@ -86,9 +86,9 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { assert.Equal(t, "user2", payloadCommits[2].Committer.UserName) assert.Equal(t, "User2", payloadCommits[2].Author.Name) assert.Equal(t, "user2", payloadCommits[2].Author.UserName) - assert.Equal(t, []string{"readme.md"}, payloadCommits[2].Added) - assert.Equal(t, []string{}, payloadCommits[2].Removed) - assert.Equal(t, []string{}, payloadCommits[2].Modified) + assert.EqualValues(t, []string{"readme.md"}, payloadCommits[2].Added) + assert.EqualValues(t, []string{}, payloadCommits[2].Removed) + assert.EqualValues(t, []string{}, payloadCommits[2].Modified) assert.Equal(t, "69554a6", headCommit.ID) assert.Equal(t, "not signed commit", headCommit.Message) @@ -97,13 +97,13 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { assert.Equal(t, "user2", headCommit.Committer.UserName) assert.Equal(t, "User2", headCommit.Author.Name) assert.Equal(t, "user2", headCommit.Author.UserName) - assert.Equal(t, []string{}, headCommit.Added) - assert.Equal(t, []string{}, headCommit.Removed) - assert.Equal(t, []string{"readme.md"}, headCommit.Modified) + assert.EqualValues(t, []string{}, headCommit.Added) + assert.EqualValues(t, []string{}, headCommit.Removed) + assert.EqualValues(t, []string{"readme.md"}, headCommit.Modified) } func TestPushCommits_AvatarLink(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) pushCommits := NewPushCommits() pushCommits.Commits = []*PushCommit{ @@ -125,59 +125,18 @@ func TestPushCommits_AvatarLink(t *testing.T) { }, } + setting.GravatarSource = "https://secure.gravatar.com/avatar" + setting.OfflineMode = true + assert.Equal(t, - "/avatars/ab53a2911ddf9b4817ac01ddcd3d975f?size="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor), + "/avatars/avatar2?size="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor), pushCommits.AvatarLink(db.DefaultContext, "user2@example.com")) assert.Equal(t, - "/assets/img/avatar_default.png", + fmt.Sprintf("https://secure.gravatar.com/avatar/%x?d=identicon&s=%d", md5.Sum([]byte("nonexistent@example.com")), 28*setting.Avatar.RenderedSizeFactor), pushCommits.AvatarLink(db.DefaultContext, "nonexistent@example.com")) } -func TestPushCommitToCommit(t *testing.T) { - now := time.Now() - sig := &git.Signature{ - Email: "example@example.com", - Name: "John Doe", - When: now, - } - const hexString = "0123456789abcdef0123456789abcdef01234567" - sha1, err := git.NewIDFromString(hexString) - require.NoError(t, err) - commit, err := PushCommitToCommit(&PushCommit{ - Sha1: sha1.String(), - Message: "Commit Message", - AuthorEmail: "example@example.com", - AuthorName: "John Doe", - CommitterEmail: "example@example.com", - CommitterName: "John Doe", - Signature: nil, - Timestamp: now, - }) - require.NoError(t, err) - assert.Equal(t, sha1, commit.ID) - assert.Equal(t, "Commit Message", commit.CommitMessage) - assert.Equal(t, sig, commit.Author) - assert.Equal(t, sig, commit.Committer) - assert.Nil(t, commit.Signature) -} - -func TestPushCommitToCommitInvalidSha(t *testing.T) { - now := time.Now() - const hexString = "012" - _, err := PushCommitToCommit(&PushCommit{ - Sha1: hexString, - Message: "Commit Message", - AuthorEmail: "example@example.com", - AuthorName: "John Doe", - CommitterEmail: "example@example.com", - CommitterName: "John Doe", - Signature: nil, - Timestamp: now, - }) - require.Error(t, err) -} - func TestCommitToPushCommit(t *testing.T) { now := time.Now() sig := &git.Signature{ @@ -187,7 +146,7 @@ func TestCommitToPushCommit(t *testing.T) { } const hexString = "0123456789abcdef0123456789abcdef01234567" sha1, err := git.NewIDFromString(hexString) - require.NoError(t, err) + assert.NoError(t, err) pushCommit := CommitToPushCommit(&git.Commit{ ID: sha1, Author: sig, @@ -213,10 +172,10 @@ func TestListToPushCommits(t *testing.T) { const hexString1 = "0123456789abcdef0123456789abcdef01234567" hash1, err := git.NewIDFromString(hexString1) - require.NoError(t, err) + assert.NoError(t, err) const hexString2 = "fedcba9876543210fedcba9876543210fedcba98" hash2, err := git.NewIDFromString(hexString2) - require.NoError(t, err) + assert.NoError(t, err) l := []*git.Commit{ { diff --git a/modules/repository/create.go b/modules/repository/create.go index becfed0370..ca2150b972 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -1,5 +1,4 @@ // Copyright 2019 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package repository @@ -12,22 +11,22 @@ import ( "path/filepath" "strings" - "forgejo.org/models" - activities_model "forgejo.org/models/activities" - "forgejo.org/models/db" - git_model "forgejo.org/models/git" - "forgejo.org/models/organization" - "forgejo.org/models/perm" - access_model "forgejo.org/models/perm/access" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unit" - user_model "forgejo.org/models/user" - "forgejo.org/models/webhook" - issue_indexer "forgejo.org/modules/indexer/issues" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - api "forgejo.org/modules/structs" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models" + activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/models/webhook" + issue_indexer "code.gitea.io/gitea/modules/indexer/issues" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" ) // CreateRepositoryByExample creates a repository for the user/organization. @@ -69,16 +68,12 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re // insert units for repo defaultUnits := unit.DefaultRepoUnits - switch { - case isFork: + if isFork { defaultUnits = unit.DefaultForkRepoUnits - case repo.IsMirror: - defaultUnits = unit.DefaultMirrorRepoUnits } units := make([]repo_model.RepoUnit, 0, len(defaultUnits)) for _, tp := range defaultUnits { - switch tp { - case unit.TypeIssues: + if tp == unit.TypeIssues { units = append(units, repo_model.RepoUnit{ RepoID: repo.ID, Type: tp, @@ -88,18 +83,17 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re EnableDependencies: setting.Service.DefaultEnableDependencies, }, }) - case unit.TypePullRequests: + } else if tp == unit.TypePullRequests { units = append(units, repo_model.RepoUnit{ RepoID: repo.ID, Type: tp, Config: &repo_model.PullRequestsConfig{ AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, AllowFastForwardOnly: true, - DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle), - DefaultUpdateStyle: repo_model.UpdateStyle(setting.Repository.PullRequest.DefaultUpdateStyle), - AllowRebaseUpdate: true, + DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle), + AllowRebaseUpdate: true, }, }) - default: + } else { units = append(units, repo_model.RepoUnit{ RepoID: repo.ID, Type: tp, @@ -245,11 +239,6 @@ func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibili e := db.GetEngine(ctx) - // If the repository was reported as abusive, a shadow copy should be created before first update. - if err := repo_model.IfNeededCreateShadowCopyForRepository(ctx, repo, true); err != nil { - return err - } - if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil { return fmt.Errorf("update: %w", err) } diff --git a/modules/repository/create_test.go b/modules/repository/create_test.go index 45f7f8e853..6a2f4deaff 100644 --- a/modules/repository/create_test.go +++ b/modules/repository/create_test.go @@ -6,41 +6,40 @@ package repository import ( "testing" - activities_model "forgejo.org/models/activities" - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" + activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestUpdateRepositoryVisibilityChanged(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) // Get sample repo and change visibility repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 9) - require.NoError(t, err) + assert.NoError(t, err) repo.IsPrivate = true // Update it err = UpdateRepository(db.DefaultContext, repo, true) - require.NoError(t, err) + assert.NoError(t, err) // Check visibility of action has become private act := activities_model.Action{} _, err = db.GetEngine(db.DefaultContext).ID(3).Get(&act) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, act.IsPrivate) } func TestGetDirectorySize(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 1) - require.NoError(t, err) + assert.NoError(t, err) size, err := getDirectorySize(repo.RepoPath()) - require.NoError(t, err) - assert.Equal(t, size, repo.Size) + assert.NoError(t, err) + assert.EqualValues(t, size, repo.Size) } diff --git a/modules/repository/delete.go b/modules/repository/delete.go index 6fff16b406..04af98beef 100644 --- a/modules/repository/delete.go +++ b/modules/repository/delete.go @@ -6,9 +6,9 @@ package repository import ( "context" - "forgejo.org/models/organization" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" + "code.gitea.io/gitea/models/organization" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" ) // CanUserDelete returns true if user could delete the repository diff --git a/modules/repository/env.go b/modules/repository/env.go index 110f6ca674..e4f32092fc 100644 --- a/modules/repository/env.go +++ b/modules/repository/env.go @@ -8,9 +8,9 @@ import ( "os" "strings" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/setting" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" ) // env keys for git hooks need diff --git a/modules/repository/fork.go b/modules/repository/fork.go index 42801fa80d..fbf0008716 100644 --- a/modules/repository/fork.go +++ b/modules/repository/fork.go @@ -6,9 +6,9 @@ package repository import ( "context" - "forgejo.org/models/organization" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" + "code.gitea.io/gitea/models/organization" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" ) // CanUserForkRepo returns true if specified user can fork repository. diff --git a/modules/repository/hooks.go b/modules/repository/hooks.go index 0f5e3afc34..95849789ab 100644 --- a/modules/repository/hooks.go +++ b/modules/repository/hooks.go @@ -7,9 +7,10 @@ import ( "fmt" "os" "path/filepath" + "runtime" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) func getHookTemplates() (hookNames, hookTpls, giteaHookTpls []string) { @@ -145,6 +146,10 @@ func CreateDelegateHooks(repoPath string) (err error) { } func checkExecutable(filename string) bool { + // windows has no concept of a executable bit + if runtime.GOOS == "windows" { + return true + } fileInfo, err := os.Stat(filename) if err != nil { return false diff --git a/modules/repository/init.go b/modules/repository/init.go index 7b1442be93..5f500c5233 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -10,14 +10,14 @@ import ( "sort" "strings" - issues_model "forgejo.org/models/issues" - repo_model "forgejo.org/models/repo" - "forgejo.org/modules/git" - "forgejo.org/modules/label" - "forgejo.org/modules/log" - "forgejo.org/modules/options" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/label" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) type OptionFile struct { diff --git a/modules/repository/init_test.go b/modules/repository/init_test.go index 1fa928105c..227efdc1db 100644 --- a/modules/repository/init_test.go +++ b/modules/repository/init_test.go @@ -14,17 +14,17 @@ func TestMergeCustomLabels(t *testing.T) { all: []string{"a", "a.yaml", "a.yml"}, custom: nil, }) - assert.Equal(t, []string{"a.yaml"}, files, "yaml file should win") + assert.EqualValues(t, []string{"a.yaml"}, files, "yaml file should win") files = mergeCustomLabelFiles(optionFileList{ all: []string{"a", "a.yaml"}, custom: []string{"a"}, }) - assert.Equal(t, []string{"a"}, files, "custom file should win") + assert.EqualValues(t, []string{"a"}, files, "custom file should win") files = mergeCustomLabelFiles(optionFileList{ all: []string{"a", "a.yml", "a.yaml"}, custom: []string{"a", "a.yml"}, }) - assert.Equal(t, []string{"a.yml"}, files, "custom yml file should win if no yaml") + assert.EqualValues(t, []string{"a.yml"}, files, "custom yml file should win if no yaml") } diff --git a/modules/repository/license.go b/modules/repository/license.go index 9776f047af..6ac3547e7b 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -1,5 +1,4 @@ // Copyright 2023 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package repository @@ -11,7 +10,7 @@ import ( "regexp" "strings" - "forgejo.org/modules/options" + "code.gitea.io/gitea/modules/options" ) type LicenseValues struct { @@ -109,9 +108,6 @@ func getLicensePlaceholder(name string) *licensePlaceholder { } // Other special placeholders can be added here. - case "BSD-4-Clause": - ret.Owner = append(ret.Owner, "COPYRIGHT HOLDER") - ret.Owner = append(ret.Owner, "the organization") } return ret } diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 3195f15dda..3b0cfa1eed 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -1,5 +1,4 @@ // Copyright 2023 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package repository @@ -9,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_getLicense(t *testing.T) { @@ -21,7 +19,7 @@ func Test_getLicense(t *testing.T) { name string args args want string - wantErr require.ErrorAssertionFunc + wantErr assert.ErrorAssertionFunc }{ { name: "regular", @@ -39,21 +37,22 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. `, - wantErr: require.NoError, + wantErr: assert.NoError, }, { name: "license not found", args: args{ name: "notfound", }, - wantErr: require.Error, + wantErr: assert.Error, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := GetLicense(tt.args.name, tt.args.values) - tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) - + if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) { + return + } assert.Equalf(t, tt.want, string(got), "GetLicense(%v, %v)", tt.args.name, tt.args.values) }) } @@ -171,31 +170,6 @@ Copyright (C) 2023 by Gitea teabot@gitea.io ... ... THE AUTHOR BE LIABLE FOR ... -`, - }, - { - name: "BSD-4-Clause", - args: args{ - name: "BSD-4-Clause", - values: &LicenseValues{Year: "2025", Owner: "Forgejo", Email: "hello@forgejo.org", Repo: "forgejo"}, - origin: ` -Copyright (c) . All rights reserved. - -... includes software developed by the organization. - -... Neither the name of the copyright holder nor - -... PROVIDED BY COPYRIGHT HOLDER "AS IS" ... NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE ... -`, - }, - want: ` -Copyright (c) 2025 Forgejo. All rights reserved. - -... includes software developed by Forgejo. - -... Neither the name of the copyright holder nor - -... PROVIDED BY Forgejo "AS IS" ... NO EVENT SHALL Forgejo BE LIABLE ... `, }, } diff --git a/modules/repository/main_test.go b/modules/repository/main_test.go index 5906b10865..f81dfcdafb 100644 --- a/modules/repository/main_test.go +++ b/modules/repository/main_test.go @@ -6,10 +6,9 @@ package repository import ( "testing" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/unittest" - _ "forgejo.org/models/actions" - _ "forgejo.org/models/forgefed" + _ "code.gitea.io/gitea/models/actions" ) func TestMain(m *testing.M) { diff --git a/modules/repository/push.go b/modules/repository/push.go index d8be0a3e8c..66d0417caf 100644 --- a/modules/repository/push.go +++ b/modules/repository/push.go @@ -4,7 +4,7 @@ package repository import ( - "forgejo.org/modules/git" + "code.gitea.io/gitea/modules/git" ) // PushUpdateOptions defines the push update options diff --git a/modules/repository/repo.go b/modules/repository/repo.go index c86d48fe52..a863bec996 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -6,23 +6,22 @@ package repository import ( "context" - "errors" "fmt" "io" "strings" "time" - "forgejo.org/models/db" - git_model "forgejo.org/models/git" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/container" - "forgejo.org/modules/git" - "forgejo.org/modules/gitrepo" - "forgejo.org/modules/lfs" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/lfs" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" ) /* @@ -90,11 +89,11 @@ func SyncReleasesWithTags(ctx context.Context, repo *repo_model.Repository, gitR if rel.IsDraft { continue } - commit, err := gitRepo.GetTagCommit(rel.TagName) + commitID, err := gitRepo.GetTagCommitID(rel.TagName) if err != nil && !git.IsErrNotExist(err) { return fmt.Errorf("unable to GetTagCommitID for %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err) } - if git.IsErrNotExist(err) || commit.ID.String() != rel.Sha1 { + if git.IsErrNotExist(err) || commitID != rel.Sha1 { if err := repo_model.PushUpdateDeleteTag(ctx, repo, rel.TagName); err != nil { return fmt.Errorf("unable to PushUpdateDeleteTag: %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err) } @@ -182,11 +181,6 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re downloadObjects := func(pointers []lfs.Pointer) error { err := lfsClient.Download(ctx, pointers, func(p lfs.Pointer, content io.ReadCloser, objectError error) error { - if errors.Is(objectError, lfs.ErrObjectNotExist) { - log.Warn("Ignoring missing upstream LFS object %-v: %v", p, objectError) - return nil - } - if objectError != nil { return objectError } @@ -342,10 +336,9 @@ func pullMirrorReleaseSync(ctx context.Context, repo *repo_model.Repository, git for _, tag := range updates { if _, err := db.GetEngine(ctx).Where("repo_id = ? AND lower_tag_name = ?", repo.ID, strings.ToLower(tag.Name)). - Cols("sha1", "created_unix"). + Cols("sha1"). Update(&repo_model.Release{ - Sha1: tag.Object.String(), - CreatedUnix: timeutil.TimeStamp(tag.Tagger.When.Unix()), + Sha1: tag.Object.String(), }); err != nil { return fmt.Errorf("unable to update tag %s for pull-mirror Repo[%d:%s/%s]: %w", tag.Name, repo.ID, repo.OwnerName, repo.Name, err) } diff --git a/modules/repository/repo_test.go b/modules/repository/repo_test.go index 45a650ba42..68980f92f9 100644 --- a/modules/repository/repo_test.go +++ b/modules/repository/repo_test.go @@ -6,7 +6,7 @@ package repository import ( "testing" - "forgejo.org/modules/git" + "code.gitea.io/gitea/modules/git" "github.com/stretchr/testify/assert" ) @@ -62,15 +62,15 @@ func Test_calcSync(t *testing.T) { } inserts, deletes, updates := calcSync(gitTags, dbReleases) - if assert.Len(t, inserts, 1, "inserts") { - assert.Equal(t, *gitTags[2], *inserts[0], "inserts equal") + if assert.EqualValues(t, 1, len(inserts), "inserts") { + assert.EqualValues(t, *gitTags[2], *inserts[0], "inserts equal") } - if assert.Len(t, deletes, 1, "deletes") { + if assert.EqualValues(t, 1, len(deletes), "deletes") { assert.EqualValues(t, 1, deletes[0], "deletes equal") } - if assert.Len(t, updates, 1, "updates") { - assert.Equal(t, *gitTags[1], *updates[0], "updates equal") + if assert.EqualValues(t, 1, len(updates), "updates") { + assert.EqualValues(t, *gitTags[1], *updates[0], "updates equal") } } diff --git a/modules/repository/temp.go b/modules/repository/temp.go index 6048c43a8e..04faa9db3d 100644 --- a/modules/repository/temp.go +++ b/modules/repository/temp.go @@ -9,9 +9,9 @@ import ( "path" "path/filepath" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) // LocalCopyPath returns the local repository temporary copy path. diff --git a/modules/secret/secret.go b/modules/secret/secret.go index fc63ec521b..e70ae1839c 100644 --- a/modules/secret/secret.go +++ b/modules/secret/secret.go @@ -27,7 +27,7 @@ func AesEncrypt(key, text []byte) ([]byte, error) { if _, err = io.ReadFull(rand.Reader, iv); err != nil { return nil, fmt.Errorf("AesEncrypt unable to read IV: %w", err) } - cfb := cipher.NewCFBEncrypter(block, iv) //nolint:staticcheck + cfb := cipher.NewCFBEncrypter(block, iv) cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b)) return ciphertext, nil } @@ -43,11 +43,11 @@ func AesDecrypt(key, text []byte) ([]byte, error) { } iv := text[:aes.BlockSize] text = text[aes.BlockSize:] - cfb := cipher.NewCFBDecrypter(block, iv) //nolint:staticcheck + cfb := cipher.NewCFBDecrypter(block, iv) cfb.XORKeyStream(text, text) data, err := base64.StdEncoding.DecodeString(string(text)) if err != nil { - return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w - it can be caused by a change of the [security].SECRET_KEY setting or a database corruption - `forgejo doctor check --run check-db-consistency --fix` will get rid of orphaned rows found in the `two_factor` table and may fix this problem if they are the one with the invalid content", err) + return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w", err) } return data, nil } diff --git a/modules/secret/secret_test.go b/modules/secret/secret_test.go index ba23718fd0..d4fb46955b 100644 --- a/modules/secret/secret_test.go +++ b/modules/secret/secret_test.go @@ -7,26 +7,25 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestEncryptDecrypt(t *testing.T) { hex, err := EncryptSecret("foo", "baz") - require.NoError(t, err) + assert.NoError(t, err) str, _ := DecryptSecret("foo", hex) assert.Equal(t, "baz", str) hex, err = EncryptSecret("bar", "baz") - require.NoError(t, err) + assert.NoError(t, err) str, _ = DecryptSecret("foo", hex) assert.NotEqual(t, "baz", str) _, err = DecryptSecret("a", "b") - require.ErrorContains(t, err, "invalid hex string") + assert.ErrorContains(t, err, "invalid hex string") _, err = DecryptSecret("a", "bb") - require.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt ciphertext too short") + assert.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt ciphertext too short") _, err = DecryptSecret("a", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") - require.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt invalid decrypted base64 string") + assert.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt invalid decrypted base64 string") } diff --git a/modules/session/db.go b/modules/session/db.go index eea7e2136e..9909f2dc1e 100644 --- a/modules/session/db.go +++ b/modules/session/db.go @@ -7,11 +7,11 @@ import ( "log" "sync" - "forgejo.org/models/auth" - "forgejo.org/models/db" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" - "code.forgejo.org/go-chi/session" + "gitea.com/go-chi/session" ) // DBStore represents a session store implementation based on the DB. diff --git a/modules/session/redis.go b/modules/session/redis.go index cf84ef21d9..d89d8bc6e2 100644 --- a/modules/session/redis.go +++ b/modules/session/redis.go @@ -22,15 +22,16 @@ import ( "sync" "time" - "forgejo.org/modules/graceful" - "forgejo.org/modules/nosql" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/nosql" - "code.forgejo.org/go-chi/session" + "gitea.com/go-chi/session" + "github.com/redis/go-redis/v9" ) // RedisStore represents a redis session store implementation. type RedisStore struct { - c nosql.RedisClient + c redis.UniversalClient prefix, sid string duration time.Duration lock sync.RWMutex @@ -38,7 +39,7 @@ type RedisStore struct { } // NewRedisStore creates and returns a redis session store. -func NewRedisStore(c nosql.RedisClient, prefix, sid string, dur time.Duration, kv map[any]any) *RedisStore { +func NewRedisStore(c redis.UniversalClient, prefix, sid string, dur time.Duration, kv map[any]any) *RedisStore { return &RedisStore{ c: c, prefix: prefix, @@ -105,7 +106,7 @@ func (s *RedisStore) Flush() error { // RedisProvider represents a redis session provider implementation. type RedisProvider struct { - c nosql.RedisClient + c redis.UniversalClient duration time.Duration prefix string } @@ -121,7 +122,8 @@ func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) { uri := nosql.ToRedisURI(configs) for k, v := range uri.Query() { - if k == "prefix" { + switch k { + case "prefix": p.prefix = v[0] } } diff --git a/modules/session/store.go b/modules/session/store.go index baab26315d..70988fcdc5 100644 --- a/modules/session/store.go +++ b/modules/session/store.go @@ -6,7 +6,7 @@ package session import ( "net/http" - "code.forgejo.org/go-chi/session" + "gitea.com/go-chi/session" ) // Store represents a session store diff --git a/modules/session/virtual.go b/modules/session/virtual.go index 1c3e1c778b..80352b6e72 100644 --- a/modules/session/virtual.go +++ b/modules/session/virtual.go @@ -7,13 +7,13 @@ import ( "fmt" "sync" - "forgejo.org/modules/json" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/json" - "code.forgejo.org/go-chi/session" - memcache "code.forgejo.org/go-chi/session/memcache" - mysql "code.forgejo.org/go-chi/session/mysql" - postgres "code.forgejo.org/go-chi/session/postgres" + "gitea.com/go-chi/session" + couchbase "gitea.com/go-chi/session/couchbase" + memcache "gitea.com/go-chi/session/memcache" + mysql "gitea.com/go-chi/session/mysql" + postgres "gitea.com/go-chi/session/postgres" ) // VirtualSessionProvider represents a shadowed session provider implementation. @@ -35,9 +35,6 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error { switch opts.Provider { case "memory": o.provider = &session.MemProvider{} - case "couchbase": - log.Warn("Couchbase as session provider is no longer supported, falling back to file as session provider") - fallthrough case "file": o.provider = &session.FileProvider{} case "redis": @@ -48,6 +45,8 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error { o.provider = &mysql.MysqlProvider{} case "postgres": o.provider = &postgres.PostgresProvider{} + case "couchbase": + o.provider = &couchbase.CouchbaseProvider{} case "memcache": o.provider = &memcache.MemcacheProvider{} default: diff --git a/modules/setting/actions.go b/modules/setting/actions.go index 52a3ad5309..804ed9ec72 100644 --- a/modules/setting/actions.go +++ b/modules/setting/actions.go @@ -12,12 +12,10 @@ import ( // Actions settings var ( Actions = struct { + LogStorage *Storage // how the created logs should be stored + ArtifactStorage *Storage // how the created artifacts should be stored + ArtifactRetentionDays int64 `ini:"ARTIFACT_RETENTION_DAYS"` Enabled bool - LogStorage *Storage // how the created logs should be stored - LogRetentionDays int64 `ini:"LOG_RETENTION_DAYS"` - LogCompression logCompression `ini:"LOG_COMPRESSION"` - ArtifactStorage *Storage // how the created artifacts should be stored - ArtifactRetentionDays int64 `ini:"ARTIFACT_RETENTION_DAYS"` DefaultActionsURL defaultActionsURL `ini:"DEFAULT_ACTIONS_URL"` ZombieTaskTimeout time.Duration `ini:"ZOMBIE_TASK_TIMEOUT"` EndlessTaskTimeout time.Duration `ini:"ENDLESS_TASK_TIMEOUT"` @@ -46,25 +44,11 @@ func (url defaultActionsURL) URL() string { } const ( - defaultActionsURLForgejo = "https://data.forgejo.org" + defaultActionsURLForgejo = "https://code.forgejo.org" defaultActionsURLGitHub = "github" // https://github.com defaultActionsURLSelf = "self" // the root URL of the self-hosted instance ) -type logCompression string - -func (c logCompression) IsValid() bool { - return c.IsNone() || c.IsZstd() -} - -func (c logCompression) IsNone() bool { - return strings.ToLower(string(c)) == "none" -} - -func (c logCompression) IsZstd() bool { - return c == "" || strings.ToLower(string(c)) == "zstd" -} - func loadActionsFrom(rootCfg ConfigProvider) error { sec := rootCfg.Section("actions") err := sec.MapTo(&Actions) @@ -77,17 +61,10 @@ func loadActionsFrom(rootCfg ConfigProvider) error { if err != nil { return err } - // default to 1 year - if Actions.LogRetentionDays <= 0 { - Actions.LogRetentionDays = 365 - } actionsSec, _ := rootCfg.GetSection("actions.artifacts") Actions.ArtifactStorage, err = getStorage(rootCfg, "actions_artifacts", "", actionsSec) - if err != nil { - return err - } // default to 90 days in Github Actions if Actions.ArtifactRetentionDays <= 0 { @@ -98,9 +75,5 @@ func loadActionsFrom(rootCfg ConfigProvider) error { Actions.EndlessTaskTimeout = sec.Key("ENDLESS_TASK_TIMEOUT").MustDuration(3 * time.Hour) Actions.AbandonedJobTimeout = sec.Key("ABANDONED_JOB_TIMEOUT").MustDuration(24 * time.Hour) - if !Actions.LogCompression.IsValid() { - return fmt.Errorf("invalid [actions] LOG_COMPRESSION: %q", Actions.LogCompression) - } - - return nil + return err } diff --git a/modules/setting/actions_test.go b/modules/setting/actions_test.go index a3cd5ced44..01f5bf74a5 100644 --- a/modules/setting/actions_test.go +++ b/modules/setting/actions_test.go @@ -17,26 +17,26 @@ func Test_getStorageInheritNameSectionTypeForActions(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadActionsFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadActionsFrom(cfg)) assert.EqualValues(t, "minio", Actions.LogStorage.Type) - assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) + assert.EqualValues(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) assert.EqualValues(t, "minio", Actions.ArtifactStorage.Type) - assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) + assert.EqualValues(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) iniStr = ` [storage.actions_log] STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadActionsFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadActionsFrom(cfg)) assert.EqualValues(t, "minio", Actions.LogStorage.Type) - assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) + assert.EqualValues(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) assert.EqualValues(t, "local", Actions.ArtifactStorage.Type) - assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path)) + assert.EqualValues(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path)) iniStr = ` [storage.actions_log] @@ -46,13 +46,13 @@ STORAGE_TYPE = my_storage STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadActionsFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadActionsFrom(cfg)) assert.EqualValues(t, "minio", Actions.LogStorage.Type) - assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) + assert.EqualValues(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) assert.EqualValues(t, "local", Actions.ArtifactStorage.Type) - assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path)) + assert.EqualValues(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path)) iniStr = ` [storage.actions_artifacts] @@ -62,13 +62,13 @@ STORAGE_TYPE = my_storage STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadActionsFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadActionsFrom(cfg)) assert.EqualValues(t, "local", Actions.LogStorage.Type) - assert.Equal(t, "actions_log", filepath.Base(Actions.LogStorage.Path)) + assert.EqualValues(t, "actions_log", filepath.Base(Actions.LogStorage.Path)) assert.EqualValues(t, "minio", Actions.ArtifactStorage.Type) - assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) + assert.EqualValues(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) iniStr = ` [storage.actions_artifacts] @@ -78,23 +78,23 @@ STORAGE_TYPE = my_storage STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadActionsFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadActionsFrom(cfg)) assert.EqualValues(t, "local", Actions.LogStorage.Type) - assert.Equal(t, "actions_log", filepath.Base(Actions.LogStorage.Path)) + assert.EqualValues(t, "actions_log", filepath.Base(Actions.LogStorage.Path)) assert.EqualValues(t, "minio", Actions.ArtifactStorage.Type) - assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) + assert.EqualValues(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) iniStr = `` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadActionsFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadActionsFrom(cfg)) assert.EqualValues(t, "local", Actions.LogStorage.Type) - assert.Equal(t, "actions_log", filepath.Base(Actions.LogStorage.Path)) + assert.EqualValues(t, "actions_log", filepath.Base(Actions.LogStorage.Path)) assert.EqualValues(t, "local", Actions.ArtifactStorage.Type) - assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path)) + assert.EqualValues(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path)) } func Test_getDefaultActionsURLForActions(t *testing.T) { @@ -117,7 +117,7 @@ func Test_getDefaultActionsURLForActions(t *testing.T) { iniStr: ` [actions] `, - wantURL: "https://data.forgejo.org", + wantURL: "https://code.forgejo.org", }, { name: "github", @@ -149,9 +149,10 @@ DEFAULT_ACTIONS_URL = https://example.com t.Run(tt.name, func(t *testing.T) { cfg, err := NewConfigProviderFromData(tt.iniStr) require.NoError(t, err) - require.NoError(t, loadActionsFrom(cfg)) - - assert.Equal(t, tt.wantURL, Actions.DefaultActionsURL.URL()) + if !assert.NoError(t, loadActionsFrom(cfg)) { + return + } + assert.EqualValues(t, tt.wantURL, Actions.DefaultActionsURL.URL()) }) } } diff --git a/modules/setting/admin.go b/modules/setting/admin.go index 7a1e071bac..eed3aa22cf 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -4,7 +4,7 @@ package setting import ( - "forgejo.org/modules/container" + "code.gitea.io/gitea/modules/container" ) // Admin settings diff --git a/modules/setting/admin_test.go b/modules/setting/admin_test.go index 744f069d82..c0b4dfff69 100644 --- a/modules/setting/admin_test.go +++ b/modules/setting/admin_test.go @@ -6,10 +6,9 @@ package setting import ( "testing" - "forgejo.org/modules/container" + "code.gitea.io/gitea/modules/container" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_loadAdminFrom(t *testing.T) { @@ -22,12 +21,12 @@ func Test_loadAdminFrom(t *testing.T) { EXTERNAL_USER_DISABLE_FEATURES = x,y ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) loadAdminFrom(cfg) - assert.True(t, Admin.DisableRegularOrgCreation) - assert.Equal(t, "z", Admin.DefaultEmailNotification) - assert.True(t, Admin.SendNotificationEmailOnNewUser) - assert.Equal(t, container.SetOf("a", "b"), Admin.UserDisabledFeatures) - assert.Equal(t, container.SetOf("x", "y"), Admin.ExternalUserDisableFeatures) + assert.EqualValues(t, true, Admin.DisableRegularOrgCreation) + assert.EqualValues(t, "z", Admin.DefaultEmailNotification) + assert.EqualValues(t, true, Admin.SendNotificationEmailOnNewUser) + assert.EqualValues(t, container.SetOf("a", "b"), Admin.UserDisabledFeatures) + assert.EqualValues(t, container.SetOf("x", "y"), Admin.ExternalUserDisableFeatures) } diff --git a/modules/setting/annex.go b/modules/setting/annex.go index aa41c14ff0..a0eeac9bb8 100644 --- a/modules/setting/annex.go +++ b/modules/setting/annex.go @@ -4,13 +4,12 @@ package setting import ( - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // Annex represents the configuration for git-annex var Annex = struct { - Enabled bool `ini:"ENABLED"` - DisableP2PHTTP bool `ini:"DISABLE_P2PHTTP"` + Enabled bool `ini:"ENABLED"` }{} func loadAnnexFrom(rootCfg ConfigProvider) { @@ -18,8 +17,4 @@ func loadAnnexFrom(rootCfg ConfigProvider) { if err := sec.MapTo(&Annex); err != nil { log.Fatal("Failed to map Annex settings: %v", err) } - if !sec.HasKey("DISABLE_P2PHTTP") { - // If DisableP2PHTTP is not explicitly set then use DisableHTTPGit as its default - Annex.DisableP2PHTTP = Repository.DisableHTTPGit - } } diff --git a/modules/setting/api.go b/modules/setting/api.go index 18180c3d07..c36f05cfd1 100644 --- a/modules/setting/api.go +++ b/modules/setting/api.go @@ -7,7 +7,7 @@ import ( "net/url" "path" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // API settings diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go index 956525f0db..0fdabb5032 100644 --- a/modules/setting/attachment.go +++ b/modules/setting/attachment.go @@ -12,7 +12,7 @@ var Attachment = struct { Enabled bool }{ Storage: &Storage{}, - AllowedTypes: ".avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip", + AllowedTypes: ".cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip", MaxSize: 2048, MaxFiles: 5, Enabled: true, @@ -25,7 +25,7 @@ func loadAttachmentFrom(rootCfg ConfigProvider) (err error) { return err } - Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip") + Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip") Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(2048) Attachment.MaxFiles = sec.Key("MAX_FILES").MustInt(5) Attachment.Enabled = sec.Key("ENABLED").MustBool(true) diff --git a/modules/setting/attachment_test.go b/modules/setting/attachment_test.go index a56fcf1c55..3e8d2da4d9 100644 --- a/modules/setting/attachment_test.go +++ b/modules/setting/attachment_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_getStorageCustomType(t *testing.T) { @@ -21,14 +20,14 @@ STORAGE_TYPE = minio MINIO_ENDPOINT = my_minio:9000 ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) + assert.NoError(t, loadAttachmentFrom(cfg)) assert.EqualValues(t, "minio", Attachment.Storage.Type) - assert.Equal(t, "my_minio:9000", Attachment.Storage.MinioConfig.Endpoint) - assert.Equal(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket) - assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "my_minio:9000", Attachment.Storage.MinioConfig.Endpoint) + assert.EqualValues(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) } func Test_getStorageTypeSectionOverridesStorageSection(t *testing.T) { @@ -43,13 +42,13 @@ MINIO_BUCKET = gitea-minio MINIO_BUCKET = gitea ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) + assert.NoError(t, loadAttachmentFrom(cfg)) assert.EqualValues(t, "minio", Attachment.Storage.Type) - assert.Equal(t, "gitea-minio", Attachment.Storage.MinioConfig.Bucket) - assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea-minio", Attachment.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) } func Test_getStorageSpecificOverridesStorage(t *testing.T) { @@ -65,23 +64,23 @@ MINIO_BUCKET = gitea STORAGE_TYPE = local ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) + assert.NoError(t, loadAttachmentFrom(cfg)) assert.EqualValues(t, "minio", Attachment.Storage.Type) - assert.Equal(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket) - assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) } func Test_getStorageGetDefaults(t *testing.T) { cfg, err := NewConfigProviderFromData("") - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) + assert.NoError(t, loadAttachmentFrom(cfg)) // default storage is local, so bucket is empty - assert.Empty(t, Attachment.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "", Attachment.Storage.MinioConfig.Bucket) } func Test_getStorageInheritNameSectionType(t *testing.T) { @@ -90,9 +89,9 @@ func Test_getStorageInheritNameSectionType(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) + assert.NoError(t, loadAttachmentFrom(cfg)) assert.EqualValues(t, "minio", Attachment.Storage.Type) } @@ -110,13 +109,13 @@ MINIO_ACCESS_KEY_ID = correct_key MINIO_SECRET_ACCESS_KEY = correct_key ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) + assert.NoError(t, loadAttachmentFrom(cfg)) storage := Attachment.Storage assert.EqualValues(t, "minio", storage.Type) - assert.Equal(t, "gitea", storage.MinioConfig.Bucket) + assert.EqualValues(t, "gitea", storage.MinioConfig.Bucket) } func Test_AttachmentStorage1(t *testing.T) { @@ -125,10 +124,10 @@ func Test_AttachmentStorage1(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) + assert.NoError(t, loadAttachmentFrom(cfg)) assert.EqualValues(t, "minio", Attachment.Storage.Type) - assert.Equal(t, "gitea", Attachment.Storage.MinioConfig.Bucket) - assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", Attachment.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) } diff --git a/modules/setting/cache.go b/modules/setting/cache.go index cdc7e1a971..bfa6ca0e61 100644 --- a/modules/setting/cache.go +++ b/modules/setting/cache.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // Cache represents cache settings diff --git a/modules/setting/camo.go b/modules/setting/camo.go index 5d31446a41..366e9a116c 100644 --- a/modules/setting/camo.go +++ b/modules/setting/camo.go @@ -3,28 +3,18 @@ package setting -import ( - "strconv" - - "forgejo.org/modules/log" -) +import "code.gitea.io/gitea/modules/log" var Camo = struct { Enabled bool ServerURL string `ini:"SERVER_URL"` HMACKey string `ini:"HMAC_KEY"` - Always bool + Allways bool }{} func loadCamoFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "camo", &Camo) if Camo.Enabled { - oldValue := rootCfg.Section("camo").Key("ALLWAYS").MustString("") - if oldValue != "" { - log.Warn("camo.ALLWAYS is deprecated, use camo.ALWAYS instead") - Camo.Always, _ = strconv.ParseBool(oldValue) - } - if Camo.ServerURL == "" || Camo.HMACKey == "" { log.Fatal(`Camo settings require "SERVER_URL" and HMAC_KEY`) } diff --git a/modules/setting/config.go b/modules/setting/config.go index 6299640e61..03558574c2 100644 --- a/modules/setting/config.go +++ b/modules/setting/config.go @@ -6,8 +6,8 @@ package setting import ( "sync" - "forgejo.org/modules/log" - "forgejo.org/modules/setting/config" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting/config" ) type PictureStruct struct { diff --git a/modules/setting/config/value.go b/modules/setting/config/value.go index 3409f61b76..f0ec120544 100644 --- a/modules/setting/config/value.go +++ b/modules/setting/config/value.go @@ -7,9 +7,9 @@ import ( "context" "sync" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) type CfgSecKey struct { diff --git a/modules/setting/config_env.go b/modules/setting/config_env.go index 458dbb51bb..fa0100dba2 100644 --- a/modules/setting/config_env.go +++ b/modules/setting/config_env.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) const ( @@ -168,22 +168,3 @@ func EnvironmentToConfig(cfg ConfigProvider, envs []string) (changed bool) { } return changed } - -// InitGiteaEnvVars initializes the environment variables for gitea -func InitGiteaEnvVars() { - // Ideally Gitea should only accept the environment variables which it clearly knows instead of unsetting the ones it doesn't want, - // but the ideal behavior would be a breaking change, and it seems not bringing enough benefits to end users, - // so at the moment we could still keep "unsetting the unnecessary environments" - - // HOME is managed by Gitea, Gitea's git should use "HOME/.gitconfig". - // But git would try "XDG_CONFIG_HOME/git/config" first if "HOME/.gitconfig" does not exist, - // then our git.InitFull would still write to "XDG_CONFIG_HOME/git/config" if XDG_CONFIG_HOME is set. - _ = os.Unsetenv("XDG_CONFIG_HOME") - - _ = os.Unsetenv("GIT_AUTHOR_NAME") - _ = os.Unsetenv("GIT_AUTHOR_EMAIL") - _ = os.Unsetenv("GIT_AUTHOR_DATE") - _ = os.Unsetenv("GIT_COMMITTER_NAME") - _ = os.Unsetenv("GIT_COMMITTER_EMAIL") - _ = os.Unsetenv("GIT_COMMITTER_DATE") -} diff --git a/modules/setting/config_env_test.go b/modules/setting/config_env_test.go index fed0f668aa..572486aec2 100644 --- a/modules/setting/config_env_test.go +++ b/modules/setting/config_env_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestDecodeEnvSectionKey(t *testing.T) { @@ -30,8 +29,8 @@ func TestDecodeEnvSectionKey(t *testing.T) { ok, section, key = decodeEnvSectionKey("SEC") assert.False(t, ok) - assert.Empty(t, section) - assert.Empty(t, key) + assert.Equal(t, "", section) + assert.Equal(t, "", key) } func TestDecodeEnvironmentKey(t *testing.T) { @@ -40,19 +39,19 @@ func TestDecodeEnvironmentKey(t *testing.T) { ok, section, key, file := decodeEnvironmentKey(prefix, suffix, "SEC__KEY") assert.False(t, ok) - assert.Empty(t, section) - assert.Empty(t, key) + assert.Equal(t, "", section) + assert.Equal(t, "", key) assert.False(t, file) ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC") assert.False(t, ok) - assert.Empty(t, section) - assert.Empty(t, key) + assert.Equal(t, "", section) + assert.Equal(t, "", key) assert.False(t, file) ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA____KEY") assert.True(t, ok) - assert.Empty(t, section) + assert.Equal(t, "", section) assert.Equal(t, "KEY", key) assert.False(t, file) @@ -72,8 +71,8 @@ func TestDecodeEnvironmentKey(t *testing.T) { // but it could be fixed in the future by adding a new suffix like "__VALUE" (no such key VALUE is used in Gitea either) ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC__FILE") assert.False(t, ok) - assert.Empty(t, section) - assert.Empty(t, key) + assert.Equal(t, "", section) + assert.Equal(t, "", key) assert.True(t, file) ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC__KEY__FILE") @@ -93,7 +92,7 @@ func TestEnvironmentToConfig(t *testing.T) { [sec] key = old `) - require.NoError(t, err) + assert.NoError(t, err) changed = EnvironmentToConfig(cfg, []string{"GITEA__sec__key=new"}) assert.True(t, changed) @@ -131,7 +130,7 @@ func TestEnvironmentToConfigSubSecKey(t *testing.T) { [sec] key = some `) - require.NoError(t, err) + assert.NoError(t, err) changed := EnvironmentToConfig(cfg, []string{"GITEA__sec_0X2E_sub__key=some"}) assert.True(t, changed) @@ -139,9 +138,9 @@ key = some tmpFile := t.TempDir() + "/test-sub-sec-key.ini" defer os.Remove(tmpFile) err = cfg.SaveTo(tmpFile) - require.NoError(t, err) + assert.NoError(t, err) bs, err := os.ReadFile(tmpFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, `[sec] key = some diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index 19f3b9008a..12cf36aa59 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -12,8 +12,8 @@ import ( "strings" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" "gopkg.in/ini.v1" //nolint:depguard ) @@ -262,7 +262,7 @@ func (p *iniConfigProvider) Save() error { } filename := p.file if filename == "" { - return errors.New("config file path must not be empty") + return fmt.Errorf("config file path must not be empty") } if p.loadedFromEmpty { if err := os.MkdirAll(filepath.Dir(filename), os.ModePerm); err != nil { diff --git a/modules/setting/config_provider_test.go b/modules/setting/config_provider_test.go index 3b99911f38..a666d124c7 100644 --- a/modules/setting/config_provider_test.go +++ b/modules/setting/config_provider_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestConfigProviderBehaviors(t *testing.T) { @@ -63,54 +62,54 @@ key = 123 // test default behavior assert.Equal(t, "123", ConfigSectionKeyString(sec, "key")) - assert.Empty(t, ConfigSectionKeyString(secSub, "key")) + assert.Equal(t, "", ConfigSectionKeyString(secSub, "key")) assert.Equal(t, "def", ConfigSectionKeyString(secSub, "key", "def")) assert.Equal(t, "123", ConfigInheritedKeyString(secSub, "key")) // Workaround for ini package's BuggyKeyOverwritten behavior - assert.Empty(t, ConfigSectionKeyString(sec, "empty")) - assert.Empty(t, ConfigSectionKeyString(secSub, "empty")) + assert.Equal(t, "", ConfigSectionKeyString(sec, "empty")) + assert.Equal(t, "", ConfigSectionKeyString(secSub, "empty")) assert.Equal(t, "def", ConfigInheritedKey(secSub, "empty").MustString("def")) assert.Equal(t, "def", ConfigInheritedKey(secSub, "empty").MustString("xyz")) - assert.Empty(t, ConfigSectionKeyString(sec, "empty")) + assert.Equal(t, "", ConfigSectionKeyString(sec, "empty")) assert.Equal(t, "def", ConfigSectionKeyString(secSub, "empty")) } func TestNewConfigProviderFromFile(t *testing.T) { cfg, err := NewConfigProviderFromFile("no-such.ini") - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, cfg.IsLoadedFromEmpty()) // load non-existing file and save testFile := t.TempDir() + "/test.ini" testFile1 := t.TempDir() + "/test1.ini" cfg, err = NewConfigProviderFromFile(testFile) - require.NoError(t, err) + assert.NoError(t, err) sec, _ := cfg.NewSection("foo") _, _ = sec.NewKey("k1", "a") - require.NoError(t, cfg.Save()) + assert.NoError(t, cfg.Save()) _, _ = sec.NewKey("k2", "b") - require.NoError(t, cfg.SaveTo(testFile1)) + assert.NoError(t, cfg.SaveTo(testFile1)) bs, err := os.ReadFile(testFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "[foo]\nk1 = a\n", string(bs)) bs, err = os.ReadFile(testFile1) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "[foo]\nk1 = a\nk2 = b\n", string(bs)) // load existing file and save cfg, err = NewConfigProviderFromFile(testFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "a", cfg.Section("foo").Key("k1").String()) sec, _ = cfg.NewSection("bar") _, _ = sec.NewKey("k1", "b") - require.NoError(t, cfg.Save()) + assert.NoError(t, cfg.Save()) bs, err = os.ReadFile(testFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "[foo]\nk1 = a\n\n[bar]\nk1 = b\n", string(bs)) } @@ -119,15 +118,15 @@ func TestNewConfigProviderForLocale(t *testing.T) { localeFile := t.TempDir() + "/locale.ini" _ = os.WriteFile(localeFile, []byte(`k1=a`), 0o644) cfg, err := NewConfigProviderForLocale(localeFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "a", cfg.Section("").Key("k1").String()) // load locale from bytes cfg, err = NewConfigProviderForLocale([]byte("k1=foo\nk2=bar")) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "foo", cfg.Section("").Key("k1").String()) cfg, err = NewConfigProviderForLocale([]byte("k1=foo\nk2=bar"), []byte("k2=xxx")) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "foo", cfg.Section("").Key("k1").String()) assert.Equal(t, "xxx", cfg.Section("").Key("k2").String()) } @@ -136,22 +135,22 @@ func TestDisableSaving(t *testing.T) { testFile := t.TempDir() + "/test.ini" _ = os.WriteFile(testFile, []byte("k1=a\nk2=b"), 0o644) cfg, err := NewConfigProviderFromFile(testFile) - require.NoError(t, err) + assert.NoError(t, err) cfg.DisableSaving() err = cfg.Save() - require.ErrorIs(t, err, errDisableSaving) + assert.ErrorIs(t, err, errDisableSaving) saveCfg, err := cfg.PrepareSaving() - require.NoError(t, err) + assert.NoError(t, err) saveCfg.Section("").Key("k1").MustString("x") saveCfg.Section("").Key("k2").SetValue("y") saveCfg.Section("").Key("k3").SetValue("z") err = saveCfg.Save() - require.NoError(t, err) + assert.NoError(t, err) bs, err := os.ReadFile(testFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "k1 = a\nk2 = y\nk3 = z\n", string(bs)) } diff --git a/modules/setting/cors.go b/modules/setting/cors.go index 5260887d9d..63daaad60b 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -5,6 +5,8 @@ package setting import ( "time" + + "code.gitea.io/gitea/modules/log" ) // CORSConfig defines CORS settings @@ -26,4 +28,7 @@ var CORSConfig = struct { func loadCorsFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "cors", &CORSConfig) + if CORSConfig.Enabled { + log.Info("CORS Service Enabled") + } } diff --git a/modules/setting/cron_test.go b/modules/setting/cron_test.go index cabfb3a325..3187ab18a2 100644 --- a/modules/setting/cron_test.go +++ b/modules/setting/cron_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_getCronSettings(t *testing.T) { @@ -28,7 +27,7 @@ SECOND = white rabbit EXTEND = true ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) extended := &Extended{ BaseStruct: BaseStruct{ @@ -37,8 +36,8 @@ EXTEND = true } _, err = getCronSettings(cfg, "test", extended) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, extended.Base) - assert.Equal(t, "white rabbit", extended.Second) + assert.EqualValues(t, extended.Second, "white rabbit") assert.True(t, extended.Extend) } diff --git a/modules/setting/database.go b/modules/setting/database.go index 96859e4cf4..76fae27164 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -10,13 +10,8 @@ import ( "net/url" "os" "path/filepath" - "strconv" "strings" "time" - - "forgejo.org/modules/log" - - "xorm.io/xorm" ) var ( @@ -29,41 +24,35 @@ var ( EnableSQLite3 bool // Database holds the database settings - Database = DatabaseSettings{ + Database = struct { + Type DatabaseType + Host string + Name string + User string + Passwd string + Schema string + SSLMode string + Path string + LogSQL bool + MysqlCharset string + CharsetCollation string + Timeout int // seconds + SQLiteJournalMode string + DBConnectRetries int + DBConnectBackoff time.Duration + MaxIdleConns int + MaxOpenConns int + ConnMaxIdleTime time.Duration + ConnMaxLifetime time.Duration + IterateBufferSize int + AutoMigration bool + SlowQueryThreshold time.Duration + }{ Timeout: 500, IterateBufferSize: 50, } ) -type DatabaseSettings struct { - Type DatabaseType - Host string - HostPrimary string - HostReplica string - LoadBalancePolicy string - LoadBalanceWeights string - Name string - User string - Passwd string - Schema string - SSLMode string - Path string - LogSQL bool - MysqlCharset string - CharsetCollation string - Timeout int // seconds - SQLiteJournalMode string - DBConnectRetries int - DBConnectBackoff time.Duration - MaxIdleConns int - MaxOpenConns int - ConnMaxIdleTime time.Duration - ConnMaxLifetime time.Duration - IterateBufferSize int - AutoMigration bool - SlowQueryThreshold time.Duration -} - // LoadDBSetting loads the database settings func LoadDBSetting() { loadDBSetting(CfgProvider) @@ -74,10 +63,6 @@ func loadDBSetting(rootCfg ConfigProvider) { Database.Type = DatabaseType(sec.Key("DB_TYPE").String()) Database.Host = sec.Key("HOST").String() - Database.HostPrimary = sec.Key("HOST_PRIMARY").String() - Database.HostReplica = sec.Key("HOST_REPLICA").String() - Database.LoadBalancePolicy = sec.Key("LOAD_BALANCE_POLICY").String() - Database.LoadBalanceWeights = sec.Key("LOAD_BALANCE_WEIGHTS").String() Database.Name = sec.Key("NAME").String() Database.User = sec.Key("USER").String() if len(Database.Passwd) == 0 { @@ -114,114 +99,8 @@ func loadDBSetting(rootCfg ConfigProvider) { } } -// DBMasterConnStr returns the connection string for the master (primary) database. -// If a primary host is defined in the configuration, it is used; -// otherwise, it falls back to Database.Host. -// Returns an error if no master host is provided but a slave is defined. -func DBMasterConnStr() (string, error) { - var host string - if Database.HostPrimary != "" { - host = Database.HostPrimary - } else { - host = Database.Host - } - if host == "" && Database.HostReplica != "" { - return "", errors.New("master host is not defined while slave is defined; cannot proceed") - } - - // For SQLite, no host is needed - if host == "" && !Database.Type.IsSQLite3() { - return "", errors.New("no database host defined") - } - - return dbConnStrWithHost(host) -} - -// DBSlaveConnStrs returns one or more connection strings for the replica databases. -// If a replica host is defined (possibly as a comma-separated list) then those DSNs are returned. -// Otherwise, this function falls back to the master DSN (with a warning log). -func DBSlaveConnStrs() ([]string, error) { - var dsns []string - if Database.HostReplica != "" { - // support multiple replica hosts separated by commas - replicas := strings.SplitSeq(Database.HostReplica, ",") - for r := range replicas { - trimmed := strings.TrimSpace(r) - if trimmed == "" { - continue - } - dsn, err := dbConnStrWithHost(trimmed) - if err != nil { - return nil, err - } - dsns = append(dsns, dsn) - } - } - // Fall back to master if no slave DSN was provided. - if len(dsns) == 0 { - master, err := DBMasterConnStr() - if err != nil { - return nil, err - } - log.Debug("Database: No dedicated replica host defined; falling back to primary DSN for replica connections") - dsns = append(dsns, master) - } - return dsns, nil -} - -func BuildLoadBalancePolicy(settings *DatabaseSettings, slaveEngines []*xorm.Engine) xorm.GroupPolicy { - var policy xorm.GroupPolicy - switch settings.LoadBalancePolicy { // Use the settings parameter directly - case "WeightRandom": - var weights []int - if settings.LoadBalanceWeights != "" { // Use the settings parameter directly - for part := range strings.SplitSeq(settings.LoadBalanceWeights, ",") { - w, err := strconv.Atoi(strings.TrimSpace(part)) - if err != nil { - w = 1 // use a default weight if conversion fails - } - weights = append(weights, w) - } - } - // If no valid weights were provided, default each slave to weight 1 - if len(weights) == 0 { - weights = make([]int, len(slaveEngines)) - for i := range weights { - weights[i] = 1 - } - } - policy = xorm.WeightRandomPolicy(weights) - case "WeightRoundRobin": - var weights []int - if settings.LoadBalanceWeights != "" { - for part := range strings.SplitSeq(settings.LoadBalanceWeights, ",") { - w, err := strconv.Atoi(strings.TrimSpace(part)) - if err != nil { - w = 1 // use a default weight if conversion fails - } - weights = append(weights, w) - } - } - // If no valid weights were provided, default each slave to weight 1 - if len(weights) == 0 { - weights = make([]int, len(slaveEngines)) - for i := range weights { - weights[i] = 1 - } - } - policy = xorm.WeightRoundRobinPolicy(weights) - case "RoundRobin": - policy = xorm.RoundRobinPolicy() - case "LeastConn": - policy = xorm.LeastConnPolicy() - default: - policy = xorm.RandomPolicy() - } - return policy -} - -// dbConnStrWithHost constructs the connection string, given a host value. -func dbConnStrWithHost(host string) (string, error) { +// DBConnStr returns database connection string +func DBConnStr() (string, error) { var connStr string paramSep := "?" if strings.Contains(Database.Name, paramSep) { @@ -230,25 +109,23 @@ func dbConnStrWithHost(host string) (string, error) { switch Database.Type { case "mysql": connType := "tcp" - // if the host starts with '/' it is assumed to be a unix socket path - if len(host) > 0 && host[0] == '/' { + if len(Database.Host) > 0 && Database.Host[0] == '/' { // looks like a unix socket connType = "unix" } tls := Database.SSLMode - // allow the "disable" value (borrowed from Postgres defaults) to behave as false - if tls == "disable" { + if tls == "disable" { // allow (Postgres-inspired) default value to work in MySQL tls = "false" } connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%sparseTime=true&tls=%s", - Database.User, Database.Passwd, connType, host, Database.Name, paramSep, tls) + Database.User, Database.Passwd, connType, Database.Host, Database.Name, paramSep, tls) case "postgres": - connStr = getPostgreSQLConnectionString(host, Database.User, Database.Passwd, Database.Name, Database.SSLMode) + connStr = getPostgreSQLConnectionString(Database.Host, Database.User, Database.Passwd, Database.Name, Database.SSLMode) case "sqlite3": if !EnableSQLite3 { return "", errors.New("this Gitea binary was not built with SQLite3 support") } if err := os.MkdirAll(filepath.Dir(Database.Path), os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directories: %w", err) + return "", fmt.Errorf("Failed to create directories: %w", err) } journalMode := "" if Database.SQLiteJournalMode != "" { @@ -259,6 +136,7 @@ func dbConnStrWithHost(host string) (string, error) { default: return "", fmt.Errorf("unknown database type: %s", Database.Type) } + return connStr, nil } diff --git a/modules/setting/database_test.go b/modules/setting/database_test.go index ce816d53e8..a742d54f8c 100644 --- a/modules/setting/database_test.go +++ b/modules/setting/database_test.go @@ -4,7 +4,6 @@ package setting import ( - "strings" "testing" "github.com/stretchr/testify/assert" @@ -108,104 +107,3 @@ func Test_getPostgreSQLConnectionString(t *testing.T) { assert.Equal(t, test.Output, connStr) } } - -func getPostgreSQLEngineGroupConnectionStrings(primaryHost, replicaHosts, user, passwd, name, sslmode string) (string, []string) { - // Determine the primary connection string. - primary := primaryHost - if strings.TrimSpace(primary) == "" { - primary = "127.0.0.1:5432" - } - primaryConn := getPostgreSQLConnectionString(primary, user, passwd, name, sslmode) - - // Build the replica connection strings. - replicaConns := []string{} - if strings.TrimSpace(replicaHosts) != "" { - // Split comma-separated replica host values. - hosts := strings.Split(replicaHosts, ",") - for _, h := range hosts { - trimmed := strings.TrimSpace(h) - if trimmed != "" { - replicaConns = append(replicaConns, - getPostgreSQLConnectionString(trimmed, user, passwd, name, sslmode)) - } - } - } - - return primaryConn, replicaConns -} - -func Test_getPostgreSQLEngineGroupConnectionStrings(t *testing.T) { - tests := []struct { - primaryHost string // primary host setting (e.g. "localhost" or "[::1]:1234") - replicaHosts string // comma-separated replica hosts (e.g. "replica1,replica2:2345") - user string - passwd string - name string - sslmode string - outputPrimary string - outputReplicas []string - }{ - { - // No primary override (empty => default) and no replicas. - primaryHost: "", - replicaHosts: "", - user: "", - passwd: "", - name: "", - sslmode: "", - outputPrimary: "postgres://:@127.0.0.1:5432?sslmode=", - outputReplicas: []string{}, - }, - { - // Primary set and one replica. - primaryHost: "localhost", - replicaHosts: "replicahost", - user: "user", - passwd: "pass", - name: "gitea", - sslmode: "disable", - outputPrimary: "postgres://user:pass@localhost:5432/gitea?sslmode=disable", - outputReplicas: []string{"postgres://user:pass@replicahost:5432/gitea?sslmode=disable"}, - }, - { - // Primary with explicit port; multiple replicas (one without and one with an explicit port). - primaryHost: "localhost:5433", - replicaHosts: "replica1,replica2:5434", - user: "test", - passwd: "secret", - name: "db", - sslmode: "require", - outputPrimary: "postgres://test:secret@localhost:5433/db?sslmode=require", - outputReplicas: []string{ - "postgres://test:secret@replica1:5432/db?sslmode=require", - "postgres://test:secret@replica2:5434/db?sslmode=require", - }, - }, - { - // IPv6 addresses for primary and replica. - primaryHost: "[::1]:1234", - replicaHosts: "[::2]:2345", - user: "ipv6", - passwd: "ipv6pass", - name: "ipv6db", - sslmode: "disable", - outputPrimary: "postgres://ipv6:ipv6pass@[::1]:1234/ipv6db?sslmode=disable", - outputReplicas: []string{ - "postgres://ipv6:ipv6pass@[::2]:2345/ipv6db?sslmode=disable", - }, - }, - } - - for _, test := range tests { - primary, replicas := getPostgreSQLEngineGroupConnectionStrings( - test.primaryHost, - test.replicaHosts, - test.user, - test.passwd, - test.name, - test.sslmode, - ) - assert.Equal(t, test.outputPrimary, primary) - assert.Equal(t, test.outputReplicas, replicas) - } -} diff --git a/modules/setting/disposable_email_domain_data.go b/modules/setting/disposable_email_domain_data.go deleted file mode 100644 index 5f39f02e4b..0000000000 --- a/modules/setting/disposable_email_domain_data.go +++ /dev/null @@ -1,3811 +0,0 @@ -// Copyright 2024 James Hatfield -// SPDX-License-Identifier: MIT -// -// Code generated by build/generate-disposable-email.go. DO NOT EDIT -// Sourced from https://raw.githubusercontent.com/disposable-email-domains/disposable-email-domains/0c27e671231d27cf66370034d7f6818037416989/disposable_email_blocklist.conf -package setting - -import "sync" - -var DisposableEmailDomains = sync.OnceValue(func() []string { - return []string{ - "0-mail.com", - "027168.com", - "0815.ru", - "0815.ry", - "0815.su", - "0845.ru", - "0box.eu", - "0clickemail.com", - "0n0ff.net", - "0nelce.com", - "0v.ro", - "0w.ro", - "0wnd.net", - "0wnd.org", - "0x207.info", - "1-8.biz", - "1-tm.com", - "10-minute-mail.com", - "1000rebates.stream", - "100likers.com", - "105kg.ru", - "10dk.email", - "10mail.com", - "10mail.org", - "10mail.tk", - "10mail.xyz", - "10minmail.de", - "10minut.com.pl", - "10minut.xyz", - "10minutemail.be", - "10minutemail.cf", - "10minutemail.co.uk", - "10minutemail.co.za", - "10minutemail.com", - "10minutemail.de", - "10minutemail.ga", - "10minutemail.gq", - "10minutemail.ml", - "10minutemail.net", - "10minutemail.nl", - "10minutemail.pro", - "10minutemail.us", - "10minutemailbox.com", - "10minutemails.in", - "10minutenemail.de", - "10minutenmail.xyz", - "10minutesmail.com", - "10minutesmail.fr", - "10minutmail.pl", - "10x9.com", - "11163.com", - "123-m.com", - "12hosting.net", - "12houremail.com", - "12minutemail.com", - "12minutemail.net", - "12storage.com", - "140unichars.com", - "147.cl", - "14n.co.uk", - "15qm.com", - "1blackmoon.com", - "1ce.us", - "1chuan.com", - "1clck2.com", - "1fsdfdsfsdf.tk", - "1mail.ml", - "1pad.de", - "1s.fr", - "1secmail.com", - "1secmail.net", - "1secmail.org", - "1st-forms.com", - "1to1mail.org", - "1usemail.com", - "1webmail.info", - "1zhuan.com", - "2012-2016.ru", - "20email.eu", - "20email.it", - "20mail.eu", - "20mail.in", - "20mail.it", - "20minutemail.com", - "20minutemail.it", - "20mm.eu", - "2120001.net", - "21cn.com", - "247web.net", - "24hinbox.com", - "24hourmail.com", - "24hourmail.net", - "2anom.com", - "2chmail.net", - "2ether.net", - "2fdgdfgdfgdf.tk", - "2odem.com", - "2prong.com", - "2wc.info", - "300book.info", - "30mail.ir", - "30minutemail.com", - "30wave.com", - "3202.com", - "36ru.com", - "3d-painting.com", - "3l6.com", - "3mail.ga", - "3trtretgfrfe.tk", - "4-n.us", - "4057.com", - "418.dk", - "42o.org", - "4gfdsgfdgfd.tk", - "4k5.net", - "4mail.cf", - "4mail.ga", - "4nextmail.com", - "4nmv.ru", - "4tb.host", - "4warding.com", - "4warding.net", - "4warding.org", - "50set.ru", - "55hosting.net", - "5ghgfhfghfgh.tk", - "5gramos.com", - "5july.org", - "5mail.cf", - "5mail.ga", - "5minutemail.net", - "5oz.ru", - "5tb.in", - "5x25.com", - "5ymail.com", - "60minutemail.com", - "672643.net", - "675hosting.com", - "675hosting.net", - "675hosting.org", - "6hjgjhgkilkj.tk", - "6ip.us", - "6mail.cf", - "6mail.ga", - "6mail.ml", - "6paq.com", - "6somok.ru", - "6url.com", - "75hosting.com", - "75hosting.net", - "75hosting.org", - "7days-printing.com", - "7mail.ga", - "7mail.ml", - "7tags.com", - "80665.com", - "8127ep.com", - "8mail.cf", - "8mail.ga", - "8mail.ml", - "99.com", - "99cows.com", - "99experts.com", - "9mail.cf", - "9me.site", - "9mot.ru", - "9ox.net", - "9q.ro", - "a-bc.net", - "a45.in", - "a7996.com", - "aa5zy64.com", - "aaqwe.ru", - "aaqwe.store", - "abacuswe.us", - "abakiss.com", - "abatido.com", - "abcmail.email", - "abevw.com", - "abilitywe.us", - "abovewe.us", - "absolutewe.us", - "abundantwe.us", - "abusemail.de", - "abuser.eu", - "abyssmail.com", - "ac20mail.in", - "academiccommunity.com", - "academywe.us", - "acceleratewe.us", - "accentwe.us", - "acceptwe.us", - "acclaimwe.us", - "accordwe.us", - "accreditedwe.us", - "achievementwe.us", - "achievewe.us", - "acornwe.us", - "acrossgracealley.com", - "acrylicwe.us", - "activatewe.us", - "activitywe.us", - "acucre.com", - "acuitywe.us", - "acumenwe.us", - "adaptivewe.us", - "adaptwe.us", - "add3000.pp.ua", - "addictingtrailers.com", - "adeptwe.us", - "adfskj.com", - "adios.email", - "adiq.eu", - "aditus.info", - "admiralwe.us", - "ado888.biz", - "adobeccepdm.com", - "adoniswe.us", - "adpugh.org", - "adroh.com", - "adsd.org", - "adubiz.info", - "adult-work.info", - "advantagewe.us", - "advantimo.com", - "adventurewe.us", - "adventwe.us", - "advisorwe.us", - "advocatewe.us", - "adwaterandstir.com", - "aegde.com", - "aegia.net", - "aegiscorp.net", - "aegiswe.us", - "aelo.es", - "aeonpsi.com", - "afarek.com", - "affiliate-nebenjob.info", - "affiliatedwe.us", - "affilikingz.de", - "affinitywe.us", - "affluentwe.us", - "affordablewe.us", - "afia.pro", - "afrobacon.com", - "afterhourswe.us", - "agedmail.com", - "agendawe.us", - "agger.ro", - "agilewe.us", - "agorawe.us", - "agtx.net", - "aheadwe.us", - "ahem.email", - "ahk.jp", - "ahmedkhlef.com", - "air2token.com", - "airmailbox.website", - "airsi.de", - "aiworldx.com", - "ajaxapp.net", - "akapost.com", - "akerd.com", - "akgq701.com", - "akmail.in", - "akugu.com", - "al-qaeda.us", - "albionwe.us", - "alchemywe.us", - "alfaceti.com", - "aliaswe.us", - "alienware13.com", - "aligamel.com", - "alina-schiesser.ch", - "alisongamel.com", - "alivance.com", - "alivewe.us", - "all-cats.ru", - "allaccesswe.us", - "allamericanwe.us", - "allaroundwe.us", - "alldirectbuy.com", - "allegiancewe.us", - "allegrowe.us", - "allemojikeyboard.com", - "allgoodwe.us", - "alliancewe.us", - "allinonewe.us", - "allofthem.net", - "alloutwe.us", - "allowed.org", - "alloywe.us", - "allprowe.us", - "allseasonswe.us", - "allstarwe.us", - "allthegoodnamesaretaken.org", - "allurewe.us", - "almondwe.us", - "alph.wtf", - "alpha-web.net", - "alphaomegawe.us", - "alpinewe.us", - "altairwe.us", - "altitudewe.us", - "altuswe.us", - "ama-trade.de", - "ama-trans.de", - "amadeuswe.us", - "amail.club", - "amail.com", - "amail1.com", - "amail4.me", - "amazon-aws.org", - "amberwe.us", - "ambiancewe.us", - "ambitiouswe.us", - "amelabs.com", - "americanawe.us", - "americasbestwe.us", - "americaswe.us", - "amicuswe.us", - "amilegit.com", - "amiri.net", - "amiriindustries.com", - "amplewe.us", - "amplifiedwe.us", - "amplifywe.us", - "ampsylike.com", - "analogwe.us", - "analysiswe.us", - "analyticalwe.us", - "analyticswe.us", - "analyticwe.us", - "anappfor.com", - "anappthat.com", - "andreihusanu.ro", - "andthen.us", - "animesos.com", - "anit.ro", - "ano-mail.net", - "anon-mail.de", - "anonbox.net", - "anonmail.top", - "anonmails.de", - "anonymail.dk", - "anonymbox.com", - "anonymized.org", - "anonymousness.com", - "anotherdomaincyka.tk", - "ansibleemail.com", - "anthony-junkmail.com", - "antireg.com", - "antireg.ru", - "antispam.de", - "antispam24.de", - "antispammail.de", - "any.pink", - "anyalias.com", - "aoeuhtns.com", - "apfelkorps.de", - "aphlog.com", - "apkmd.com", - "appc.se", - "appinventor.nl", - "appixie.com", - "apps.dj", - "appzily.com", - "arduino.hk", - "ariaz.jetzt", - "armyspy.com", - "aron.us", - "arroisijewellery.com", - "art-en-ligne.pro", - "artman-conception.com", - "arur01.tk", - "arurgitu.gq", - "arvato-community.de", - "aschenbrandt.net", - "asdasd.nl", - "asdasd.ru", - "ashleyandrew.com", - "ask-mail.com", - "asorent.com", - "ass.pp.ua", - "astonut.tk", - "astroempires.info", - "asu.mx", - "asu.su", - "at.hm", - "at0mik.org", - "atnextmail.com", - "attnetwork.com", - "augmentationtechnology.com", - "ausgefallen.info", - "auti.st", - "autorobotica.com", - "autosouvenir39.ru", - "autotwollow.com", - "autowb.com", - "averdov.com", - "avia-tonic.fr", - "avls.pt", - "awatum.de", - "awdrt.org", - "awiki.org", - "awsoo.com", - "axiz.org", - "axon7zte.com", - "axsup.net", - "ayakamail.cf", - "azazazatashkent.tk", - "azcomputerworks.com", - "azmeil.tk", - "b1of96u.com", - "b2bx.net", - "b2cmail.de", - "badgerland.eu", - "badoop.com", - "badpotato.tk", - "balaket.com", - "bangban.uk", - "banit.club", - "banit.me", - "bank-opros1.ru", - "bareed.ws", - "barooko.com", - "barryogorman.com", - "bartdevos.be", - "basscode.org", - "bauwerke-online.com", - "bazaaboom.com", - "bbbbyyzz.info", - "bbhost.us", - "bbitf.com", - "bbitj.com", - "bbitq.com", - "bcaoo.com", - "bcast.ws", - "bcb.ro", - "bccto.me", - "bdmuzic.pw", - "beaconmessenger.com", - "bearsarefuzzy.com", - "beddly.com", - "beefmilk.com", - "belamail.org", - "belgianairways.com", - "belljonestax.com", - "beluckygame.com", - "benipaula.org", - "bepureme.com", - "beribase.ru", - "beribaza.ru", - "berirabotay.ru", - "best-john-boats.com", - "bestchoiceusedcar.com", - "bestlistbase.com", - "bestoption25.club", - "bestparadize.com", - "bestsoundeffects.com", - "besttempmail.com", - "betr.co", - "bgtmail.com", - "bgx.ro", - "bheps.com", - "bidourlnks.com", - "big1.us", - "bigprofessor.so", - "bigstring.com", - "bigwhoop.co.za", - "bij.pl", - "binka.me", - "binkmail.com", - "binnary.com", - "bio-muesli.info", - "bio-muesli.net", - "bione.co", - "bitwhites.top", - "bitymails.us", - "blackgoldagency.ru", - "blackmarket.to", - "bladesmail.net", - "blip.ch", - "blnkt.net", - "block521.com", - "blogmyway.org", - "blogos.net", - "blogspam.ro", - "blondemorkin.com", - "blondmail.com", - "bluedumpling.info", - "bluewerks.com", - "bnote.com", - "boatmail.us", - "bobgf.ru", - "bobgf.store", - "bobmail.info", - "bobmurchison.com", - "bofthew.com", - "bonobo.email", - "boofx.com", - "bookthemmore.com", - "bootybay.de", - "borged.com", - "borged.net", - "borged.org", - "bot.nu", - "boun.cr", - "bouncr.com", - "box-mail.ru", - "box-mail.store", - "boxem.ru", - "boxem.store", - "boxformail.in", - "boximail.com", - "boxlet.ru", - "boxlet.store", - "boxmail.lol", - "boxomail.live", - "boxtemp.com.br", - "bptfp.net", - "brand-app.biz", - "brandallday.net", - "brasx.org", - "breakthru.com", - "brefmail.com", - "brennendesreich.de", - "briggsmarcus.com", - "broadbandninja.com", - "bsnow.net", - "bspamfree.org", - "bspooky.com", - "bst-72.com", - "btb-notes.com", - "btc.email", - "btcmail.pw", - "btcmod.com", - "btizet.pl", - "buccalmassage.ru", - "budaya-tionghoa.com", - "budayationghoa.com", - "buffemail.com", - "bugfoo.com", - "bugmenever.com", - "bugmenot.com", - "bukhariansiddur.com", - "bulrushpress.com", - "bum.net", - "bumpymail.com", - "bunchofidiots.com", - "bund.us", - "bundes-li.ga", - "bunsenhoneydew.com", - "burnthespam.info", - "burstmail.info", - "businessbackend.com", - "businesssuccessislifesuccess.com", - "buspad.org", - "bussitussi.com", - "buymoreplays.com", - "buyordie.info", - "buyusdomain.com", - "buyusedlibrarybooks.org", - "buzzcluby.com", - "byebyemail.com", - "byespm.com", - "byom.de", - "c01.kr", - "c51vsgq.com", - "cachedot.net", - "californiafitnessdeals.com", - "cam4you.cc", - "camping-grill.info", - "candymail.de", - "cane.pw", - "capitalistdilemma.com", - "car101.pro", - "carbtc.net", - "cars2.club", - "carsencyclopedia.com", - "cartelera.org", - "caseedu.tk", - "cashflow35.com", - "casualdx.com", - "catgroup.uk", - "cavi.mx", - "cbair.com", - "cbes.net", - "cbty.ru", - "cbty.store", - "cc.liamria", - "ccmail.uk", - "cdfaq.com", - "cdpa.cc", - "ceed.se", - "cek.pm", - "cellurl.com", - "centermail.com", - "centermail.net", - "cetpass.com", - "cfo2go.ro", - "chacuo.net", - "chaichuang.com", - "chalupaurybnicku.cz", - "chammy.info", - "chapsmail.com", - "chasefreedomactivate.com", - "chatich.com", - "cheaphub.net", - "cheatmail.de", - "chenbot.email", - "chewydonut.com", - "chibakenma.ml", - "chickenkiller.com", - "chielo.com", - "childsavetrust.org", - "chilkat.com", - "chinamkm.com", - "chithinh.com", - "chitthi.in", - "choco.la", - "chogmail.com", - "choicemail1.com", - "chong-mail.com", - "chong-mail.net", - "chong-mail.org", - "chumpstakingdumps.com", - "cigar-auctions.com", - "civikli.com", - "civx.org", - "ckaazaza.tk", - "ckiso.com", - "cl-cl.org", - "cl0ne.net", - "claimab.com", - "clandest.in", - "classesmail.com", - "clearwatermail.info", - "click-email.com", - "clickdeal.co", - "clipmail.eu", - "clixser.com", - "clonemoi.tk", - "cloud-mail.top", - "clout.wiki", - "clowmail.com", - "clrmail.com", - "cmail.club", - "cmail.com", - "cmail.net", - "cmail.org", - "cnamed.com", - "cndps.com", - "cnew.ir", - "cnmsg.net", - "cnsds.de", - "co.cc", - "cobarekyo1.ml", - "cocoro.uk", - "cocovpn.com", - "codeandscotch.com", - "codivide.com", - "coffeetimer24.com", - "coieo.com", - "coin-host.net", - "coinlink.club", - "coldemail.info", - "compareshippingrates.org", - "completegolfswing.com", - "comwest.de", - "conf.work", - "consumerriot.com", - "contbay.com", - "cooh-2.site", - "coolandwacky.us", - "coolimpool.org", - "copyhome.win", - "coreclip.com", - "cosmorph.com", - "courrieltemporaire.com", - "coza.ro", - "crankhole.com", - "crapmail.org", - "crastination.de", - "crazespaces.pw", - "crazymailing.com", - "cream.pink", - "crepeau12.com", - "cringemonster.com", - "cross-law.ga", - "cross-law.gq", - "crossmailjet.com", - "crossroadsmail.com", - "crunchcompass.com", - "crusthost.com", - "cs.email", - "csh.ro", - "cszbl.com", - "ctmailing.us", - "ctos.ch", - "cu.cc", - "cubene.com", - "cubiclink.com", - "cuendita.com", - "cuirushi.org", - "cuoly.com", - "cupbest.com", - "curlhph.tk", - "currentmail.com", - "curryworld.de", - "cust.in", - "cutout.club", - "cutradition.com", - "cuvox.de", - "cyber-innovation.club", - "cyber-phone.eu", - "cylab.org", - "d1yun.com", - "d3p.dk", - "daabox.com", - "dab.ro", - "dacoolest.com", - "daemsteam.com", - "daibond.info", - "daily-email.com", - "daintly.com", - "damai.webcam", - "dammexe.net", - "damnthespam.com", - "dandikmail.com", - "darkharvestfilms.com", - "daryxfox.net", - "dasdasdascyka.tk", - "dash-pads.com", - "dataarca.com", - "datarca.com", - "datazo.ca", - "datenschutz.ru", - "datum2.com", - "davidkoh.net", - "davidlcreative.com", - "dawin.com", - "daymail.life", - "daymailonline.com", - "dayrep.com", - "dbunker.com", - "dcctb.com", - "dcemail.com", - "ddcrew.com", - "de-a.org", - "dea-21olympic.com", - "deadaddress.com", - "deadchildren.org", - "deadfake.cf", - "deadfake.ga", - "deadfake.ml", - "deadfake.tk", - "deadspam.com", - "deagot.com", - "dealja.com", - "dealrek.com", - "deekayen.us", - "defomail.com", - "degradedfun.net", - "deinbox.com", - "delayload.com", - "delayload.net", - "delikkt.de", - "delivrmail.com", - "demen.ml", - "dengekibunko.ga", - "dengekibunko.gq", - "dengekibunko.ml", - "der-kombi.de", - "derkombi.de", - "derluxuswagen.de", - "desoz.com", - "despam.it", - "despammed.com", - "dev-null.cf", - "dev-null.ga", - "dev-null.gq", - "dev-null.ml", - "developermail.com", - "devnullmail.com", - "deyom.com", - "dharmatel.net", - "dhm.ro", - "dhy.cc", - "dialogus.com", - "diapaulpainting.com", - "dicopto.com", - "digdig.org", - "digital-message.com", - "digitalesbusiness.info", - "digitalmail.info", - "digitalmariachis.com", - "digitalsanctuary.com", - "dildosfromspace.com", - "dim-coin.com", - "dingbone.com", - "diolang.com", - "directmail24.net", - "disaq.com", - "disbox.net", - "disbox.org", - "discard.cf", - "discard.email", - "discard.ga", - "discard.gq", - "discard.ml", - "discard.tk", - "discardmail.com", - "discardmail.de", - "discos4.com", - "dishcatfish.com", - "disign-concept.eu", - "disign-revelation.com", - "dispo.in", - "dispomail.eu", - "disposable-e.ml", - "disposable-email.ml", - "disposable.cf", - "disposable.ga", - "disposable.ml", - "disposable.site", - "disposableaddress.com", - "disposableemailaddresses.com", - "disposableinbox.com", - "disposablemails.com", - "dispose.it", - "disposeamail.com", - "disposemail.com", - "disposemymail.com", - "dispostable.com", - "divad.ga", - "divermail.com", - "divismail.ru", - "diwaq.com", - "dlemail.ru", - "dmarc.ro", - "dndent.com", - "dnses.ro", - "doanart.com", - "dob.jp", - "dodgeit.com", - "dodgemail.de", - "dodgit.com", - "dodgit.org", - "dodsi.com", - "doiea.com", - "dolphinnet.net", - "domforfb1.tk", - "domforfb18.tk", - "domforfb19.tk", - "domforfb2.tk", - "domforfb23.tk", - "domforfb27.tk", - "domforfb29.tk", - "domforfb3.tk", - "domforfb4.tk", - "domforfb5.tk", - "domforfb6.tk", - "domforfb7.tk", - "domforfb8.tk", - "domforfb9.tk", - "domozmail.com", - "donebyngle.com", - "donemail.ru", - "dongqing365.com", - "dontreg.com", - "dontsendmespam.de", - "doojazz.com", - "doquier.tk", - "dotman.de", - "dotmsg.com", - "dotslashrage.com", - "doublemail.de", - "douchelounge.com", - "dozvon-spb.ru", - "dp76.com", - "dpptd.com", - "dr69.site", - "drdrb.com", - "drdrb.net", - "dred.ru", - "drevo.si", - "drivetagdev.com", - "drmail.in", - "droolingfanboy.de", - "dropcake.de", - "dropjar.com", - "droplar.com", - "dropmail.me", - "dropsin.net", - "drowblock.com", - "dsgvo.party", - "dsgvo.ru", - "dshfjdafd.cloud", - "dsiay.com", - "dspwebservices.com", - "duam.net", - "duck2.club", - "dudmail.com", - "duk33.com", - "dukedish.com", - "dump-email.info", - "dumpandjunk.com", - "dumpmail.de", - "dumpyemail.com", - "durandinterstellar.com", - "duskmail.com", - "dwse.edu.pl", - "dyceroprojects.com", - "dz17.net", - "e-mail.com", - "e-mail.org", - "e-marketstore.ru", - "e-tomarigi.com", - "e3z.de", - "e4ward.com", - "eanok.com", - "easy-trash-mail.com", - "easynetwork.info", - "easytrashmail.com", - "eatmea2z.club", - "eay.jp", - "ebbob.com", - "ebeschlussbuch.de", - "ecallheandi.com", - "ecolo-online.fr", - "edgex.ru", - "edinburgh-airporthotels.com", - "edupolska.edu.pl", - "edv.to", - "ee1.pl", - "ee2.pl", - "eeedv.de", - "eelmail.com", - "efxs.ca", - "egzones.com", - "einmalmail.de", - "einrot.com", - "einrot.de", - "eintagsmail.de", - "elearningjournal.org", - "electro.mn", - "elitevipatlantamodels.com", - "elki-mkzn.ru", - "email-fake.cf", - "email-fake.com", - "email-fake.ga", - "email-fake.gq", - "email-fake.ml", - "email-fake.tk", - "email-jetable.fr", - "email-lab.com", - "email-temp.com", - "email.edu.pl", - "email.net", - "email1.pro", - "email60.com", - "emailage.cf", - "emailage.ga", - "emailage.gq", - "emailage.ml", - "emailage.tk", - "emailate.com", - "emailbin.net", - "emailcbox.pro", - "emailcu.icu", - "emaildienst.de", - "emaildrop.io", - "emailfake.com", - "emailfake.ml", - "emailfoxi.pro", - "emailfreedom.ml", - "emailgenerator.de", - "emailgo.de", - "emailias.com", - "emailigo.de", - "emailinfive.com", - "emailisvalid.com", - "emaillime.com", - "emailmiser.com", - "emailna.co", - "emailnax.com", - "emailo.pro", - "emailondeck.com", - "emailportal.info", - "emailproxsy.com", - "emailresort.com", - "emails.ga", - "emailsecurer.com", - "emailsensei.com", - "emailsingularity.net", - "emailspam.cf", - "emailspam.ga", - "emailspam.gq", - "emailspam.ml", - "emailspam.tk", - "emailsy.info", - "emailtech.info", - "emailtemporanea.com", - "emailtemporanea.net", - "emailtemporar.ro", - "emailtemporario.com.br", - "emailthe.net", - "emailtmp.com", - "emailto.de", - "emailure.net", - "emailwarden.com", - "emailxfer.com", - "emailz.cf", - "emailz.ga", - "emailz.gq", - "emailz.ml", - "emeil.in", - "emeil.ir", - "emeraldwebmail.com", - "emkei.cf", - "emkei.ga", - "emkei.gq", - "emkei.ml", - "emkei.tk", - "eml.pp.ua", - "emlhub.com", - "emlpro.com", - "emltmp.com", - "empireanime.ga", - "emstjzh.com", - "emz.net", - "enayu.com", - "enterto.com", - "envy17.com", - "eoffice.top", - "eoopy.com", - "epb.ro", - "epbox.ru", - "epbox.store", - "ephemail.net", - "ephemeral.email", - "eposta.buzz", - "eposta.work", - "epostal.ru", - "epostal.store", - "eqiluxspam.ga", - "ereplyzy.com", - "ericjohnson.ml", - "eripo.net", - "ero-tube.org", - "esadverse.com", - "esbano-ru.ru", - "esc.la", - "escapehatchapp.com", - "esemay.com", - "esgeneri.com", - "esiix.com", - "esprity.com", - "estate-invest.fr", - "esterace.com", - "eth2btc.info", - "ether123.net", - "ethereum1.top", - "ethersports.org", - "ethersportz.info", - "etotvibor.ru", - "etranquil.com", - "etranquil.net", - "etranquil.org", - "euaqa.com", - "evanfox.info", - "eveav.com", - "evilcomputer.com", - "evopo.com", - "evvgo.com", - "evyush.com", - "exdonuts.com", - "exelica.com", - "existiert.net", - "exitstageleft.net", - "explodemail.com", - "express.net.ua", - "extracurricularsociety.com", - "extremail.ru", - "exweme.com", - "eyepaste.com", - "ez.lv", - "ezehe.com", - "ezfill.com", - "ezstest.com", - "ezztt.com", - "f4k.es", - "facebook-email.cf", - "facebook-email.ga", - "facebook-email.ml", - "facebookmail.gq", - "facebookmail.ml", - "fackme.gq", - "fadingemail.com", - "faecesmail.me", - "fag.wf", - "failbone.com", - "faithkills.com", - "fake-box.com", - "fake-email.pp.ua", - "fake-mail.cf", - "fake-mail.ga", - "fake-mail.ml", - "fakedemail.com", - "fakeinbox.cf", - "fakeinbox.com", - "fakeinbox.ga", - "fakeinbox.info", - "fakeinbox.ml", - "fakeinbox.tk", - "fakeinformation.com", - "fakemail.fr", - "fakemail.io", - "fakemailgenerator.com", - "fakemailz.com", - "fallinhay.com", - "fammix.com", - "fanclub.pm", - "fangoh.com", - "fansworldwide.de", - "fantasymail.de", - "farrse.co.uk", - "fasssd.ru", - "fasssd.store", - "fast-email.info", - "fast-mail.fr", - "fastacura.com", - "fastchevy.com", - "fastchrysler.com", - "fasternet.biz", - "fastkawasaki.com", - "fastmazda.com", - "fastmitsubishi.com", - "fastnissan.com", - "fastsubaru.com", - "fastsuzuki.com", - "fasttoyota.com", - "fastyamaha.com", - "fatflap.com", - "fbma.tk", - "fddns.ml", - "fdfdsfds.com", - "femailtor.com", - "fer-gabon.org", - "fermaxxi.ru", - "fettometern.com", - "fexbox.org", - "fexbox.ru", - "fexpost.com", - "fextemp.com", - "ficken.de", - "fictionsite.com", - "fightallspam.com", - "figjs.com", - "figshot.com", - "figurescoin.com", - "fiifke.de", - "filbert4u.com", - "filberts4u.com", - "film-blog.biz", - "filzmail.com", - "findemail.info", - "findu.pl", - "finews.biz", - "fir.hk", - "firemailbox.club", - "fitnesrezink.ru", - "fivemail.de", - "fivermail.com", - "fixmail.tk", - "fizmail.com", - "fleckens.hu", - "flemail.ru", - "flexvio.com", - "fliegender.fish", - "flowu.com", - "flu.cc", - "fluidsoft.us", - "flurred.com", - "fly-ts.de", - "flyinggeek.net", - "flymail.tk", - "flyspam.com", - "fncp.ru", - "fncp.store", - "foobarbot.net", - "footard.com", - "foreastate.com", - "forecastertests.com", - "foreskin.cf", - "foreskin.ga", - "foreskin.gq", - "foreskin.ml", - "foreskin.tk", - "forgetmail.com", - "fornow.eu", - "forspam.net", - "forward.cat", - "fosil.pro", - "foxja.com", - "foxtrotter.info", - "fr.cr", - "fr.nf", - "fr33mail.info", - "fragolina2.tk", - "frapmail.com", - "frappina.tk", - "free-email.cf", - "free-email.ga", - "free-temp.net", - "freebabysittercam.com", - "freeblackbootytube.com", - "freecat.net", - "freedom4you.info", - "freedompop.us", - "freefattymovies.com", - "freehotmail.net", - "freeinbox.email", - "freelance-france.eu", - "freeletter.me", - "freemail.ms", - "freemails.cf", - "freemails.ga", - "freemails.ml", - "freemeil.ga", - "freemeil.gq", - "freemeil.ml", - "freeml.net", - "freeplumpervideos.com", - "freerubli.ru", - "freeschoolgirlvids.com", - "freesistercam.com", - "freeteenbums.com", - "freundin.ru", - "friendlymail.co.uk", - "front14.org", - "frwdmail.com", - "ftp.sh", - "ftpinc.ca", - "fuckedupload.com", - "fuckingduh.com", - "fuckme69.club", - "fucknloveme.top", - "fuckxxme.top", - "fudgerub.com", - "fuirio.com", - "fukaru.com", - "fukurou.ch", - "fullangle.org", - "fulvie.com", - "fun64.com", - "funnycodesnippets.com", - "funnymail.de", - "furzauflunge.de", - "futuramind.com", - "fuvk.ru", - "fuvk.store", - "fuwa.be", - "fuwa.li", - "fuwamofu.com", - "fuwari.be", - "fux0ringduh.com", - "fxnxs.com", - "fyii.de", - "g14l71lb.com", - "g1xmail.top", - "g2xmail.top", - "g3xmail.top", - "g4hdrop.us", - "gafy.net", - "gage.ga", - "galaxy.tv", - "gally.jp", - "gamail.top", - "gamegregious.com", - "gamgling.com", - "garasikita.pw", - "garbagecollector.org", - "garbagemail.org", - "gardenscape.ca", - "garizo.com", - "garliclife.com", - "garrymccooey.com", - "gav0.com", - "gawab.com", - "gbcmail.win", - "gbmail.top", - "gcmail.top", - "gdmail.top", - "gedmail.win", - "geekforex.com", - "geew.ru", - "gehensiemirnichtaufdensack.de", - "geldwaschmaschine.de", - "gelitik.in", - "genderfuck.net", - "geronra.com", - "geschent.biz", - "get-mail.cf", - "get-mail.ga", - "get-mail.ml", - "get-mail.tk", - "get.pp.ua", - "get1mail.com", - "get2mail.fr", - "getairmail.cf", - "getairmail.com", - "getairmail.ga", - "getairmail.gq", - "getairmail.ml", - "getairmail.tk", - "geteit.com", - "getfun.men", - "getmails.eu", - "getmule.com", - "getnada.com", - "getnowtoday.cf", - "getonemail.com", - "getonemail.net", - "getover.de", - "getsimpleemail.com", - "gett.icu", - "gexik.com", - "ggmal.ml", - "ggvk.ru", - "ggvk.store", - "ghosttexter.de", - "giacmosuaviet.info", - "giaiphapmuasam.com", - "giantmail.de", - "gifto12.com", - "gimpmail.com", - "ginzi.be", - "ginzi.co.uk", - "ginzi.es", - "ginzi.net", - "ginzy.co.uk", - "ginzy.eu", - "giratex.com", - "girlfriend.ru", - "girlmail.win", - "girlsindetention.com", - "girlsundertheinfluence.com", - "gishpuppy.com", - "giveh2o.info", - "givememail.club", - "givmail.com", - "gixenmixen.com", - "glitch.sx", - "globaltouron.com", - "glubex.com", - "glucosegrin.com", - "gmal.com", - "gmatch.org", - "gmial.com", - "gmx1mail.top", - "gmxmail.top", - "gmxmail.win", - "gnctr-calgary.com", - "go2usa.info", - "go2vpn.net", - "goatmail.uk", - "goemailgo.com", - "golemico.com", - "gomail.in", - "goonby.com", - "goplaygame.ru", - "gorillaswithdirtyarmpits.com", - "goround.info", - "gosarlar.com", - "gosuslugi-spravka.ru", - "gothere.biz", - "gotmail.com", - "gotmail.net", - "gotmail.org", - "gowikibooks.com", - "gowikicampus.com", - "gowikicars.com", - "gowikifilms.com", - "gowikigames.com", - "gowikimusic.com", - "gowikinetwork.com", - "gowikitravel.com", - "gowikitv.com", - "grandmamail.com", - "grandmasmail.com", - "grassdev.com", - "great-host.in", - "greencafe24.com", - "greendike.com", - "greenhousemail.com", - "greensloth.com", - "greggamel.com", - "greggamel.net", - "gregorsky.zone", - "gregorygamel.com", - "gregorygamel.net", - "grish.de", - "griuc.schule", - "grn.cc", - "groupbuff.com", - "grr.la", - "gruene-no-thanks.xyz", - "grugrug.ru", - "gruz-m.ru", - "gs-arc.org", - "gsredcross.org", - "gsrv.co.uk", - "gsxstring.ga", - "gudanglowongan.com", - "guerillamail.biz", - "guerillamail.com", - "guerillamail.de", - "guerillamail.info", - "guerillamail.net", - "guerillamail.org", - "guerillamailblock.com", - "guerrillamail.biz", - "guerrillamail.com", - "guerrillamail.de", - "guerrillamail.info", - "guerrillamail.net", - "guerrillamail.org", - "guerrillamailblock.com", - "gufum.com", - "gustr.com", - "guysmail.com", - "gxemail.men", - "gynzi.co.uk", - "gynzi.es", - "gynzy.at", - "gynzy.es", - "gynzy.eu", - "gynzy.gr", - "gynzy.info", - "gynzy.lt", - "gynzy.mobi", - "gynzy.pl", - "gynzy.ro", - "gynzy.sk", - "gzb.ro", - "h8s.org", - "habitue.net", - "hacccc.com", - "hackersquad.tk", - "hackthatbit.ch", - "hahawrong.com", - "haida-edu.cn", - "hairs24.ru", - "haltospam.com", - "hamham.uk", - "hangxomcuatoilatotoro.ml", - "happy2023year.com", - "happydomik.ru", - "harakirimail.com", - "haribu.com", - "hartbot.de", - "hasanmail.ml", - "hat-geld.de", - "hatespam.org", - "hawrong.com", - "haydoo.com", - "hazelnut4u.com", - "hazelnuts4u.com", - "hazmatshipping.org", - "hccmail.win", - "headstrong.de", - "heathenhammer.com", - "heathenhero.com", - "hecat.es", - "heisei.be", - "hellodream.mobi", - "helloricky.com", - "helpinghandtaxcenter.org", - "helpjobs.ru", - "heros3.com", - "herp.in", - "herpderp.nl", - "hezll.com", - "hi2.in", - "hi5.si", - "hiddentragedy.com", - "hidebox.org", - "hidebusiness.xyz", - "hidemail.de", - "hidemail.pro", - "hidemail.us", - "hidzz.com", - "highbros.org", - "hiltonvr.com", - "himail.online", - "hmail.us", - "hmamail.com", - "hmh.ro", - "hoanggiaanh.com", - "hoanglong.tech", - "hochsitze.com", - "hola.org", - "holl.ga", - "honeys.be", - "honor-8.com", - "hopemail.biz", - "hornyalwary.top", - "host1s.com", - "hostcalls.com", - "hostguru.top", - "hostingmail.me", - "hostlaba.com", - "hot-mail.cf", - "hot-mail.ga", - "hot-mail.gq", - "hot-mail.ml", - "hot-mail.tk", - "hotmai.com", - "hotmailproduct.com", - "hotmial.com", - "hotpop.com", - "hotprice.co", - "hotsoup.be", - "housat.com", - "hpc.tw", - "hs.vc", - "ht.cx", - "hthlm.com", - "huangniu8.com", - "huizk.com", - "hukkmu.tk", - "hulapla.de", - "humaility.com", - "hungpackage.com", - "hushmail.cf", - "huskion.net", - "hvastudiesucces.nl", - "hwsye.net", - "hxopi.ru", - "hxopi.store", - "hypenated-domain.com", - "i2pmail.org", - "i6.cloudns.cc", - "iaoss.com", - "ibnuh.bz", - "icantbelieveineedtoexplainthisshit.com", - "icemail.club", - "ich-essen-fleisch.bio", - "ichigo.me", - "icx.in", - "icx.ro", - "icznn.com", - "idx4.com", - "idxue.com", - "ieatspam.eu", - "ieatspam.info", - "ieh-mail.de", - "iencm.com", - "iffymedia.com", - "ige.es", - "igg.biz", - "ignoremail.com", - "ihateyoualot.info", - "ihazspam.ca", - "iheartspam.org", - "ikbenspamvrij.nl", - "ikuromi.com", - "illistnoise.com", - "ilovespam.com", - "imail1.net", - "imails.info", - "imailt.com", - "imgof.com", - "imgv.de", - "immo-gerance.info", - "imperialcnk.com", - "imstations.com", - "imul.info", - "in-ulm.de", - "in2reach.com", - "inactivemachine.com", - "inbax.tk", - "inbound.plus", - "inbox.si", - "inbox2.info", - "inboxalias.com", - "inboxbear.com", - "inboxclean.com", - "inboxclean.org", - "inboxdesign.me", - "inboxed.im", - "inboxed.pw", - "inboxkitten.com", - "inboxnow.ru", - "inboxnow.store", - "inboxproxy.com", - "inboxstore.me", - "inclusiveprogress.com", - "incognitomail.com", - "incognitomail.net", - "incognitomail.org", - "incq.com", - "ind.st", - "indieclad.com", - "indirect.ws", - "indomaed.pw", - "indomina.cf", - "indoserver.stream", - "indosukses.press", - "ineec.net", - "infocom.zp.ua", - "inggo.org", - "inkiny.com", - "inkomail.com", - "inmynetwork.tk", - "inoutmail.de", - "inoutmail.eu", - "inoutmail.info", - "inoutmail.net", - "inpwa.com", - "insanumingeniumhomebrew.com", - "insorg-mail.info", - "instaddr.ch", - "instaddr.uk", - "instaddr.win", - "instance-email.com", - "instant-mail.de", - "instantblingmail.info", - "instantemailaddress.com", - "instantmail.fr", - "instmail.uk", - "internet-v-stavropole.ru", - "internetkeno.com", - "internetoftags.com", - "interstats.org", - "intersteller.com", - "intopwa.com", - "intopwa.net", - "intopwa.org", - "investore.co", - "iozak.com", - "ip4.pp.ua", - "ip6.li", - "ip6.pp.ua", - "ipoo.org", - "ippandansei.tk", - "ipsur.org", - "irabops.com", - "iralborz.bid", - "irc.so", - "irish2me.com", - "irishspringrealty.com", - "iroid.com", - "ironiebehindert.de", - "irssi.tv", - "is.af", - "isdaq.com", - "ishop2k.com", - "isosq.com", - "istii.ro", - "isukrainestillacountry.com", - "it7.ovh", - "italy-mail.com", - "itcompu.com", - "itfast.net", - "itsjiff.com", - "itunesgiftcodegenerator.com", - "iubridge.com", - "iuemail.men", - "iwi.net", - "ixaks.com", - "ixx.io", - "j-p.us", - "jafps.com", - "jaga.email", - "jajxz.com", - "jakemsr.com", - "janproz.com", - "jaqis.com", - "jdmadventures.com", - "jdz.ro", - "je-recycle.info", - "jellow.ml", - "jellyrolls.com", - "jeoce.com", - "jet-renovation.fr", - "jetable.com", - "jetable.net", - "jetable.org", - "jetable.pp.ua", - "ji5.de", - "ji6.de", - "ji7.de", - "jiooq.com", - "jmail.ovh", - "jmail.ro", - "jnxjn.com", - "jobbikszimpatizans.hu", - "jobbrett.com", - "jobposts.net", - "jobs-to-be-done.net", - "joelpet.com", - "joetestalot.com", - "jofuso.com", - "jopho.com", - "joseihorumon.info", - "josse.ltd", - "jourrapide.com", - "jpco.org", - "jsrsolutions.com", - "jumonji.tk", - "jungkamushukum.com", - "junk.to", - "junk1e.com", - "junkmail.ga", - "junkmail.gq", - "just-email.com", - "justemail.ml", - "juyouxi.com", - "jwork.ru", - "kademen.com", - "kadokawa.cf", - "kadokawa.ga", - "kadokawa.gq", - "kadokawa.ml", - "kadokawa.tk", - "kaengu.ru", - "kagi.be", - "kakadua.net", - "kalapi.org", - "kamen-market.ru", - "kamsg.com", - "kaovo.com", - "kappala.info", - "kara-turk.net", - "karatraman.ml", - "kariplan.com", - "karta-kykyruza.ru", - "kartvelo.com", - "kasmail.com", - "kaspop.com", - "katztube.com", - "kazelink.ml", - "kbox.li", - "kcrw.de", - "keepmymail.com", - "keinhirn.de", - "keipino.de", - "kekita.com", - "kellychibale-researchgroup-uct.com", - "kemptvillebaseball.com", - "kiani.com", - "killmail.com", - "killmail.net", - "kimsdisk.com", - "kinda.email", - "kindamail.com", - "kingsq.ga", - "kino-100.ru", - "kiois.com", - "kismail.ru", - "kisstwink.com", - "kitnastar.com", - "kjkszpjcompany.com", - "kkmail.be", - "kkoup.com", - "kksm.be", - "klassmaster.com", - "klassmaster.net", - "klick-tipp.us", - "klipschx12.com", - "kloap.com", - "klovenode.com", - "kludgemush.com", - "klzlk.com", - "kmail.li", - "kmail.live", - "kmhow.com", - "knickerbockerban.de", - "knol-power.nl", - "kobrandly.com", - "kommunity.biz", - "kon42.com", - "konican.com", - "konultant-jurist.ru", - "kook.ml", - "kopagas.com", - "kopaka.net", - "korona-nedvizhimosti.ru", - "koshu.ru", - "kosmetik-obatkuat.com", - "kostenlosemailadresse.de", - "koszmail.pl", - "kpay.be", - "kpooa.com", - "kpost.be", - "krd.ag", - "krsw.tk", - "kruay.com", - "krypton.tk", - "ksmtrck.tk", - "kuhrap.com", - "kuku.lu", - "kulmeo.com", - "kulturbetrieb.info", - "kumli.racing", - "kurzepost.de", - "kutakbisajauhjauh.gq", - "kvhrr.com", - "kvhrs.com", - "kvhrw.com", - "kwift.net", - "kwilco.net", - "kyal.pl", - "kyois.com", - "kzccv.com", - "l-c-a.us", - "l33r.eu", - "l6factors.com", - "laafd.com", - "labetteraverouge.at", - "labworld.org", - "lacedmail.com", - "lackmail.net", - "lackmail.ru", - "lacto.info", - "lags.us", - "lain.ch", - "lak.pp.ua", - "lakelivingstonrealestate.com", - "lakqs.com", - "lamasticots.com", - "lambsauce.de", - "landmail.co", - "laoeq.com", - "larisia.com", - "larland.com", - "last-chance.pro", - "laste.ml", - "lastmail.co", - "lastmail.com", - "lawlita.com", - "laxex.ru", - "laxex.store", - "laymro.com", - "lazyinbox.com", - "lazyinbox.us", - "ldaho.biz", - "ldop.com", - "ldtp.com", - "le-tim.ru", - "lee.mx", - "leeching.net", - "leetmail.co", - "legalrc.loan", - "lellno.gq", - "lenovog4.com", - "lerbhe.com", - "letmeinonthis.com", - "letthemeatspam.com", - "lez.se", - "lgxscreen.com", - "lhsdv.com", - "liamcyrus.com", - "lifebyfood.com", - "lifetimefriends.info", - "lifetotech.com", - "ligsb.com", - "lillemap.net", - "lilo.me", - "lilspam.com", - "lindenbaumjapan.com", - "link2mail.net", - "linkedintuts2016.pw", - "linshiyou.com", - "linshiyouxiang.net", - "linuxmail.so", - "lista.cc", - "litedrop.com", - "liveradio.tk", - "lkgn.se", - "llogin.ru", - "loadby.us", - "loan101.pro", - "loaoa.com", - "loapq.com", - "locanto1.club", - "locantofuck.top", - "locantowsite.club", - "locomodev.net", - "login-email.cf", - "login-email.ga", - "login-email.ml", - "login-email.tk", - "logular.com", - "loh.pp.ua", - "loin.in", - "lolfreak.net", - "lolmail.biz", - "lookugly.com", - "lordsofts.com", - "lortemail.dk", - "losemymail.com", - "lovemeet.faith", - "lovemeleaveme.com", - "lpfmgmtltd.com", - "lr7.us", - "lr78.com", - "lroid.com", - "lru.me", - "ls-server.ru", - "lsyx24.com", - "luckymail.org", - "lukecarriere.com", - "lukemail.info", - "lukop.dk", - "luv2.us", - "lyfestylecreditsolutions.com", - "lyft.live", - "lyricspad.net", - "lzoaq.com", - "m21.cc", - "m4ilweb.info", - "maboard.com", - "mac-24.com", - "macr2.com", - "macromaid.com", - "macromice.info", - "magamail.com", - "maggotymeat.ga", - "magicbox.ro", - "magim.be", - "magspam.net", - "maidlow.info", - "mail-card.net", - "mail-easy.fr", - "mail-filter.com", - "mail-help.net", - "mail-hosting.co", - "mail-hub.info", - "mail-now.top", - "mail-owl.com", - "mail-share.com", - "mail-temporaire.com", - "mail-temporaire.fr", - "mail-tester.com", - "mail.by", - "mail.wtf", - "mail0.ga", - "mail1.top", - "mail114.net", - "mail1a.de", - "mail1web.org", - "mail21.cc", - "mail22.club", - "mail2rss.org", - "mail333.com", - "mail4trash.com", - "mail666.ru", - "mail7.io", - "mail707.com", - "mail72.com", - "mailapp.top", - "mailback.com", - "mailbidon.com", - "mailbiscuit.com", - "mailbiz.biz", - "mailblocks.com", - "mailbox.in.ua", - "mailbox.zip", - "mailbox52.ga", - "mailbox80.biz", - "mailbox82.biz", - "mailbox87.de", - "mailbox92.biz", - "mailboxify.ru", - "mailboxify.store", - "mailboxly.ru", - "mailboxly.store", - "mailboxy.fun", - "mailboxy.ru", - "mailboxy.store", - "mailbucket.org", - "mailcat.biz", - "mailcatch.com", - "mailchop.com", - "mailcker.com", - "maildax.me", - "mailde.de", - "mailde.info", - "maildrop.cc", - "maildrop.cf", - "maildrop.ga", - "maildrop.gq", - "maildrop.ml", - "maildu.de", - "maildx.com", - "maileater.com", - "mailed.in", - "mailed.ro", - "maileimer.de", - "maileme101.com", - "mailers.edu.pl", - "mailexpire.com", - "mailf5.com", - "mailfa.tk", - "mailfall.com", - "mailfast.pro", - "mailfirst.icu", - "mailforspam.com", - "mailfree.ga", - "mailfree.gq", - "mailfree.ml", - "mailfreeonline.com", - "mailfs.com", - "mailguard.me", - "mailgutter.com", - "mailhazard.com", - "mailhazard.us", - "mailhex.com", - "mailhub.pro", - "mailhz.me", - "mailimate.com", - "mailin8r.com", - "mailinatar.com", - "mailinater.com", - "mailinator.co.uk", - "mailinator.com", - "mailinator.gq", - "mailinator.info", - "mailinator.net", - "mailinator.org", - "mailinator.us", - "mailinator0.com", - "mailinator1.com", - "mailinator2.com", - "mailinator2.net", - "mailinator3.com", - "mailinator4.com", - "mailinator5.com", - "mailinator6.com", - "mailinator7.com", - "mailinator8.com", - "mailinator9.com", - "mailincubator.com", - "mailisia.com", - "mailismagic.com", - "mailita.tk", - "mailjunk.cf", - "mailjunk.ga", - "mailjunk.gq", - "mailjunk.ml", - "mailjunk.tk", - "mailmate.com", - "mailme.gq", - "mailme.ir", - "mailme.lv", - "mailme24.com", - "mailmenot.io", - "mailmetrash.com", - "mailmoat.com", - "mailmoth.com", - "mailms.com", - "mailna.biz", - "mailna.co", - "mailna.in", - "mailna.me", - "mailnator.com", - "mailnesia.com", - "mailnull.com", - "mailnuo.com", - "mailonaut.com", - "mailorc.com", - "mailorg.org", - "mailosaur.net", - "mailox.fun", - "mailpick.biz", - "mailpluss.com", - "mailpooch.com", - "mailpoof.com", - "mailpress.gq", - "mailproxsy.com", - "mailquack.com", - "mailrock.biz", - "mailsac.com", - "mailscrap.com", - "mailseal.de", - "mailshell.com", - "mailshiv.com", - "mailsiphon.com", - "mailslapping.com", - "mailslite.com", - "mailsucker.net", - "mailt.net", - "mailt.top", - "mailtechx.com", - "mailtemp.info", - "mailtemporaire.com", - "mailtemporaire.fr", - "mailto.plus", - "mailtome.de", - "mailtothis.com", - "mailtraps.com", - "mailtrash.net", - "mailtrix.net", - "mailtv.net", - "mailtv.tv", - "mailuniverse.co.uk", - "mailzi.ru", - "mailzilla.com", - "mailzilla.org", - "mainerfolg.info", - "makemenaughty.club", - "makemetheking.com", - "malahov.de", - "malayalamdtp.com", - "mama3.org", - "mamulenok.ru", - "mandraghen.cf", - "manifestgenerator.com", - "mannawo.com", - "mansiondev.com", - "manybrain.com", - "mark-compressoren.ru", - "marketlink.info", - "markmurfin.com", - "mask03.ru", - "maskmy.id", - "masonline.info", - "maswae.world", - "matamuasu.ga", - "matchpol.net", - "matra.site", - "max-mail.org", - "maxturns.com", - "mbox.re", - "mbx.cc", - "mcache.net", - "mciek.com", - "mdhc.tk", - "mdz.email", - "meantinc.com", - "mebelnu.info", - "mechanicalresumes.com", - "medkabinet-uzi.ru", - "meepsheep.eu", - "mehr-bitcoin.de", - "meidecn.com", - "meinspamschutz.de", - "meltedbrownies.com", - "meltmail.com", - "memsg.site", - "mentonit.net", - "mepost.pw", - "merepost.com", - "merry.pink", - "meruado.uk", - "messagebeamer.de", - "messwiththebestdielikethe.rest", - "metadownload.org", - "metaintern.net", - "metalunits.com", - "mezimages.net", - "mfsa.info", - "mfsa.ru", - "mfunza.com", - "mhzayt.online", - "miaferrari.com", - "miauj.com", - "midcoastcustoms.com", - "midcoastcustoms.net", - "midcoastsolutions.com", - "midcoastsolutions.net", - "midiharmonica.com", - "midlertidig.com", - "midlertidig.net", - "midlertidig.org", - "mierdamail.com", - "migmail.net", - "migmail.pl", - "migumail.com", - "mihep.com", - "mijnhva.nl", - "minimail.gq", - "ministry-of-silly-walks.de", - "minsmail.com", - "mintemail.com", - "mirai.re", - "misterpinball.de", - "miucce.com", - "mji.ro", - "mjj.edu.ge", - "mjukglass.nu", - "mkpfilm.com", - "ml8.ca", - "mliok.com", - "mm.my", - "mm5.se", - "mnode.me", - "moakt.cc", - "moakt.co", - "moakt.com", - "moakt.ws", - "mobileninja.co.uk", - "mobilevpn.top", - "moburl.com", - "mockmyid.com", - "moeri.org", - "mofu.be", - "mohmal.com", - "mohmal.im", - "mohmal.in", - "mohmal.tech", - "moimoi.re", - "molms.com", - "momentics.ru", - "monachat.tk", - "monadi.ml", - "moneypipe.net", - "monumentmail.com", - "moonwake.com", - "moot.es", - "moreawesomethanyou.com", - "moreorcs.com", - "morriesworld.ml", - "morsin.com", - "moruzza.com", - "motique.de", - "mountainregionallibrary.net", - "mox.pp.ua", - "moy-elektrik.ru", - "moza.pl", - "mozej.com", - "mp-j.ga", - "mr24.co", - "mrvpm.net", - "mrvpt.com", - "msgos.com", - "mspeciosa.com", - "msrc.ml", - "mswork.ru", - "msxd.com", - "mt2009.com", - "mt2014.com", - "mt2015.com", - "mtmdev.com", - "muathegame.com", - "muchomail.com", - "mucincanon.com", - "muehlacker.tk", - "muell.icu", - "muell.io", - "muell.monster", - "muell.xyz", - "muellemail.com", - "muellmail.com", - "munoubengoshi.gq", - "musiccode.me", - "mutant.me", - "mvrht.com", - "mvrht.net", - "mwarner.org", - "mxclip.com", - "mxfuel.com", - "my-pomsies.ru", - "my-teddyy.ru", - "my10minutemail.com", - "mybitti.de", - "mycleaninbox.net", - "mycorneroftheinter.net", - "myde.ml", - "mydefipet.live", - "mydemo.equipment", - "myecho.es", - "myemailboxy.com", - "mygeoweb.info", - "myindohome.services", - "myinfoinc.com", - "myinterserver.ml", - "mykickassideas.com", - "mymail-in.net", - "mymail90.com", - "mymailoasis.com", - "mymaily.lol", - "mynetstore.de", - "myopang.com", - "mypacks.net", - "mypartyclip.de", - "myphantomemail.com", - "mysamp.de", - "myspaceinc.com", - "myspaceinc.net", - "myspaceinc.org", - "myspacepimpedup.com", - "myspamless.com", - "mystvpn.com", - "mysugartime.ru", - "mytemp.email", - "mytempemail.com", - "mytempmail.com", - "mytrashmail.com", - "mywarnernet.net", - "mywrld.site", - "mywrld.top", - "myzx.com", - "mzico.com", - "n1nja.org", - "na-cat.com", - "naah.ru", - "naah.store", - "nabuma.com", - "nada.email", - "nada.ltd", - "nagi.be", - "nakedtruth.biz", - "namewok.com", - "nanonym.ch", - "naslazhdai.ru", - "nationalgardeningclub.com", - "navalcadets.com", - "nawmin.info", - "naymedia.com", - "nbzmr.com", - "negated.com", - "neko2.net", - "nekochan.fr", - "nekosan.uk", - "neomailbox.com", - "neotlozhniy-zaim.ru", - "nepwk.com", - "nervmich.net", - "nervtmich.net", - "net1mail.com", - "netcom.ws", - "netmails.com", - "netmails.net", - "netricity.nl", - "netris.net", - "netviewer-france.com", - "netzidiot.de", - "nevermail.de", - "newbpotato.tk", - "newfilm24.ru", - "newideasfornewpeople.info", - "newmail.top", - "next.ovh", - "nextmail.info", - "nextstopvalhalla.com", - "nezdiro.org", - "nezid.com", - "nezumi.be", - "nezzart.com", - "nfast.net", - "nguyenusedcars.com", - "nh3.ro", - "nice-4u.com", - "nicknassar.com", - "nincsmail.com", - "nincsmail.hu", - "niseko.be", - "niwl.net", - "nm123.com", - "nm7.cc", - "nmail.cf", - "nnh.com", - "nnot.net", - "nnoway.ru", - "no-spam.ws", - "no-trash.ru", - "no-ux.com", - "noblepioneer.com", - "nobugmail.com", - "nobulk.com", - "nobuma.com", - "noclickemail.com", - "nocp.ru", - "nocp.store", - "nodezine.com", - "nogmailspam.info", - "noicd.com", - "nokiamail.com", - "nolemail.ga", - "nomail.cf", - "nomail.ga", - "nomail.pw", - "nomail2me.com", - "nomorespamemails.com", - "nonspam.eu", - "nonspammer.de", - "nonze.ro", - "noref.in", - "norseforce.com", - "norwegischlernen.info", - "nospam4.us", - "nospamfor.us", - "nospamthanks.info", - "nothingtoseehere.ca", - "notif.me", - "notmailinator.com", - "notrnailinator.com", - "notsharingmy.info", - "now.im", - "nowhere.org", - "nowmymail.com", - "nowmymail.net", - "nproxi.com", - "nthrl.com", - "ntlhelp.net", - "nubescontrol.com", - "nullbox.info", - "nurfuerspam.de", - "nut.cc", - "nutpa.net", - "nuts2trade.com", - "nvhrw.com", - "nwldx.com", - "nwytg.com", - "nwytg.net", - "ny7.me", - "nyasan.com", - "nypato.com", - "nyrmusic.com", - "o2stk.org", - "o7i.net", - "oalsp.com", - "obfusko.com", - "objectmail.com", - "obobbo.com", - "oborudovanieizturcii.ru", - "obxpestcontrol.com", - "octovie.com", - "odaymail.com", - "odem.com", - "odnorazovoe.ru", - "oepia.com", - "oerpub.org", - "offshore-proxies.net", - "ofisher.net", - "ohaaa.de", - "ohi.tw", - "oida.icu", - "oing.cf", - "okclprojects.com", - "okinawa.li", - "okrent.us", - "okzk.com", - "olimp-case.ru", - "oloh.ru", - "oloh.store", - "olypmall.ru", - "omail.pro", - "omnievents.org", - "omtecha.com", - "one-mail.top", - "one-time.email", - "one2mail.info", - "onekisspresave.com", - "onemail.host", - "oneoffemail.com", - "oneoffmail.com", - "onetm.jp", - "onewaymail.com", - "onlatedotcom.info", - "online.ms", - "onlineidea.info", - "onlyapp.net", - "onqin.com", - "ontyne.biz", - "oohioo.com", - "oolus.com", - "oonies-shoprus.ru", - "oopi.org", - "oosln.com", - "oovk.ru", - "oovk.store", - "opayq.com", - "openavz.com", - "opendns.ro", - "opentrash.com", - "opmmedia.ga", - "opp24.com", - "optimaweb.me", - "opwebw.com", - "oranek.com", - "ordinaryamerican.net", - "oreidresume.com", - "orgmbx.cc", - "oroki.de", - "orsbap.com", - "oshietechan.link", - "otherinbox.com", - "ourklips.com", - "ourpreviewdomain.com", - "outlawspam.com", - "outlook.edu.pl", - "outmail.win", - "ovomail.co", - "ovpn.to", - "owleyes.ch", - "owlpic.com", - "ownsyou.de", - "oxopoha.com", - "ozatvn.com", - "ozyl.de", - "p-banlis.ru", - "p33.org", - "p71ce1m.com", - "pa9e.com", - "pachilly.com", - "packiu.com", - "pagamenti.tk", - "paharpurmim.ga", - "pakadebu.ga", - "pamaweb.com", - "pancakemail.com", - "papierkorb.me", - "paplease.com", - "para2019.ru", - "parlimentpetitioner.tk", - "pastebitch.com", - "patonce.com", - "pavilionx2.com", - "payperex2.com", - "payspun.com", - "pe.hu", - "pecinan.com", - "pecinan.net", - "pecinan.org", - "penisgoes.in", - "penoto.tk", - "pepbot.com", - "peterdethier.com", - "petloca.com", - "petrzilka.net", - "pewpewpewpew.pw", - "pflege-schoene-haut.de", - "pfui.ru", - "phone-elkey.ru", - "photo-impact.eu", - "photomark.net", - "pi.vu", - "piaa.me", - "pig.pp.ua", - "pii.at", - "piki.si", - "pimpedupmyspace.com", - "pinehill-seattle.org", - "pingir.com", - "pipemail.space", - "pisls.com", - "pitaniezdorovie.ru", - "pivo-bar.ru", - "pixiil.com", - "pizu.ru", - "pizu.store", - "pizzajunk.com", - "pjjkp.com", - "placebomail10.com", - "pleasenoham.org", - "plexfirm.com", - "plexolan.de", - "plhk.ru", - "ploae.com", - "ploncy.com", - "plw.me", - "poehali-otdihat.ru", - "pojok.ml", - "pokemail.net", - "pokiemobile.com", - "polarkingxx.ml", - "politikerclub.de", - "polyfaust.net", - "pooae.com", - "poofy.org", - "pookmail.com", - "poopiebutt.club", - "popcornfarm7.com", - "popcornfly.com", - "popesodomy.com", - "popgx.com", - "porjoton.com", - "porsh.net", - "posdz.com", - "posta.store", - "postacin.com", - "postbx.ru", - "postbx.store", - "postonline.me", - "poutineyourface.com", - "powered.name", - "powerencry.com", - "powlearn.com", - "pp7rvv.com", - "ppetw.com", - "pptrvv.com", - "pqoia.com", - "pratikmail.com", - "pratikmail.net", - "pratikmail.org", - "prazdnik-37.ru", - "predatorrat.cf", - "predatorrat.ga", - "predatorrat.gq", - "predatorrat.ml", - "predatorrat.tk", - "premium-mail.fr", - "primabananen.net", - "prin.be", - "privacy.net", - "privatdemail.net", - "privmail.edu.pl", - "privy-mail.com", - "privy-mail.de", - "privymail.de", - "pro-tag.org", - "pro5g.com", - "procrackers.com", - "profast.top", - "projectcl.com", - "promailt.com", - "proprietativalcea.ro", - "propscore.com", - "protempmail.com", - "proxymail.eu", - "proxyparking.com", - "prtnx.com", - "prtshr.com", - "prtz.eu", - "psh.me", - "psles.com", - "psnator.com", - "psoxs.com", - "puglieisi.com", - "puji.pro", - "punkass.com", - "puppetmail.de", - "purcell.email", - "purelogistics.org", - "pursip.com", - "put2.net", - "puttanamaiala.tk", - "putthisinyourspamdatabase.com", - "pwpwa.com", - "pwrby.com", - "qabq.com", - "qasti.com", - "qbfree.us", - "qc.to", - "qibl.at", - "qiott.com", - "qipmail.net", - "qiq.us", - "qisdo.com", - "qisoa.com", - "qmrbe.com", - "qodiq.com", - "qoika.com", - "qopow.com", - "qq.my", - "qsl.ro", - "qtum-ico.com", - "quadrafit.com", - "quick-mail.cc", - "quickemail.info", - "quickinbox.com", - "quickmail.nl", - "quicksend.ch", - "quipas.com", - "ququb.com", - "qvy.me", - "qwickmail.com", - "r4nd0m.de", - "ra3.us", - "rabin.ca", - "rabiot.reisen", - "rackabzar.com", - "raetp9.com", - "rainbowly.ml", - "raketenmann.de", - "ramenmail.de", - "ramin200.site", - "rancidhome.net", - "randomail.io", - "randomail.net", - "rapt.be", - "raqid.com", - "rax.la", - "raxtest.com", - "razemail.com", - "razuz.com", - "rbb.org", - "rcasd.com", - "rcpt.at", - "rdklcrv.xyz", - "re-gister.com", - "reality-concept.club", - "reallymymail.com", - "realquickemail.com", - "realtyalerts.ca", - "rebates.stream", - "receiveee.com", - "recipeforfailure.com", - "recode.me", - "reconmail.com", - "recyclemail.dk", - "redfeathercrow.com", - "reftoken.net", - "regapts.com", - "regbypass.com", - "regspaces.tk", - "reimondo.com", - "rejectmail.com", - "rejo.technology", - "reliable-mail.com", - "remail.cf", - "remail.ga", - "remarkable.rocks", - "remote.li", - "rentaen.com", - "replyloop.com", - "reptilegenetics.com", - "resgedvgfed.tk", - "revolvingdoorhoax.org", - "rfc822.org", - "rhyta.com", - "richfinances.pw", - "riddermark.de", - "rifkian.ga", - "rinseart.com", - "rippb.com", - "risingsuntouch.com", - "riski.cf", - "risu.be", - "rklips.com", - "rkomo.com", - "rm2rf.com", - "rma.ec", - "rmqkr.net", - "rnailinator.com", - "ro.lt", - "robertspcrepair.com", - "roborena.com", - "robot-mail.com", - "rollindo.agency", - "ronnierage.net", - "rootfest.net", - "rosebearmylove.ru", - "rotaniliam.com", - "rover.info", - "rowe-solutions.com", - "royal.net", - "royaldoodles.org", - "royalmarket.life", - "royandk.com", - "rppkn.com", - "rsvhr.com", - "rteet.com", - "rtrtr.com", - "rtskiya.xyz", - "rudymail.ml", - "rumgel.com", - "runi.ca", - "rupayamail.com", - "ruru.be", - "rustydoor.com", - "rustyload.com", - "ruu.kr", - "rvb.ro", - "ryteto.me", - "ryyr.ru", - "ryyr.store", - "s0ny.net", - "s33db0x.com", - "sabrestlouis.com", - "sackboii.com", - "saeoil.com", - "safaat.cf", - "safermail.info", - "safersignup.de", - "safetymail.info", - "safetypost.de", - "saharanightstempe.com", - "sailmail.io", - "salmeow.tk", - "samsclass.info", - "sandcars.net", - "sandelf.de", - "sandwhichvideo.com", - "sanfinder.com", - "sanim.net", - "sanstr.com", - "sast.ro", - "satisfyme.club", - "satukosong.com", - "sausen.com", - "saynotospams.com", - "scatmail.com", - "scay.net", - "schachrol.com", - "schafmail.de", - "schmeissweg.tk", - "schrott-email.de", - "scrsot.com", - "sd3.in", - "sdvft.com", - "sdvgeft.com", - "sdvrecft.com", - "secmail.pw", - "secretemail.de", - "secure-mail.biz", - "secure-mail.cc", - "secured-link.net", - "securehost.com.es", - "seekapps.com", - "seekjobs4u.com", - "sejaa.lv", - "selfdestructingmail.com", - "selfdestructingmail.org", - "send22u.info", - "sendapp.uk", - "sendfree.org", - "sendingspecialflyers.com", - "sendnow.win", - "sendspamhere.com", - "senseless-entertainment.com", - "seosnaps.com", - "server.ms", - "services391.com", - "sexforswingers.com", - "sexical.com", - "sexyalwasmi.top", - "sfolkar.com", - "sgatra.com", - "shadap.org", - "shalar.net", - "sharedmailbox.org", - "sharkfaces.com", - "sharklasers.com", - "shchiba.uk", - "sheryli.com", - "shhmail.com", - "shhuut.org", - "shieldedmail.com", - "shieldemail.com", - "shiftmail.com", - "shipfromto.com", - "shiphazmat.org", - "shipping-regulations.com", - "shippingterms.org", - "shitaway.tk", - "shitmail.de", - "shitmail.me", - "shitmail.org", - "shmeriously.com", - "shopxda.com", - "shortmail.net", - "shotmail.ru", - "showslow.de", - "shrib.com", - "shut.name", - "shut.ws", - "siberpay.com", - "sidelka-mytischi.ru", - "siftportal.ru", - "sify.com", - "sika3.com", - "sikux.com", - "silenceofthespam.com", - "siliwangi.ga", - "silvercoin.life", - "sim-simka.ru", - "simaenaga.com", - "simpleitsecurity.info", - "sin.cl", - "sinaite.net", - "sinema.ml", - "sinfiltro.cl", - "singlespride.com", - "sinnlos-mail.de", - "sino.tw", - "siteposter.net", - "sizzlemctwizzle.com", - "sjuaq.com", - "skeefmail.com", - "skrak.com", - "skrx.tk", - "sky-inbox.com", - "sky-ts.de", - "skygazerhub.com", - "skyrt.de", - "slapsfromlastnight.com", - "slaskpost.se", - "slave-auctions.net", - "slippery.email", - "slipry.net", - "slopsbox.com", - "slothmail.net", - "slushmail.com", - "sluteen.com", - "sly.io", - "smallker.tk", - "smapfree24.com", - "smapfree24.de", - "smapfree24.eu", - "smapfree24.info", - "smapfree24.org", - "smartemailbox.co", - "smartnator.com", - "smarttalent.pw", - "smashmail.de", - "smellfear.com", - "smellrear.com", - "smellypotato.tk", - "smtp99.com", - "smwg.info", - "snakebutt.com", - "snakemail.com", - "snapmail.cc", - "snapwet.com", - "sneakmail.de", - "snece.com", - "social-mailer.tk", - "socialfurry.org", - "sociallymediocre.com", - "sofia.re", - "sofimail.com", - "sofort-mail.de", - "sofortmail.de", - "sofrge.com", - "softkey-office.ru", - "softpls.asia", - "sogetthis.com", - "sohai.ml", - "sohus.cn", - "soioa.com", - "soisz.com", - "solar-impact.pro", - "solvemail.info", - "solventtrap.wiki", - "songsign.com", - "sonshi.cf", - "soodmail.com", - "soodomail.com", - "soodonims.com", - "soombo.com", - "soon.it", - "spacebazzar.ru", - "spam-be-gone.com", - "spam.care", - "spam.ceo", - "spam.la", - "spam.org.es", - "spam.su", - "spam4.me", - "spamail.de", - "spamarrest.com", - "spamavert.com", - "spambob.com", - "spambob.net", - "spambob.org", - "spambog.com", - "spambog.de", - "spambog.net", - "spambog.ru", - "spambooger.com", - "spambox.info", - "spambox.me", - "spambox.org", - "spambox.us", - "spamcero.com", - "spamcon.org", - "spamcorptastic.com", - "spamcowboy.com", - "spamcowboy.net", - "spamcowboy.org", - "spamday.com", - "spamdecoy.net", - "spamex.com", - "spamfellas.com", - "spamfighter.cf", - "spamfighter.ga", - "spamfighter.gq", - "spamfighter.ml", - "spamfighter.tk", - "spamfree.eu", - "spamfree24.com", - "spamfree24.de", - "spamfree24.eu", - "spamfree24.info", - "spamfree24.net", - "spamfree24.org", - "spamgoes.in", - "spamherelots.com", - "spamhereplease.com", - "spamhole.com", - "spamify.com", - "spaminator.de", - "spamkill.info", - "spaml.com", - "spaml.de", - "spamlot.net", - "spammer.fail", - "spammotel.com", - "spammy.host", - "spamobox.com", - "spamoff.de", - "spamsalad.in", - "spamsandwich.com", - "spamslicer.com", - "spamsphere.com", - "spamspot.com", - "spamstack.net", - "spamthis.co.uk", - "spamthis.network", - "spamthisplease.com", - "spamtrail.com", - "spamtrap.ro", - "spamtroll.net", - "spamwc.cf", - "spamwc.ga", - "spamwc.gq", - "spamwc.ml", - "speedgaus.net", - "sperma.cf", - "spicysoda.com", - "spikio.com", - "spindl-e.com", - "spoofmail.de", - "sportrid.com", - "spr.io", - "spritzzone.de", - "spruzme.com", - "spybox.de", - "spymail.com", - "spymail.one", - "squizzy.de", - "squizzy.net", - "sroff.com", - "sry.li", - "ssoia.com", - "stanfordujjain.com", - "starlight-breaker.net", - "starmail.net", - "starpower.space", - "startfu.com", - "startkeys.com", - "statdvr.com", - "stathost.net", - "statiix.com", - "stayhome.li", - "steam-area.ru", - "steambot.net", - "stexsy.com", - "stinkefinger.net", - "stop-my-spam.cf", - "stop-my-spam.com", - "stop-my-spam.ga", - "stop-my-spam.ml", - "stop-my-spam.pp.ua", - "stop-my-spam.tk", - "stopspam.app", - "storiqax.top", - "storj99.com", - "storj99.top", - "streetwisemail.com", - "stromox.com", - "stuckmail.com", - "stuffmail.de", - "stumpfwerk.com", - "stylist-volos.ru", - "submic.com", - "suburbanthug.com", - "suckmyd.com", - "sudern.de", - "sueshaw.com", - "suexamplesb.com", - "suioe.com", - "super-auswahl.de", - "superblohey.com", - "supergreatmail.com", - "supermailer.jp", - "superplatyna.com", - "superrito.com", - "supersave.net", - "superstachel.de", - "superyp.com", - "suremail.info", - "sute.jp", - "svip520.cn", - "svk.jp", - "svxr.org", - "sweetpotato.ml", - "sweetxxx.de", - "swift-mail.net", - "swift10minutemail.com", - "syinxun.com", - "sylvannet.com", - "symphonyresume.com", - "syosetu.gq", - "syujob.accountants", - "szerz.com", - "tafmail.com", - "tafoi.gr", - "taglead.com", - "tagmymedia.com", - "tagyourself.com", - "talkinator.com", - "talmetry.com", - "tanlanav.com", - "tanukis.org", - "taobudao.com", - "tapchicuoihoi.com", - "taphear.com", - "tapi.re", - "tarzanmail.cf", - "tastrg.com", - "tatsu.uk", - "taukah.com", - "tb-on-line.net", - "tcwlm.com", - "tcwlx.com", - "tdtda.com", - "tech69.com", - "techblast.ch", - "techemail.com", - "techgroup.me", - "technoproxy.ru", - "teerest.com", - "teewars.org", - "tefl.ro", - "telecomix.pl", - "teleg.eu", - "telegmail.com", - "teleworm.com", - "teleworm.us", - "tellos.xyz", - "telvetto.com", - "teml.net", - "temp-link.net", - "temp-mail.com", - "temp-mail.de", - "temp-mail.org", - "temp-mail.pp.ua", - "temp-mail.ru", - "temp-mails.com", - "tempail.com", - "tempalias.com", - "tempe-mail.com", - "tempemail.biz", - "tempemail.co.za", - "tempemail.com", - "tempemail.net", - "tempinbox.co.uk", - "tempinbox.com", - "tempmail.cn", - "tempmail.co", - "tempmail.de", - "tempmail.eu", - "tempmail.it", - "tempmail.pp.ua", - "tempmail.us", - "tempmail.ws", - "tempmail2.com", - "tempmaildemo.com", - "tempmailer.com", - "tempmailer.de", - "tempmailer.net", - "tempmailo.com", - "tempomail.fr", - "tempomail.org", - "temporarily.de", - "temporarioemail.com.br", - "temporary-mail.net", - "temporaryemail.net", - "temporaryemail.us", - "temporaryforwarding.com", - "temporaryinbox.com", - "temporarymailaddress.com", - "tempr.email", - "tempsky.com", - "temptami.com", - "tempthe.net", - "tempymail.com", - "tensi.org", - "ternaklele.ga", - "testore.co", - "testudine.com", - "thanksnospam.info", - "thankyou2010.com", - "thatim.info", - "thc.st", - "theaviors.com", - "thebearshark.com", - "thecarinformation.com", - "thechildrensfocus.com", - "thecity.biz", - "thecloudindex.com", - "thediamants.org", - "thedirhq.info", - "theeyeoftruth.com", - "thejoker5.com", - "thelightningmail.net", - "thelimestones.com", - "thembones.com.au", - "themegreview.com", - "themostemail.com", - "thereddoors.online", - "theroyalweb.club", - "thescrappermovie.com", - "thespamfather.com", - "theteastory.info", - "thex.ro", - "thichanthit.com", - "thietbivanphong.asia", - "thisisnotmyrealemail.com", - "thismail.net", - "thisurl.website", - "thnikka.com", - "thoas.ru", - "thraml.com", - "thrma.com", - "throam.com", - "thrott.com", - "throwam.com", - "throwawayemailaddress.com", - "throwawaymail.com", - "throwawaymail.pp.ua", - "throya.com", - "thrubay.com", - "thunderbolt.science", - "thunkinator.org", - "thxmate.com", - "tiapz.com", - "tic.ec", - "tilien.com", - "timgiarevn.com", - "timkassouf.com", - "tinoza.org", - "tinyurl24.com", - "tipsb.com", - "tittbit.in", - "tiv.cc", - "tizi.com", - "tkitc.de", - "tlpn.org", - "tmail.com", - "tmail.io", - "tmail.link", - "tmail.ws", - "tmail3.com", - "tmail9.com", - "tmailinator.com", - "tmails.net", - "tmmbt.net", - "tmpbox.net", - "tmpemails.com", - "tmpeml.com", - "tmpeml.info", - "tmpjr.me", - "tmpmail.net", - "tmpmail.org", - "tmpmailtor.com", - "tmpnator.live", - "tmpx.sa.com", - "toddsbighug.com", - "tofeat.com", - "toiea.com", - "tokem.co", - "tokenmail.de", - "tonaeto.com", - "tonne.to", - "tonymanso.com", - "toomail.biz", - "toon.ml", - "top-shop-tovar.ru", - "top101.de", - "top1mail.ru", - "top1post.ru", - "topinrock.cf", - "topmail2.com", - "topmail2.net", - "topofertasdehoy.com", - "topranklist.de", - "toprumours.com", - "tormail.org", - "tospage.com", - "toss.pw", - "tosunkaya.com", - "totallynotfake.net", - "totalvista.com", - "totesmail.com", - "totoan.info", - "tourcc.com", - "tp-qa-mail.com", - "tpwlb.com", - "tqoai.com", - "tqosi.com", - "trackden.com", - "tradermail.info", - "tranceversal.com", - "trap-mail.de", - "trash-amil.com", - "trash-mail.at", - "trash-mail.cf", - "trash-mail.com", - "trash-mail.de", - "trash-mail.ga", - "trash-mail.gq", - "trash-mail.ml", - "trash-mail.tk", - "trash-me.com", - "trash2009.com", - "trash2010.com", - "trash2011.com", - "trashcanmail.com", - "trashdevil.com", - "trashdevil.de", - "trashemail.de", - "trashemails.de", - "trashinbox.com", - "trashmail.at", - "trashmail.com", - "trashmail.de", - "trashmail.gq", - "trashmail.io", - "trashmail.me", - "trashmail.net", - "trashmail.org", - "trashmail.ws", - "trashmailer.com", - "trashmailgenerator.de", - "trashmails.com", - "trashymail.com", - "trashymail.net", - "trasz.com", - "trayna.com", - "trbvm.com", - "trbvn.com", - "trbvo.com", - "trend-maker.ru", - "trgfu.com", - "trgovinanaveliko.info", - "trialmail.de", - "trickmail.net", - "trillianpro.com", - "triots.com", - "trixtrux1.ru", - "trollproject.com", - "tropicalbass.info", - "trungtamtoeic.com", - "truthfinderlogin.com", - "tryalert.com", - "tryninja.io", - "tryzoe.com", - "tsderp.com", - "ttirv.org", - "ttszuo.xyz", - "tualias.com", - "tuofs.com", - "tupmail.com", - "turoid.com", - "turual.com", - "turuma.com", - "tutuapp.bid", - "tvchd.com", - "tverya.com", - "twinmail.de", - "twkly.ml", - "twocowmail.net", - "twoweirdtricks.com", - "twzhhq.online", - "txcct.com", - "txen.de", - "txtadvertise.com", - "tyhe.ro", - "tyldd.com", - "tympe.net", - "uacro.com", - "uber-mail.com", - "ubinert.com", - "ubismail.net", - "ubm.md", - "ucche.us", - "ucupdong.ml", - "uemail99.com", - "ufacturing.com", - "uggsrock.com", - "uguuchantele.com", - "uhe2.com", - "uhhu.ru", - "uiu.us", - "ujijima1129.gq", - "uk.to", - "ultra.fyi", - "ultrada.ru", - "uma3.be", - "umail.net", - "undo.it", - "unicodeworld.com", - "unids.com", - "unimark.org", - "unit7lahaina.com", - "unmail.ru", - "uooos.com", - "uorak.com", - "upliftnow.com", - "uplipht.com", - "uploadnolimit.com", - "upozowac.info", - "urfunktion.se", - "urhen.com", - "uroid.com", - "us.af", - "us.to", - "usa.cc", - "usako.net", - "usbc.be", - "used-product.fr", - "ushijima1129.cf", - "ushijima1129.ga", - "ushijima1129.gq", - "ushijima1129.ml", - "ushijima1129.tk", - "utiket.us", - "uu.gl", - "uu2.ovh", - "uuf.me", - "uwork4.us", - "uyhip.com", - "vaasfc4.tk", - "vaati.org", - "valemail.net", - "valhalladev.com", - "vankin.de", - "vasteron.com", - "vctel.com", - "vda.ro", - "vddaz.com", - "vdig.com", - "veanlo.com", - "vemomail.win", - "venompen.com", - "veo.kr", - "ver0.cf", - "ver0.ga", - "ver0.gq", - "ver0.ml", - "ver0.tk", - "vercelli.cf", - "vercelli.ga", - "vercelli.gq", - "vercelli.ml", - "verdejo.com", - "vermutlich.net", - "veryday.ch", - "veryday.eu", - "veryday.info", - "veryrealemail.com", - "vesa.pw", - "vevs.de", - "vfemail.net", - "via.tokyo.jp", - "vickaentb.tk", - "victime.ninja", - "victoriantwins.com", - "vidchart.com", - "viditag.com", - "viewcastmedia.com", - "viewcastmedia.net", - "viewcastmedia.org", - "vikingsonly.com", - "vinernet.com", - "vintomaper.com", - "vipepe.com", - "vipmail.name", - "vipmail.pw", - "vipxm.net", - "viralplays.com", - "virtualemail.info", - "visal007.tk", - "visal168.cf", - "visal168.ga", - "visal168.gq", - "visal168.ml", - "visal168.tk", - "visignal.com", - "vixletdev.com", - "vixtricks.com", - "vjoid.ru", - "vjoid.store", - "vjuum.com", - "vkbb.ru", - "vkbb.store", - "vkbt.ru", - "vkbt.store", - "vkcbt.ru", - "vkcbt.store", - "vkcode.ru", - "vkfu.ru", - "vkfu.store", - "vkpr.store", - "vkr1.com", - "vkrr.ru", - "vkrr.store", - "vmailing.info", - "vmani.com", - "vmpanda.com", - "vnedu.me", - "voidbay.com", - "volaj.com", - "voltaer.com", - "vomoto.com", - "vorga.org", - "votiputox.org", - "voxelcore.com", - "vpn.st", - "vps30.com", - "vps911.net", - "vradportal.com", - "vremonte24-store.ru", - "vrmtr.com", - "vsimcard.com", - "vssms.com", - "vtxmail.us", - "vubby.com", - "vuiy.pw", - "vusra.com", - "vztc.com", - "w-asertun.ru", - "w3internet.co.uk", - "wakingupesther.com", - "walala.org", - "walkmail.net", - "walkmail.ru", - "wallm.com", - "wanko.be", - "watch-harry-potter.com", - "watchever.biz", - "watchfull.net", - "watchironman3onlinefreefullmovie.com", - "waterisgone.com", - "watrf.com", - "wazabi.club", - "wbdev.tech", - "wbml.net", - "web-contact.info", - "web-ideal.fr", - "web-inc.net", - "web-mail.pp.ua", - "web2mailco.com", - "webcontact-france.eu", - "webemail.me", - "webhook.site", - "webm4il.info", - "webmail24.top", - "webtrip.ch", - "webuser.in", - "wecp.ru", - "wecp.store", - "wee.my", - "wef.gr", - "weg-werf-email.de", - "wegwerf-email-addressen.de", - "wegwerf-email-adressen.de", - "wegwerf-email.at", - "wegwerf-email.de", - "wegwerf-email.net", - "wegwerf-emails.de", - "wegwerfadresse.de", - "wegwerfemail.com", - "wegwerfemail.de", - "wegwerfemail.info", - "wegwerfemail.net", - "wegwerfemail.org", - "wegwerfemailadresse.com", - "wegwerfmail.de", - "wegwerfmail.info", - "wegwerfmail.net", - "wegwerfmail.org", - "wegwerpmailadres.nl", - "wegwrfmail.de", - "wegwrfmail.net", - "wegwrfmail.org", - "weizixu.com", - "wekawa.com", - "welikecookies.com", - "wellsfargocomcardholders.com", - "wemel.top", - "wenkuu.com", - "wentcity.com", - "wetrainbayarea.com", - "wetrainbayarea.org", - "wfgdfhj.tk", - "wg0.com", - "wh4f.org", - "whaaaaaaaaaat.com", - "whatiaas.com", - "whatifanalytics.com", - "whatpaas.com", - "whatsaas.com", - "whiffles.org", - "whopy.com", - "whyspam.me", - "wibblesmith.com", - "wickmail.net", - "widaryanto.info", - "widget.gg", - "wiemei.com", - "wierie.tk", - "wifimaple.com", - "wifioak.com", - "wikfee.com", - "wikidocuslava.ru", - "wilemail.com", - "willhackforfood.biz", - "willselfdestruct.com", - "wimsg.com", - "winemaven.info", - "wins.com.br", - "wlist.ro", - "wmail.cf", - "wmail.club", - "wokcy.com", - "wolfmail.ml", - "wolfsmail.tk", - "wollan.info", - "worldspace.link", - "wpdork.com", - "wpg.im", - "wralawfirm.com", - "writeme.us", - "wronghead.com", - "ws.gy", - "wsym.de", - "wudet.men", - "wuespdj.xyz", - "wupics.com", - "wuuvo.com", - "wuzak.com", - "wuzup.net", - "wuzupmail.net", - "wwjmp.com", - "wwvk.ru", - "wwvk.store", - "wwwnew.eu", - "wxnw.net", - "x24.com", - "xagloo.co", - "xagloo.com", - "xbaby69.top", - "xcode.ro", - "xcodes.net", - "xcompress.com", - "xcoxc.com", - "xcpy.com", - "xemaps.com", - "xemne.com", - "xents.com", - "xepa.ru", - "xjoi.com", - "xkx.me", - "xl.cx", - "xmail.com", - "xmailer.be", - "xmaily.com", - "xn--9kq967o.com", - "xn--d-bga.net", - "xojxe.com", - "xost.us", - "xoxox.cc", - "xperiae5.com", - "xrap.de", - "xrho.com", - "xvx.us", - "xww.ro", - "xxhamsterxx.ga", - "xxi2.com", - "xxlocanto.us", - "xxolocanto.us", - "xxqx3802.com", - "xxvk.ru", - "xxvk.store", - "xxxhi.cc", - "xy9ce.tk", - "xylar.ru", - "xylar.store", - "xyzfree.net", - "xzsok.com", - "yabai-oppai.tk", - "yahmail.top", - "yahooproduct.net", - "yamail.win", - "yanet.me", - "yannmail.win", - "yapped.net", - "yaqp.com", - "yarnpedia.ga", - "ycare.de", - "ycn.ro", - "ye.vc", - "yecp.ru", - "yecp.store", - "yedi.org", - "yeezus.ru", - "yep.it", - "yermail.net", - "yhg.biz", - "ynmrealty.com", - "yodx.ro", - "yogamaven.com", - "yoggm.com", - "yomail.info", - "yoo.ro", - "yopmail.com", - "yopmail.fr", - "yopmail.gq", - "yopmail.net", - "yopmail.pp.ua", - "yordanmail.cf", - "you-spam.com", - "yougotgoated.com", - "youmail.ga", - "youmailr.com", - "youneedmore.info", - "youpymail.com", - "your5.ru", - "your5.store", - "yourdomain.com", - "youremail.cf", - "yourewronghereswhy.com", - "yourlms.biz", - "yourspamgoesto.space", - "yourtube.ml", - "youxiang.dev", - "yroid.com", - "yspend.com", - "ytpayy.com", - "yugasandrika.com", - "yui.it", - "yuoia.com", - "yuurok.com", - "yxdad.ru", - "yxdad.store", - "yxzx.net", - "yyolf.net", - "z-o-e-v-a.ru", - "z0d.eu", - "z1p.biz", - "z86.ru", - "zain.site", - "zainmax.net", - "zaktouni.fr", - "zarabotokdoma11.ru", - "zasod.com", - "zaym-zaym.ru", - "zcovz.ru", - "zcovz.store", - "zcrcd.com", - "zdenka.net", - "ze.tc", - "zebins.com", - "zebins.eu", - "zehnminuten.de", - "zehnminutenmail.de", - "zemzar.net", - "zepp.dk", - "zetmail.com", - "zfymail.com", - "zhaoqian.ninja", - "zhaoyuanedu.cn", - "zhcne.com", - "zhewei88.com", - "zhorachu.com", - "zik.dj", - "zipcad.com", - "zipcatfish.com", - "zipo1.gq", - "zippymail.info", - "zipsendtest.com", - "ziragold.com", - "zoaxe.com", - "zoemail.com", - "zoemail.net", - "zoemail.org", - "zoetropes.org", - "zombie-hive.com", - "zomg.info", - "zsero.com", - "zumpul.com", - "zv68.com", - "zxcv.com", - "zxcvbnm.com", - "zymuying.com", - "zzi.us", - "zzrgg.com", - "zzz.com", - } -}) diff --git a/modules/setting/f3.go b/modules/setting/f3.go index 31d12294b8..8669b70562 100644 --- a/modules/setting/f3.go +++ b/modules/setting/f3.go @@ -3,7 +3,7 @@ package setting import ( - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // Friendly Forge Format (F3) settings diff --git a/modules/setting/federation.go b/modules/setting/federation.go index 510ac128ee..2bea900633 100644 --- a/modules/setting/federation.go +++ b/modules/setting/federation.go @@ -4,9 +4,9 @@ package setting import ( - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" - "github.com/42wim/httpsig" + "github.com/go-fed/httpsig" ) // Federation settings @@ -15,20 +15,18 @@ var ( Enabled bool ShareUserStatistics bool MaxSize int64 - SignatureAlgorithms []string + Algorithms []string DigestAlgorithm string GetHeaders []string PostHeaders []string - SignatureEnforced bool }{ Enabled: false, ShareUserStatistics: true, MaxSize: 4, - SignatureAlgorithms: []string{"rsa-sha256", "rsa-sha512", "ed25519"}, + Algorithms: []string{"rsa-sha256", "rsa-sha512", "ed25519"}, DigestAlgorithm: "SHA-256", - GetHeaders: []string{"(request-target)", "Date", "Host"}, - PostHeaders: []string{"(request-target)", "Date", "Host", "Digest"}, - SignatureEnforced: true, + GetHeaders: []string{"(request-target)", "Date"}, + PostHeaders: []string{"(request-target)", "Date", "Digest"}, } ) @@ -46,8 +44,8 @@ func loadFederationFrom(rootCfg ConfigProvider) { // Get MaxSize in bytes instead of MiB Federation.MaxSize = 1 << 20 * Federation.MaxSize - HttpsigAlgs = make([]httpsig.Algorithm, len(Federation.SignatureAlgorithms)) - for i, alg := range Federation.SignatureAlgorithms { + HttpsigAlgs = make([]httpsig.Algorithm, len(Federation.Algorithms)) + for i, alg := range Federation.Algorithms { HttpsigAlgs[i] = httpsig.Algorithm(alg) } } diff --git a/modules/setting/forgejo_storage_test.go b/modules/setting/forgejo_storage_test.go index 42c46beb77..9071067cde 100644 --- a/modules/setting/forgejo_storage_test.go +++ b/modules/setting/forgejo_storage_test.go @@ -14,7 +14,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestForgejoDocs_StorageTypes(t *testing.T) { @@ -257,8 +256,8 @@ STORAGE_TYPE = %s func testStoragePathMatch(t *testing.T, iniStr string, storageType StorageType, testSectionToPath testSectionToPathFun, section string, storage **Storage) { cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err, iniStr) - require.NoError(t, loadCommonSettingsFrom(cfg), iniStr) - assert.Equal(t, testSectionToPath(storageType, section), testStorageGetPath(*storage), iniStr) - assert.Equal(t, storageType, (*storage).Type, iniStr) + assert.NoError(t, err, iniStr) + assert.NoError(t, loadCommonSettingsFrom(cfg), iniStr) + assert.EqualValues(t, testSectionToPath(storageType, section), testStorageGetPath(*storage), iniStr) + assert.EqualValues(t, storageType, (*storage).Type, iniStr) } diff --git a/modules/setting/git.go b/modules/setting/git.go index f35592a924..48a4e7f30d 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // Git settings @@ -37,7 +37,6 @@ var Git = struct { Clone int Pull int GC int `ini:"GC"` - Grep int } `ini:"git.timeout"` }{ DisableDiffHighlight: false, @@ -60,7 +59,6 @@ var Git = struct { Clone int Pull int GC int `ini:"GC"` - Grep int }{ Default: 360, Migrate: 600, @@ -68,7 +66,6 @@ var Git = struct { Clone: 300, Pull: 300, GC: 60, - Grep: 2, }, } diff --git a/modules/setting/git_test.go b/modules/setting/git_test.go index 5604151907..441c514d8c 100644 --- a/modules/setting/git_test.go +++ b/modules/setting/git_test.go @@ -6,45 +6,50 @@ package setting import ( "testing" - "forgejo.org/modules/test" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestGitConfig(t *testing.T) { - defer test.MockProtect(&Git)() - defer test.MockProtect(&GitConfig)() + oldGit := Git + oldGitConfig := GitConfig + defer func() { + Git = oldGit + GitConfig = oldGitConfig + }() cfg, err := NewConfigProviderFromData(` [git.config] a.b = 1 `) - require.NoError(t, err) + assert.NoError(t, err) loadGitFrom(cfg) - assert.Equal(t, "1", GitConfig.Options["a.b"]) - assert.Equal(t, "histogram", GitConfig.Options["diff.algorithm"]) + assert.EqualValues(t, "1", GitConfig.Options["a.b"]) + assert.EqualValues(t, "histogram", GitConfig.Options["diff.algorithm"]) cfg, err = NewConfigProviderFromData(` [git.config] diff.algorithm = other `) - require.NoError(t, err) + assert.NoError(t, err) loadGitFrom(cfg) - assert.Equal(t, "other", GitConfig.Options["diff.algorithm"]) + assert.EqualValues(t, "other", GitConfig.Options["diff.algorithm"]) } func TestGitReflog(t *testing.T) { - defer test.MockProtect(&Git)() - defer test.MockProtect(&GitConfig)() + oldGit := Git + oldGitConfig := GitConfig + defer func() { + Git = oldGit + GitConfig = oldGitConfig + }() // default reflog config without legacy options cfg, err := NewConfigProviderFromData(``) - require.NoError(t, err) + assert.NoError(t, err) loadGitFrom(cfg) - assert.Equal(t, "true", GitConfig.GetOption("core.logAllRefUpdates")) - assert.Equal(t, "90", GitConfig.GetOption("gc.reflogExpire")) + assert.EqualValues(t, "true", GitConfig.GetOption("core.logAllRefUpdates")) + assert.EqualValues(t, "90", GitConfig.GetOption("gc.reflogExpire")) // custom reflog config by legacy options cfg, err = NewConfigProviderFromData(` @@ -52,9 +57,9 @@ func TestGitReflog(t *testing.T) { ENABLED = false EXPIRATION = 123 `) - require.NoError(t, err) + assert.NoError(t, err) loadGitFrom(cfg) - assert.Equal(t, "false", GitConfig.GetOption("core.logAllRefUpdates")) - assert.Equal(t, "123", GitConfig.GetOption("gc.reflogExpire")) + assert.EqualValues(t, "false", GitConfig.GetOption("core.logAllRefUpdates")) + assert.EqualValues(t, "123", GitConfig.GetOption("gc.reflogExpire")) } diff --git a/modules/setting/i18n.go b/modules/setting/i18n.go index a400cf844c..889e52beb6 100644 --- a/modules/setting/i18n.go +++ b/modules/setting/i18n.go @@ -9,9 +9,7 @@ var defaultI18nLangNames = []string{ "zh-CN", "简体中文", "zh-HK", "繁體中文(香港)", "zh-TW", "繁體中文(台灣)", - "da", "Dansk", "de-DE", "Deutsch", - "nds", "Plattdüütsch", "fr-FR", "Français", "nl-NL", "Nederlands", "lv-LV", "Latviešu", diff --git a/modules/setting/incoming_email.go b/modules/setting/incoming_email.go index e592220de6..287e72941c 100644 --- a/modules/setting/incoming_email.go +++ b/modules/setting/incoming_email.go @@ -4,12 +4,11 @@ package setting import ( - "errors" "fmt" "net/mail" "strings" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) var IncomingEmail = struct { @@ -69,7 +68,7 @@ func checkReplyToAddress() error { } if parsed.Name != "" { - return errors.New("name must not be set") + return fmt.Errorf("name must not be set") } c := strings.Count(IncomingEmail.ReplyToAddress, IncomingEmail.TokenPlaceholder) diff --git a/modules/setting/incoming_email_test.go b/modules/setting/incoming_email_test.go index 6d181cae3c..0fdd44d333 100644 --- a/modules/setting/incoming_email_test.go +++ b/modules/setting/incoming_email_test.go @@ -31,8 +31,8 @@ func Test_loadIncomingEmailFrom(t *testing.T) { loadIncomingEmailFrom(cfg) - assert.Equal(t, "jane.doe@example.com", IncomingEmail.Username) - assert.Equal(t, "y0u'll n3v3r gUess th1S!!1", IncomingEmail.Password) + assert.EqualValues(t, "jane.doe@example.com", IncomingEmail.Username) + assert.EqualValues(t, "y0u'll n3v3r gUess th1S!!1", IncomingEmail.Password) }) t.Run("Port settings", func(t *testing.T) { @@ -45,7 +45,7 @@ func Test_loadIncomingEmailFrom(t *testing.T) { loadIncomingEmailFrom(cfg) - assert.Equal(t, 143, IncomingEmail.Port) + assert.EqualValues(t, 143, IncomingEmail.Port) }) t.Run("no port, with tls", func(t *testing.T) { @@ -56,7 +56,7 @@ func Test_loadIncomingEmailFrom(t *testing.T) { loadIncomingEmailFrom(cfg) - assert.Equal(t, 993, IncomingEmail.Port) + assert.EqualValues(t, 993, IncomingEmail.Port) }) t.Run("port overrides tls", func(t *testing.T) { @@ -68,7 +68,7 @@ func Test_loadIncomingEmailFrom(t *testing.T) { loadIncomingEmailFrom(cfg) - assert.Equal(t, 1993, IncomingEmail.Port) + assert.EqualValues(t, 1993, IncomingEmail.Port) }) }) } diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index 6a464ee0de..3c96b58740 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" "github.com/gobwas/glob" ) @@ -109,7 +109,7 @@ func IndexerGlobFromString(globstr string) []Glob { expr = strings.TrimSpace(expr) if expr != "" { if g, err := glob.Compile(expr, '.', '/'); err != nil { - log.Warn("Invalid glob expression '%s' (skipped): %v", expr, err) + log.Info("Invalid glob expression '%s' (skipped): %v", expr, err) } else { extarr = append(extarr, Glob{glob: g, pattern: expr}) } diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index 452bfae737..750101747f 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -7,35 +7,25 @@ import ( "fmt" "time" - "forgejo.org/modules/generate" + "code.gitea.io/gitea/modules/generate" ) -// LFS represents the server-side configuration for Git LFS. -// Ideally these options should be in a section like "[lfs_server]", -// but they are in "[server]" section due to historical reasons. -// Could be refactored in the future while keeping backwards compatibility. +// LFS represents the configuration for Git LFS var LFS = struct { StartServer bool `ini:"LFS_START_SERVER"` JWTSecretBytes []byte `ini:"-"` HTTPAuthExpiry time.Duration `ini:"LFS_HTTP_AUTH_EXPIRY"` MaxFileSize int64 `ini:"LFS_MAX_FILE_SIZE"` LocksPagingNum int `ini:"LFS_LOCKS_PAGING_NUM"` - MaxBatchSize int `ini:"LFS_MAX_BATCH_SIZE"` Storage *Storage }{} -// LFSClient represents configuration for Gitea's LFS clients, for example: mirroring upstream Git LFS -var LFSClient = struct { - BatchSize int `ini:"BATCH_SIZE"` - BatchOperationConcurrency int `ini:"BATCH_OPERATION_CONCURRENCY"` -}{} - func loadLFSFrom(rootCfg ConfigProvider) error { - mustMapSetting(rootCfg, "lfs_client", &LFSClient) - - mustMapSetting(rootCfg, "server", &LFS) sec := rootCfg.Section("server") + if err := sec.MapTo(&LFS); err != nil { + return fmt.Errorf("failed to map LFS settings: %v", err) + } lfsSec, _ := rootCfg.GetSection("lfs") @@ -62,15 +52,6 @@ func loadLFSFrom(rootCfg ConfigProvider) error { LFS.LocksPagingNum = 50 } - if LFSClient.BatchSize < 1 { - LFSClient.BatchSize = 20 - } - - if LFSClient.BatchOperationConcurrency < 1 { - // match the default git-lfs's `lfs.concurrenttransfers` https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-config.adoc#upload-and-download-transfer-settings - LFSClient.BatchOperationConcurrency = 8 - } - LFS.HTTPAuthExpiry = sec.Key("LFS_HTTP_AUTH_EXPIRY").MustDuration(24 * time.Hour) if !LFS.StartServer || !InstallLock { @@ -80,7 +61,10 @@ func loadLFSFrom(rootCfg ConfigProvider) error { jwtSecretBase64 := loadSecret(rootCfg.Section("server"), "LFS_JWT_SECRET_URI", "LFS_JWT_SECRET") LFS.JWTSecretBytes, err = generate.DecodeJwtSecret(jwtSecretBase64) if err != nil { - LFS.JWTSecretBytes, jwtSecretBase64 = generate.NewJwtSecret() + LFS.JWTSecretBytes, jwtSecretBase64, err = generate.NewJwtSecret() + if err != nil { + return fmt.Errorf("error generating JWT Secret for custom config: %v", err) + } // Save secret saveCfg, err := rootCfg.PrepareSaving() diff --git a/modules/setting/lfs_test.go b/modules/setting/lfs_test.go index 0abf401fa0..10c54fec0a 100644 --- a/modules/setting/lfs_test.go +++ b/modules/setting/lfs_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_getStorageInheritNameSectionTypeForLFS(t *testing.T) { @@ -16,11 +15,11 @@ func Test_getStorageInheritNameSectionTypeForLFS(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "minio", LFS.Storage.Type) - assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath) iniStr = ` [server] @@ -29,8 +28,8 @@ LFS_CONTENT_PATH = path_ignored PATH = path_used ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "local", LFS.Storage.Type) assert.Contains(t, LFS.Storage.Path, "path_used") @@ -40,8 +39,8 @@ PATH = path_used LFS_CONTENT_PATH = deprecatedpath ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "local", LFS.Storage.Type) assert.Contains(t, LFS.Storage.Path, "deprecatedpath") @@ -51,11 +50,11 @@ LFS_CONTENT_PATH = deprecatedpath STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "minio", LFS.Storage.Type) - assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath) iniStr = ` [lfs] @@ -65,11 +64,11 @@ STORAGE_TYPE = my_minio STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "minio", LFS.Storage.Type) - assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath) iniStr = ` [lfs] @@ -80,11 +79,11 @@ MINIO_BASE_PATH = my_lfs/ STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "minio", LFS.Storage.Type) - assert.Equal(t, "my_lfs/", LFS.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "my_lfs/", LFS.Storage.MinioConfig.BasePath) } func Test_LFSStorage1(t *testing.T) { @@ -93,39 +92,10 @@ func Test_LFSStorage1(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) + assert.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "minio", LFS.Storage.Type) - assert.Equal(t, "gitea", LFS.Storage.MinioConfig.Bucket) - assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath) -} - -func Test_LFSClientServerConfigs(t *testing.T) { - iniStr := ` -[server] -LFS_MAX_BATCH_SIZE = 100 -[lfs_client] -# will default to 20 -BATCH_SIZE = 0 -` - cfg, err := NewConfigProviderFromData(iniStr) - assert.NoError(t, err) - - assert.NoError(t, loadLFSFrom(cfg)) - assert.Equal(t, 100, LFS.MaxBatchSize) - assert.Equal(t, 20, LFSClient.BatchSize) - assert.Equal(t, 8, LFSClient.BatchOperationConcurrency) - - iniStr = ` -[lfs_client] -BATCH_SIZE = 50 -BATCH_OPERATION_CONCURRENCY = 10 -` - cfg, err = NewConfigProviderFromData(iniStr) - assert.NoError(t, err) - - assert.NoError(t, loadLFSFrom(cfg)) - assert.Equal(t, 50, LFSClient.BatchSize) - assert.Equal(t, 10, LFSClient.BatchOperationConcurrency) + assert.EqualValues(t, "gitea", LFS.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath) } diff --git a/modules/setting/log.go b/modules/setting/log.go index 0747ac4dac..e404074b72 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -11,8 +11,8 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/log" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) type LogGlobalConfig struct { @@ -133,25 +133,18 @@ func loadLogModeByName(rootCfg ConfigProvider, loggerName, modeName string) (wri writerMode.StacktraceLevel = log.LevelFromString(ConfigInheritedKeyString(sec, "STACKTRACE_LEVEL", Log.StacktraceLogLevel.String())) writerMode.Prefix = ConfigInheritedKeyString(sec, "PREFIX") writerMode.Expression = ConfigInheritedKeyString(sec, "EXPRESSION") - // flags are updated and set below + writerMode.Flags = log.FlagsFromString(ConfigInheritedKeyString(sec, "FLAGS", defaultFlags)) switch writerType { case "console": - // if stderr is on journald, prefer stderr by default - useStderr := ConfigInheritedKey(sec, "STDERR").MustBool(log.JournaldOnStderr) + useStderr := ConfigInheritedKey(sec, "STDERR").MustBool(false) defaultCanColor := log.CanColorStdout - defaultJournald := log.JournaldOnStdout if useStderr { defaultCanColor = log.CanColorStderr - defaultJournald = log.JournaldOnStderr } writerOption := log.WriterConsoleOption{Stderr: useStderr} writerMode.Colorize = ConfigInheritedKey(sec, "COLORIZE").MustBool(defaultCanColor) writerMode.WriterOption = writerOption - // if we are ultimately on journald, update default flags - if defaultJournald { - defaultFlags = "journaldflags" - } case "file": fileName := LogPrepareFilenameForWriter(ConfigInheritedKey(sec, "FILE_NAME").String(), defaultFilaName) writerOption := log.WriterFileOption{} @@ -176,9 +169,6 @@ func loadLogModeByName(rootCfg ConfigProvider, loggerName, modeName string) (wri } } - // set flags last because the console writer code may update default flags - writerMode.Flags = log.FlagsFromString(ConfigInheritedKeyString(sec, "FLAGS", defaultFlags)) - return writerName, writerType, writerMode, nil } diff --git a/modules/setting/log_test.go b/modules/setting/log_test.go index eda6dc36af..87b14f0b1d 100644 --- a/modules/setting/log_test.go +++ b/modules/setting/log_test.go @@ -8,9 +8,10 @@ import ( "strings" "testing" - "forgejo.org/modules/json" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -22,7 +23,7 @@ func initLoggersByConfig(t *testing.T, config string) (*log.LoggerManager, func( }() cfg, err := NewConfigProviderFromData(config) - require.NoError(t, err) + assert.NoError(t, err) manager := log.NewManager() initManagedLoggers(manager, cfg) diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index 9c004c6ce0..cfedb4613f 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -8,10 +8,9 @@ import ( "net" "net/mail" "strings" - "text/template" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" shellquote "github.com/kballard/go-shellquote" ) @@ -47,10 +46,6 @@ type Mailer struct { SendmailArgs []string `ini:"-"` SendmailTimeout time.Duration `ini:"SENDMAIL_TIMEOUT"` SendmailConvertCRLF bool `ini:"SENDMAIL_CONVERT_CRLF"` - - // Customization - FromDisplayNameFormat string `ini:"FROM_DISPLAY_NAME_FORMAT"` - FromDisplayNameFormatTemplate *template.Template `ini:"-"` } // MailService the global mailer @@ -215,11 +210,6 @@ func loadMailerFrom(rootCfg ConfigProvider) { if err != nil { log.Error("Failed to parse Sendmail args: '%s' with error %v", sec.Key("SENDMAIL_ARGS").String(), err) } - - if len(MailService.SendmailArgs) == 0 || MailService.SendmailArgs[len(MailService.SendmailArgs)-1] != "--" { - log.Warn("SENDMAIL_ARGS setting does not end in \"--\", appending it to prevent argument injection") - MailService.SendmailArgs = append(MailService.SendmailArgs, "--") - } case "smtp", "smtps", "smtp+starttls", "smtp+unix": ips := tryResolveAddr(MailService.SMTPAddr) if MailService.Protocol == "smtp" { @@ -244,16 +234,6 @@ func loadMailerFrom(rootCfg ConfigProvider) { log.Error("no mailer.FROM provided, email system may not work.") } - MailService.FromDisplayNameFormatTemplate, _ = template.New("mailFrom").Parse("{{ .DisplayName }}") - if MailService.FromDisplayNameFormat != "" { - template, err := template.New("mailFrom").Parse(MailService.FromDisplayNameFormat) - if err != nil { - log.Error("mailer.FROM_DISPLAY_NAME_FORMAT is no valid template: %v", err) - } else { - MailService.FromDisplayNameFormatTemplate = template - } - } - switch MailService.EnvelopeFrom { case "": MailService.OverrideEnvelopeFrom = false @@ -268,6 +248,8 @@ func loadMailerFrom(rootCfg ConfigProvider) { MailService.OverrideEnvelopeFrom = true MailService.EnvelopeFrom = parsed.Address } + + log.Info("Mail Service Enabled") } func loadRegisterMailFrom(rootCfg ConfigProvider) { @@ -278,6 +260,7 @@ func loadRegisterMailFrom(rootCfg ConfigProvider) { return } Service.RegisterEmailConfirm = true + log.Info("Register Mail Service Enabled") } func loadNotifyMailFrom(rootCfg ConfigProvider) { @@ -288,6 +271,7 @@ func loadNotifyMailFrom(rootCfg ConfigProvider) { return } Service.EnableNotifyMail = true + log.Info("Notify Mail Service Enabled") } func tryResolveAddr(addr string) []net.IPAddr { diff --git a/modules/setting/mailer_test.go b/modules/setting/mailer_test.go index 4523cc91dd..f8af4a78c1 100644 --- a/modules/setting/mailer_test.go +++ b/modules/setting/mailer_test.go @@ -34,8 +34,8 @@ func Test_loadMailerFrom(t *testing.T) { // Check mailer setting loadMailerFrom(cfg) - assert.Equal(t, kase.SMTPAddr, MailService.SMTPAddr) - assert.Equal(t, kase.SMTPPort, MailService.SMTPPort) + assert.EqualValues(t, kase.SMTPAddr, MailService.SMTPAddr) + assert.EqualValues(t, kase.SMTPPort, MailService.SMTPPort) }) } @@ -48,31 +48,7 @@ func Test_loadMailerFrom(t *testing.T) { loadMailerFrom(cfg) - assert.Equal(t, "jane.doe@example.com", MailService.User) - assert.Equal(t, "y0u'll n3v3r gUess th1S!!1", MailService.Passwd) - }) - - t.Run("sendmail argument sanitization", func(t *testing.T) { - cfg, _ := NewConfigProviderFromData("") - sec := cfg.Section("mailer") - sec.NewKey("ENABLED", "true") - sec.NewKey("PROTOCOL", "sendmail") - sec.NewKey("SENDMAIL_ARGS", "-B 8BITMIME") - - loadMailerFrom(cfg) - - assert.Equal(t, []string{"-B", "8BITMIME", "--"}, MailService.SendmailArgs) - }) - - t.Run("empty sendmail args", func(t *testing.T) { - cfg, _ := NewConfigProviderFromData("") - sec := cfg.Section("mailer") - sec.NewKey("ENABLED", "true") - sec.NewKey("PROTOCOL", "sendmail") - sec.NewKey("SENDMAIL_ARGS", "") - - loadMailerFrom(cfg) - - assert.Equal(t, []string{"--"}, MailService.SendmailArgs) + assert.EqualValues(t, "jane.doe@example.com", MailService.User) + assert.EqualValues(t, "y0u'll n3v3r gUess th1S!!1", MailService.Passwd) }) } diff --git a/modules/setting/markup.go b/modules/setting/markup.go index 4ab9e7b2d1..e893c1c2f1 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -7,7 +7,7 @@ import ( "regexp" "strings" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // ExternalMarkupRenderers represents the external markup renderers @@ -62,7 +62,7 @@ type MarkupSanitizerRule struct { func loadMarkupFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "markdown", &Markdown) - MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(50000) + MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000) FilePreviewMaxLines = rootCfg.Section("markup").Key("FILEPREVIEW_MAX_LINES").MustInt(50) ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10) ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, 10) diff --git a/modules/setting/mirror.go b/modules/setting/mirror.go index 58c57c5c95..3aa530a1f4 100644 --- a/modules/setting/mirror.go +++ b/modules/setting/mirror.go @@ -6,7 +6,7 @@ package setting import ( "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // Mirror settings diff --git a/modules/setting/moderation.go b/modules/setting/moderation.go deleted file mode 100644 index 5f35a284d6..0000000000 --- a/modules/setting/moderation.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package setting - -// Moderation settings -var Moderation = struct { - Enabled bool `ini:"ENABLED"` -}{ - Enabled: false, -} - -func loadModerationFrom(rootCfg ConfigProvider) { - mustMapSetting(rootCfg, "moderation", &Moderation) -} diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 9e95e1c6a9..76820adff0 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -8,8 +8,8 @@ import ( "path/filepath" "sync/atomic" - "forgejo.org/modules/generate" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/generate" + "code.gitea.io/gitea/modules/log" ) // OAuth2UsernameType is enum describing the way gitea 'name' should be generated from oauth2 data @@ -92,25 +92,23 @@ func parseScopes(sec ConfigSection, name string) []string { } var OAuth2 = struct { - Enabled bool - AccessTokenExpirationTime int64 - RefreshTokenExpirationTime int64 - InvalidateRefreshTokens bool - JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"` - JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"` - MaxTokenLength int - DefaultApplications []string - EnableAdditionalGrantScopes bool + Enabled bool + AccessTokenExpirationTime int64 + RefreshTokenExpirationTime int64 + InvalidateRefreshTokens bool + JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"` + JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"` + MaxTokenLength int + DefaultApplications []string }{ - Enabled: true, - AccessTokenExpirationTime: 3600, - RefreshTokenExpirationTime: 730, - InvalidateRefreshTokens: true, - JWTSigningAlgorithm: "RS256", - JWTSigningPrivateKeyFile: "jwt/private.pem", - MaxTokenLength: math.MaxInt16, - DefaultApplications: []string{"git-credential-oauth", "git-credential-manager", "tea"}, - EnableAdditionalGrantScopes: false, + Enabled: true, + AccessTokenExpirationTime: 3600, + RefreshTokenExpirationTime: 730, + InvalidateRefreshTokens: false, + JWTSigningAlgorithm: "RS256", + JWTSigningPrivateKeyFile: "jwt/private.pem", + MaxTokenLength: math.MaxInt16, + DefaultApplications: []string{"git-credential-oauth", "git-credential-manager", "tea"}, } func loadOAuth2From(rootCfg ConfigProvider) { @@ -138,7 +136,10 @@ func loadOAuth2From(rootCfg ConfigProvider) { if InstallLock { jwtSecretBytes, err := generate.DecodeJwtSecret(jwtSecretBase64) if err != nil { - jwtSecretBytes, jwtSecretBase64 = generate.NewJwtSecret() + jwtSecretBytes, jwtSecretBase64, err = generate.NewJwtSecret() + if err != nil { + log.Fatal("error generating JWT secret: %v", err) + } saveCfg, err := rootCfg.PrepareSaving() if err != nil { log.Fatal("save oauth2.JWT_SECRET failed: %v", err) @@ -158,7 +159,10 @@ var generalSigningSecret atomic.Pointer[[]byte] func GetGeneralTokenSigningSecret() []byte { old := generalSigningSecret.Load() if old == nil || len(*old) == 0 { - jwtSecret, _ := generate.NewJwtSecret() + jwtSecret, _, err := generate.NewJwtSecret() + if err != nil { + log.Fatal("Unable to generate general JWT secret: %v", err) + } if generalSigningSecret.CompareAndSwap(old, &jwtSecret) { return jwtSecret } diff --git a/modules/setting/oauth2_test.go b/modules/setting/oauth2_test.go index 7a1f4842a4..1951c4c0a2 100644 --- a/modules/setting/oauth2_test.go +++ b/modules/setting/oauth2_test.go @@ -7,11 +7,10 @@ import ( "os" "testing" - "forgejo.org/modules/generate" - "forgejo.org/modules/test" + "code.gitea.io/gitea/modules/generate" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestGetGeneralSigningSecret(t *testing.T) { @@ -32,7 +31,7 @@ JWT_SECRET = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB actual := GetGeneralTokenSigningSecret() expected, _ := generate.DecodeJwtSecret("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB") assert.Len(t, actual, 32) - assert.Equal(t, expected, actual) + assert.EqualValues(t, expected, actual) } func TestGetGeneralSigningSecretSave(t *testing.T) { @@ -56,6 +55,6 @@ func TestGetGeneralSigningSecretSave(t *testing.T) { assert.Equal(t, generated, again) iniContent, err := os.ReadFile(tmpFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Contains(t, string(iniContent), "JWT_SECRET = ") } diff --git a/modules/setting/other.go b/modules/setting/other.go index db60cd2205..4ba494765b 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -3,7 +3,7 @@ package setting -import "forgejo.org/modules/log" +import "code.gitea.io/gitea/modules/log" type OtherConfig struct { ShowFooterVersion bool diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 87e41fb5a0..b225615a24 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -21,32 +21,29 @@ var ( ChunkedUploadPath string RegistryHost string - LimitTotalOwnerCount int64 - LimitTotalOwnerSize int64 - LimitSizeAlpine int64 - LimitSizeArch int64 - LimitSizeCargo int64 - LimitSizeChef int64 - LimitSizeComposer int64 - LimitSizeConan int64 - LimitSizeConda int64 - LimitSizeContainer int64 - LimitSizeCran int64 - LimitSizeDebian int64 - LimitSizeGeneric int64 - LimitSizeGo int64 - LimitSizeHelm int64 - LimitSizeMaven int64 - LimitSizeNpm int64 - LimitSizeNuGet int64 - LimitSizePub int64 - LimitSizePyPI int64 - LimitSizeRpm int64 - LimitSizeAlt int64 - LimitSizeRubyGems int64 - LimitSizeSwift int64 - LimitSizeVagrant int64 - DefaultRPMSignEnabled bool + LimitTotalOwnerCount int64 + LimitTotalOwnerSize int64 + LimitSizeAlpine int64 + LimitSizeCargo int64 + LimitSizeChef int64 + LimitSizeComposer int64 + LimitSizeConan int64 + LimitSizeConda int64 + LimitSizeContainer int64 + LimitSizeCran int64 + LimitSizeDebian int64 + LimitSizeGeneric int64 + LimitSizeGo int64 + LimitSizeHelm int64 + LimitSizeMaven int64 + LimitSizeNpm int64 + LimitSizeNuGet int64 + LimitSizePub int64 + LimitSizePyPI int64 + LimitSizeRpm int64 + LimitSizeRubyGems int64 + LimitSizeSwift int64 + LimitSizeVagrant int64 }{ Enabled: true, LimitTotalOwnerCount: -1, @@ -85,7 +82,6 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) { Packages.LimitTotalOwnerSize = mustBytes(sec, "LIMIT_TOTAL_OWNER_SIZE") Packages.LimitSizeAlpine = mustBytes(sec, "LIMIT_SIZE_ALPINE") - Packages.LimitSizeArch = mustBytes(sec, "LIMIT_SIZE_ARCH") Packages.LimitSizeCargo = mustBytes(sec, "LIMIT_SIZE_CARGO") Packages.LimitSizeChef = mustBytes(sec, "LIMIT_SIZE_CHEF") Packages.LimitSizeComposer = mustBytes(sec, "LIMIT_SIZE_COMPOSER") @@ -106,8 +102,6 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) { Packages.LimitSizeRubyGems = mustBytes(sec, "LIMIT_SIZE_RUBYGEMS") Packages.LimitSizeSwift = mustBytes(sec, "LIMIT_SIZE_SWIFT") Packages.LimitSizeVagrant = mustBytes(sec, "LIMIT_SIZE_VAGRANT") - Packages.DefaultRPMSignEnabled = sec.Key("DEFAULT_RPM_SIGN_ENABLED").MustBool(false) - Packages.LimitSizeAlt = mustBytes(sec, "LIMIT_SIZE_ALT") return nil } diff --git a/modules/setting/packages_test.go b/modules/setting/packages_test.go index 85a4656da0..87de276041 100644 --- a/modules/setting/packages_test.go +++ b/modules/setting/packages_test.go @@ -7,13 +7,12 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMustBytes(t *testing.T) { test := func(value string) int64 { cfg, err := NewConfigProviderFromData("[test]") - require.NoError(t, err) + assert.NoError(t, err) sec := cfg.Section("test") sec.NewKey("VALUE", value) @@ -38,11 +37,11 @@ func Test_getStorageInheritNameSectionTypeForPackages(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadPackagesFrom(cfg)) assert.EqualValues(t, "minio", Packages.Storage.Type) - assert.Equal(t, "packages/", Packages.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "packages/", Packages.Storage.MinioConfig.BasePath) // we can also configure packages storage directly iniStr = ` @@ -50,11 +49,11 @@ STORAGE_TYPE = minio STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadPackagesFrom(cfg)) assert.EqualValues(t, "minio", Packages.Storage.Type) - assert.Equal(t, "packages/", Packages.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "packages/", Packages.Storage.MinioConfig.BasePath) // or we can indicate the storage type in the packages section iniStr = ` @@ -65,11 +64,11 @@ STORAGE_TYPE = my_minio STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadPackagesFrom(cfg)) assert.EqualValues(t, "minio", Packages.Storage.Type) - assert.Equal(t, "packages/", Packages.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "packages/", Packages.Storage.MinioConfig.BasePath) // or we can indicate the storage type and minio base path in the packages section iniStr = ` @@ -81,11 +80,11 @@ MINIO_BASE_PATH = my_packages/ STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadPackagesFrom(cfg)) assert.EqualValues(t, "minio", Packages.Storage.Type) - assert.Equal(t, "my_packages/", Packages.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "my_packages/", Packages.Storage.MinioConfig.BasePath) } func Test_PackageStorage1(t *testing.T) { @@ -104,14 +103,14 @@ MINIO_ACCESS_KEY_ID = correct_key MINIO_SECRET_ACCESS_KEY = correct_key ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, loadPackagesFrom(cfg)) storage := Packages.Storage assert.EqualValues(t, "minio", storage.Type) - assert.Equal(t, "gitea", storage.MinioConfig.Bucket) - assert.Equal(t, "packages/", storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", storage.MinioConfig.Bucket) + assert.EqualValues(t, "packages/", storage.MinioConfig.BasePath) assert.True(t, storage.MinioConfig.ServeDirect) } @@ -131,14 +130,14 @@ MINIO_ACCESS_KEY_ID = correct_key MINIO_SECRET_ACCESS_KEY = correct_key ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, loadPackagesFrom(cfg)) storage := Packages.Storage assert.EqualValues(t, "minio", storage.Type) - assert.Equal(t, "gitea", storage.MinioConfig.Bucket) - assert.Equal(t, "packages/", storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", storage.MinioConfig.Bucket) + assert.EqualValues(t, "packages/", storage.MinioConfig.BasePath) assert.True(t, storage.MinioConfig.ServeDirect) } @@ -159,14 +158,14 @@ MINIO_ACCESS_KEY_ID = correct_key MINIO_SECRET_ACCESS_KEY = correct_key ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, loadPackagesFrom(cfg)) storage := Packages.Storage assert.EqualValues(t, "minio", storage.Type) - assert.Equal(t, "gitea", storage.MinioConfig.Bucket) - assert.Equal(t, "my_packages/", storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", storage.MinioConfig.Bucket) + assert.EqualValues(t, "my_packages/", storage.MinioConfig.BasePath) assert.True(t, storage.MinioConfig.ServeDirect) } @@ -187,13 +186,13 @@ MINIO_ACCESS_KEY_ID = correct_key MINIO_SECRET_ACCESS_KEY = correct_key ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, loadPackagesFrom(cfg)) storage := Packages.Storage assert.EqualValues(t, "minio", storage.Type) - assert.Equal(t, "gitea", storage.MinioConfig.Bucket) - assert.Equal(t, "my_packages/", storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", storage.MinioConfig.Bucket) + assert.EqualValues(t, "my_packages/", storage.MinioConfig.BasePath) assert.True(t, storage.MinioConfig.ServeDirect) } diff --git a/modules/setting/path.go b/modules/setting/path.go index 33f27db8fd..85d0e06302 100644 --- a/modules/setting/path.go +++ b/modules/setting/path.go @@ -10,7 +10,7 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) var ( @@ -34,7 +34,11 @@ var ( func getAppPath() (string, error) { var appPath string var err error - appPath, err = exec.LookPath(os.Args[0]) + if IsWindows && filepath.IsAbs(os.Args[0]) { + appPath = filepath.Clean(os.Args[0]) + } else { + appPath, err = exec.LookPath(os.Args[0]) + } if err != nil { if !errors.Is(err, exec.ErrDot) { return "", err diff --git a/modules/setting/proxy.go b/modules/setting/proxy.go index 7a9de9568b..4ff420d090 100644 --- a/modules/setting/proxy.go +++ b/modules/setting/proxy.go @@ -6,7 +6,7 @@ package setting import ( "net/url" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // Proxy settings diff --git a/modules/setting/queue.go b/modules/setting/queue.go index 06d007c140..251a6c1e30 100644 --- a/modules/setting/queue.go +++ b/modules/setting/queue.go @@ -7,8 +7,8 @@ import ( "path/filepath" "runtime" - "forgejo.org/modules/json" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" ) // QueueSettings represent the settings for a queue from the ini diff --git a/modules/setting/quota.go b/modules/setting/quota.go deleted file mode 100644 index 05e14baa9c..0000000000 --- a/modules/setting/quota.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package setting - -// Quota settings -var Quota = struct { - Enabled bool `ini:"ENABLED"` - DefaultGroups []string `ini:"DEFAULT_GROUPS"` - - Default struct { - Total int64 - } `ini:"quota.default"` -}{ - Enabled: false, - DefaultGroups: []string{}, - Default: struct { - Total int64 - }{ - Total: -1, - }, -} - -func loadQuotaFrom(rootCfg ConfigProvider) { - mustMapSetting(rootCfg, "quota", &Quota) -} diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 7e774f0139..6086dd1d57 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -1,19 +1,15 @@ // Copyright 2019 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting import ( - "os" "os/exec" "path" "path/filepath" "strings" - "forgejo.org/modules/log" - - "golang.org/x/crypto/ssh" + "code.gitea.io/gitea/modules/log" ) // enumerates all the policy repository creating @@ -30,8 +26,6 @@ var MaxUserCardsPerPage = 36 // MaxForksPerPage sets maximum amount of forks shown per page var MaxForksPerPage = 40 -var SSHInstanceKey ssh.PublicKey - // Repository settings var ( Repository = struct { @@ -53,7 +47,6 @@ var ( DisabledRepoUnits []string DefaultRepoUnits []string DefaultForkRepoUnits []string - DefaultMirrorRepoUnits []string PrefixArchiveFiles bool DisableMigrations bool DisableStars bool @@ -94,9 +87,9 @@ var ( DefaultMergeMessageAllAuthors bool DefaultMergeMessageMaxApprovers int DefaultMergeMessageOfficialApproversOnly bool - DefaultUpdateStyle string PopulateSquashCommentWithCommitMessages bool AddCoCommitterTrailers bool + TestConflictingPatchesWithGitApply bool RetargetChildrenOnMerge bool } `ini:"repository.pull-request"` @@ -115,7 +108,6 @@ var ( SigningKey string SigningName string SigningEmail string - Format string InitialCommit []string CRUDActions []string `ini:"CRUD_ACTIONS"` Merges []string @@ -177,7 +169,6 @@ var ( DisabledRepoUnits: []string{}, DefaultRepoUnits: []string{}, DefaultForkRepoUnits: []string{}, - DefaultMirrorRepoUnits: []string{}, PrefixArchiveFiles: true, DisableMigrations: false, DisableStars: false, @@ -225,9 +216,9 @@ var ( DefaultMergeMessageAllAuthors bool DefaultMergeMessageMaxApprovers int DefaultMergeMessageOfficialApproversOnly bool - DefaultUpdateStyle string PopulateSquashCommentWithCommitMessages bool AddCoCommitterTrailers bool + TestConflictingPatchesWithGitApply bool RetargetChildrenOnMerge bool }{ WorkInProgressPrefixes: []string{"WIP:", "[WIP]"}, @@ -241,7 +232,6 @@ var ( DefaultMergeMessageAllAuthors: false, DefaultMergeMessageMaxApprovers: 10, DefaultMergeMessageOfficialApproversOnly: true, - DefaultUpdateStyle: "merge", PopulateSquashCommentWithCommitMessages: false, AddCoCommitterTrailers: true, RetargetChildrenOnMerge: true, @@ -269,7 +259,6 @@ var ( SigningKey string SigningName string SigningEmail string - Format string InitialCommit []string CRUDActions []string `ini:"CRUD_ACTIONS"` Merges []string @@ -279,7 +268,6 @@ var ( SigningKey: "default", SigningName: "", SigningEmail: "", - Format: "openpgp", InitialCommit: []string{"always"}, CRUDActions: []string{"pubkey", "twofa", "parentsigned"}, Merges: []string{"pubkey", "twofa", "basesigned", "commitssigned"}, @@ -298,7 +286,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) { // Determine and create root git repository path. sec := rootCfg.Section("repository") Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool() - Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool(true) + Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool() Repository.GoGetCloneURLProtocol = sec.Key("GO_GET_CLONE_URL_PROTOCOL").MustString("https") Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1) Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch) @@ -385,15 +373,4 @@ func loadRepositoryFrom(rootCfg ConfigProvider) { log.Fatal("loadRepoArchiveFrom: %v", err) } Repository.EnableFlags = sec.Key("ENABLE_FLAGS").MustBool() - - if Repository.Signing.Format == "ssh" && Repository.Signing.SigningKey != "none" && Repository.Signing.SigningKey != "" { - sshPublicKey, err := os.ReadFile(Repository.Signing.SigningKey) - if err != nil { - log.Fatal("Could not read repository signing key in %q: %v", Repository.Signing.SigningKey, err) - } - SSHInstanceKey, _, _, _, err = ssh.ParseAuthorizedKey(sshPublicKey) - if err != nil { - log.Fatal("Could not parse the SSH signing key %q: %v", sshPublicKey, err) - } - } } diff --git a/modules/setting/repository_archive_test.go b/modules/setting/repository_archive_test.go index cff59f3663..a0f91f0da1 100644 --- a/modules/setting/repository_archive_test.go +++ b/modules/setting/repository_archive_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_getStorageInheritNameSectionTypeForRepoArchive(t *testing.T) { @@ -17,11 +16,11 @@ func Test_getStorageInheritNameSectionTypeForRepoArchive(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadRepoArchiveFrom(cfg)) assert.EqualValues(t, "minio", RepoArchive.Storage.Type) - assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) // we can also configure packages storage directly iniStr = ` @@ -29,11 +28,11 @@ STORAGE_TYPE = minio STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadRepoArchiveFrom(cfg)) assert.EqualValues(t, "minio", RepoArchive.Storage.Type) - assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) // or we can indicate the storage type in the packages section iniStr = ` @@ -44,11 +43,11 @@ STORAGE_TYPE = my_minio STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadRepoArchiveFrom(cfg)) assert.EqualValues(t, "minio", RepoArchive.Storage.Type) - assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) // or we can indicate the storage type and minio base path in the packages section iniStr = ` @@ -60,11 +59,11 @@ MINIO_BASE_PATH = my_archive/ STORAGE_TYPE = minio ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, err) + assert.NoError(t, loadRepoArchiveFrom(cfg)) assert.EqualValues(t, "minio", RepoArchive.Storage.Type) - assert.Equal(t, "my_archive/", RepoArchive.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "my_archive/", RepoArchive.Storage.MinioConfig.BasePath) } func Test_RepoArchiveStorage(t *testing.T) { @@ -80,13 +79,13 @@ MINIO_ACCESS_KEY_ID = correct_key MINIO_SECRET_ACCESS_KEY = correct_key ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, loadRepoArchiveFrom(cfg)) storage := RepoArchive.Storage assert.EqualValues(t, "minio", storage.Type) - assert.Equal(t, "gitea", storage.MinioConfig.Bucket) + assert.EqualValues(t, "gitea", storage.MinioConfig.Bucket) iniStr = ` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -102,11 +101,11 @@ MINIO_ACCESS_KEY_ID = correct_key MINIO_SECRET_ACCESS_KEY = correct_key ` cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, loadRepoArchiveFrom(cfg)) storage = RepoArchive.Storage assert.EqualValues(t, "minio", storage.Type) - assert.Equal(t, "gitea", storage.MinioConfig.Bucket) + assert.EqualValues(t, "gitea", storage.MinioConfig.Bucket) } diff --git a/modules/setting/repository_test.go b/modules/setting/repository_test.go deleted file mode 100644 index d36e739f6b..0000000000 --- a/modules/setting/repository_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package setting - -import ( - "fmt" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "golang.org/x/crypto/ssh" -) - -func TestSSHInstanceKey(t *testing.T) { - sshSigningKeyPath, err := filepath.Abs("../../tests/integration/ssh-signing-key.pub") - require.NoError(t, err) - - t.Run("None value", func(t *testing.T) { - cfg, err := NewConfigProviderFromData(` -[repository.signing] -FORMAT = ssh -SIGNING_KEY = none -`) - require.NoError(t, err) - - loadRepositoryFrom(cfg) - - assert.Nil(t, SSHInstanceKey) - }) - - t.Run("No value", func(t *testing.T) { - cfg, err := NewConfigProviderFromData(` -[repository.signing] -FORMAT = ssh -`) - require.NoError(t, err) - - loadRepositoryFrom(cfg) - - assert.Nil(t, SSHInstanceKey) - }) - t.Run("Normal", func(t *testing.T) { - iniStr := fmt.Sprintf(` -[repository.signing] -FORMAT = ssh -SIGNING_KEY = %s -`, sshSigningKeyPath) - cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - - loadRepositoryFrom(cfg) - - assert.NotNil(t, SSHInstanceKey) - assert.Equal(t, "ssh-ed25519", SSHInstanceKey.Type()) - assert.EqualValues(t, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFeRC8GfFyXtiy0f1E7hLv77BXW7e68tFvIcs8/29YqH\n", ssh.MarshalAuthorizedKey(SSHInstanceKey)) - }) -} diff --git a/modules/setting/security.go b/modules/setting/security.go index f3480d1056..3d7b1f9ce7 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -8,10 +8,9 @@ import ( "os" "strings" - "forgejo.org/modules/auth/password/hash" - "forgejo.org/modules/generate" - "forgejo.org/modules/keying" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/auth/password/hash" + "code.gitea.io/gitea/modules/generate" + "code.gitea.io/gitea/modules/log" ) var ( @@ -111,7 +110,6 @@ func loadSecurityFrom(rootCfg ConfigProvider) { // Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value SecretKey = "!#@FDEWREWR&*(" //nolint:gosec } - keying.Init([]byte(SecretKey)) CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible") diff --git a/modules/setting/server.go b/modules/setting/server.go index 3ff91d2cde..5cc33f6fc4 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -13,11 +13,9 @@ import ( "strings" "time" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/util" - - "github.com/caddyserver/certmagic" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) // Scheme describes protocol types @@ -208,7 +206,7 @@ func loadServerFrom(rootCfg ConfigProvider) { EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) } if EnableAcme { - AcmeURL = sec.Key("ACME_URL").MustString(certmagic.LetsEncryptProductionCA) + AcmeURL = sec.Key("ACME_URL").MustString("") AcmeCARoot = sec.Key("ACME_CA_ROOT").MustString("") if sec.HasKey("ACME_ACCEPTTOS") { @@ -267,7 +265,7 @@ func loadServerFrom(rootCfg ConfigProvider) { } UnixSocketPermission = uint32(UnixSocketPermissionParsed) - if HTTPAddr[0] != '@' && !filepath.IsAbs(HTTPAddr) { + if !filepath.IsAbs(HTTPAddr) { HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr) } } diff --git a/modules/setting/server_test.go b/modules/setting/server_test.go index 3c6faa2311..8db8168854 100644 --- a/modules/setting/server_test.go +++ b/modules/setting/server_test.go @@ -6,10 +6,9 @@ package setting import ( "testing" - "forgejo.org/modules/test" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestDisplayNameDefault(t *testing.T) { @@ -35,54 +34,3 @@ func TestDisplayNameCustomFormat(t *testing.T) { displayName := generateDisplayName() assert.Equal(t, "Forgejo - Beyond coding. We Forge.", displayName) } - -func TestMaxUserRedirectsDefault(t *testing.T) { - iniStr := `` - cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - loadServiceFrom(cfg) - - assert.EqualValues(t, 0, Service.UsernameCooldownPeriod) - assert.EqualValues(t, 0, Service.MaxUserRedirects) - - iniStr = `[service] -MAX_USER_REDIRECTS = 8` - cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - loadServiceFrom(cfg) - - assert.EqualValues(t, 0, Service.UsernameCooldownPeriod) - assert.EqualValues(t, 8, Service.MaxUserRedirects) - - iniStr = `[service] -USERNAME_COOLDOWN_PERIOD = 3` - cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - loadServiceFrom(cfg) - - assert.EqualValues(t, 3, Service.UsernameCooldownPeriod) - assert.EqualValues(t, 5, Service.MaxUserRedirects) - - iniStr = `[service] -USERNAME_COOLDOWN_PERIOD = 3 -MAX_USER_REDIRECTS = 8` - cfg, err = NewConfigProviderFromData(iniStr) - require.NoError(t, err) - loadServiceFrom(cfg) - - assert.EqualValues(t, 3, Service.UsernameCooldownPeriod) - assert.EqualValues(t, 8, Service.MaxUserRedirects) -} - -func TestUnixSocketAbstractNamespace(t *testing.T) { - iniStr := ` - [server] - PROTOCOL=http+unix - HTTP_ADDR=@forgejo - ` - cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - loadServerFrom(cfg) - - assert.Equal(t, "@forgejo", HTTPAddr) -} diff --git a/modules/setting/service.go b/modules/setting/service.go index 5717225578..afaee18101 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -1,18 +1,15 @@ // Copyright 2019 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved // SPDX-License-Identifier: MIT package setting import ( - "net/url" "regexp" - "slices" "strings" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/structs" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/structs" "github.com/gobwas/glob" ) @@ -40,12 +37,10 @@ var Service = struct { RegisterManualConfirm bool EmailDomainAllowList []glob.Glob EmailDomainBlockList []glob.Glob - EmailDomainBlockDisposable bool DisableRegistration bool AllowOnlyInternalRegistration bool AllowOnlyExternalRegistration bool ShowRegistrationButton bool - EnableInternalSignIn bool ShowMilestonesDashboardPage bool RequireSignInView bool EnableNotifyMail bool @@ -87,8 +82,6 @@ var Service = struct { DefaultOrgMemberVisible bool UserDeleteWithCommentsMaxTime time.Duration ValidSiteURLSchemes []string - UsernameCooldownPeriod int64 - MaxUserRedirects int64 // OpenID settings EnableOpenIDSignIn bool @@ -98,10 +91,8 @@ var Service = struct { // Explore page settings Explore struct { - RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` - DisableUsersPage bool `ini:"DISABLE_USERS_PAGE"` - DisableOrganizationsPage bool `ini:"DISABLE_ORGANIZATIONS_PAGE"` - DisableCodePage bool `ini:"DISABLE_CODE_PAGE"` + RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` + DisableUsersPage bool `ini:"DISABLE_USERS_PAGE"` } `ini:"service.explore"` }{ AllowedUserVisibilityModesSlice: []bool{true, true, true}, @@ -142,25 +133,6 @@ func CompileEmailGlobList(sec ConfigSection, keys ...string) (globs []glob.Glob) return globs } -// LoadServiceSetting loads the service settings -func LoadServiceSetting() { - loadServiceFrom(CfgProvider) -} - -func appURLAsGlob(fqdn string) (glob.Glob, error) { - localFqdn, err := url.ParseRequestURI(fqdn) - if err != nil { - log.Error("Error in EmailDomainAllowList: %v", err) - return nil, err - } - appFqdn, err := glob.Compile(localFqdn.Hostname(), ',') - if err != nil { - log.Error("Error in EmailDomainAllowList: %v", err) - return nil, err - } - return appFqdn, nil -} - func loadServiceFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("service") Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) @@ -180,34 +152,9 @@ func loadServiceFrom(rootCfg ConfigProvider) { if sec.HasKey("EMAIL_DOMAIN_WHITELIST") { deprecatedSetting(rootCfg, "service", "EMAIL_DOMAIN_WHITELIST", "service", "EMAIL_DOMAIN_ALLOWLIST", "1.21") } - emailDomainAllowList := CompileEmailGlobList(sec, "EMAIL_DOMAIN_WHITELIST", "EMAIL_DOMAIN_ALLOWLIST") - - if len(emailDomainAllowList) > 0 && Federation.Enabled { - appURL, err := appURLAsGlob(AppURL) - if err == nil { - emailDomainAllowList = append(emailDomainAllowList, appURL) - } - } - Service.EmailDomainAllowList = emailDomainAllowList + Service.EmailDomainAllowList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_WHITELIST", "EMAIL_DOMAIN_ALLOWLIST") Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST") - Service.EmailDomainBlockDisposable = sec.Key("EMAIL_DOMAIN_BLOCK_DISPOSABLE").MustBool(false) - if Service.EmailDomainBlockDisposable { - toAdd := make([]glob.Glob, 0, len(DisposableEmailDomains())) - for _, domain := range DisposableEmailDomains() { - domain = strings.ToLower(domain) - // Only add domains that aren't blocked yet. - if !slices.ContainsFunc(Service.EmailDomainBlockList, func(g glob.Glob) bool { return g.Match(domain) }) { - if g, err := glob.Compile(domain); err != nil { - log.Error("Error in disposable domain %s: %v", domain, err) - } else { - toAdd = append(toAdd, g) - } - } - } - Service.EmailDomainBlockList = append(Service.EmailDomainBlockList, toAdd...) - } - Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration && !Service.AllowOnlyExternalRegistration) - Service.EnableInternalSignIn = sec.Key("ENABLE_INTERNAL_SIGNIN").MustBool(true) + Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration)) Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true) Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true) @@ -288,14 +235,6 @@ func loadServiceFrom(rootCfg ConfigProvider) { } } Service.ValidSiteURLSchemes = schemes - Service.UsernameCooldownPeriod = sec.Key("USERNAME_COOLDOWN_PERIOD").MustInt64(0) - - // Only set a default if USERNAME_COOLDOWN_PERIOD's feature is active. - maxUserRedirectsDefault := int64(0) - if Service.UsernameCooldownPeriod > 0 { - maxUserRedirectsDefault = 5 - } - Service.MaxUserRedirects = sec.Key("MAX_USER_REDIRECTS").MustInt64(maxUserRedirectsDefault) mustMapSetting(rootCfg, "service.explore", &Service.Explore) diff --git a/modules/setting/service_test.go b/modules/setting/service_test.go index 4fc09021b6..1647bcec16 100644 --- a/modules/setting/service_test.go +++ b/modules/setting/service_test.go @@ -4,28 +4,14 @@ package setting import ( - "fmt" - "sort" - "strings" "testing" - "forgejo.org/modules/structs" + "code.gitea.io/gitea/modules/structs" "github.com/gobwas/glob" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "golang.org/x/net/publicsuffix" ) -func match(globs []glob.Glob, s string) bool { - for _, g := range globs { - if g.Match(s) { - return true - } - } - return false -} - func TestLoadServices(t *testing.T) { oldService := Service defer func() { @@ -38,9 +24,18 @@ EMAIL_DOMAIN_WHITELIST = d1, *.w EMAIL_DOMAIN_ALLOWLIST = d2, *.a EMAIL_DOMAIN_BLOCKLIST = d3, *.b `) - require.NoError(t, err) + assert.NoError(t, err) loadServiceFrom(cfg) + match := func(globs []glob.Glob, s string) bool { + for _, g := range globs { + if g.Match(s) { + return true + } + } + return false + } + assert.True(t, match(Service.EmailDomainAllowList, "d1")) assert.True(t, match(Service.EmailDomainAllowList, "foo.w")) assert.True(t, match(Service.EmailDomainAllowList, "d2")) @@ -52,121 +47,6 @@ EMAIL_DOMAIN_BLOCKLIST = d3, *.b assert.False(t, match(Service.EmailDomainBlockList, "d1")) } -func TestLoadServiceBlockDisposable(t *testing.T) { - oldService := Service - defer func() { - Service = oldService - }() - - cfg, err := NewConfigProviderFromData(` -[service] -EMAIL_DOMAIN_BLOCK_DISPOSABLE = true -`) - - require.NoError(t, err) - loadServiceFrom(cfg) - - for _, domain := range DisposableEmailDomains() { - require.True(t, match(Service.EmailDomainBlockList, domain)) - } - - require.Len(t, Service.EmailDomainBlockList, len(DisposableEmailDomains())) - - knownGood := [...]string{ - "aol.com", - "gmx.com", - "mail.com", - "zoho.com", - "proton.me", - "gmail.com", - "yahoo.com", - "icloud.com", - "outlook.com", - "protonmail.com", - } - - for _, domain := range knownGood { - require.False(t, match(Service.EmailDomainBlockList, domain)) - } -} - -func TestLoadServiceBlockDisposableWithExistingGlobs(t *testing.T) { - oldService := Service - defer func() { - Service = oldService - }() - - tldCounts := make(map[string]int) - for _, domain := range DisposableEmailDomains() { - tld, _ := publicsuffix.PublicSuffix(domain) - tldCounts[tld]++ - } - - type tldkv struct { - Tld string - Count int - } - - sortedTldCounts := make([]tldkv, 0) - for tld, count := range tldCounts { - sortedTldCounts = append(sortedTldCounts, tldkv{tld, count}) - } - - sort.Slice(sortedTldCounts, func(i, j int) bool { - return sortedTldCounts[i].Count > sortedTldCounts[j].Count - }) - require.GreaterOrEqual(t, len(sortedTldCounts), 2) - - blockString := fmt.Sprintf("*.%s,*.%s", sortedTldCounts[0].Tld, sortedTldCounts[1].Tld) - - cfg, err := NewConfigProviderFromData(fmt.Sprintf(` -[service] -EMAIL_DOMAIN_BLOCKLIST = %s -EMAIL_DOMAIN_BLOCK_DISPOSABLE = true -`, blockString)) - - require.NoError(t, err) - loadServiceFrom(cfg) - - for _, domain := range DisposableEmailDomains() { - require.True(t, match(Service.EmailDomainBlockList, domain)) - } - - redundant := 0 - for _, val := range DisposableEmailDomains() { - if strings.HasSuffix(val, sortedTldCounts[0].Tld) || - strings.HasSuffix(val, sortedTldCounts[1].Tld) { - redundant++ - } - } - - expected := len(DisposableEmailDomains()) - redundant + 2 - require.Len(t, Service.EmailDomainBlockList, expected) -} - -func TestLoadServiceBlockDisposableWithComplementGlobs(t *testing.T) { - oldService := Service - defer func() { - Service = oldService - }() - - cfg, err := NewConfigProviderFromData(` -[service] -EMAIL_DOMAIN_BLOCKLIST = *.random -EMAIL_DOMAIN_BLOCK_DISPOSABLE = true -`) - - require.NoError(t, err) - loadServiceFrom(cfg) - - for _, domain := range DisposableEmailDomains() { - require.True(t, match(Service.EmailDomainBlockList, domain)) - } - - expected := len(DisposableEmailDomains()) + 1 - require.Len(t, Service.EmailDomainBlockList, expected) -} - func TestLoadServiceVisibilityModes(t *testing.T) { oldService := Service defer func() { @@ -239,7 +119,7 @@ ALLOWED_USER_VISIBILITY_MODES = public, limit, privated for kase, fun := range kases { t.Run(kase, func(t *testing.T) { cfg, err := NewConfigProviderFromData(kase) - require.NoError(t, err) + assert.NoError(t, err) loadServiceFrom(cfg) fun() // reset diff --git a/modules/setting/session.go b/modules/setting/session.go index e9ff9bf0bc..e9637fdfc5 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -9,8 +9,8 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" ) // SessionConfig defines Session settings @@ -73,4 +73,6 @@ func loadSessionFrom(rootCfg ConfigProvider) { SessionConfig.ProviderConfig = string(shadowConfig) SessionConfig.OriginalProvider = SessionConfig.Provider SessionConfig.Provider = "VirtualSession" + + log.Info("Session Service Enabled") } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 1349325f81..97fb05403f 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1,6 +1,5 @@ // Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2017 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved // SPDX-License-Identifier: MIT package setting @@ -8,12 +7,13 @@ package setting import ( "fmt" "os" + "runtime" "strings" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/optional" - "forgejo.org/modules/user" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/user" + "code.gitea.io/gitea/modules/util" ) var ForgejoVersion = "1.0.0" @@ -33,6 +33,7 @@ var ( RunMode string RunUser string IsProd bool + IsWindows bool // IsInTesting indicates whether the testing is running. A lot of unreliable code causes a lot of nonsense error logs during testing // TODO: this is only a temporary solution, we should make the test code more reliable @@ -40,18 +41,22 @@ var ( ) func init() { + IsWindows = runtime.GOOS == "windows" if AppVer == "" { AppVer = "dev" } + // We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically // By default set this logger at Info - we'll change it later, but we need to start with something. log.SetConsoleLogger(log.DEFAULT, "console", log.INFO) } // IsRunUserMatchCurrentUser returns false if configured run user does not match // actual user that runs the app. The first return value is the actual user name. +// This check is ignored under Windows since SSH remote login is not the main +// method to login on Windows. func IsRunUserMatchCurrentUser(runUser string) (string, bool) { - if SSH.StartBuiltinServer { + if IsWindows || SSH.StartBuiltinServer { return "", true } @@ -151,7 +156,6 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error { loadAnnexFrom(cfg) loadMirrorFrom(cfg) loadMarkupFrom(cfg) - loadQuotaFrom(cfg) loadOtherFrom(cfg) return nil } @@ -163,7 +167,7 @@ func loadRunModeFrom(rootCfg ConfigProvider) { // The following is a purposefully undocumented option. Please do not run Forgejo as root. It will only cause future headaches. // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. unsafeAllowRunAsRoot := ConfigSectionKeyBool(rootSec, "I_AM_BEING_UNSAFE_RUNNING_AS_ROOT") - unsafeAllowRunAsRoot = unsafeAllowRunAsRoot || optional.ParseBool(os.Getenv("GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT")).Value() + unsafeAllowRunAsRoot = unsafeAllowRunAsRoot || util.OptionalBoolParse(os.Getenv("GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT")).Value() RunMode = os.Getenv("GITEA_RUN_MODE") if RunMode == "" { RunMode = rootSec.Key("RUN_MODE").MustString("prod") @@ -206,7 +210,6 @@ func LoadSettings() { initAllLoggers() loadDBSetting(CfgProvider) - loadFederationFrom(CfgProvider) loadServiceFrom(CfgProvider) loadOAuth2ClientFrom(CfgProvider) loadCacheFrom(CfgProvider) @@ -221,14 +224,12 @@ func LoadSettings() { LoadQueueSettings() loadProjectFrom(CfgProvider) loadMimeTypeMapFrom(CfgProvider) + loadFederationFrom(CfgProvider) loadF3From(CfgProvider) - loadModerationFrom(CfgProvider) } // LoadSettingsForInstall initializes the settings for install func LoadSettingsForInstall() { - initAllLoggers() - loadDBSetting(CfgProvider) loadServiceFrom(CfgProvider) loadMailerFrom(CfgProvider) diff --git a/modules/setting/setting_test.go b/modules/setting/setting_test.go index 1fef9e068a..f77ee65974 100644 --- a/modules/setting/setting_test.go +++ b/modules/setting/setting_test.go @@ -1,5 +1,4 @@ // Copyright 2020 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved // SPDX-License-Identifier: MIT package setting @@ -7,10 +6,9 @@ package setting import ( "testing" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMakeAbsoluteAssetURL(t *testing.T) { @@ -32,84 +30,3 @@ func TestMakeManifestData(t *testing.T) { jsonBytes := MakeManifestData(`Example App '\"`, "https://example.com", "https://example.com/foo/bar") assert.True(t, json.Valid(jsonBytes)) } - -func TestLoadServiceDomainListsForFederation(t *testing.T) { - oldAppURL := AppURL - oldFederation := Federation - oldService := Service - - defer func() { - AppURL = oldAppURL - Federation = oldFederation - Service = oldService - }() - - cfg, err := NewConfigProviderFromData(` -[federation] -ENABLED = true -[service] -EMAIL_DOMAIN_ALLOWLIST = *.allow.random -EMAIL_DOMAIN_BLOCKLIST = *.block.random -`) - - require.NoError(t, err) - loadServerFrom(cfg) - loadFederationFrom(cfg) - loadServiceFrom(cfg) - - assert.True(t, match(Service.EmailDomainAllowList, "d1.allow.random")) - assert.True(t, match(Service.EmailDomainAllowList, "localhost")) -} - -func TestLoadServiceDomainListsNoFederation(t *testing.T) { - oldAppURL := AppURL - oldFederation := Federation - oldService := Service - - defer func() { - AppURL = oldAppURL - Federation = oldFederation - Service = oldService - }() - - cfg, err := NewConfigProviderFromData(` -[federation] -ENABLED = false -[service] -EMAIL_DOMAIN_ALLOWLIST = *.allow.random -EMAIL_DOMAIN_BLOCKLIST = *.block.random -`) - - require.NoError(t, err) - loadServerFrom(cfg) - loadFederationFrom(cfg) - loadServiceFrom(cfg) - - assert.True(t, match(Service.EmailDomainAllowList, "d1.allow.random")) -} - -func TestLoadServiceDomainListsFederationEmptyAllowList(t *testing.T) { - oldAppURL := AppURL - oldFederation := Federation - oldService := Service - - defer func() { - AppURL = oldAppURL - Federation = oldFederation - Service = oldService - }() - - cfg, err := NewConfigProviderFromData(` -[federation] -ENABLED = true -[service] -EMAIL_DOMAIN_BLOCKLIST = *.block.random -`) - - require.NoError(t, err) - loadServerFrom(cfg) - loadFederationFrom(cfg) - loadServiceFrom(cfg) - - assert.Empty(t, Service.EmailDomainAllowList) -} diff --git a/modules/setting/ssh.go b/modules/setting/ssh.go index 1ad826a17a..ea387e521f 100644 --- a/modules/setting/ssh.go +++ b/modules/setting/ssh.go @@ -11,8 +11,8 @@ import ( "text/template" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" gossh "golang.org/x/crypto/ssh" ) @@ -56,7 +56,7 @@ var SSH = struct { Domain: "", Port: 22, ServerCiphers: []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"}, - ServerKeyExchanges: []string{"mlkem768x25519-sha256", "curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"}, + ServerKeyExchanges: []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"}, ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"}, KeygenPath: "", MinimumKeySizeCheck: true, diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 532842064c..8ee5c0f0ab 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -170,8 +170,8 @@ func getStorageTargetSection(rootCfg ConfigProvider, name, typ string, sec Confi targetSec, _ := rootCfg.GetSection(storageSectionName + "." + name) if targetSec != nil { targetType := targetSec.Key("STORAGE_TYPE").String() - switch targetType { - case "": + switch { + case targetType == "": if targetSec.Key("PATH").String() == "" { // both storage type and path are empty, use default return getDefaultStorageSection(rootCfg), targetSecIsDefault, nil } diff --git a/modules/setting/storage_test.go b/modules/setting/storage_test.go index a1b687ba5b..6f38bf1d55 100644 --- a/modules/setting/storage_test.go +++ b/modules/setting/storage_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_getStorageMultipleName(t *testing.T) { @@ -24,19 +23,19 @@ STORAGE_TYPE = minio MINIO_BUCKET = gitea-storage ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) - assert.Equal(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket) - assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) + assert.NoError(t, loadAttachmentFrom(cfg)) + assert.EqualValues(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) - require.NoError(t, loadLFSFrom(cfg)) - assert.Equal(t, "gitea-lfs", LFS.Storage.MinioConfig.Bucket) - assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath) + assert.NoError(t, loadLFSFrom(cfg)) + assert.EqualValues(t, "gitea-lfs", LFS.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath) - require.NoError(t, loadAvatarsFrom(cfg)) - assert.Equal(t, "gitea-storage", Avatar.Storage.MinioConfig.Bucket) - assert.Equal(t, "avatars/", Avatar.Storage.MinioConfig.BasePath) + assert.NoError(t, loadAvatarsFrom(cfg)) + assert.EqualValues(t, "gitea-storage", Avatar.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "avatars/", Avatar.Storage.MinioConfig.BasePath) } func Test_getStorageUseOtherNameAsType(t *testing.T) { @@ -49,15 +48,15 @@ STORAGE_TYPE = minio MINIO_BUCKET = gitea-storage ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadAttachmentFrom(cfg)) - assert.Equal(t, "gitea-storage", Attachment.Storage.MinioConfig.Bucket) - assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) + assert.NoError(t, loadAttachmentFrom(cfg)) + assert.EqualValues(t, "gitea-storage", Attachment.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "attachments/", Attachment.Storage.MinioConfig.BasePath) - require.NoError(t, loadLFSFrom(cfg)) - assert.Equal(t, "gitea-storage", LFS.Storage.MinioConfig.Bucket) - assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath) + assert.NoError(t, loadLFSFrom(cfg)) + assert.EqualValues(t, "gitea-storage", LFS.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath) } func Test_getStorageInheritStorageType(t *testing.T) { @@ -66,36 +65,36 @@ func Test_getStorageInheritStorageType(t *testing.T) { STORAGE_TYPE = minio ` cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, loadPackagesFrom(cfg)) + assert.NoError(t, loadPackagesFrom(cfg)) assert.EqualValues(t, "minio", Packages.Storage.Type) - assert.Equal(t, "gitea", Packages.Storage.MinioConfig.Bucket) - assert.Equal(t, "packages/", Packages.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", Packages.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "packages/", Packages.Storage.MinioConfig.BasePath) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, loadRepoArchiveFrom(cfg)) assert.EqualValues(t, "minio", RepoArchive.Storage.Type) - assert.Equal(t, "gitea", RepoArchive.Storage.MinioConfig.Bucket) - assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", RepoArchive.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) - require.NoError(t, loadActionsFrom(cfg)) + assert.NoError(t, loadActionsFrom(cfg)) assert.EqualValues(t, "minio", Actions.LogStorage.Type) - assert.Equal(t, "gitea", Actions.LogStorage.MinioConfig.Bucket) - assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", Actions.LogStorage.MinioConfig.Bucket) + assert.EqualValues(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath) assert.EqualValues(t, "minio", Actions.ArtifactStorage.Type) - assert.Equal(t, "gitea", Actions.ArtifactStorage.MinioConfig.Bucket) - assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", Actions.ArtifactStorage.MinioConfig.Bucket) + assert.EqualValues(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath) - require.NoError(t, loadAvatarsFrom(cfg)) + assert.NoError(t, loadAvatarsFrom(cfg)) assert.EqualValues(t, "minio", Avatar.Storage.Type) - assert.Equal(t, "gitea", Avatar.Storage.MinioConfig.Bucket) - assert.Equal(t, "avatars/", Avatar.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", Avatar.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "avatars/", Avatar.Storage.MinioConfig.BasePath) - require.NoError(t, loadRepoAvatarFrom(cfg)) + assert.NoError(t, loadRepoAvatarFrom(cfg)) assert.EqualValues(t, "minio", RepoAvatar.Storage.Type) - assert.Equal(t, "gitea", RepoAvatar.Storage.MinioConfig.Bucket) - assert.Equal(t, "repo-avatars/", RepoAvatar.Storage.MinioConfig.BasePath) + assert.EqualValues(t, "gitea", RepoAvatar.Storage.MinioConfig.Bucket) + assert.EqualValues(t, "repo-avatars/", RepoAvatar.Storage.MinioConfig.BasePath) } type testLocalStoragePathCase struct { @@ -106,15 +105,15 @@ type testLocalStoragePathCase struct { func testLocalStoragePath(t *testing.T, appDataPath, iniStr string, cases []testLocalStoragePathCase) { cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) + assert.NoError(t, err) AppDataPath = appDataPath for _, c := range cases { - require.NoError(t, c.loader(cfg)) + assert.NoError(t, c.loader(cfg)) storage := *c.storagePtr assert.EqualValues(t, "local", storage.Type) assert.True(t, filepath.IsAbs(storage.Path)) - assert.Equal(t, filepath.Clean(c.expectedPath), filepath.Clean(storage.Path)) + assert.EqualValues(t, filepath.Clean(c.expectedPath), filepath.Clean(storage.Path)) } } @@ -316,9 +315,9 @@ func Test_getStorageConfiguration20(t *testing.T) { STORAGE_TYPE = my_storage PATH = archives `) - require.NoError(t, err) + assert.NoError(t, err) - require.Error(t, loadRepoArchiveFrom(cfg)) + assert.Error(t, loadRepoArchiveFrom(cfg)) } func Test_getStorageConfiguration21(t *testing.T) { @@ -345,15 +344,15 @@ STORAGE_TYPE = minio MINIO_ACCESS_KEY_ID = my_access_key MINIO_SECRET_ACCESS_KEY = my_secret_key `) - require.NoError(t, err) + assert.NoError(t, err) _, err = getStorage(cfg, "", "", nil) - require.Error(t, err) + assert.Error(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, loadRepoArchiveFrom(cfg)) cp := RepoArchive.Storage.ToShadowCopy() - assert.Equal(t, "******", cp.MinioConfig.AccessKeyID) - assert.Equal(t, "******", cp.MinioConfig.SecretAccessKey) + assert.EqualValues(t, "******", cp.MinioConfig.AccessKeyID) + assert.EqualValues(t, "******", cp.MinioConfig.SecretAccessKey) } func Test_getStorageConfiguration24(t *testing.T) { @@ -365,8 +364,8 @@ STORAGE_TYPE = my_archive ; unsupported, storage type should be defined explicitly PATH = archives `) - require.NoError(t, err) - require.Error(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, err) + assert.Error(t, loadRepoArchiveFrom(cfg)) } func Test_getStorageConfiguration25(t *testing.T) { @@ -379,8 +378,8 @@ STORAGE_TYPE = my_archive STORAGE_TYPE = unknown // should be local or minio PATH = archives `) - require.NoError(t, err) - require.Error(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, err) + assert.Error(t, loadRepoArchiveFrom(cfg)) } func Test_getStorageConfiguration26(t *testing.T) { @@ -392,10 +391,10 @@ MINIO_SECRET_ACCESS_KEY = my_secret_key ; wrong configuration MINIO_USE_SSL = abc `) - require.NoError(t, err) - // require.Error(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, err) + // assert.Error(t, loadRepoArchiveFrom(cfg)) // FIXME: this should return error but now ini package's MapTo() doesn't check type - require.NoError(t, loadRepoArchiveFrom(cfg)) + assert.NoError(t, loadRepoArchiveFrom(cfg)) } func Test_getStorageConfiguration27(t *testing.T) { @@ -406,12 +405,12 @@ MINIO_ACCESS_KEY_ID = my_access_key MINIO_SECRET_ACCESS_KEY = my_secret_key MINIO_USE_SSL = true `) - require.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) - assert.Equal(t, "my_access_key", RepoArchive.Storage.MinioConfig.AccessKeyID) - assert.Equal(t, "my_secret_key", RepoArchive.Storage.MinioConfig.SecretAccessKey) - assert.True(t, RepoArchive.Storage.MinioConfig.UseSSL) - assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) + assert.NoError(t, err) + assert.NoError(t, loadRepoArchiveFrom(cfg)) + assert.EqualValues(t, "my_access_key", RepoArchive.Storage.MinioConfig.AccessKeyID) + assert.EqualValues(t, "my_secret_key", RepoArchive.Storage.MinioConfig.SecretAccessKey) + assert.EqualValues(t, true, RepoArchive.Storage.MinioConfig.UseSSL) + assert.EqualValues(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) } func Test_getStorageConfiguration28(t *testing.T) { @@ -423,12 +422,12 @@ MINIO_SECRET_ACCESS_KEY = my_secret_key MINIO_USE_SSL = true MINIO_BASE_PATH = /prefix `) - require.NoError(t, err) - require.NoError(t, loadRepoArchiveFrom(cfg)) - assert.Equal(t, "my_access_key", RepoArchive.Storage.MinioConfig.AccessKeyID) - assert.Equal(t, "my_secret_key", RepoArchive.Storage.MinioConfig.SecretAccessKey) - assert.True(t, RepoArchive.Storage.MinioConfig.UseSSL) - assert.Equal(t, "/prefix/repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) + assert.NoError(t, err) + assert.NoError(t, loadRepoArchiveFrom(cfg)) + assert.EqualValues(t, "my_access_key", RepoArchive.Storage.MinioConfig.AccessKeyID) + assert.EqualValues(t, "my_secret_key", RepoArchive.Storage.MinioConfig.SecretAccessKey) + assert.EqualValues(t, true, RepoArchive.Storage.MinioConfig.UseSSL) + assert.EqualValues(t, "/prefix/repo-archive/", RepoArchive.Storage.MinioConfig.BasePath) cfg, err = NewConfigProviderFromData(` [storage] @@ -441,12 +440,12 @@ MINIO_BASE_PATH = /prefix [lfs] MINIO_BASE_PATH = /lfs `) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) - assert.Equal(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID) - assert.Equal(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey) - assert.True(t, LFS.Storage.MinioConfig.UseSSL) - assert.Equal(t, "/lfs", LFS.Storage.MinioConfig.BasePath) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) + assert.EqualValues(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID) + assert.EqualValues(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey) + assert.EqualValues(t, true, LFS.Storage.MinioConfig.UseSSL) + assert.EqualValues(t, "/lfs", LFS.Storage.MinioConfig.BasePath) cfg, err = NewConfigProviderFromData(` [storage] @@ -459,10 +458,10 @@ MINIO_BASE_PATH = /prefix [storage.lfs] MINIO_BASE_PATH = /lfs `) - require.NoError(t, err) - require.NoError(t, loadLFSFrom(cfg)) - assert.Equal(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID) - assert.Equal(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey) - assert.True(t, LFS.Storage.MinioConfig.UseSSL) - assert.Equal(t, "/lfs", LFS.Storage.MinioConfig.BasePath) + assert.NoError(t, err) + assert.NoError(t, loadLFSFrom(cfg)) + assert.EqualValues(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID) + assert.EqualValues(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey) + assert.EqualValues(t, true, LFS.Storage.MinioConfig.UseSSL) + assert.EqualValues(t, "/lfs", LFS.Storage.MinioConfig.BasePath) } diff --git a/modules/setting/time.go b/modules/setting/time.go index 1211fd475a..39acba12ef 100644 --- a/modules/setting/time.go +++ b/modules/setting/time.go @@ -6,7 +6,7 @@ package setting import ( "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // DefaultUILocation is the location on the UI, so that we can display the time on UI. @@ -20,6 +20,7 @@ func loadTimeFrom(rootCfg ConfigProvider) { if err != nil { log.Fatal("Load time zone failed: %v", err) } + log.Info("Default UI Location is %v", zone) } if DefaultUILocation == nil { DefaultUILocation = time.Local diff --git a/modules/setting/ui.go b/modules/setting/ui.go index 2e6a3df4c6..056d670ba6 100644 --- a/modules/setting/ui.go +++ b/modules/setting/ui.go @@ -6,8 +6,8 @@ package setting import ( "time" - "forgejo.org/modules/container" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" ) // UI settings @@ -88,7 +88,6 @@ var UI = struct { Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`, `forgejo`}, CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:", "forgejo": ":forgejo:"}, - ExploreDefaultSort: "recentupdate", PreferredTimestampTense: "mixed", AmbiguousUnicodeDetection: true, diff --git a/modules/setting/webhook.go b/modules/setting/webhook.go index 071b729aa1..7b1ab4db1f 100644 --- a/modules/setting/webhook.go +++ b/modules/setting/webhook.go @@ -6,28 +6,26 @@ package setting import ( "net/url" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) // Webhook settings var Webhook = struct { - QueueLength int - DeliverTimeout int - SkipTLSVerify bool - AllowedHostList string - PagingNum int - ProxyURL string - ProxyURLFixed *url.URL - ProxyHosts []string - PayloadCommitLimit int + QueueLength int + DeliverTimeout int + SkipTLSVerify bool + AllowedHostList string + PagingNum int + ProxyURL string + ProxyURLFixed *url.URL + ProxyHosts []string }{ - QueueLength: 1000, - DeliverTimeout: 5, - SkipTLSVerify: false, - PagingNum: 10, - ProxyURL: "", - ProxyHosts: []string{}, - PayloadCommitLimit: 15, + QueueLength: 1000, + DeliverTimeout: 5, + SkipTLSVerify: false, + PagingNum: 10, + ProxyURL: "", + ProxyHosts: []string{}, } func loadWebhookFrom(rootCfg ConfigProvider) { @@ -47,5 +45,4 @@ func loadWebhookFrom(rootCfg ConfigProvider) { } } Webhook.ProxyHosts = sec.Key("PROXY_HOSTS").Strings(",") - Webhook.PayloadCommitLimit = sec.Key("PAYLOAD_COMMIT_LIMIT").MustInt(15) } diff --git a/modules/sitemap/sitemap_test.go b/modules/sitemap/sitemap_test.go index 39a2178c09..1180463cd7 100644 --- a/modules/sitemap/sitemap_test.go +++ b/modules/sitemap/sitemap_test.go @@ -11,7 +11,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestNewSitemap(t *testing.T) { @@ -83,7 +82,7 @@ func TestNewSitemap(t *testing.T) { if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) } else { - require.NoError(t, err) + assert.NoError(t, err) assert.Equalf(t, tt.want, buf.String(), "NewSitemap()") } }) @@ -159,7 +158,7 @@ func TestNewSitemapIndex(t *testing.T) { if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) } else { - require.NoError(t, err) + assert.NoError(t, err) assert.Equalf(t, tt.want, buf.String(), "NewSitemapIndex()") } }) diff --git a/modules/ssh/init.go b/modules/ssh/init.go index 1ccd95b18b..21d4f89936 100644 --- a/modules/ssh/init.go +++ b/modules/ssh/init.go @@ -11,8 +11,8 @@ import ( "strconv" "strings" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) func Init() error { diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 19cac0b603..f8e4f569b8 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -11,6 +11,7 @@ import ( "crypto/x509" "encoding/pem" "errors" + "fmt" "io" "net" "os" @@ -21,17 +22,21 @@ import ( "sync" "syscall" - asymkey_model "forgejo.org/models/asymkey" - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/process" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/gliderlabs/ssh" gossh "golang.org/x/crypto/ssh" ) +type contextKey string + +const giteaKeyID = contextKey("gitea-key-id") + func getExitStatusFromError(err error) int { if err == nil { return 0 @@ -57,7 +62,7 @@ func getExitStatusFromError(err error) int { } func sessionHandler(session ssh.Session) { - keyID := session.ConnPermissions().Extensions["forgejo-key-id"] + keyID := fmt.Sprintf("%d", session.Context().Value(giteaKeyID).(int64)) command := session.RawCommand() @@ -233,10 +238,7 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary log.Debug("Successfully authenticated: %s Certificate Fingerprint: %s Principal: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(key), principal) } - if ctx.Permissions().Extensions == nil { - ctx.Permissions().Extensions = map[string]string{} - } - ctx.Permissions().Extensions["forgejo-key-id"] = strconv.FormatInt(pkey.ID, 10) + ctx.SetValue(giteaKeyID, pkey.ID) return true } @@ -264,10 +266,7 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary log.Debug("Successfully authenticated: %s Public Key Fingerprint: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) } - if ctx.Permissions().Extensions == nil { - ctx.Permissions().Extensions = map[string]string{} - } - ctx.Permissions().Extensions["forgejo-key-id"] = strconv.FormatInt(pkey.ID, 10) + ctx.SetValue(giteaKeyID, pkey.ID) return true } diff --git a/modules/ssh/ssh_graceful.go b/modules/ssh/ssh_graceful.go index 825313ab1c..cad2c685bd 100644 --- a/modules/ssh/ssh_graceful.go +++ b/modules/ssh/ssh_graceful.go @@ -4,9 +4,9 @@ package ssh import ( - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "github.com/gliderlabs/ssh" ) diff --git a/modules/storage/helper.go b/modules/storage/helper.go index 8bec3a0042..95f1c7b9a8 100644 --- a/modules/storage/helper.go +++ b/modules/storage/helper.go @@ -30,7 +30,7 @@ func (s DiscardStorage) Delete(_ string) error { return fmt.Errorf("%s", s) } -func (s DiscardStorage) URL(_, _ string, _ url.Values) (*url.URL, error) { +func (s DiscardStorage) URL(_, _ string) (*url.URL, error) { return nil, fmt.Errorf("%s", s) } diff --git a/modules/storage/helper_test.go b/modules/storage/helper_test.go index dd30c9b8ac..f1f9791044 100644 --- a/modules/storage/helper_test.go +++ b/modules/storage/helper_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_discardStorage(t *testing.T) { @@ -21,30 +20,30 @@ func Test_discardStorage(t *testing.T) { { got, err := tt.Open("path") assert.Nil(t, got) - require.Error(t, err, string(tt)) + assert.Error(t, err, string(tt)) } { got, err := tt.Save("path", bytes.NewReader([]byte{0}), 1) assert.Equal(t, int64(0), got) - require.Error(t, err, string(tt)) + assert.Error(t, err, string(tt)) } { got, err := tt.Stat("path") assert.Nil(t, got) - require.Error(t, err, string(tt)) + assert.Error(t, err, string(tt)) } { err := tt.Delete("path") - require.Error(t, err, string(tt)) + assert.Error(t, err, string(tt)) } { - got, err := tt.URL("path", "name", nil) + got, err := tt.URL("path", "name") assert.Nil(t, got) - require.Errorf(t, err, string(tt)) + assert.Errorf(t, err, string(tt)) } { err := tt.IterateObjects("", func(_ string, _ Object) error { return nil }) - require.Error(t, err, string(tt)) + assert.Error(t, err, string(tt)) } }) } diff --git a/modules/storage/local.go b/modules/storage/local.go index 6f851983b1..9bb532f1df 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -11,9 +11,9 @@ import ( "os" "path/filepath" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) var _ ObjectStorage = &LocalStorage{} @@ -114,7 +114,7 @@ func (l *LocalStorage) Delete(path string) error { } // URL gets the redirect URL to a file -func (l *LocalStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) { +func (l *LocalStorage) URL(path, name string) (*url.URL, error) { return nil, ErrURLNotSupported } diff --git a/modules/storage/local_test.go b/modules/storage/local_test.go index d74c6bbc41..e230323f67 100644 --- a/modules/storage/local_test.go +++ b/modules/storage/local_test.go @@ -8,7 +8,7 @@ import ( "path/filepath" "testing" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) @@ -50,7 +50,7 @@ func TestBuildLocalPath(t *testing.T) { t.Run(k.path, func(t *testing.T) { l := LocalStorage{dir: k.localDir} - assert.Equal(t, k.expected, l.buildLocalPath(k.path)) + assert.EqualValues(t, k.expected, l.buildLocalPath(k.path)) }) } } diff --git a/modules/storage/minio.go b/modules/storage/minio.go index bf51a1642a..d0c2dec65b 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -15,9 +15,9 @@ import ( "strings" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" @@ -231,7 +231,7 @@ type minioFileInfo struct { } func (m minioFileInfo) Name() string { - return path.Base(m.Key) + return path.Base(m.ObjectInfo.Key) } func (m minioFileInfo) Size() int64 { @@ -243,7 +243,7 @@ func (m minioFileInfo) ModTime() time.Time { } func (m minioFileInfo) IsDir() bool { - return strings.HasSuffix(m.Key, "/") + return strings.HasSuffix(m.ObjectInfo.Key, "/") } func (m minioFileInfo) Mode() os.FileMode { @@ -276,12 +276,8 @@ func (m *MinioStorage) Delete(path string) error { } // URL gets the redirect URL to a file. The presigned link is valid for 5 minutes. -func (m *MinioStorage) URL(path, name string, serveDirectReqParams url.Values) (*url.URL, error) { - // copy serveDirectReqParams - reqParams, err := url.ParseQuery(serveDirectReqParams.Encode()) - if err != nil { - return nil, err - } +func (m *MinioStorage) URL(path, name string) (*url.URL, error) { + reqParams := make(url.Values) // TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we? reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"") u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams) diff --git a/modules/storage/minio_test.go b/modules/storage/minio_test.go index ec1b2fc77a..3fe01825e9 100644 --- a/modules/storage/minio_test.go +++ b/modules/storage/minio_test.go @@ -10,22 +10,20 @@ import ( "os" "testing" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/minio/minio-go/v7" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMinioStorageIterator(t *testing.T) { - endpoint := os.Getenv("TEST_MINIO_ENDPOINT") - if endpoint == "" { - t.Skip("TEST_MINIO_ENDPOINT not set") + if os.Getenv("CI") == "" { + t.Skip("minioStorage not present outside of CI") return } testStorageIterator(t, setting.MinioStorageType, &setting.Storage{ MinioConfig: setting.MinioStorageConfig{ - Endpoint: endpoint, + Endpoint: "minio:9000", AccessKeyID: "123456", SecretAccessKey: "12345678", Bucket: "gitea", @@ -35,14 +33,13 @@ func TestMinioStorageIterator(t *testing.T) { } func TestVirtualHostMinioStorage(t *testing.T) { - endpoint := os.Getenv("TEST_MINIO_ENDPOINT") - if endpoint == "" { - t.Skip("TEST_MINIO_ENDPOINT not set") + if os.Getenv("CI") == "" { + t.Skip("minioStorage not present outside of CI") return } testStorageIterator(t, setting.MinioStorageType, &setting.Storage{ MinioConfig: setting.MinioStorageConfig{ - Endpoint: endpoint, + Endpoint: "minio:9000", AccessKeyID: "123456", SecretAccessKey: "12345678", Bucket: "gitea", @@ -54,19 +51,19 @@ func TestVirtualHostMinioStorage(t *testing.T) { func TestMinioStoragePath(t *testing.T) { m := &MinioStorage{basePath: ""} - assert.Empty(t, m.buildMinioPath("/")) - assert.Empty(t, m.buildMinioPath(".")) + assert.Equal(t, "", m.buildMinioPath("/")) + assert.Equal(t, "", m.buildMinioPath(".")) assert.Equal(t, "a", m.buildMinioPath("/a")) assert.Equal(t, "a/b", m.buildMinioPath("/a/b/")) - assert.Empty(t, m.buildMinioDirPrefix("")) + assert.Equal(t, "", m.buildMinioDirPrefix("")) assert.Equal(t, "a/", m.buildMinioDirPrefix("/a/")) m = &MinioStorage{basePath: "/"} - assert.Empty(t, m.buildMinioPath("/")) - assert.Empty(t, m.buildMinioPath(".")) + assert.Equal(t, "", m.buildMinioPath("/")) + assert.Equal(t, "", m.buildMinioPath(".")) assert.Equal(t, "a", m.buildMinioPath("/a")) assert.Equal(t, "a/b", m.buildMinioPath("/a/b/")) - assert.Empty(t, m.buildMinioDirPrefix("")) + assert.Equal(t, "", m.buildMinioDirPrefix("")) assert.Equal(t, "a/", m.buildMinioDirPrefix("/a/")) m = &MinioStorage{basePath: "/base"} @@ -87,14 +84,13 @@ func TestMinioStoragePath(t *testing.T) { } func TestS3StorageBadRequest(t *testing.T) { - endpoint := os.Getenv("TEST_MINIO_ENDPOINT") - if endpoint == "" { - t.Skip("TEST_MINIO_ENDPOINT not set") + if os.Getenv("CI") == "" { + t.Skip("S3Storage not present outside of CI") return } cfg := &setting.Storage{ MinioConfig: setting.MinioStorageConfig{ - Endpoint: endpoint, + Endpoint: "minio:9000", AccessKeyID: "123456", SecretAccessKey: "12345678", Bucket: "bucket", @@ -112,7 +108,7 @@ func TestS3StorageBadRequest(t *testing.T) { } } _, err := NewStorage(setting.MinioStorageType, cfg) - require.ErrorContains(t, err, message) + assert.ErrorContains(t, err, message) } func TestMinioCredentials(t *testing.T) { @@ -132,7 +128,7 @@ func TestMinioCredentials(t *testing.T) { creds := buildMinioCredentials(cfg, FakeEndpoint) v, err := creds.Get() - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, ExpectedAccessKey, v.AccessKeyID) assert.Equal(t, ExpectedSecretAccessKey, v.SecretAccessKey) }) @@ -147,7 +143,7 @@ func TestMinioCredentials(t *testing.T) { creds := buildMinioCredentials(cfg, FakeEndpoint) v, err := creds.Get() - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, ExpectedAccessKey+"Minio", v.AccessKeyID) assert.Equal(t, ExpectedSecretAccessKey+"Minio", v.SecretAccessKey) }) @@ -159,7 +155,7 @@ func TestMinioCredentials(t *testing.T) { creds := buildMinioCredentials(cfg, FakeEndpoint) v, err := creds.Get() - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, ExpectedAccessKey+"AWS", v.AccessKeyID) assert.Equal(t, ExpectedSecretAccessKey+"AWS", v.SecretAccessKey) }) @@ -172,7 +168,7 @@ func TestMinioCredentials(t *testing.T) { creds := buildMinioCredentials(cfg, FakeEndpoint) v, err := creds.Get() - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, ExpectedAccessKey+"MinioFile", v.AccessKeyID) assert.Equal(t, ExpectedSecretAccessKey+"MinioFile", v.SecretAccessKey) }) @@ -185,7 +181,7 @@ func TestMinioCredentials(t *testing.T) { creds := buildMinioCredentials(cfg, FakeEndpoint) v, err := creds.Get() - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, ExpectedAccessKey+"AWSFile", v.AccessKeyID) assert.Equal(t, ExpectedSecretAccessKey+"AWSFile", v.SecretAccessKey) }) @@ -211,7 +207,7 @@ func TestMinioCredentials(t *testing.T) { creds := buildMinioCredentials(cfg, server.URL) v, err := creds.Get() - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, ExpectedAccessKey+"IAM", v.AccessKeyID) assert.Equal(t, ExpectedSecretAccessKey+"IAM", v.SecretAccessKey) }) diff --git a/modules/storage/storage.go b/modules/storage/storage.go index db081e0768..b83b1c7929 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -11,13 +11,32 @@ import ( "net/url" "os" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) // ErrURLNotSupported represents url is not supported var ErrURLNotSupported = errors.New("url method not supported") +// ErrInvalidConfiguration is called when there is invalid configuration for a storage +type ErrInvalidConfiguration struct { + cfg any + err error +} + +func (err ErrInvalidConfiguration) Error() string { + if err.err != nil { + return fmt.Sprintf("Invalid Configuration Argument: %v: Error: %v", err.cfg, err.err) + } + return fmt.Sprintf("Invalid Configuration Argument: %v", err.cfg) +} + +// IsErrInvalidConfiguration checks if an error is an ErrInvalidConfiguration +func IsErrInvalidConfiguration(err error) bool { + _, ok := err.(ErrInvalidConfiguration) + return ok +} + type Type = setting.StorageType // NewStorageFunc is a function that creates a storage @@ -44,7 +63,7 @@ type ObjectStorage interface { Save(path string, r io.Reader, size int64) (int64, error) Stat(path string) (os.FileInfo, error) Delete(path string) error - URL(path, name string, reqParams url.Values) (*url.URL, error) + URL(path, name string) (*url.URL, error) IterateObjects(path string, iterator func(path string, obj Object) error) error } @@ -112,7 +131,7 @@ var ( ActionsArtifacts ObjectStorage = UninitializedStorage ) -// Init init the storage +// Init init the stoarge func Init() error { for _, f := range []func() error{ initAttachments, diff --git a/modules/storage/storage_test.go b/modules/storage/storage_test.go index af3dd9520e..5e3e9c7dba 100644 --- a/modules/storage/storage_test.go +++ b/modules/storage/storage_test.go @@ -7,15 +7,14 @@ import ( "bytes" "testing" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func testStorageIterator(t *testing.T, typStr Type, cfg *setting.Storage) { l, err := NewStorage(typStr, cfg) - require.NoError(t, err) + assert.NoError(t, err) testFiles := [][]string{ {"a/1.txt", "a1"}, @@ -28,7 +27,7 @@ func testStorageIterator(t *testing.T, typStr Type, cfg *setting.Storage) { } for _, f := range testFiles { _, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1) - require.NoError(t, err) + assert.NoError(t, err) } expectedList := map[string][]string{ @@ -46,7 +45,7 @@ func testStorageIterator(t *testing.T, typStr Type, cfg *setting.Storage) { count++ return nil }) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, expected, count) } } diff --git a/modules/structs/action.go b/modules/structs/action.go deleted file mode 100644 index f47b228d75..0000000000 --- a/modules/structs/action.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package structs - -import ( - "time" -) - -// ActionRunJob represents a job of a run -// swagger:model -type ActionRunJob struct { - // the action run job id - ID int64 `json:"id"` - // the repository id - RepoID int64 `json:"repo_id"` - // the owner id - OwnerID int64 `json:"owner_id"` - // the action run job name - Name string `json:"name"` - // the action run job needed ids - Needs []string `json:"needs"` - // the action run job labels to run on - RunsOn []string `json:"runs_on"` - // the action run job latest task id - TaskID int64 `json:"task_id"` - // the action run job status - Status string `json:"status"` -} - -// ActionRun represents an action run -// swagger:model -type ActionRun struct { - // the action run id - ID int64 `json:"id"` - // the action run's title - Title string `json:"title"` - // the repo this action is part of - Repo *Repository `json:"repository"` - // the name of workflow file - WorkflowID string `json:"workflow_id"` - // a unique number for each run of a repository - Index int64 `json:"index_in_repo"` - // the user that triggered this action run - TriggerUser *User `json:"trigger_user"` - // the cron id for the schedule trigger - ScheduleID int64 - // the commit/tag/… the action run ran on - PrettyRef string `json:"prettyref"` - // has the commit/tag/… the action run ran on been deleted - IsRefDeleted bool `json:"is_ref_deleted"` - // the commit sha the action run ran on - CommitSHA string `json:"commit_sha"` - // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow. - IsForkPullRequest bool `json:"is_fork_pull_request"` - // may need approval if it's a fork pull request - NeedApproval bool `json:"need_approval"` - // who approved this action run - ApprovedBy int64 `json:"approved_by"` - // the webhook event that causes the workflow to run - Event string `json:"event"` - // the payload of the webhook event that causes the workflow to run - EventPayload string `json:"event_payload"` - // the trigger event defined in the `on` configuration of the triggered workflow - TriggerEvent string `json:"trigger_event"` - // the current status of this run - Status string `json:"status"` - // when the action run was started - Started time.Time `json:"started,omitempty"` - // when the action run was stopped - Stopped time.Time `json:"stopped,omitempty"` - // when the action run was created - Created time.Time `json:"created,omitempty"` - // when the action run was last updated - Updated time.Time `json:"updated,omitempty"` - // how long the action run ran for - Duration time.Duration `json:"duration,omitempty"` - // the url of this action run - HTMLURL string `json:"html_url"` -} - -// ListActionRunResponse return a list of ActionRun -type ListActionRunResponse struct { - Entries []*ActionRun `json:"workflow_runs"` - TotalCount int64 `json:"total_count"` -} diff --git a/modules/structs/activity.go b/modules/structs/activity.go index 1bb83135c3..ea27fbfd77 100644 --- a/modules/structs/activity.go +++ b/modules/structs/activity.go @@ -10,7 +10,7 @@ type Activity struct { UserID int64 `json:"user_id"` // Receiver user // the type of action // - // enum: ["create_repo", "rename_repo", "star_repo", "watch_repo", "commit_repo", "create_issue", "create_pull_request", "transfer_repo", "push_tag", "comment_issue", "merge_pull_request", "close_issue", "reopen_issue", "close_pull_request", "reopen_pull_request", "delete_tag", "delete_branch", "mirror_sync_push", "mirror_sync_create", "mirror_sync_delete", "approve_pull_request", "reject_pull_request", "comment_pull", "publish_release", "pull_review_dismissed", "pull_request_ready_for_review", "auto_merge_pull_request"] + // enum: create_repo,rename_repo,star_repo,watch_repo,commit_repo,create_issue,create_pull_request,transfer_repo,push_tag,comment_issue,merge_pull_request,close_issue,reopen_issue,close_pull_request,reopen_pull_request,delete_tag,delete_branch,mirror_sync_push,mirror_sync_create,mirror_sync_delete,approve_pull_request,reject_pull_request,comment_pull,publish_release,pull_review_dismissed,pull_request_ready_for_review,auto_merge_pull_request OpType string `json:"op_type"` ActUserID int64 `json:"act_user_id"` ActUser *User `json:"act_user"` diff --git a/modules/structs/admin_user.go b/modules/structs/admin_user.go index 8a4d066d72..5b7df127b4 100644 --- a/modules/structs/admin_user.go +++ b/modules/structs/admin_user.go @@ -15,7 +15,7 @@ type CreateUserOption struct { FullName string `json:"full_name" binding:"MaxSize(100)"` // required: true // swagger:strfmt email - Email string `json:"email" binding:"Required;EmailForAdmin;MaxSize(254)"` + Email string `json:"email" binding:"Required;Email;MaxSize(254)"` Password string `json:"password" binding:"MaxSize(255)"` MustChangePassword *bool `json:"must_change_password"` SendNotify bool `json:"send_notify"` diff --git a/modules/structs/attachment.go b/modules/structs/attachment.go index 746f618cf0..38beca5e99 100644 --- a/modules/structs/attachment.go +++ b/modules/structs/attachment.go @@ -1,7 +1,7 @@ // Copyright 2017 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package structs // import "forgejo.org/modules/structs" +package structs // import "code.gitea.io/gitea/modules/structs" import ( "time" @@ -18,20 +18,10 @@ type Attachment struct { Created time.Time `json:"created_at"` UUID string `json:"uuid"` DownloadURL string `json:"browser_download_url"` - // enum: ["attachment", "external"] - Type string `json:"type"` -} - -// WebAttachment the generic attachment with mime type -type WebAttachment struct { - *Attachment - MimeType string `json:"mime_type"` } // EditAttachmentOptions options for editing attachments // swagger:model type EditAttachmentOptions struct { Name string `json:"name"` - // (Can only be set if existing attachment is of external type) - DownloadURL string `json:"browser_download_url"` } diff --git a/modules/structs/fork.go b/modules/structs/fork.go index 8fc73647bd..eb7774afbc 100644 --- a/modules/structs/fork.go +++ b/modules/structs/fork.go @@ -10,11 +10,3 @@ type CreateForkOption struct { // name of the forked repository Name *string `json:"name"` } - -// SyncForkInfo information about syncing a fork -type SyncForkInfo struct { - Allowed bool `json:"allowed"` - ForkCommit string `json:"fork_commit"` - BaseCommit string `json:"base_commit"` - CommitsBehind int `json:"commits_behind"` -} diff --git a/modules/structs/git_blob.go b/modules/structs/git_blob.go index ef06693905..96c7a271a9 100644 --- a/modules/structs/git_blob.go +++ b/modules/structs/git_blob.go @@ -3,8 +3,8 @@ package structs -// GitBlob represents a git blob -type GitBlob struct { +// GitBlobResponse represents a git blob +type GitBlobResponse struct { Content string `json:"content"` Encoding string `json:"encoding"` URL string `json:"url"` diff --git a/modules/structs/hook.go b/modules/structs/hook.go index 11372ca6e1..bb40aa06c0 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" ) // ErrInvalidReceiveHook FIXME @@ -45,7 +45,7 @@ type CreateHookOptionConfig map[string]string // CreateHookOption options when create a hook type CreateHookOption struct { // required: true - // enum: ["forgejo", "dingtalk", "discord", "gitea", "gogs", "msteams", "slack", "telegram", "feishu", "wechatwork", "packagist"] + // enum: forgejo,dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,wechatwork,packagist Type string `json:"type" binding:"Required"` // required: true Config CreateHookOptionConfig `json:"config" binding:"Required"` @@ -118,7 +118,6 @@ var ( _ Payloader = &RepositoryPayload{} _ Payloader = &ReleasePayload{} _ Payloader = &PackagePayload{} - _ Payloader = &ActionPayload{} ) // _________ __ @@ -142,6 +141,26 @@ func (p *CreatePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } +// ParseCreateHook parses create event hook content. +func ParseCreateHook(raw []byte) (*CreatePayload, error) { + hook := new(CreatePayload) + if err := json.Unmarshal(raw, hook); err != nil { + return nil, err + } + + // it is possible the JSON was parsed, however, + // was not from Gogs (maybe was from Bitbucket) + // So we'll check to be sure certain key fields + // were populated + switch { + case hook.Repo == nil: + return nil, ErrInvalidReceiveHook + case len(hook.Ref) == 0: + return nil, ErrInvalidReceiveHook + } + return hook, nil +} + // ________ .__ __ // \______ \ ____ | | _____/ |_ ____ // | | \_/ __ \| | _/ __ \ __\/ __ \ @@ -202,14 +221,13 @@ const ( // IssueCommentPayload represents a payload information of issue comment event. type IssueCommentPayload struct { - Action HookIssueCommentAction `json:"action"` - Issue *Issue `json:"issue"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - Comment *Comment `json:"comment"` - Changes *ChangesPayload `json:"changes,omitempty"` - Repository *Repository `json:"repository"` - Sender *User `json:"sender"` - IsPull bool `json:"is_pull"` + Action HookIssueCommentAction `json:"action"` + Issue *Issue `json:"issue"` + Comment *Comment `json:"comment"` + Changes *ChangesPayload `json:"changes,omitempty"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` + IsPull bool `json:"is_pull"` } // JSONPayload implements Payload @@ -273,6 +291,22 @@ func (p *PushPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } +// ParsePushHook parses push event hook content. +func ParsePushHook(raw []byte) (*PushPayload, error) { + hook := new(PushPayload) + if err := json.Unmarshal(raw, hook); err != nil { + return nil, err + } + + switch { + case hook.Repo == nil: + return nil, ErrInvalidReceiveHook + case len(hook.Ref) == 0: + return nil, ErrInvalidReceiveHook + } + return hook, nil +} + // Branch returns branch name from a payload func (p *PushPayload) Branch() string { return strings.ReplaceAll(p.Ref, "refs/heads/", "") @@ -328,7 +362,6 @@ type IssuePayload struct { Repository *Repository `json:"repository"` Sender *User `json:"sender"` CommitID string `json:"commit_id"` - Label *Label `json:"label,omitempty"` } // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces. @@ -366,7 +399,6 @@ type PullRequestPayload struct { Sender *User `json:"sender"` CommitID string `json:"commit_id"` Review *ReviewPayload `json:"review"` - Label *Label `json:"label,omitempty"` } // JSONPayload FIXME @@ -484,36 +516,3 @@ type PackagePayload struct { func (p *PackagePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } - -// _ _ _ -// / \ ___| |_(_) ___ _ __ -// / _ \ / __| __| |/ _ \| '_ \ -// / ___ \ (__| |_| | (_) | | | | -// /_/ \_\___|\__|_|\___/|_| |_| - -// this name is ridiculous, yes -// it's the sub-type of hook that has something to do with Forgejo Actions -type HookActionAction string - -const ( - HookActionFailure HookActionAction = "failure" - HookActionRecover HookActionAction = "recover" - HookActionSuccess HookActionAction = "success" -) - -// ActionPayload payload for action webhooks -type ActionPayload struct { - Action HookActionAction `json:"action"` - Run *ActionRun `json:"run"` - // the status of this run before it completed - // this must be a not done status - PriorStatus string `json:"prior_status"` - // the last run for the same workflow - // could be nil when Run is the first for it's workflow - LastRun *ActionRun `json:"last_run,omitempty"` -} - -// JSONPayload return payload information -func (p *ActionPayload) JSONPayload() ([]byte, error) { - return json.MarshalIndent(p, "", " ") -} diff --git a/modules/structs/issue.go b/modules/structs/issue.go index a67bdcf50e..7ba7f77158 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -63,7 +63,7 @@ type Issue struct { // Whether the issue is open or closed // // type: string - // enum: ["open", "closed"] + // enum: open,closed State StateType `json:"state"` IsLocked bool `json:"is_locked"` Comments int `json:"comments"` diff --git a/modules/structs/issue_milestone.go b/modules/structs/issue_milestone.go index 051824469a..a840cf1820 100644 --- a/modules/structs/issue_milestone.go +++ b/modules/structs/issue_milestone.go @@ -31,7 +31,7 @@ type CreateMilestoneOption struct { Description string `json:"description"` // swagger:strfmt date-time Deadline *time.Time `json:"due_on"` - // enum: ["open", "closed"] + // enum: open,closed State string `json:"state"` } diff --git a/modules/structs/issue_test.go b/modules/structs/issue_test.go index 2003e22e0a..fa7a20db8b 100644 --- a/modules/structs/issue_test.go +++ b/modules/structs/issue_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) @@ -98,7 +97,7 @@ labels: if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) } else { - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, tt.want, tt.tmpl) } }) diff --git a/modules/structs/mirror.go b/modules/structs/mirror.go index 1b6566803a..8259583cde 100644 --- a/modules/structs/mirror.go +++ b/modules/structs/mirror.go @@ -12,7 +12,6 @@ type CreatePushMirrorOption struct { RemotePassword string `json:"remote_password"` Interval string `json:"interval"` SyncOnCommit bool `json:"sync_on_commit"` - UseSSH bool `json:"use_ssh"` } // PushMirror represents information of a push mirror @@ -28,5 +27,4 @@ type PushMirror struct { LastError string `json:"last_error"` Interval string `json:"interval"` SyncOnCommit bool `json:"sync_on_commit"` - PublicKey string `json:"public_key"` } diff --git a/modules/structs/miscellaneous.go b/modules/structs/miscellaneous.go index 7866cb5fc0..bff10f95b7 100644 --- a/modules/structs/miscellaneous.go +++ b/modules/structs/miscellaneous.go @@ -37,10 +37,6 @@ type MarkupOption struct { // // in: body FilePath string - // The current branch path where the form gets posted - // - // in: body - BranchPath string } // MarkupRender is a rendered markup document diff --git a/modules/structs/org.go b/modules/structs/org.go index 451153b620..c0a545ac1c 100644 --- a/modules/structs/org.go +++ b/modules/structs/org.go @@ -38,7 +38,7 @@ type CreateOrgOption struct { Website string `json:"website" binding:"ValidUrl;MaxSize(255)"` Location string `json:"location" binding:"MaxSize(50)"` // possible values are `public` (default), `limited` or `private` - // enum: ["public", "limited", "private"] + // enum: public,limited,private Visibility string `json:"visibility" binding:"In(,public,limited,private)"` RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"` } @@ -47,22 +47,13 @@ type CreateOrgOption struct { // EditOrgOption options for editing an organization type EditOrgOption struct { - FullName string `json:"full_name" binding:"MaxSize(100)"` - Email *string `json:"email" binding:"MaxSize(255)"` - Description string `json:"description" binding:"MaxSize(255)"` - Website string `json:"website" binding:"ValidUrl;MaxSize(255)"` - Location string `json:"location" binding:"MaxSize(50)"` + FullName string `json:"full_name" binding:"MaxSize(100)"` + Email string `json:"email" binding:"MaxSize(255)"` + Description string `json:"description" binding:"MaxSize(255)"` + Website string `json:"website" binding:"ValidUrl;MaxSize(255)"` + Location string `json:"location" binding:"MaxSize(50)"` // possible values are `public`, `limited` or `private` - // enum: ["public", "limited", "private"] + // enum: public,limited,private Visibility string `json:"visibility" binding:"In(,public,limited,private)"` RepoAdminChangeTeamAccess *bool `json:"repo_admin_change_team_access"` } - -// RenameOrgOption options when renaming an organization -type RenameOrgOption struct { - // New username for this org. This name cannot be in use yet by any other user. - // - // required: true - // unique: true - NewName string `json:"new_name" binding:"Required"` -} diff --git a/modules/structs/org_team.go b/modules/structs/org_team.go index 4417758024..f8899b236b 100644 --- a/modules/structs/org_team.go +++ b/modules/structs/org_team.go @@ -11,7 +11,7 @@ type Team struct { Description string `json:"description"` Organization *Organization `json:"organization"` IncludesAllRepositories bool `json:"includes_all_repositories"` - // enum: ["none", "read", "write", "admin", "owner"] + // enum: none,read,write,admin,owner Permission string `json:"permission"` // example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.projects","repo.ext_wiki"] // Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions. @@ -27,7 +27,7 @@ type CreateTeamOption struct { Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(255)"` Description string `json:"description" binding:"MaxSize(255)"` IncludesAllRepositories bool `json:"includes_all_repositories"` - // enum: ["read", "write", "admin"] + // enum: read,write,admin Permission string `json:"permission"` // example: ["repo.actions","repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.ext_wiki","repo.pulls","repo.releases","repo.projects","repo.ext_wiki"] // Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions. @@ -43,7 +43,7 @@ type EditTeamOption struct { Name string `json:"name" binding:"AlphaDashDot;MaxSize(255)"` Description *string `json:"description" binding:"MaxSize(255)"` IncludesAllRepositories *bool `json:"includes_all_repositories"` - // enum: ["read", "write", "admin"] + // enum: read,write,admin Permission string `json:"permission"` // example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.projects","repo.ext_wiki"] // Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions. diff --git a/modules/structs/pull.go b/modules/structs/pull.go index 1ce7550e19..525d90c28e 100644 --- a/modules/structs/pull.go +++ b/modules/structs/pull.go @@ -9,22 +9,21 @@ import ( // PullRequest represents a pull request type PullRequest struct { - ID int64 `json:"id"` - URL string `json:"url"` - Index int64 `json:"number"` - Poster *User `json:"user"` - Title string `json:"title"` - Body string `json:"body"` - Labels []*Label `json:"labels"` - Milestone *Milestone `json:"milestone"` - Assignee *User `json:"assignee"` - Assignees []*User `json:"assignees"` - RequestedReviewers []*User `json:"requested_reviewers"` - RequestedReviewersTeams []*Team `json:"requested_reviewers_teams"` - State StateType `json:"state"` - Draft bool `json:"draft"` - IsLocked bool `json:"is_locked"` - Comments int `json:"comments"` + ID int64 `json:"id"` + URL string `json:"url"` + Index int64 `json:"number"` + Poster *User `json:"user"` + Title string `json:"title"` + Body string `json:"body"` + Labels []*Label `json:"labels"` + Milestone *Milestone `json:"milestone"` + Assignee *User `json:"assignee"` + Assignees []*User `json:"assignees"` + RequestedReviewers []*User `json:"requested_reviewers"` + State StateType `json:"state"` + Draft bool `json:"draft"` + IsLocked bool `json:"is_locked"` + Comments int `json:"comments"` // number of review comments made on the diff of a PR review (not including comments on commits or issues in a PR) ReviewComments int `json:"review_comments"` Additions int `json:"additions"` @@ -57,8 +56,7 @@ type PullRequest struct { // swagger:strfmt date-time Closed *time.Time `json:"closed_at"` - PinOrder int `json:"pin_order"` - Flow int64 `json:"flow"` + PinOrder int `json:"pin_order"` } // PRBranchInfo information about a branch diff --git a/modules/structs/pull_review.go b/modules/structs/pull_review.go index f89c1f2a63..c77ebea07d 100644 --- a/modules/structs/pull_review.go +++ b/modules/structs/pull_review.go @@ -89,6 +89,7 @@ type CreatePullReviewComment struct { NewLineNum int64 `json:"new_position"` } +// CreatePullReviewCommentOptions are options to create a pull review comment type CreatePullReviewCommentOptions CreatePullReviewComment // SubmitPullReviewOptions are options to submit a pending pull review diff --git a/modules/structs/quota.go b/modules/structs/quota.go deleted file mode 100644 index cb8874ab0c..0000000000 --- a/modules/structs/quota.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package structs - -// QuotaInfo represents information about a user's quota -type QuotaInfo struct { - Used QuotaUsed `json:"used"` - Groups QuotaGroupList `json:"groups"` -} - -// QuotaUsed represents the quota usage of a user -type QuotaUsed struct { - Size QuotaUsedSize `json:"size"` -} - -// QuotaUsedSize represents the size-based quota usage of a user -type QuotaUsedSize struct { - Repos QuotaUsedSizeRepos `json:"repos"` - Git QuotaUsedSizeGit `json:"git"` - Assets QuotaUsedSizeAssets `json:"assets"` -} - -// QuotaUsedSizeRepos represents the size-based repository quota usage of a user -type QuotaUsedSizeRepos struct { - // Storage size of the user's public repositories - Public int64 `json:"public"` - // Storage size of the user's private repositories - Private int64 `json:"private"` -} - -// QuotaUsedSizeGit represents the size-based git (lfs) quota usage of a user -type QuotaUsedSizeGit struct { - // Storage size of the user's Git LFS objects - LFS int64 `json:"LFS"` -} - -// QuotaUsedSizeAssets represents the size-based asset usage of a user -type QuotaUsedSizeAssets struct { - Attachments QuotaUsedSizeAssetsAttachments `json:"attachments"` - // Storage size used for the user's artifacts - Artifacts int64 `json:"artifacts"` - Packages QuotaUsedSizeAssetsPackages `json:"packages"` -} - -// QuotaUsedSizeAssetsAttachments represents the size-based attachment quota usage of a user -type QuotaUsedSizeAssetsAttachments struct { - // Storage size used for the user's issue & comment attachments - Issues int64 `json:"issues"` - // Storage size used for the user's release attachments - Releases int64 `json:"releases"` -} - -// QuotaUsedSizeAssetsPackages represents the size-based package quota usage of a user -type QuotaUsedSizeAssetsPackages struct { - // Storage suze used for the user's packages - All int64 `json:"all"` -} - -// QuotaRuleInfo contains information about a quota rule -type QuotaRuleInfo struct { - // Name of the rule (only shown to admins) - Name string `json:"name,omitempty"` - // The limit set by the rule - Limit int64 `json:"limit"` - // Subjects the rule affects - Subjects []string `json:"subjects,omitempty"` -} - -// QuotaGroupList represents a list of quota groups -type QuotaGroupList []QuotaGroup - -// QuotaGroup represents a quota group -type QuotaGroup struct { - // Name of the group - Name string `json:"name,omitempty"` - // Rules associated with the group - Rules []QuotaRuleInfo `json:"rules"` -} - -// CreateQutaGroupOptions represents the options for creating a quota group -type CreateQuotaGroupOptions struct { - // Name of the quota group to create - Name string `json:"name" binding:"Required"` - // Rules to add to the newly created group. - // If a rule does not exist, it will be created. - Rules []CreateQuotaRuleOptions `json:"rules"` -} - -// CreateQuotaRuleOptions represents the options for creating a quota rule -type CreateQuotaRuleOptions struct { - // Name of the rule to create - Name string `json:"name" binding:"Required"` - // The limit set by the rule - Limit *int64 `json:"limit"` - // The subjects affected by the rule - Subjects []string `json:"subjects"` -} - -// EditQuotaRuleOptions represents the options for editing a quota rule -type EditQuotaRuleOptions struct { - // The limit set by the rule - Limit *int64 `json:"limit"` - // The subjects affected by the rule - Subjects *[]string `json:"subjects"` -} - -// SetUserQuotaGroupsOptions represents the quota groups of a user -type SetUserQuotaGroupsOptions struct { - // Quota groups the user shall have - // required: true - Groups *[]string `json:"groups"` -} - -// QuotaUsedAttachmentList represents a list of attachment counting towards a user's quota -type QuotaUsedAttachmentList []*QuotaUsedAttachment - -// QuotaUsedAttachment represents an attachment counting towards a user's quota -type QuotaUsedAttachment struct { - // Filename of the attachment - Name string `json:"name"` - // Size of the attachment (in bytes) - Size int64 `json:"size"` - // API URL for the attachment - APIURL string `json:"api_url"` - // Context for the attachment: URLs to the containing object - ContainedIn struct { - // API URL for the object that contains this attachment - APIURL string `json:"api_url"` - // HTML URL for the object that contains this attachment - HTMLURL string `json:"html_url"` - } `json:"contained_in"` -} - -// QuotaUsedPackageList represents a list of packages counting towards a user's quota -type QuotaUsedPackageList []*QuotaUsedPackage - -// QuotaUsedPackage represents a package counting towards a user's quota -type QuotaUsedPackage struct { - // Name of the package - Name string `json:"name"` - // Type of the package - Type string `json:"type"` - // Version of the package - Version string `json:"version"` - // Size of the package version - Size int64 `json:"size"` - // HTML URL to the package version - HTMLURL string `json:"html_url"` -} - -// QuotaUsedArtifactList represents a list of artifacts counting towards a user's quota -type QuotaUsedArtifactList []*QuotaUsedArtifact - -// QuotaUsedArtifact represents an artifact counting towards a user's quota -type QuotaUsedArtifact struct { - // Name of the artifact - Name string `json:"name"` - // Size of the artifact (compressed) - Size int64 `json:"size"` - // HTML URL to the action run containing the artifact - HTMLURL string `json:"html_url"` -} diff --git a/modules/structs/repo.go b/modules/structs/repo.go index c9cd729cf3..2aa4136597 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -105,12 +105,11 @@ type Repository struct { DefaultDeleteBranchAfterMerge bool `json:"default_delete_branch_after_merge"` DefaultMergeStyle string `json:"default_merge_style"` DefaultAllowMaintainerEdit bool `json:"default_allow_maintainer_edit"` - DefaultUpdateStyle string `json:"default_update_style"` AvatarURL string `json:"avatar_url"` Internal bool `json:"internal"` MirrorInterval string `json:"mirror_interval"` // ObjectFormatName of the underlying git repository - // enum: ["sha1", "sha256"] + // enum: sha1,sha256 ObjectFormatName string `json:"object_format_name"` // swagger:strfmt date-time MirrorUpdated time.Time `json:"mirror_updated,omitempty"` @@ -155,10 +154,10 @@ type CreateRepoOption struct { // DefaultBranch of the repository (used when initializes and in template) DefaultBranch string `json:"default_branch" binding:"GitRefName;MaxSize(100)"` // TrustModel of the repository - // enum: ["default", "collaborator", "committer", "collaboratorcommitter"] + // enum: default,collaborator,committer,collaboratorcommitter TrustModel string `json:"trust_model"` // ObjectFormatName of the underlying git repository - // enum: ["sha1", "sha256"] + // enum: sha1,sha256 ObjectFormatName string `json:"object_format_name" binding:"MaxSize(6)"` } @@ -224,10 +223,8 @@ type EditRepoOption struct { AllowRebaseUpdate *bool `json:"allow_rebase_update,omitempty"` // set to `true` to delete pr branch after merge by default DefaultDeleteBranchAfterMerge *bool `json:"default_delete_branch_after_merge,omitempty"` - // set to a merge style to be used by this repository: "merge", "rebase", "rebase-merge", "squash", "fast-forward-only", "manually-merged", or "rebase-update-only". - DefaultMergeStyle *string `json:"default_merge_style,omitempty" binding:"In(merge,rebase,rebase-merge,squash,fast-forward-only,manually-merged,rebase-update-only)"` - // set to a update style to be used by this repository: "rebase" or "merge" - DefaultUpdateStyle *string `json:"default_update_style,omitempty" binding:"In(merge,rebase)"` + // set to a merge style to be used by this repository: "merge", "rebase", "rebase-merge", "squash", or "fast-forward-only". + DefaultMergeStyle *string `json:"default_merge_style,omitempty"` // set to `true` to allow edits from maintainers by default DefaultAllowMaintainerEdit *bool `json:"default_allow_maintainer_edit,omitempty"` // set to `true` to archive this repository. @@ -293,16 +290,6 @@ type CreateBranchRepoOption struct { OldRefName string `json:"old_ref_name" binding:"GitRefName;MaxSize(100)"` } -// UpdateBranchRepoOption options when updating a branch in a repository -// swagger:model -type UpdateBranchRepoOption struct { - // New branch name - // - // required: true - // unique: true - Name string `json:"name" binding:"Required;GitRefName;MaxSize(100)"` -} - // TransferRepoOption options when transfer a repository's ownership // swagger:model type TransferRepoOption struct { @@ -330,7 +317,7 @@ const ( ) // Name represents the service type's name -// WARNING: the name have to be equal to that on goth's library +// WARNNING: the name have to be equal to that on goth's library func (gt GitServiceType) Name() string { return strings.ToLower(gt.Title()) } @@ -372,7 +359,7 @@ type MigrateRepoOptions struct { // required: true RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"` - // enum: ["git", "github", "gitea", "gitlab", "gogs", "onedev", "gitbucket", "codebase"] + // enum: git,github,gitea,gitlab,gogs,onedev,gitbucket,codebase Service string `json:"service"` AuthUsername string `json:"auth_username"` AuthPassword string `json:"auth_password"` diff --git a/modules/structs/repo_collaborator.go b/modules/structs/repo_collaborator.go index 2f03f0a725..946a6ec7e7 100644 --- a/modules/structs/repo_collaborator.go +++ b/modules/structs/repo_collaborator.go @@ -5,7 +5,6 @@ package structs // AddCollaboratorOption options when adding a user as a collaborator of a repository type AddCollaboratorOption struct { - // enum: ["read", "write", "admin"] Permission *string `json:"permission"` } diff --git a/modules/structs/repo_compare.go b/modules/structs/repo_compare.go index 6e77a813d3..8a12498705 100644 --- a/modules/structs/repo_compare.go +++ b/modules/structs/repo_compare.go @@ -5,7 +5,6 @@ package structs // Compare represents a comparison between two commits. type Compare struct { - TotalCommits int `json:"total_commits"` // Total number of commits in the comparison. - Commits []*Commit `json:"commits"` // List of commits in the comparison. - Files []*CommitAffectedFiles `json:"files"` // Total files modified in this comparison. + TotalCommits int `json:"total_commits"` // Total number of commits in the comparison. + Commits []*Commit `json:"commits"` // List of commits in the comparison. } diff --git a/modules/structs/repo_file.go b/modules/structs/repo_file.go index 242343493b..82bde96ab6 100644 --- a/modules/structs/repo_file.go +++ b/modules/structs/repo_file.go @@ -4,8 +4,6 @@ package structs -import "time" - // FileOptions options for all file APIs type FileOptions struct { // message (optional) for the commit of this file. if not supplied, a default message will be used @@ -33,7 +31,7 @@ type CreateFileOptions struct { // Branch returns branch name func (o *CreateFileOptions) Branch() string { - return o.BranchName + return o.FileOptions.BranchName } // DeleteFileOptions options for deleting files (used for other File structs below) @@ -47,7 +45,7 @@ type DeleteFileOptions struct { // Branch returns branch name func (o *DeleteFileOptions) Branch() string { - return o.BranchName + return o.FileOptions.BranchName } // UpdateFileOptions options for updating files @@ -63,14 +61,14 @@ type UpdateFileOptions struct { // Branch returns branch name func (o *UpdateFileOptions) Branch() string { - return o.BranchName + return o.FileOptions.BranchName } // ChangeFileOperation for creating, updating or deleting a file type ChangeFileOperation struct { // indicates what to do with the file // required: true - // enum: ["create", "update", "delete"] + // enum: create,update,delete Operation string `json:"operation" binding:"Required"` // path to the existing or new file // required: true @@ -94,7 +92,7 @@ type ChangeFilesOptions struct { // Branch returns branch name func (o *ChangeFilesOptions) Branch() string { - return o.BranchName + return o.FileOptions.BranchName } // FileOptionInterface provides a unified interface for the different file options @@ -123,8 +121,6 @@ type ContentsResponse struct { Path string `json:"path"` SHA string `json:"sha"` LastCommitSHA string `json:"last_commit_sha"` - // swagger:strfmt date-time - LastCommitWhen time.Time `json:"last_commit_when"` // `type` will be `file`, `dir`, `symlink`, or `submodule` Type string `json:"type"` Size int64 `json:"size"` diff --git a/modules/structs/repo_note.go b/modules/structs/repo_note.go index 76c6c17898..4eaf5a255d 100644 --- a/modules/structs/repo_note.go +++ b/modules/structs/repo_note.go @@ -8,7 +8,3 @@ type Note struct { Message string `json:"message"` Commit *Commit `json:"commit"` } - -type NoteOptions struct { - Message string `json:"message"` -} diff --git a/modules/structs/task.go b/modules/structs/task.go index 84b618119a..ed11a33e28 100644 --- a/modules/structs/task.go +++ b/modules/structs/task.go @@ -13,9 +13,8 @@ func (taskType TaskType) Name() string { switch taskType { case TaskTypeMigrateRepo: return "Migrate Repository" - default: - return "" } + return "" } // TaskStatus defines task status diff --git a/modules/structs/user.go b/modules/structs/user.go index 49e4c495cf..be20349e53 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -6,7 +6,7 @@ package structs import ( "time" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" ) // User represents a user @@ -27,7 +27,7 @@ type User struct { Email string `json:"email"` // URL to the user's avatar AvatarURL string `json:"avatar_url"` - // URL to the user's profile page + // URL to the user's gitea page HTMLURL string `json:"html_url"` // User locale Language string `json:"language"` @@ -62,7 +62,7 @@ type User struct { // MarshalJSON implements the json.Marshaler interface for User, adding field(s) for backward compatibility func (u User) MarshalJSON() ([]byte, error) { - // Redeclaring User to avoid recursion + // Re-declaring User to avoid recursion type shadow User return json.Marshal(struct { shadow @@ -84,7 +84,6 @@ type UserSettings struct { EnableRepoUnitHints bool `json:"enable_repo_unit_hints"` // Privacy HideEmail bool `json:"hide_email"` - HidePronouns bool `json:"hide_pronouns"` HideActivity bool `json:"hide_activity"` } @@ -102,7 +101,6 @@ type UserSettingsOptions struct { EnableRepoUnitHints *bool `json:"enable_repo_unit_hints"` // Privacy HideEmail *bool `json:"hide_email"` - HidePronouns *bool `json:"hide_pronouns"` HideActivity *bool `json:"hide_activity"` } diff --git a/modules/structs/user_app.go b/modules/structs/user_app.go index 6592c1cd48..7f78fbd495 100644 --- a/modules/structs/user_app.go +++ b/modules/structs/user_app.go @@ -23,11 +23,9 @@ type AccessToken struct { type AccessTokenList []*AccessToken // CreateAccessTokenOption options when create access token -// swagger:model CreateAccessTokenOption type CreateAccessTokenOption struct { // required: true - Name string `json:"name" binding:"Required"` - // example: ["all", "read:activitypub","read:issue", "write:misc", "read:notification", "read:organization", "read:package", "read:repository", "read:user"] + Name string `json:"name" binding:"Required"` Scopes []string `json:"scopes"` } diff --git a/modules/structs/user_email.go b/modules/structs/user_email.go index 485d0de1af..9319667e8f 100644 --- a/modules/structs/user_email.go +++ b/modules/structs/user_email.go @@ -7,7 +7,7 @@ package structs // Email an email address belonging to a user type Email struct { // swagger:strfmt email - Email string `json:"email" binding:"EmailWithAllowedDomain"` + Email string `json:"email"` Verified bool `json:"verified"` Primary bool `json:"primary"` UserID int64 `json:"user_id"` diff --git a/modules/structs/workflow.go b/modules/structs/workflow.go index 704ed0e65b..c4429ea0a2 100644 --- a/modules/structs/workflow.go +++ b/modules/structs/workflow.go @@ -12,18 +12,4 @@ type DispatchWorkflowOption struct { Ref string `json:"ref"` // Input keys and values configured in the workflow file. Inputs map[string]string `json:"inputs"` - // Flag to return the run info - // default: false - ReturnRunInfo bool `json:"return_run_info"` -} - -// DispatchWorkflowRun represents a workflow run -// swagger:model -type DispatchWorkflowRun struct { - // the workflow run id - ID int64 `json:"id"` - // a unique number for each run of a repository - RunNumber int64 `json:"run_number"` - // the jobs name - Jobs []string `json:"jobs"` } diff --git a/modules/svg/svg.go b/modules/svg/svg.go index e00d8de2d1..016e1dc08b 100644 --- a/modules/svg/svg.go +++ b/modules/svg/svg.go @@ -9,9 +9,9 @@ import ( "path" "strings" - gitea_html "forgejo.org/modules/html" - "forgejo.org/modules/log" - "forgejo.org/modules/public" + gitea_html "code.gitea.io/gitea/modules/html" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/public" ) var svgIcons map[string]string diff --git a/modules/sync/status_pool.go b/modules/sync/status_pool.go index f22e3e155b..6f075d54b7 100644 --- a/modules/sync/status_pool.go +++ b/modules/sync/status_pool.go @@ -6,7 +6,7 @@ package sync import ( "sync" - "forgejo.org/modules/container" + "code.gitea.io/gitea/modules/container" ) // StatusTable is a table maintains true/false values. diff --git a/modules/system/appstate_test.go b/modules/system/appstate_test.go index d19900c03d..d4b9e167c2 100644 --- a/modules/system/appstate_test.go +++ b/modules/system/appstate_test.go @@ -6,11 +6,10 @@ package system import ( "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMain(m *testing.M) { @@ -37,30 +36,30 @@ func (*testItem2) Name() string { } func TestAppStateDB(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, unittest.PrepareTestDatabase()) as := &DBStore{} item1 := new(testItem1) - require.NoError(t, as.Get(db.DefaultContext, item1)) - assert.Empty(t, item1.Val1) - assert.Equal(t, 0, item1.Val2) + assert.NoError(t, as.Get(db.DefaultContext, item1)) + assert.Equal(t, "", item1.Val1) + assert.EqualValues(t, 0, item1.Val2) item1 = new(testItem1) item1.Val1 = "a" item1.Val2 = 2 - require.NoError(t, as.Set(db.DefaultContext, item1)) + assert.NoError(t, as.Set(db.DefaultContext, item1)) item2 := new(testItem2) item2.K = "V" - require.NoError(t, as.Set(db.DefaultContext, item2)) + assert.NoError(t, as.Set(db.DefaultContext, item2)) item1 = new(testItem1) - require.NoError(t, as.Get(db.DefaultContext, item1)) + assert.NoError(t, as.Get(db.DefaultContext, item1)) assert.Equal(t, "a", item1.Val1) - assert.Equal(t, 2, item1.Val2) + assert.EqualValues(t, 2, item1.Val2) item2 = new(testItem2) - require.NoError(t, as.Get(db.DefaultContext, item2)) + assert.NoError(t, as.Get(db.DefaultContext, item2)) assert.Equal(t, "V", item2.K) } diff --git a/modules/system/db.go b/modules/system/db.go index 384087ab4f..17178283d9 100644 --- a/modules/system/db.go +++ b/modules/system/db.go @@ -6,9 +6,9 @@ package system import ( "context" - "forgejo.org/models/system" - "forgejo.org/modules/json" - "forgejo.org/modules/util" + "code.gitea.io/gitea/models/system" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" ) // DBStore can be used to store app state items in local filesystem diff --git a/modules/templates/base.go b/modules/templates/base.go index 76d8e3271e..2c2f35bbed 100644 --- a/modules/templates/base.go +++ b/modules/templates/base.go @@ -7,8 +7,8 @@ import ( "slices" "strings" - "forgejo.org/modules/assetfs" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/setting" ) func AssetFS() *assetfs.LayeredFS { diff --git a/modules/templates/dynamic.go b/modules/templates/dynamic.go index c5752c8c72..e1babd83c9 100644 --- a/modules/templates/dynamic.go +++ b/modules/templates/dynamic.go @@ -6,8 +6,8 @@ package templates import ( - "forgejo.org/modules/assetfs" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/setting" ) func BuiltinAssets() *assetfs.Layer { diff --git a/modules/templates/eval/eval.go b/modules/templates/eval/eval.go index 487a1de4b0..5d4ac915b9 100644 --- a/modules/templates/eval/eval.go +++ b/modules/templates/eval/eval.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) type Num struct { diff --git a/modules/templates/eval/eval_test.go b/modules/templates/eval/eval_test.go index 3e68203638..c9e514b5eb 100644 --- a/modules/templates/eval/eval_test.go +++ b/modules/templates/eval/eval_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func tokens(s string) (a []any) { @@ -21,15 +20,15 @@ func tokens(s string) (a []any) { func TestEval(t *testing.T) { n, err := Expr(0, "/", 0.0) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, math.IsNaN(n.Value.(float64))) _, err = Expr(nil) - require.ErrorContains(t, err, "unsupported token type") + assert.ErrorContains(t, err, "unsupported token type") _, err = Expr([]string{}) - require.ErrorContains(t, err, "unsupported token type") + assert.ErrorContains(t, err, "unsupported token type") _, err = Expr(struct{}{}) - require.ErrorContains(t, err, "unsupported token type") + assert.ErrorContains(t, err, "unsupported token type") cases := []struct { expr string @@ -70,8 +69,9 @@ func TestEval(t *testing.T) { for _, c := range cases { n, err := Expr(tokens(c.expr)...) - require.NoError(t, err, "expr: %s", c.expr) - assert.Equal(t, c.want, n.Value) + if assert.NoError(t, err, "expr: %s", c.expr) { + assert.Equal(t, c.want, n.Value) + } } bads := []struct { @@ -89,6 +89,6 @@ func TestEval(t *testing.T) { } for _, c := range bads { _, err = Expr(tokens(c.expr)...) - require.ErrorContains(t, err, c.errMsg, "expr: %s", c.expr) + assert.ErrorContains(t, err, c.errMsg, "expr: %s", c.expr) } } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 02b175e6f6..f1ae1c8bb1 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -14,14 +14,15 @@ import ( "strings" "time" - user_model "forgejo.org/models/user" - "forgejo.org/modules/base" - "forgejo.org/modules/markup" - "forgejo.org/modules/setting" - "forgejo.org/modules/svg" - "forgejo.org/modules/templates/eval" - "forgejo.org/modules/util" - "forgejo.org/services/gitdiff" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/svg" + "code.gitea.io/gitea/modules/templates/eval" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/gitdiff" ) // NewFuncMap returns functions for injecting to templates @@ -51,7 +52,6 @@ func NewFuncMap() template.FuncMap { "StringUtils": NewStringUtils, "SliceUtils": NewSliceUtils, "JsonUtils": NewJsonUtils, - "DateUtils": NewDateUtils, // ----------------------------------------------------------------- // svg / avatar / icon / color @@ -64,18 +64,16 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // time / number / format - "FileSize": FileSizePanic, - "CountFmt": base.FormatNumberSI, - "Sec2Time": util.SecToTime, + "FileSize": FileSizePanic, + "CountFmt": base.FormatNumberSI, + "TimeSince": timeutil.TimeSince, + "TimeSinceUnix": timeutil.TimeSinceUnix, + "DateTime": timeutil.DateTime, + "Sec2Time": util.SecToTime, "LoadTimes": func(startTime time.Time) string { return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" }, - // for backward compatibility only, do not use them anymore - "TimeSince": timeSinceLegacy, - "TimeSinceUnix": timeSinceLegacy, - "DateTime": dateTimeLegacy, - // ----------------------------------------------------------------- // setting "AppName": func() string { @@ -103,10 +101,6 @@ func NewFuncMap() template.FuncMap { "AppVer": func() string { return setting.AppVer }, - "AppVerNoMetadata": func() string { - version, _, _ := strings.Cut(setting.AppVer, "+") - return version - }, "AppDomain": func() string { // documented in mail-templates.md return setting.Domain }, @@ -178,17 +172,15 @@ func NewFuncMap() template.FuncMap { "RenderCommitMessage": RenderCommitMessage, "RenderCommitMessageLinkSubject": RenderCommitMessageLinkSubject, - "RenderCommitBody": RenderCommitBody, - "RenderCodeBlock": RenderCodeBlock, - "RenderIssueTitle": RenderIssueTitle, - "RenderRefIssueTitle": RenderRefIssueTitle, - "RenderEmoji": RenderEmoji, - "ReactionToEmoji": ReactionToEmoji, + "RenderCommitBody": RenderCommitBody, + "RenderCodeBlock": RenderCodeBlock, + "RenderIssueTitle": RenderIssueTitle, + "RenderEmoji": RenderEmoji, + "ReactionToEmoji": ReactionToEmoji, "RenderMarkdownToHtml": RenderMarkdownToHtml, "RenderLabel": RenderLabel, "RenderLabels": RenderLabels, - "RenderReviewRequest": RenderReviewRequest, // ----------------------------------------------------------------- // misc diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go index d60397df08..55a55dd7f4 100644 --- a/modules/templates/htmlrenderer.go +++ b/modules/templates/htmlrenderer.go @@ -19,12 +19,12 @@ import ( "sync/atomic" texttemplate "text/template" - "forgejo.org/modules/assetfs" - "forgejo.org/modules/graceful" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/templates/scopedtmpl" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates/scopedtmpl" + "code.gitea.io/gitea/modules/util" ) type TemplateExecutor scopedtmpl.TemplateExecutor diff --git a/modules/templates/htmlrenderer_test.go b/modules/templates/htmlrenderer_test.go index d7a4cd7161..2a74b74c23 100644 --- a/modules/templates/htmlrenderer_test.go +++ b/modules/templates/htmlrenderer_test.go @@ -10,10 +10,9 @@ import ( "strings" "testing" - "forgejo.org/modules/assetfs" + "code.gitea.io/gitea/modules/assetfs" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestExtractErrorLine(t *testing.T) { @@ -61,12 +60,12 @@ func TestHandleError(t *testing.T) { test := func(s string, h func(error) string, expect string) { err := os.WriteFile(dir+"/test.tmpl", []byte(s), 0o644) - require.NoError(t, err) + assert.NoError(t, err) tmpl := template.New("test") _, err = tmpl.Parse(s) - require.Error(t, err) + assert.Error(t, err) msg := h(err) - assert.Equal(t, strings.TrimSpace(expect), strings.TrimSpace(msg)) + assert.EqualValues(t, strings.TrimSpace(expect), strings.TrimSpace(msg)) } test("{{", p.handleGenericTemplateError, ` @@ -94,7 +93,7 @@ template error: tmp:test:1 : unexpected "3" in operand // no idea about how to trigger such strange error, so mock an error to test it err := os.WriteFile(dir+"/test.tmpl", []byte("god knows XXX"), 0o644) - require.NoError(t, err) + assert.NoError(t, err) expectedMsg := ` template error: tmp:test:1 : expected end; found XXX ---------------------------------------------------------------------- @@ -103,5 +102,5 @@ god knows XXX ---------------------------------------------------------------------- ` actualMsg := p.handleExpectedEndError(errors.New("template: test:1: expected end; found XXX")) - assert.Equal(t, strings.TrimSpace(expectedMsg), strings.TrimSpace(actualMsg)) + assert.EqualValues(t, strings.TrimSpace(expectedMsg), strings.TrimSpace(actualMsg)) } diff --git a/modules/templates/mailer.go b/modules/templates/mailer.go index a40728d7c7..ee79755dbb 100644 --- a/modules/templates/mailer.go +++ b/modules/templates/mailer.go @@ -11,9 +11,9 @@ import ( "strings" texttmpl "text/template" - "forgejo.org/modules/base" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}\s*$`) diff --git a/modules/templates/main_test.go b/modules/templates/main_test.go index 946bc603f6..bbdf5d2f99 100644 --- a/modules/templates/main_test.go +++ b/modules/templates/main_test.go @@ -7,12 +7,11 @@ import ( "context" "testing" - "forgejo.org/models/unittest" - "forgejo.org/modules/markup" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/markup" - _ "forgejo.org/models" - _ "forgejo.org/models/forgefed" - _ "forgejo.org/models/issues" + _ "code.gitea.io/gitea/models" + _ "code.gitea.io/gitea/models/issues" ) func TestMain(m *testing.M) { diff --git a/modules/templates/scopedtmpl/scopedtmpl.go b/modules/templates/scopedtmpl/scopedtmpl.go index 41a8ca86e9..2722ba97a2 100644 --- a/modules/templates/scopedtmpl/scopedtmpl.go +++ b/modules/templates/scopedtmpl/scopedtmpl.go @@ -192,21 +192,21 @@ func newScopedTemplateSet(all *template.Template, name string) (*scopedTemplateS collectTemplates(nodeList.Nodes) } else if node.Type() == parse.NodeIf { nodeIf := node.(*parse.IfNode) - collectTemplates(nodeIf.List.Nodes) - if nodeIf.ElseList != nil { - collectTemplates(nodeIf.ElseList.Nodes) + collectTemplates(nodeIf.BranchNode.List.Nodes) + if nodeIf.BranchNode.ElseList != nil { + collectTemplates(nodeIf.BranchNode.ElseList.Nodes) } } else if node.Type() == parse.NodeRange { nodeRange := node.(*parse.RangeNode) - collectTemplates(nodeRange.List.Nodes) - if nodeRange.ElseList != nil { - collectTemplates(nodeRange.ElseList.Nodes) + collectTemplates(nodeRange.BranchNode.List.Nodes) + if nodeRange.BranchNode.ElseList != nil { + collectTemplates(nodeRange.BranchNode.ElseList.Nodes) } } else if node.Type() == parse.NodeWith { nodeWith := node.(*parse.WithNode) - collectTemplates(nodeWith.List.Nodes) - if nodeWith.ElseList != nil { - collectTemplates(nodeWith.ElseList.Nodes) + collectTemplates(nodeWith.BranchNode.List.Nodes) + if nodeWith.BranchNode.ElseList != nil { + collectTemplates(nodeWith.BranchNode.ElseList.Nodes) } } } diff --git a/modules/templates/scopedtmpl/scopedtmpl_test.go b/modules/templates/scopedtmpl/scopedtmpl_test.go index 9bbd0c7c70..774b8c7d42 100644 --- a/modules/templates/scopedtmpl/scopedtmpl_test.go +++ b/modules/templates/scopedtmpl/scopedtmpl_test.go @@ -12,7 +12,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestScopedTemplateSetFuncMap(t *testing.T) { @@ -23,7 +22,7 @@ func TestScopedTemplateSetFuncMap(t *testing.T) { }}) _, err := all.New("base").Parse(`{{CtxFunc "base"}}`) - require.NoError(t, err) + assert.NoError(t, err) _, err = all.New("test").Parse(strings.TrimSpace(` {{template "base"}} @@ -31,10 +30,10 @@ func TestScopedTemplateSetFuncMap(t *testing.T) { {{template "base"}} {{CtxFunc "test"}} `)) - require.NoError(t, err) + assert.NoError(t, err) ts, err := newScopedTemplateSet(all, "test") - require.NoError(t, err) + assert.NoError(t, err) // try to use different CtxFunc to render concurrently @@ -58,12 +57,12 @@ func TestScopedTemplateSetFuncMap(t *testing.T) { wg.Add(2) go func() { err := ts.newExecutor(funcMap1).Execute(&out1, nil) - require.NoError(t, err) + assert.NoError(t, err) wg.Done() }() go func() { err := ts.newExecutor(funcMap2).Execute(&out2, nil) - require.NoError(t, err) + assert.NoError(t, err) wg.Done() }() wg.Wait() @@ -74,17 +73,17 @@ func TestScopedTemplateSetFuncMap(t *testing.T) { func TestScopedTemplateSetEscape(t *testing.T) { all := template.New("") _, err := all.New("base").Parse(`{{.text}}`) - require.NoError(t, err) + assert.NoError(t, err) _, err = all.New("test").Parse(`{{template "base" .}}
    {{.text}}
    `) - require.NoError(t, err) + assert.NoError(t, err) ts, err := newScopedTemplateSet(all, "test") - require.NoError(t, err) + assert.NoError(t, err) out := bytes.Buffer{} err = ts.newExecutor(nil).Execute(&out, map[string]string{"param": "/", "text": "<"}) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, `<
    <
    `, out.String()) } @@ -92,8 +91,8 @@ func TestScopedTemplateSetEscape(t *testing.T) { func TestScopedTemplateSetUnsafe(t *testing.T) { all := template.New("") _, err := all.New("test").Parse(``) - require.NoError(t, err) + assert.NoError(t, err) _, err = newScopedTemplateSet(all, "test") - require.ErrorContains(t, err, "appears in an ambiguous context within a URL") + assert.ErrorContains(t, err, "appears in an ambiguous context within a URL") } diff --git a/modules/templates/static.go b/modules/templates/static.go index 776548c853..b5a7e561ec 100644 --- a/modules/templates/static.go +++ b/modules/templates/static.go @@ -8,8 +8,8 @@ package templates import ( "time" - "forgejo.org/modules/assetfs" - "forgejo.org/modules/timeutil" + "code.gitea.io/gitea/modules/assetfs" + "code.gitea.io/gitea/modules/timeutil" ) // GlobalModTime provide a global mod time for embedded asset files diff --git a/modules/templates/util_avatar.go b/modules/templates/util_avatar.go index 93ebec51e4..85832cf264 100644 --- a/modules/templates/util_avatar.go +++ b/modules/templates/util_avatar.go @@ -9,13 +9,13 @@ import ( "html" "html/template" - activities_model "forgejo.org/models/activities" - "forgejo.org/models/avatars" - "forgejo.org/models/organization" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - gitea_html "forgejo.org/modules/html" - "forgejo.org/modules/setting" + activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/avatars" + "code.gitea.io/gitea/models/organization" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + gitea_html "code.gitea.io/gitea/modules/html" + "code.gitea.io/gitea/modules/setting" ) type AvatarUtils struct { @@ -34,7 +34,7 @@ func AvatarHTML(src string, size int, class, name string) template.HTML { name = "avatar" } - return template.HTML(``) + return template.HTML(``) } // Avatar renders user avatars. args: user, size (int), class (string) diff --git a/modules/templates/util_date.go b/modules/templates/util_date.go deleted file mode 100644 index bb83bf692a..0000000000 --- a/modules/templates/util_date.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package templates - -import ( - "fmt" - "html" - "html/template" - "strings" - "time" - - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" - "forgejo.org/modules/translation" -) - -type DateUtils struct{} - -func NewDateUtils() *DateUtils { - return (*DateUtils)(nil) // the util is stateless, and we do not need to create an instance -} - -// AbsoluteShort renders in "Jan 01, 2006" format -func (du *DateUtils) AbsoluteShort(time any) template.HTML { - return dateTimeFormat("short", time) -} - -// AbsoluteLong renders in "January 01, 2006" format -func (du *DateUtils) AbsoluteLong(time any) template.HTML { - return dateTimeFormat("long", time) -} - -// FullTime renders in "Jan 01, 2006 20:33:44" format -func (du *DateUtils) FullTime(time any) template.HTML { - return dateTimeFormat("full", time) -} - -func (du *DateUtils) TimeSince(time any) template.HTML { - return TimeSince(time) -} - -// ParseLegacy parses the datetime in legacy format, eg: "2016-01-02" in server's timezone. -// It shouldn't be used in new code. New code should use Time or TimeStamp as much as possible. -func (du *DateUtils) ParseLegacy(datetime string) time.Time { - return parseLegacy(datetime) -} - -func parseLegacy(datetime string) time.Time { - t, err := time.Parse(time.RFC3339, datetime) - if err != nil { - t, _ = time.ParseInLocation(time.DateOnly, datetime, setting.DefaultUILocation) - } - return t -} - -func dateTimeLegacy(format string, datetime any, _ ...string) template.HTML { - if !setting.IsProd || setting.IsInTesting { - panic("dateTimeLegacy is for backward compatibility only, do not use it in new code") - } - if s, ok := datetime.(string); ok { - datetime = parseLegacy(s) - } - return dateTimeFormat(format, datetime) -} - -func timeSinceLegacy(time any, _ translation.Locale) template.HTML { - if !setting.IsProd || setting.IsInTesting { - panic("timeSinceLegacy is for backward compatibility only, do not use it in new code") - } - return TimeSince(time) -} - -func anyToTime(any any) (t time.Time, isZero bool) { - switch v := any.(type) { - case nil: - // it is zero - case *time.Time: - if v != nil { - t = *v - } - case time.Time: - t = v - case timeutil.TimeStamp: - t = v.AsTime() - case timeutil.TimeStampNano: - t = v.AsTime() - case int: - t = timeutil.TimeStamp(v).AsTime() - case int64: - t = timeutil.TimeStamp(v).AsTime() - default: - panic(fmt.Sprintf("Unsupported time type %T", any)) - } - return t, t.IsZero() || t.Unix() == 0 -} - -func dateTimeFormat(format string, datetime any) template.HTML { - t, isZero := anyToTime(datetime) - if isZero { - return "-" - } - var textEscaped string - datetimeEscaped := html.EscapeString(t.Format(time.RFC3339)) - if format == "full" { - textEscaped = html.EscapeString(t.Format("2006-01-02 15:04:05 -07:00")) - } else { - textEscaped = html.EscapeString(t.Format("2006-01-02")) - } - - attrs := []string{`weekday=""`, `year="numeric"`} - switch format { - case "short", "long": // date only - attrs = append(attrs, `month="`+format+`"`, `day="numeric"`) - return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) - case "full": // full date including time - attrs = append(attrs, `format="datetime"`, `month="short"`, `day="numeric"`, `hour="numeric"`, `minute="numeric"`, `second="numeric"`, `data-tooltip-content`, `data-tooltip-interactive="true"`) - return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) - default: - panic(fmt.Sprintf("Unsupported format %s", format)) - } -} - -func timeSinceTo(then any, now time.Time) template.HTML { - thenTime, isZero := anyToTime(then) - if isZero { - return "-" - } - - friendlyText := thenTime.Format("2006-01-02 15:04:05 -07:00") - - // document: https://github.com/github/relative-time-element - attrs := `tense="past"` - isFuture := now.Before(thenTime) - if isFuture { - attrs = `tense="future"` - } - - // declare data-tooltip-content attribute to switch from "title" tooltip to "tippy" tooltip - htm := fmt.Sprintf(`%s`, - attrs, thenTime.Format(time.RFC3339), friendlyText) - return template.HTML(htm) -} - -// TimeSince renders relative time HTML given a time -func TimeSince(then any) template.HTML { - if setting.UI.PreferredTimestampTense == "absolute" { - return dateTimeFormat("full", then) - } - return timeSinceTo(then, time.Now()) -} diff --git a/modules/templates/util_date_test.go b/modules/templates/util_date_test.go deleted file mode 100644 index 37caf0d422..0000000000 --- a/modules/templates/util_date_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package templates - -import ( - "html/template" - "testing" - "time" - - "forgejo.org/modules/setting" - "forgejo.org/modules/test" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestDateTime(t *testing.T) { - testTz, err := time.LoadLocation("America/New_York") - require.NoError(t, err) - defer test.MockVariableValue(&setting.DefaultUILocation, testTz)() - defer test.MockVariableValue(&setting.IsInTesting, false)() - - du := NewDateUtils() - - refTimeStr := "2018-01-01T00:00:00Z" - refDateStr := "2018-01-01" - refTime, _ := time.Parse(time.RFC3339, refTimeStr) - refTimeStamp := timeutil.TimeStamp(refTime.Unix()) - - for _, val := range []any{nil, 0, time.Time{}, timeutil.TimeStamp(0)} { - for _, fun := range []func(val any) template.HTML{du.AbsoluteLong, du.AbsoluteShort, du.FullTime} { - assert.EqualValues(t, "-", fun(val)) - } - } - - actual := dateTimeLegacy("short", "invalid") - assert.EqualValues(t, `-`, actual) - - actual = dateTimeLegacy("short", refTimeStr) - assert.EqualValues(t, `2018-01-01`, actual) - - actual = du.AbsoluteShort(refTime) - assert.EqualValues(t, `2018-01-01`, actual) - - actual = du.AbsoluteLong(refTime) - assert.EqualValues(t, `2018-01-01`, actual) - - actual = dateTimeLegacy("short", refDateStr) - assert.EqualValues(t, `2018-01-01`, actual) - - actual = du.AbsoluteShort(refTimeStamp) - assert.EqualValues(t, `2017-12-31`, actual) - - actual = du.AbsoluteLong(refTimeStamp) - assert.EqualValues(t, `2017-12-31`, actual) - - actual = du.FullTime(refTimeStamp) - assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) -} - -func TestTimeSince(t *testing.T) { - testTz, _ := time.LoadLocation("America/New_York") - defer test.MockVariableValue(&setting.DefaultUILocation, testTz)() - defer test.MockVariableValue(&setting.IsInTesting, false)() - - du := NewDateUtils() - assert.EqualValues(t, "-", du.TimeSince(nil)) - - refTimeStr := "2018-01-01T00:00:00Z" - refTime, _ := time.Parse(time.RFC3339, refTimeStr) - - actual := du.TimeSince(refTime) - assert.EqualValues(t, `2018-01-01 00:00:00 +00:00`, actual) - - actual = timeSinceTo(&refTime, time.Time{}) - assert.EqualValues(t, `2018-01-01 00:00:00 +00:00`, actual) - - actual = timeSinceLegacy(timeutil.TimeStampNano(refTime.UnixNano()), nil) - assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) -} diff --git a/modules/templates/util_dict.go b/modules/templates/util_dict.go index 16f722e61b..8d6376b522 100644 --- a/modules/templates/util_dict.go +++ b/modules/templates/util_dict.go @@ -4,15 +4,14 @@ package templates import ( - "errors" "fmt" "html" "html/template" "reflect" - "forgejo.org/modules/container" - "forgejo.org/modules/json" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/setting" ) func dictMerge(base map[string]any, arg any) bool { @@ -34,7 +33,7 @@ func dictMerge(base map[string]any, arg any) bool { // The dot syntax is highly discouraged because it might cause unclear key conflicts. It's always good to use explicit keys. func dict(args ...any) (map[string]any, error) { if len(args)%2 != 0 { - return nil, errors.New("invalid dict constructor syntax: must have key-value pairs") + return nil, fmt.Errorf("invalid dict constructor syntax: must have key-value pairs") } m := make(map[string]any, len(args)/2) for i := 0; i < len(args); i += 2 { diff --git a/modules/templates/util_json.go b/modules/templates/util_json.go index 3bc80e8f21..71a4e23d36 100644 --- a/modules/templates/util_json.go +++ b/modules/templates/util_json.go @@ -6,7 +6,7 @@ package templates import ( "bytes" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" ) type JsonUtils struct{} //nolint:revive diff --git a/modules/templates/util_misc.go b/modules/templates/util_misc.go index 60f918be47..774385483b 100644 --- a/modules/templates/util_misc.go +++ b/modules/templates/util_misc.go @@ -1,5 +1,4 @@ // Copyright 2023 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package templates @@ -13,16 +12,14 @@ import ( "strings" "time" - activities_model "forgejo.org/models/activities" - asymkey_model "forgejo.org/models/asymkey" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" - giturl "forgejo.org/modules/git/url" - "forgejo.org/modules/json" - "forgejo.org/modules/log" - "forgejo.org/modules/repository" - "forgejo.org/modules/svg" + activities_model "code.gitea.io/gitea/models/activities" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" + giturl "code.gitea.io/gitea/modules/git/url" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/svg" "github.com/editorconfig/editorconfig-core-go/v2" ) @@ -41,11 +38,10 @@ func SortArrow(normSort, revSort, urlSort string, isDefault bool) template.HTML } else { // if sort arg is in url test if it correlates with column header sort arguments // the direction of the arrow should indicate the "current sort order", up means ASC(normal), down means DESC(rev) - switch urlSort { - case normSort: + if urlSort == normSort { // the table is sorted with this header normal return svg.RenderHTML("octicon-triangle-up", 16) - case revSort: + } else if urlSort == revSort { // the table is sorted with this header reverse return svg.RenderHTML("octicon-triangle-down", 16) } @@ -63,7 +59,6 @@ func IsMultilineCommitMessage(msg string) bool { type Actioner interface { GetOpType() activities_model.ActionType GetActUserName(ctx context.Context) string - GetRepo(ctx context.Context) *repo_model.Repository GetRepoUserName(ctx context.Context) string GetRepoName(ctx context.Context) string GetRepoPath(ctx context.Context) string @@ -113,7 +108,7 @@ func ActionIcon(opType activities_model.ActionType) string { } // ActionContent2Commits converts action content to push commits -func ActionContent2Commits(ctx context.Context, act Actioner) *repository.PushCommits { +func ActionContent2Commits(act Actioner) *repository.PushCommits { push := repository.NewPushCommits() if act == nil || act.GetContent() == "" { @@ -127,23 +122,6 @@ func ActionContent2Commits(ctx context.Context, act Actioner) *repository.PushCo if push.Len == 0 { push.Len = len(push.Commits) } - repo := act.GetRepo(ctx) - for _, commit := range push.Commits { - gitCommit, err := repository.PushCommitToCommit(commit) - if err != nil { - // Only happens if the commit has an invalid sha - commit.Verification = &asymkey_model.ObjectVerification{ - Verified: false, - Reason: "git.error.invalid_commit_id", - } - continue - } - verification := asymkey_model.ParseCommitWithSignature(ctx, gitCommit) - _ = asymkey_model.CalculateTrustStatus(verification, repo.GetTrustModel(), func(user *user_model.User) (bool, error) { - return repo_model.IsOwnerMemberCollaborator(ctx, repo, user.ID) - }, nil) - commit.Verification = verification - } return push } diff --git a/modules/templates/util_misc_test.go b/modules/templates/util_misc_test.go deleted file mode 100644 index 3d59f29bd1..0000000000 --- a/modules/templates/util_misc_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package templates - -import ( - "testing" - - activities_model "forgejo.org/models/activities" - asymkey_model "forgejo.org/models/asymkey" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - "forgejo.org/modules/git" - "forgejo.org/modules/json" - "forgejo.org/modules/repository" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func pushCommits() *repository.PushCommits { - pushCommits := repository.NewPushCommits() - pushCommits.Commits = []*repository.PushCommit{ - { - Sha1: "x", - CommitterEmail: "user2@example.com", - CommitterName: "User2", - AuthorEmail: "user2@example.com", - AuthorName: "User2", - Message: "invalid sha1", - }, - { - Sha1: "2c54faec6c45d31c1abfaecdab471eac6633738a", - CommitterEmail: "user2@example.com", - CommitterName: "User2", - AuthorEmail: "user2@example.com", - AuthorName: "User2", - Message: "not signed commit", - }, - { - Sha1: "2d491b2985a7ff848d5c02748e7ea9f9f7619f9f", - CommitterEmail: "non-existent", - CommitterName: "user2", - AuthorEmail: "non-existent", - AuthorName: "user2", - Message: "Using email that isn't known to Forgejo", - Signature: &git.ObjectSignature{ - Payload: `tree 2d491b2985a7ff848d5c02748e7ea9f9f7619f9f -parent 45b03601635a1f463b81963a4022c7f87ce96ef9 -author user2 1699710556 +0100 -committer user2 1699710556 +0100 - -Using email that isn't known to Forgejo -`, - Signature: `-----BEGIN SSH SIGNATURE----- -U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgoGSe9Zy7Ez9bSJcaTNjh/Y7p95 -f5DujjqkpzFRtw6CEAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 -AAAAQIMufOuSjZeDUujrkVK4sl7ICa0WwEftas8UAYxx0Thdkiw2qWjR1U1PKfTLm16/w8 -/bS1LX1lZNuzm2LR2qEgw= ------END SSH SIGNATURE----- -`, - }, - }, - { - Sha1: "853694aae8816094a0d875fee7ea26278dbf5d0f", - CommitterEmail: "user2@example.com", - CommitterName: "user2", - AuthorEmail: "user2@example.com", - AuthorName: "user2", - Message: "Add content", - Signature: &git.ObjectSignature{ - Payload: `tree 853694aae8816094a0d875fee7ea26278dbf5d0f -parent c2780d5c313da2a947eae22efd7dacf4213f4e7f -author user2 1699707877 +0100 -committer user2 1699707877 +0100 - -Add content -`, - Signature: `-----BEGIN SSH SIGNATURE----- -U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgoGSe9Zy7Ez9bSJcaTNjh/Y7p95 -f5DujjqkpzFRtw6CEAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 -AAAAQBe2Fwk/FKY3SBCnG6jSYcO6ucyahp2SpQ/0P+otslzIHpWNW8cQ0fGLdhhaFynJXQ -fs9cMpZVM9BfIKNUSO8QY= ------END SSH SIGNATURE----- -`, - }, - }, - } - return pushCommits -} - -func TestActionContent2Commits_VerificationState(t *testing.T) { - defer unittest.OverrideFixtures("models/fixtures/TestParseCommitWithSSHSignature/")() - require.NoError(t, unittest.PrepareTestDatabase()) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: user2.ID}) - commits, err := json.Marshal(pushCommits()) - require.NoError(t, err) - - act := &activities_model.Action{ - OpType: activities_model.ActionCommitRepo, - Repo: repo, - Content: string(commits), - } - push := ActionContent2Commits(t.Context(), act) - - assert.Equal(t, 4, push.Len) - assert.False(t, push.Commits[0].Verification.Verified) - assert.Empty(t, push.Commits[0].Verification.TrustStatus) - assert.Equal(t, "git.error.invalid_commit_id", push.Commits[0].Verification.Reason) - - assert.False(t, push.Commits[1].Verification.Verified) - assert.Empty(t, push.Commits[1].Verification.TrustStatus) - assert.Equal(t, asymkey_model.NotSigned, push.Commits[1].Verification.Reason) - - assert.False(t, push.Commits[2].Verification.Verified) - assert.Empty(t, push.Commits[2].Verification.TrustStatus) - assert.Equal(t, asymkey_model.NoKeyFound, push.Commits[2].Verification.Reason) - - assert.True(t, push.Commits[3].Verification.Verified) - assert.Equal(t, "user2 / SHA256:TKfwbZMR7e9OnlV2l1prfah1TXH8CmqR0PvFEXVCXA4", push.Commits[3].Verification.Reason) - assert.Equal(t, "trusted", push.Commits[3].Verification.TrustStatus) -} diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index a4d7a82eea..c4c5376afd 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -14,14 +14,14 @@ import ( "strings" "unicode" - issues_model "forgejo.org/models/issues" - "forgejo.org/modules/emoji" - "forgejo.org/modules/log" - "forgejo.org/modules/markup" - "forgejo.org/modules/markup/markdown" - "forgejo.org/modules/setting" - "forgejo.org/modules/translation" - "forgejo.org/modules/util" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/modules/emoji" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/util" ) // RenderCommitMessage renders commit message with XSS-safe and special links. @@ -130,17 +130,6 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) return template.HTML(renderedText) } -// RenderRefIssueTitle renders referenced issue/pull title with defined post processors -func RenderRefIssueTitle(ctx context.Context, text string) template.HTML { - renderedText, err := markup.RenderRefIssueTitle(&markup.RenderContext{Ctx: ctx}, template.HTMLEscapeString(text)) - if err != nil { - log.Error("RenderRefIssueTitle: %v", err) - return "" - } - - return template.HTML(renderedText) -} - // RenderLabel renders a label // locale is needed due to an import cycle with our context providing the `Tr` function func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { @@ -256,21 +245,9 @@ func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issu if isPull { issuesOrPull = "pulls" } - htmlCode += fmt.Sprintf("%s ", + htmlCode += fmt.Sprintf("%s ", repoLink, issuesOrPull, label.ID, RenderLabel(ctx, locale, label)) } htmlCode += "" return template.HTML(htmlCode) } - -func RenderReviewRequest(users []issues_model.RequestReviewTarget) template.HTML { - usernames := make([]string, 0, len(users)) - for _, user := range users { - usernames = append(usernames, template.HTMLEscapeString(user.Name())) - } - - htmlCode := `` - htmlCode += strings.Join(usernames, ", ") - htmlCode += "" - return template.HTML(htmlCode) -} diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go index 62e063213c..ea01612ac3 100644 --- a/modules/templates/util_render_test.go +++ b/modules/templates/util_render_test.go @@ -8,10 +8,10 @@ import ( "html/template" "testing" - "forgejo.org/models/db" - issues_model "forgejo.org/models/issues" - "forgejo.org/models/unittest" - "forgejo.org/modules/translation" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) @@ -35,8 +35,8 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit mail@domain.com @mention-user test #123 - space -` + "`code :+1: #123 code`\n" + space +` var testMetas = map[string]string{ "user": "user13", @@ -46,13 +46,13 @@ var testMetas = map[string]string{ } func TestApostrophesInMentions(t *testing.T) { - rendered := RenderMarkdownToHtml(t.Context(), "@mention-user's comment") - assert.Equal(t, template.HTML("

    @mention-user's comment

    \n"), rendered) + rendered := RenderMarkdownToHtml(context.Background(), "@mention-user's comment") + assert.EqualValues(t, template.HTML("

    @mention-user's comment

    \n"), rendered) } func TestNonExistantUserMention(t *testing.T) { - rendered := RenderMarkdownToHtml(t.Context(), "@ThisUserDoesNotExist @mention-user") - assert.Equal(t, template.HTML("

    @ThisUserDoesNotExist @mention-user

    \n"), rendered) + rendered := RenderMarkdownToHtml(context.Background(), "@ThisUserDoesNotExist @mention-user") + assert.EqualValues(t, template.HTML("

    @ThisUserDoesNotExist @mention-user

    \n"), rendered) } func TestRenderCommitBody(t *testing.T) { @@ -69,7 +69,7 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines", args: args{ - ctx: t.Context(), + ctx: context.Background(), msg: "first line\nsecond line", }, want: "second line", @@ -77,7 +77,7 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines with leading newlines", args: args{ - ctx: t.Context(), + ctx: context.Background(), msg: "\n\n\n\nfirst line\nsecond line", }, want: "second line", @@ -85,7 +85,7 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines with trailing newlines", args: args{ - ctx: t.Context(), + ctx: context.Background(), msg: "first line\nsecond line\n\n\n", }, want: "second line", @@ -111,25 +111,25 @@ func TestRenderCommitBody(t *testing.T) { com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare 88fc37a3c0 com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit -👍 +👍 mail@domain.com @mention-user test #123 - space -` + "`code 👍 #123 code`" - assert.EqualValues(t, expected, RenderCommitBody(t.Context(), testInput, testMetas)) + space` + + assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas)) } func TestRenderCommitMessage(t *testing.T) { expected := `space @mention-user ` - assert.EqualValues(t, expected, RenderCommitMessage(t.Context(), testInput, testMetas)) + assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas)) } func TestRenderCommitMessageLinkSubject(t *testing.T) { expected := `space @mention-user` - assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(t.Context(), testInput, "https://example.com/link", testMetas)) + assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas)) } func TestRenderIssueTitle(t *testing.T) { @@ -148,66 +148,38 @@ https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb.. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit -👍 +👍 mail@domain.com @mention-user test #123 - space -code :+1: #123 code + space ` - assert.EqualValues(t, expected, RenderIssueTitle(t.Context(), testInput, testMetas)) -} - -func TestRenderRefIssueTitle(t *testing.T) { - expected := ` space @mention-user -/just/a/path.bin -https://example.com/file.bin -[local link](file.bin) -[remote link](https://example.com) -[[local link|file.bin]] -[[remote link|https://example.com]] -![local image](image.jpg) -![remote image](https://example.com/image.jpg) -[[local image|image.jpg]] -[[remote link|https://example.com/image.jpg]] -https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash -com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare -https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb -com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit -👍 -mail@domain.com -@mention-user test -#123 - space -code :+1: #123 code -` - assert.EqualValues(t, expected, RenderRefIssueTitle(t.Context(), testInput)) + assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas)) } func TestRenderMarkdownToHtml(t *testing.T) { - expected := `

    space @mention-user
    + expected := `

    space @mention-user
    /just/a/path.bin https://example.com/file.bin local link remote link local link remote link -local image -remote image - - +local image +remote image +local image +remote link 88fc37a3c0...12fc37a3c0 (hash) com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare 88fc37a3c0 com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit -👍 +👍 mail@domain.com -@mention-user test +@mention-user test #123 -space -code :+1: #123 code

    +space

    ` - assert.EqualValues(t, expected, RenderMarkdownToHtml(t.Context(), testInput)) + assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput)) } func TestRenderLabels(t *testing.T) { diff --git a/modules/templates/util_string.go b/modules/templates/util_string.go index 2d255e54a7..f23b74786a 100644 --- a/modules/templates/util_string.go +++ b/modules/templates/util_string.go @@ -8,7 +8,7 @@ import ( "html/template" "strings" - "forgejo.org/modules/base" + "code.gitea.io/gitea/modules/base" ) type StringUtils struct{} @@ -19,10 +19,6 @@ func NewStringUtils() *StringUtils { return &stringUtils } -func (su *StringUtils) Make(arr ...string) []string { - return arr -} - func (su *StringUtils) HasPrefix(s any, prefix string) bool { switch v := s.(type) { case string: diff --git a/modules/templates/util_test.go b/modules/templates/util_test.go index e28da8090b..febaf7fa88 100644 --- a/modules/templates/util_test.go +++ b/modules/templates/util_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestDict(t *testing.T) { @@ -28,8 +27,9 @@ func TestDict(t *testing.T) { for _, c := range cases { got, err := dict(c.args...) - require.NoError(t, err) - assert.Equal(t, c.want, got) + if assert.NoError(t, err) { + assert.EqualValues(t, c.want, got) + } } bads := []struct { @@ -41,7 +41,7 @@ func TestDict(t *testing.T) { } for _, c := range bads { _, err := dict(c.args...) - require.Error(t, err) + assert.Error(t, err) } } @@ -51,7 +51,7 @@ func TestUtils(t *testing.T) { tmpl.Funcs(template.FuncMap{"SliceUtils": NewSliceUtils, "StringUtils": NewStringUtils}) template.Must(tmpl.Parse(code)) w := &strings.Builder{} - require.NoError(t, tmpl.Execute(w, data)) + assert.NoError(t, tmpl.Execute(w, data)) return w.String() } @@ -75,5 +75,5 @@ func TestUtils(t *testing.T) { template.Must(tmpl.Parse("{{SliceUtils.Contains .Slice .Value}}")) // error is like this: `template: test:1:12: executing "test" at : error calling Contains: ...` err := tmpl.Execute(io.Discard, map[string]any{"Slice": struct{}{}}) - require.ErrorContains(t, err, "invalid type, expected slice or array") + assert.ErrorContains(t, err, "invalid type, expected slice or array") } diff --git a/modules/templates/vars/vars_test.go b/modules/templates/vars/vars_test.go index a0c3490c3a..8f421d9e4b 100644 --- a/modules/templates/vars/vars_test.go +++ b/modules/templates/vars/vars_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestExpandVars(t *testing.T) { @@ -61,11 +60,11 @@ func TestExpandVars(t *testing.T) { for _, kase := range kases { t.Run(kase.tmpl, func(t *testing.T) { res, err := Expand(kase.tmpl, kase.data) - assert.Equal(t, kase.out, res) + assert.EqualValues(t, kase.out, res) if kase.error { - require.Error(t, err) + assert.Error(t, err) } else { - require.NoError(t, err) + assert.NoError(t, err) } }) } diff --git a/modules/test/distant_federation_server_mock.go b/modules/test/distant_federation_server_mock.go deleted file mode 100644 index 9bd908e2b9..0000000000 --- a/modules/test/distant_federation_server_mock.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package test - -import ( - "fmt" - "io" - "net/http" - "net/http/httptest" - "strings" - "testing" -) - -type FederationServerMockPerson struct { - ID int64 - Name string - PubKey string -} -type FederationServerMockRepository struct { - ID int64 -} -type FederationServerMock struct { - Persons []FederationServerMockPerson - Repositories []FederationServerMockRepository - LastPost string -} - -func NewFederationServerMockPerson(id int64, name string) FederationServerMockPerson { - return FederationServerMockPerson{ - ID: id, - Name: name, - PubKey: `"-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA18H5s7N6ItZUAh9tneII\nIuZdTTa3cZlLa/9ejWAHTkcp3WLW+/zbsumlMrWYfBy2/yTm56qasWt38iY4D6ul\n` + - `CPiwhAqX3REvVq8tM79a2CEqZn9ka6vuXoDgBg/sBf/BUWqf7orkjUXwk/U0Egjf\nk5jcurF4vqf1u+rlAHH37dvSBaDjNj6Qnj4OP12bjfaY/yvs7+jue/eNXFHjzN4E\n` + - `T2H4B/yeKTJ4UuAwTlLaNbZJul2baLlHelJPAsxiYaziVuV5P+IGWckY6RSerRaZ\nAkc4mmGGtjAyfN9aewe+lNVfwS7ElFx546PlLgdQgjmeSwLX8FWxbPE5A/PmaXCs\n` + - `nx+nou+3dD7NluULLtdd7K+2x02trObKXCAzmi5/Dc+yKTzpFqEz+hLNCz7TImP/\ncK//NV9Q+X67J9O27baH9R9ZF4zMw8rv2Pg0WLSw1z7lLXwlgIsDapeMCsrxkVO4\n` + - `LXX5AQ1xQNtlssnVoUBqBrvZsX2jUUKUocvZqMGuE4hfAgMBAAE=\n-----END PUBLIC KEY-----\n"`, - } -} - -func NewFederationServerMockRepository(id int64) FederationServerMockRepository { - return FederationServerMockRepository{ - ID: id, - } -} - -func (p FederationServerMockPerson) marshal(host string) string { - return fmt.Sprintf(`{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],`+ - `"id":"http://%[1]v/api/activitypub/user-id/%[2]v",`+ - `"type":"Person",`+ - `"icon":{"type":"Image","mediaType":"image/png","url":"http://%[1]v/avatars/1bb05d9a5f6675ed0272af9ea193063c"},`+ - `"url":"http://%[1]v/%[2]v",`+ - `"inbox":"http://%[1]v/api/activitypub/user-id/%[2]v/inbox",`+ - `"outbox":"http://%[1]v/api/activitypub/user-id/%[2]v/outbox",`+ - `"preferredUsername":"%[3]v",`+ - `"publicKey":{"id":"http://%[1]v/api/activitypub/user-id/%[2]v#main-key",`+ - `"owner":"http://%[1]v/api/activitypub/user-id/%[2]v",`+ - `"publicKeyPem":%[4]v}}`, host, p.ID, p.Name, p.PubKey) -} - -func NewFederationServerMock() *FederationServerMock { - return &FederationServerMock{ - Persons: []FederationServerMockPerson{ - NewFederationServerMockPerson(15, "stargoose1"), - NewFederationServerMockPerson(30, "stargoose2"), - }, - Repositories: []FederationServerMockRepository{ - NewFederationServerMockRepository(1), - }, - LastPost: "", - } -} - -func (mock *FederationServerMock) DistantServer(t *testing.T) *httptest.Server { - federatedRoutes := http.NewServeMux() - federatedRoutes.HandleFunc("/.well-known/nodeinfo", - func(res http.ResponseWriter, req *http.Request) { - // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/.well-known/nodeinfo - // TODO: as soon as content-type will become important: content-type: application/json;charset=utf-8 - fmt.Fprintf(res, `{"links":[{"href":"http://%s/api/v1/nodeinfo","rel":"http://nodeinfo.diaspora.software/ns/schema/2.1"}]}`, req.Host) - }) - federatedRoutes.HandleFunc("/api/v1/nodeinfo", - func(res http.ResponseWriter, req *http.Request) { - // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/nodeinfo - fmt.Fprint(res, `{"version":"2.1","software":{"name":"forgejo","version":"1.20.0+dev-3183-g976d79044",`+ - `"repository":"https://codeberg.org/forgejo/forgejo.git","homepage":"https://forgejo.org/"},`+ - `"protocols":["activitypub"],"services":{"inbound":[],"outbound":["rss2.0"]},`+ - `"openRegistrations":true,"usage":{"users":{"total":14,"activeHalfyear":2}},"metadata":{}}`) - }) - for _, person := range mock.Persons { - federatedRoutes.HandleFunc(fmt.Sprintf("/api/v1/activitypub/user-id/%v", person.ID), - func(res http.ResponseWriter, req *http.Request) { - // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/2 - fmt.Fprint(res, person.marshal(req.Host)) - }) - } - for _, repository := range mock.Repositories { - federatedRoutes.HandleFunc(fmt.Sprintf("/api/v1/activitypub/repository-id/%v/inbox", repository.ID), - func(res http.ResponseWriter, req *http.Request) { - if req.Method != "POST" { - t.Errorf("POST expected at: %q", req.URL.EscapedPath()) - } - buf := new(strings.Builder) - _, err := io.Copy(buf, req.Body) - if err != nil { - t.Errorf("Error reading body: %q", err) - } - mock.LastPost = buf.String() - }) - } - federatedRoutes.HandleFunc("/", - func(res http.ResponseWriter, req *http.Request) { - t.Errorf("Unhandled request: %q", req.URL.EscapedPath()) - }) - federatedSrv := httptest.NewServer(federatedRoutes) - return federatedSrv -} diff --git a/modules/test/logchecker.go b/modules/test/logchecker.go index 8e8fc32216..0f12257f3e 100644 --- a/modules/test/logchecker.go +++ b/modules/test/logchecker.go @@ -11,7 +11,7 @@ import ( "sync/atomic" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) type LogChecker struct { diff --git a/modules/test/logchecker_test.go b/modules/test/logchecker_test.go index d81142bf1c..0f410fed12 100644 --- a/modules/test/logchecker_test.go +++ b/modules/test/logchecker_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" "github.com/stretchr/testify/assert" ) diff --git a/modules/test/utils.go b/modules/test/utils.go index db131f19d0..3d884b6cbe 100644 --- a/modules/test/utils.go +++ b/modules/test/utils.go @@ -7,9 +7,8 @@ import ( "net/http" "net/http/httptest" "strings" - "time" - "forgejo.org/modules/json" + "code.gitea.io/gitea/modules/json" ) // RedirectURL returns the redirect URL of a http response. @@ -47,8 +46,3 @@ func MockProtect[T any](p *T) (reset func()) { old := *p return func() { *p = old } } - -// When this is called, sleep until the unix time was increased by one. -func SleepTillNextSecond() { - time.Sleep(time.Second - time.Since(time.Now().Truncate(time.Second))) -} diff --git a/modules/testlogger/testlogger.go b/modules/testlogger/testlogger.go index 772ae47e71..95cbb86591 100644 --- a/modules/testlogger/testlogger.go +++ b/modules/testlogger/testlogger.go @@ -16,9 +16,8 @@ import ( "testing" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/queue" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/queue" ) var ( @@ -132,8 +131,6 @@ var ignoredErrorMessage = []string{ `:SSHLog() [E] ssh: Not allowed to push to protected branch protected. HookPreReceive(last) failed: internal API error response, status=403`, // TestGit/HTTP/BranchProtectMerge `:SSHLog() [E] ssh: branch protected is protected from force push. HookPreReceive(last) failed: internal API error response, status=403`, - // TestGit/HTTP/BranchProtect - `:SSHLog() [E] ssh: branch before-create-2 is protected from changing file protected-file-data-`, // TestGit/HTTP/MergeFork/CreatePRAndMerge `:DeleteBranchPost() [E] DeleteBranch: GetBranch: branch does not exist [repo_id: 1099 name: user2:master]`, // sqlite "s/web/repo/branch.go:108:DeleteBranchPost() [E] DeleteBranch: GetBranch: branch does not exist [repo_id: 10000 name: user2:master]", // mysql @@ -363,12 +360,6 @@ var ignoredErrorMessage = []string{ // TestDatabaseCollation `[E] [Error SQL Query] INSERT INTO test_collation_tbl (txt) VALUES ('main') []`, - - // Test_CmdForgejo_Actions - `DB: No dedicated replica host defined; falling back to primary DSN for replica connections`, - - // TestDevtestErrorpages - `ErrorPage() [E] Example error: Example error`, } func (w *testLoggerWriterCloser) recordError(msg string) { @@ -452,7 +443,10 @@ func (w *testLoggerWriterCloser) Reset() error { func PrintCurrentTest(t testing.TB, skip ...int) func() { t.Helper() start := time.Now() - actualSkip := util.OptionalArg(skip) + 1 + actualSkip := 1 + if len(skip) > 0 { + actualSkip = skip[0] + 1 + } _, filename, line, _ := runtime.Caller(actualSkip) if log.CanColorStdout { @@ -477,7 +471,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() { _, _ = fmt.Fprintf(os.Stdout, "+++ %s ... still flushing after %v ...\n", t.Name(), SlowFlush) } }) - if err := queue.GetManager().FlushAll(t.Context(), time.Minute); err != nil { + if err := queue.GetManager().FlushAll(context.Background(), time.Minute); err != nil { t.Errorf("Flushing queues failed with error %v", err) } timer.Stop() @@ -492,7 +486,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() { if err := WriterCloser.popT(); err != nil { // disable test failure for now (too flacky) - _, _ = fmt.Fprintf(os.Stdout, "testlogger.go:recordError() FATAL ERROR: log.Error has been called: %v\n", err) + _, _ = fmt.Fprintf(os.Stdout, "testlogger.go:recordError() FATAL ERROR: log.Error has been called: %v", err) // t.Errorf("testlogger.go:recordError() FATAL ERROR: log.Error has been called: %v", err) } } diff --git a/modules/timeutil/datetime.go b/modules/timeutil/datetime.go new file mode 100644 index 0000000000..c089173560 --- /dev/null +++ b/modules/timeutil/datetime.go @@ -0,0 +1,68 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package timeutil + +import ( + "fmt" + "html" + "html/template" + "strings" + "time" +) + +// DateTime renders an absolute time HTML element by datetime. +func DateTime(format string, datetime any, extraAttrs ...string) template.HTML { + // TODO: remove the extraAttrs argument, it's not used in any call to DateTime + + if p, ok := datetime.(*time.Time); ok { + datetime = *p + } + if p, ok := datetime.(*TimeStamp); ok { + datetime = *p + } + switch v := datetime.(type) { + case TimeStamp: + datetime = v.AsTime() + case int: + datetime = TimeStamp(v).AsTime() + case int64: + datetime = TimeStamp(v).AsTime() + } + + var datetimeEscaped, textEscaped string + switch v := datetime.(type) { + case nil: + return "-" + case string: + datetimeEscaped = html.EscapeString(v) + textEscaped = datetimeEscaped + case time.Time: + if v.IsZero() || v.Unix() == 0 { + return "-" + } + datetimeEscaped = html.EscapeString(v.Format(time.RFC3339)) + if format == "full" { + textEscaped = html.EscapeString(v.Format("2006-01-02 15:04:05 -07:00")) + } else { + textEscaped = html.EscapeString(v.Format("2006-01-02")) + } + default: + panic(fmt.Sprintf("Unsupported time type %T", datetime)) + } + + attrs := make([]string, 0, 10+len(extraAttrs)) + attrs = append(attrs, extraAttrs...) + attrs = append(attrs, `weekday=""`, `year="numeric"`) + + switch format { + case "short", "long": // date only + attrs = append(attrs, `month="`+format+`"`, `day="numeric"`) + return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) + case "full": // full date including time + attrs = append(attrs, `format="datetime"`, `month="short"`, `day="numeric"`, `hour="numeric"`, `minute="numeric"`, `second="numeric"`, `data-tooltip-content`, `data-tooltip-interactive="true"`) + return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) + default: + panic(fmt.Sprintf("Unsupported format %s", format)) + } +} diff --git a/modules/timeutil/datetime_test.go b/modules/timeutil/datetime_test.go new file mode 100644 index 0000000000..ac2ce35ba2 --- /dev/null +++ b/modules/timeutil/datetime_test.go @@ -0,0 +1,47 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package timeutil + +import ( + "testing" + "time" + + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + + "github.com/stretchr/testify/assert" +) + +func TestDateTime(t *testing.T) { + testTz, _ := time.LoadLocation("America/New_York") + defer test.MockVariableValue(&setting.DefaultUILocation, testTz)() + + refTimeStr := "2018-01-01T00:00:00Z" + refDateStr := "2018-01-01" + refTime, _ := time.Parse(time.RFC3339, refTimeStr) + refTimeStamp := TimeStamp(refTime.Unix()) + + assert.EqualValues(t, "-", DateTime("short", nil)) + assert.EqualValues(t, "-", DateTime("short", 0)) + assert.EqualValues(t, "-", DateTime("short", time.Time{})) + assert.EqualValues(t, "-", DateTime("short", TimeStamp(0))) + + actual := DateTime("short", "invalid") + assert.EqualValues(t, `invalid`, actual) + + actual = DateTime("short", refTimeStr) + assert.EqualValues(t, `2018-01-01T00:00:00Z`, actual) + + actual = DateTime("short", refTime) + assert.EqualValues(t, `2018-01-01`, actual) + + actual = DateTime("short", refDateStr) + assert.EqualValues(t, `2018-01-01`, actual) + + actual = DateTime("short", refTimeStamp) + assert.EqualValues(t, `2017-12-31`, actual) + + actual = DateTime("full", refTimeStamp) + assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) +} diff --git a/modules/timeutil/executable.go b/modules/timeutil/executable.go index 7b30176df0..57ae8b2a9d 100644 --- a/modules/timeutil/executable.go +++ b/modules/timeutil/executable.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "forgejo.org/modules/log" + "code.gitea.io/gitea/modules/log" ) var ( diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go index f296a2dc86..dba42c793a 100644 --- a/modules/timeutil/since.go +++ b/modules/timeutil/since.go @@ -4,10 +4,13 @@ package timeutil import ( + "fmt" + "html/template" "strings" "time" - "forgejo.org/modules/translation" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation" ) // Seconds-based time units @@ -78,11 +81,16 @@ func computeTimeDiffFloor(diff int64, lang translation.Locale) (int64, string) { return diff, diffStr } -// MinutesToFriendly returns a user-friendly string with number of minutes +// MinutesToFriendly returns a user friendly string with number of minutes // converted to hours and minutes. func MinutesToFriendly(minutes int, lang translation.Locale) string { duration := time.Duration(minutes) * time.Minute - return timeSincePro(time.Now().Add(-duration), time.Now(), lang) + return TimeSincePro(time.Now().Add(-duration), lang) +} + +// TimeSincePro calculates the time interval and generate full user-friendly string. +func TimeSincePro(then time.Time, lang translation.Locale) string { + return timeSincePro(then, time.Now(), lang) } func timeSincePro(then, now time.Time, lang translation.Locale) string { @@ -96,9 +104,42 @@ func timeSincePro(then, now time.Time, lang translation.Locale) string { } var timeStr, diffStr string - for diff != 0 { + for { + if diff == 0 { + break + } + diff, diffStr = computeTimeDiffFloor(diff, lang) timeStr += ", " + diffStr } return strings.TrimPrefix(timeStr, ", ") } + +func timeSinceUnix(then, now time.Time, _ translation.Locale) template.HTML { + friendlyText := then.Format("2006-01-02 15:04:05 -07:00") + + // document: https://github.com/github/relative-time-element + attrs := `tense="past"` + isFuture := now.Before(then) + if isFuture { + attrs = `tense="future"` + } + + // declare data-tooltip-content attribute to switch from "title" tooltip to "tippy" tooltip + htm := fmt.Sprintf(`%s`, + attrs, then.Format(time.RFC3339), friendlyText) + return template.HTML(htm) +} + +// TimeSince renders relative time HTML given a time.Time +func TimeSince(then time.Time, lang translation.Locale) template.HTML { + if setting.UI.PreferredTimestampTense == "absolute" { + return DateTime("full", then) + } + return timeSinceUnix(then, time.Now(), lang) +} + +// TimeSinceUnix renders relative time HTML given a TimeStamp +func TimeSinceUnix(then TimeStamp, lang translation.Locale) template.HTML { + return TimeSince(then.AsLocalTime(), lang) +} diff --git a/modules/timeutil/since_test.go b/modules/timeutil/since_test.go index b47b2c76dd..40fefe8700 100644 --- a/modules/timeutil/since_test.go +++ b/modules/timeutil/since_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "forgejo.org/modules/setting" - "forgejo.org/modules/translation" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) diff --git a/modules/timeutil/timestamp.go b/modules/timeutil/timestamp.go index 783ccba30b..27a80b6682 100644 --- a/modules/timeutil/timestamp.go +++ b/modules/timeutil/timestamp.go @@ -6,7 +6,7 @@ package timeutil import ( "time" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // TimeStamp defines a timestamp diff --git a/modules/timeutil/timestampnano.go b/modules/timeutil/timestampnano.go index e2e86b863f..4a9f7955b9 100644 --- a/modules/timeutil/timestampnano.go +++ b/modules/timeutil/timestampnano.go @@ -6,7 +6,7 @@ package timeutil import ( "time" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // TimeStampNano is for nano time in database, do not use it unless there is a real requirement. diff --git a/modules/translation/i18n/dummy.go b/modules/translation/i18n/dummy.go deleted file mode 100644 index 9f1e682f11..0000000000 --- a/modules/translation/i18n/dummy.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package i18n - -import ( - "fmt" - "html/template" - "reflect" - "slices" - "strings" -) - -type KeyLocale struct{} - -var _ Locale = (*KeyLocale)(nil) - -func (k *KeyLocale) Language() string { - return "dummy" -} - -// HasKey implements Locale. -func (k *KeyLocale) HasKey(trKey string) bool { - return true -} - -// TrHTML implements Locale. -func (k *KeyLocale) TrHTML(trKey string, trArgs ...any) template.HTML { - return template.HTML(k.TrString(trKey, PrepareArgsForHTML(trArgs...)...)) -} - -// TrString implements Locale. -func (k *KeyLocale) TrString(trKey string, trArgs ...any) string { - return FormatDummy(trKey, trArgs...) -} - -// TrPluralString implements Locale. -func (k *KeyLocale) TrPluralString(count any, trKey string, trArgs ...any) template.HTML { - return template.HTML(FormatDummy(trKey, PrepareArgsForHTML(trArgs...)...)) -} - -// TrPluralStringAllForms implements Locale. -func (k *KeyLocale) TrPluralStringAllForms(trKey string) ([]string, []string) { - return []string{trKey}, nil -} - -func FormatDummy(trKey string, args ...any) string { - if len(args) == 0 { - return fmt.Sprintf("(%s)", trKey) - } - - fmtArgs := make([]any, 0, len(args)+1) - fmtArgs = append(fmtArgs, trKey) - for _, arg := range args { - val := reflect.ValueOf(arg) - if val.Kind() == reflect.Slice { - for i := 0; i < val.Len(); i++ { - fmtArgs = append(fmtArgs, val.Index(i).Interface()) - } - } else { - fmtArgs = append(fmtArgs, arg) - } - } - - template := fmt.Sprintf("(%%s: %s)", strings.Join(slices.Repeat([]string{"%v"}, len(fmtArgs)-1), ", ")) - return fmt.Sprintf(template, fmtArgs...) -} diff --git a/modules/translation/i18n/dummy_test.go b/modules/translation/i18n/dummy_test.go deleted file mode 100644 index 1df3d0c348..0000000000 --- a/modules/translation/i18n/dummy_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package i18n_test - -import ( - "testing" - - "forgejo.org/modules/translation/i18n" - - "github.com/stretchr/testify/assert" -) - -func TestFormatDummy(t *testing.T) { - assert.Equal(t, "(admin.config.git_max_diff_lines)", i18n.FormatDummy("admin.config.git_max_diff_lines")) - assert.Equal(t, "(dashboard)", i18n.FormatDummy("dashboard")) - assert.Equal(t, "(branch.create_branch: main)", i18n.FormatDummy("branch.create_branch", "main")) - assert.Equal(t, "(test.test: a, 1, true)", i18n.FormatDummy("test.test", "a", 1, true)) -} diff --git a/modules/translation/i18n/errors.go b/modules/translation/i18n/errors.go index 63a5f48dfa..7f64ccf908 100644 --- a/modules/translation/i18n/errors.go +++ b/modules/translation/i18n/errors.go @@ -4,12 +4,10 @@ package i18n import ( - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) var ( - ErrLocaleAlreadyExist = util.SilentWrap{Message: "lang already exists", Err: util.ErrAlreadyExist} - ErrLocaleDoesNotExist = util.SilentWrap{Message: "lang does not exist", Err: util.ErrNotExist} - ErrTranslationDoesNotExist = util.SilentWrap{Message: "translation does not exist", Err: util.ErrNotExist} - ErrUncertainArguments = util.SilentWrap{Message: "arguments to i18n should not contain uncertain slices", Err: util.ErrInvalidArgument} + ErrLocaleAlreadyExist = util.SilentWrap{Message: "lang already exists", Err: util.ErrAlreadyExist} + ErrUncertainArguments = util.SilentWrap{Message: "arguments to i18n should not contain uncertain slices", Err: util.ErrInvalidArgument} ) diff --git a/modules/translation/i18n/i18n.go b/modules/translation/i18n/i18n.go index 10ed8ac199..1555cd961e 100644 --- a/modules/translation/i18n/i18n.go +++ b/modules/translation/i18n/i18n.go @@ -8,36 +8,15 @@ import ( "io" ) -type ( - PluralFormIndex uint8 - PluralFormRule func(int64) PluralFormIndex -) - -const ( - PluralFormZero PluralFormIndex = iota - PluralFormOne - PluralFormTwo - PluralFormFew - PluralFormMany - PluralFormOther -) - var DefaultLocales = NewLocaleStore() type Locale interface { - Language() string // TrString translates a given key and arguments for a language TrString(trKey string, trArgs ...any) string - // TrPluralString translates a given pluralized key and arguments for a language. - // This function returns an error if new-style support for the given key is not available. - TrPluralString(count any, trKey string, trArgs ...any) template.HTML // TrHTML translates a given key and arguments for a language, string arguments are escaped to HTML TrHTML(trKey string, trArgs ...any) template.HTML // HasKey reports if a locale has a translation for a given key HasKey(trKey string) bool - // TrPluralStringAllForms returns all plural form variants for a given string, and also - // the fallbacks for the default language if the translation is incomplete. - TrPluralStringAllForms(trKey string) ([]string, []string) } // LocaleStore provides the functions common to all locale stores @@ -46,18 +25,14 @@ type LocaleStore interface { // SetDefaultLang sets the default language to fall back to SetDefaultLang(lang string) - // GetDefaultLang returns the name of the default language to fall back to - GetDefaultLang() string // ListLangNameDesc provides paired slices of language names to descriptors ListLangNameDesc() (names, desc []string) // Locale return the locale for the provided language or the default language if not found Locale(langName string) (Locale, bool) // HasLang returns whether a given language is present in the store HasLang(langName string) bool - // AddLocaleByIni adds a new old-style language to the store - AddLocaleByIni(langName, langDesc string, pluralRule PluralFormRule, usedPluralForms []PluralFormIndex, source, moreSource []byte) error - // AddLocaleByJSON adds new-style content to an existing language to the store - AddToLocaleFromJSON(langName string, source []byte) error + // AddLocaleByIni adds a new language to the store + AddLocaleByIni(langName, langDesc string, source, moreSource []byte) error } // ResetDefaultLocales resets the current default locales diff --git a/modules/translation/i18n/i18n_test.go b/modules/translation/i18n/i18n_test.go index ac086d75d9..b364992dfe 100644 --- a/modules/translation/i18n/i18n_test.go +++ b/modules/translation/i18n/i18n_test.go @@ -9,32 +9,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var MockPluralRule PluralFormRule = func(n int64) PluralFormIndex { - if n == 0 { - return PluralFormZero - } - if n == 1 { - return PluralFormOne - } - if n >= 2 && n <= 4 { - return PluralFormFew - } - return PluralFormOther -} - -var MockPluralRuleEnglish PluralFormRule = func(n int64) PluralFormIndex { - if n == 1 { - return PluralFormOne - } - return PluralFormOther -} - -var ( - UsedPluralFormsEnglish = []PluralFormIndex{PluralFormOne, PluralFormOther} - UsedPluralFormsMock = []PluralFormIndex{PluralFormZero, PluralFormOne, PluralFormFew, PluralFormOther} ) func TestLocaleStore(t *testing.T) { @@ -52,48 +26,11 @@ fmt = %[2]s %[1]s [section] sub = Changed Sub String -commits = fallback value for commits -`) - - testDataJSON2 := []byte(` -{ - "section.json": "the JSON is %s", - "section.commits": { - "one": "one %d commit", - "few": "some %d commits", - "other": "lots of %d commits" - }, - "section.incomplete": { - "few": "some %d objects (translated)" - }, - "nested": { - "outer": { - "inner": { - "json": "Hello World", - "issue": { - "one": "one %d issue", - "few": "some %d issues", - "other": "lots of %d issues" - } - } - } - } -} -`) - testDataJSON1 := []byte(` -{ - "section.incomplete": { - "one": "[untranslated] some %d object", - "other": "[untranslated] some %d objects" - } -} `) ls := NewLocaleStore() - require.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", MockPluralRuleEnglish, UsedPluralFormsEnglish, testData1, nil)) - require.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", MockPluralRule, UsedPluralFormsMock, testData2, nil)) - require.NoError(t, ls.AddToLocaleFromJSON("lang1", testDataJSON1)) - require.NoError(t, ls.AddToLocaleFromJSON("lang2", testDataJSON2)) + assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, nil)) + assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2, nil)) ls.SetDefaultLang("lang1") lang1, _ := ls.Locale("lang1") @@ -118,61 +55,13 @@ commits = fallback value for commits result2 := lang2.TrHTML("section.mixed", "a&b") assert.EqualValues(t, `test value; a&b`, result2) - result = lang2.TrString("section.json", "valid") - assert.Equal(t, "the JSON is valid", result) - - result = lang2.TrString("nested.outer.inner.json") - assert.Equal(t, "Hello World", result) - - result = lang2.TrString("section.commits") - assert.Equal(t, "lots of %d commits", result) - - result2 = lang2.TrPluralString(1, "section.commits", 1) - assert.EqualValues(t, "one 1 commit", result2) - - result2 = lang2.TrPluralString(3, "section.commits", 3) - assert.EqualValues(t, "some 3 commits", result2) - - result2 = lang2.TrPluralString(8, "section.commits", 8) - assert.EqualValues(t, "lots of 8 commits", result2) - - result2 = lang2.TrPluralString(0, "section.commits") - assert.EqualValues(t, "section.commits", result2) - - result2 = lang2.TrPluralString(1, "nested.outer.inner.issue", 1) - assert.EqualValues(t, "one 1 issue", result2) - - result2 = lang2.TrPluralString(3, "nested.outer.inner.issue", 3) - assert.EqualValues(t, "some 3 issues", result2) - - result2 = lang2.TrPluralString(9, "nested.outer.inner.issue", 9) - assert.EqualValues(t, "lots of 9 issues", result2) - - result2 = lang2.TrPluralString(3, "section.incomplete", 3) - assert.EqualValues(t, "some 3 objects (translated)", result2) - - result2 = lang2.TrPluralString(1, "section.incomplete", 1) - assert.EqualValues(t, "[untranslated] some 1 object", result2) - - result2 = lang2.TrPluralString(7, "section.incomplete", 7) - assert.EqualValues(t, "[untranslated] some 7 objects", result2) - langs, descs := ls.ListLangNameDesc() assert.ElementsMatch(t, []string{"lang1", "lang2"}, langs) assert.ElementsMatch(t, []string{"Lang1", "Lang2"}, descs) - // Test HasKey for JSON - found := lang2.HasKey("section.json") - assert.True(t, found) - - // Test HasKey for INI - found = lang2.HasKey("section.sub") - assert.True(t, found) - - found = lang1.HasKey("no-such") + found := lang1.HasKey("no-such") assert.False(t, found) - assert.Equal(t, "no-such", lang1.TrString("no-such")) - require.NoError(t, ls.Close()) + assert.NoError(t, ls.Close()) } func TestLocaleStoreMoreSource(t *testing.T) { @@ -187,7 +76,7 @@ c=22 `) ls := NewLocaleStore() - require.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", MockPluralRule, UsedPluralFormsMock, testData1, testData2)) + assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, testData2)) lang1, _ := ls.Locale("lang1") assert.Equal(t, "11", lang1.TrString("a")) assert.Equal(t, "21", lang1.TrString("b")) @@ -228,7 +117,7 @@ func (e *errorPointerReceiver) Error() string { func TestLocaleWithTemplate(t *testing.T) { ls := NewLocaleStore() - require.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", MockPluralRule, UsedPluralFormsMock, []byte(`key=%s`), nil)) + assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", []byte(`key=%s`), nil)) lang1, _ := ls.Locale("lang1") tmpl := template.New("test").Funcs(template.FuncMap{"tr": lang1.TrHTML}) @@ -254,7 +143,7 @@ func TestLocaleWithTemplate(t *testing.T) { buf := &strings.Builder{} for _, c := range cases { buf.Reset() - require.NoError(t, tmpl.Execute(buf, map[string]any{"var": c.in})) + assert.NoError(t, tmpl.Execute(buf, map[string]any{"var": c.in})) assert.Equal(t, c.want, buf.String()) } } @@ -291,11 +180,11 @@ func TestLocaleStoreQuirks(t *testing.T) { for _, testData := range testDataList { ls := NewLocaleStore() - err := ls.AddLocaleByIni("lang1", "Lang1", nil, nil, []byte("a="+testData.in), nil) + err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil) lang1, _ := ls.Locale("lang1") - require.NoError(t, err, testData.hint) + assert.NoError(t, err, testData.hint) assert.Equal(t, testData.out, lang1.TrString("a"), testData.hint) - require.NoError(t, ls.Close()) + assert.NoError(t, ls.Close()) } // TODO: Crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes diff --git a/modules/translation/i18n/localestore.go b/modules/translation/i18n/localestore.go index fc27c75d13..0e6ddab401 100644 --- a/modules/translation/i18n/localestore.go +++ b/modules/translation/i18n/localestore.go @@ -1,5 +1,4 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package i18n @@ -9,10 +8,8 @@ import ( "html/template" "slices" - "forgejo.org/modules/log" - "forgejo.org/modules/setting" - "forgejo.org/modules/translation/localeiter" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) // This file implements the static LocaleStore that will not watch for changes @@ -21,10 +18,6 @@ type locale struct { store *localeStore langName string idxToMsgMap map[int]string // the map idx is generated by store's trKeyToIdxMap - - newStyleMessages map[string]string - pluralRule PluralFormRule - usedPluralForms []PluralFormIndex } var _ Locale = (*locale)(nil) @@ -45,19 +38,8 @@ func NewLocaleStore() LocaleStore { return &localeStore{localeMap: make(map[string]*locale), trKeyToIdxMap: make(map[string]int)} } -const ( - PluralFormSeparator string = "\036" -) - -// A note about pluralization rules. -// go-i18n supports plural rules in theory. -// In practice, it relies on another library that hardcodes a list of common languages -// and their plural rules, and does not support languages not hardcoded there. -// So we pretend that all languages are English and use our own function to extract -// the correct plural form for a given count and language. - // AddLocaleByIni adds locale by ini into the store -func (store *localeStore) AddLocaleByIni(langName, langDesc string, pluralRule PluralFormRule, usedPluralForms []PluralFormIndex, source, moreSource []byte) error { +func (store *localeStore) AddLocaleByIni(langName, langDesc string, source, moreSource []byte) error { if _, ok := store.localeMap[langName]; ok { return ErrLocaleAlreadyExist } @@ -65,7 +47,7 @@ func (store *localeStore) AddLocaleByIni(langName, langDesc string, pluralRule P store.langNames = append(store.langNames, langName) store.langDescs = append(store.langDescs, langDesc) - l := &locale{store: store, langName: langName, idxToMsgMap: make(map[int]string), pluralRule: pluralRule, usedPluralForms: usedPluralForms, newStyleMessages: make(map[string]string)} + l := &locale{store: store, langName: langName, idxToMsgMap: make(map[int]string)} store.localeMap[l.langName] = l iniFile, err := setting.NewConfigProviderForLocale(source, moreSource) @@ -96,68 +78,6 @@ func (store *localeStore) AddLocaleByIni(langName, langDesc string, pluralRule P return nil } -func (store *localeStore) AddToLocaleFromJSON(langName string, source []byte) error { - locale, ok := store.localeMap[langName] - if !ok { - return ErrLocaleDoesNotExist - } - - return localeiter.IterateMessagesNextContent(source, func(key, pluralForm, value string) error { - msgKey := key - if pluralForm != "" { - msgKey = key + PluralFormSeparator + pluralForm - } - locale.newStyleMessages[msgKey] = value - return nil - }) -} - -func (l *locale) LookupNewStyleMessage(trKey string) string { - if msg, ok := l.newStyleMessages[trKey]; ok { - return msg - } - return "" -} - -func (l *locale) LookupPluralByCount(trKey string, count any) string { - n, err := util.ToInt64(count) - if err != nil { - log.Error("Invalid plural count '%s'", count) - return "" - } - - pluralForm := l.pluralRule(n) - return l.LookupPluralByForm(trKey, pluralForm) -} - -func (l *locale) LookupPluralByForm(trKey string, pluralForm PluralFormIndex) string { - suffix := "" - switch pluralForm { - case PluralFormZero: - suffix = PluralFormSeparator + "zero" - case PluralFormOne: - suffix = PluralFormSeparator + "one" - case PluralFormTwo: - suffix = PluralFormSeparator + "two" - case PluralFormFew: - suffix = PluralFormSeparator + "few" - case PluralFormMany: - suffix = PluralFormSeparator + "many" - case PluralFormOther: - // No suffix for the "other" string. - default: - log.Error("Invalid plural form index %d", pluralForm) - return "" - } - - if result, ok := l.newStyleMessages[trKey+suffix]; ok { - return result - } - - log.Error("Missing translation for plural form %s", suffix) - return "" -} - func (store *localeStore) HasLang(langName string) bool { _, ok := store.localeMap[langName] return ok @@ -172,10 +92,6 @@ func (store *localeStore) SetDefaultLang(lang string) { store.defaultLang = lang } -func (store *localeStore) GetDefaultLang() string { - return store.defaultLang -} - // Locale returns the locale for the lang or the default language func (store *localeStore) Locale(lang string) (Locale, bool) { l, found := store.localeMap[lang] @@ -194,45 +110,25 @@ func (store *localeStore) Close() error { return nil } -func (l *locale) Language() string { - return l.langName -} - func (l *locale) TrString(trKey string, trArgs ...any) string { format := trKey - if msg := l.LookupNewStyleMessage(trKey); msg != "" { - format = msg - } else { - // First fallback: old-style translation - idx, foundIndex := l.store.trKeyToIdxMap[trKey] - found := false - if foundIndex { - if msg, ok := l.idxToMsgMap[idx]; ok { - format = msg // use the found translation + idx, ok := l.store.trKeyToIdxMap[trKey] + found := false + if ok { + if msg, ok := l.idxToMsgMap[idx]; ok { + format = msg // use the found translation + found = true + } else if def, ok := l.store.localeMap[l.store.defaultLang]; ok { + // try to use default locale's translation + if msg, ok := def.idxToMsgMap[idx]; ok { + format = msg found = true } } - - if !found { - // Second fallback: new-style default language - if defaultLang, ok := l.store.localeMap[l.store.defaultLang]; ok { - if msg := defaultLang.LookupNewStyleMessage(trKey); msg != "" { - format = msg - found = true - } else if foundIndex { - // Third fallback: old-style default language - if msg, ok := defaultLang.idxToMsgMap[idx]; ok { - format = msg - found = true - } - } - } - - if !found { - log.Error("Missing translation %q", trKey) - } - } + } + if !found { + log.Error("Missing translation %q", trKey) } msg, err := Format(format, trArgs...) @@ -242,7 +138,7 @@ func (l *locale) TrString(trKey string, trArgs ...any) string { return msg } -func PrepareArgsForHTML(trArgs ...any) []any { +func (l *locale) TrHTML(trKey string, trArgs ...any) template.HTML { args := slices.Clone(trArgs) for i, v := range args { switch v := v.(type) { @@ -256,68 +152,11 @@ func PrepareArgsForHTML(trArgs ...any) []any { args[i] = template.HTMLEscapeString(fmt.Sprint(v)) } } - return args -} - -func (l *locale) TrHTML(trKey string, trArgs ...any) template.HTML { - return template.HTML(l.TrString(trKey, PrepareArgsForHTML(trArgs...)...)) -} - -func (l *locale) TrPluralString(count any, trKey string, trArgs ...any) template.HTML { - message := l.LookupPluralByCount(trKey, count) - - if message == "" { - if defaultLang, ok := l.store.localeMap[l.store.defaultLang]; ok { - message = defaultLang.LookupPluralByCount(trKey, count) - } - if message == "" { - message = trKey - } - } - - message, err := Format(message, PrepareArgsForHTML(trArgs...)...) - if err != nil { - log.Error("Error whilst formatting %q in %s: %v", trKey, l.langName, err) - } - return template.HTML(message) -} - -func (l *locale) TrPluralStringAllForms(trKey string) ([]string, []string) { - defaultLang, hasDefaultLang := l.store.localeMap[l.store.defaultLang] - - var fallback []string - fallback = nil - - result := make([]string, len(l.usedPluralForms)) - allPresent := true - - for i, form := range l.usedPluralForms { - result[i] = l.LookupPluralByForm(trKey, form) - if result[i] == "" { - allPresent = false - } - } - - if !allPresent { - if hasDefaultLang { - fallback = make([]string, len(defaultLang.usedPluralForms)) - for i, form := range defaultLang.usedPluralForms { - fallback[i] = defaultLang.LookupPluralByForm(trKey, form) - } - } else { - log.Error("Plural set for '%s' is incomplete and no fallback language is set.", trKey) - } - } - - return result, fallback + return template.HTML(l.TrString(trKey, args...)) } // HasKey returns whether a key is present in this locale or not func (l *locale) HasKey(trKey string) bool { - _, ok := l.newStyleMessages[trKey] - if ok { - return true - } idx, ok := l.store.trKeyToIdxMap[trKey] if !ok { return false diff --git a/modules/translation/localeiter/utils.go b/modules/translation/localeiter/utils.go deleted file mode 100644 index de398258e2..0000000000 --- a/modules/translation/localeiter/utils.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -// extracted from `/build/lint-locale.go`, `/build/lint-locale-usage.go` - -package localeiter - -import ( - "encoding/json" //nolint:depguard - "fmt" - - "forgejo.org/modules/setting" -) - -func IterateMessagesContent(localeContent []byte, onMsgid func(string, string) error) error { - cfg, err := setting.NewConfigProviderForLocale(localeContent) - if err != nil { - return err - } - - for _, section := range cfg.Sections() { - for _, key := range section.Keys() { - var trKey string - // see https://codeberg.org/forgejo/discussions/issues/104 - // https://github.com/WeblateOrg/weblate/issues/10831 - // for an explanation of why "common" is an alternative - if section.Name() == "" || section.Name() == "DEFAULT" || section.Name() == "common" { - trKey = key.Name() - } else { - trKey = section.Name() + "." + key.Name() - } - if err := onMsgid(trKey, key.Value()); err != nil { - return err - } - } - } - - return nil -} - -func iterateMessagesNextInner(onMsgid func(string, string, string) error, data map[string]any, trKey string) error { - for key, value := range data { - fullKey := key - if trKey != "" { - fullKey = trKey + "." + key - } - switch value := value.(type) { - case string: - // Check whether we are adding a plural form to the parent object, or a new nested JSON object. - realKey := trKey - pluralSuffix := "" - - switch key { - case "zero", "one", "two", "few", "many": - pluralSuffix = key - case "other": - // do nothing - default: - realKey = fullKey - } - - if err := onMsgid(realKey, pluralSuffix, value); err != nil { - return err - } - - case map[string]any: - if err := iterateMessagesNextInner(onMsgid, value, fullKey); err != nil { - return err - } - - case nil: - // do nothing - - default: - return fmt.Errorf("Unexpected JSON type: %s - %T", fullKey, value) - } - } - - return nil -} - -func IterateMessagesNextContent(localeContent []byte, onMsgid func(string, string, string) error) error { - var localeData map[string]any - if err := json.Unmarshal(localeContent, &localeData); err != nil { - return err - } - return iterateMessagesNextInner(onMsgid, localeData, "") -} diff --git a/modules/translation/mock.go b/modules/translation/mock.go index fc1c6a83fd..fe3a1502ea 100644 --- a/modules/translation/mock.go +++ b/modules/translation/mock.go @@ -6,15 +6,11 @@ package translation import ( "fmt" "html/template" - - "forgejo.org/modules/translation/i18n" ) -// MockLocale provides a mocked locale without any translations, other than those inserted into MockTranslations by a testcase +// MockLocale provides a mocked locale without any translations type MockLocale struct { Lang, LangName string // these fields are used directly in templates: ctx.Locale.Lang - - MockTranslations map[string]string } var _ Locale = (*MockLocale)(nil) @@ -24,37 +20,21 @@ func (l MockLocale) Language() string { } func (l MockLocale) TrString(s string, _ ...any) string { - if val, ok := l.MockTranslations[s]; ok { - return val - } return s } func (l MockLocale) Tr(s string, a ...any) template.HTML { - return template.HTML(l.TrString(s)) + return template.HTML(s) } func (l MockLocale) TrN(cnt any, key1, keyN string, args ...any) template.HTML { return template.HTML(key1) } -func (l MockLocale) TrPluralString(count any, trKey string, trArgs ...any) template.HTML { - return template.HTML(trKey) -} - -// TrPluralStringAllForms implements Locale. -func (l MockLocale) TrPluralStringAllForms(trKey string) ([]string, []string) { - return []string{l.TrString(trKey + i18n.PluralFormSeparator + "one"), l.TrString(trKey + i18n.PluralFormSeparator + "other")}, nil -} - func (l MockLocale) TrSize(s int64) ReadableSize { return ReadableSize{fmt.Sprint(s), ""} } -func (l MockLocale) HasKey(key string) bool { - return true -} - func (l MockLocale) PrettyNumber(v any) string { return fmt.Sprint(v) } diff --git a/modules/translation/plural_rules.go b/modules/translation/plural_rules.go deleted file mode 100644 index 59665da255..0000000000 --- a/modules/translation/plural_rules.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -// Some useful links: -// https://www.unicode.org/cldr/charts/46/supplemental/language_plural_rules.html -// https://translate.codeberg.org/languages/$LANGUAGE_CODE/#information -// https://github.com/WeblateOrg/language-data/blob/main/languages.csv -// Note that in some cases there is ambiguity about the correct form for a given language. In this case, ask the locale's translators. - -package translation - -import ( - "strings" - - "forgejo.org/modules/log" - "forgejo.org/modules/translation/i18n" -) - -// The constants refer to indices below in `PluralRules` and also in i18n.js, keep them in sync! -const ( - PluralRuleDefault = 0 - PluralRuleBengali = 1 - PluralRuleIcelandic = 2 - PluralRuleFilipino = 3 - PluralRuleOneForm = 4 - PluralRuleCzech = 5 - PluralRuleRussian = 6 - PluralRulePolish = 7 - PluralRuleLatvian = 8 - PluralRuleLithuanian = 9 - PluralRuleFrench = 10 - PluralRuleCatalan = 11 - PluralRuleSlovenian = 12 - PluralRuleArabic = 13 -) - -func GetPluralRuleImpl(langName string) int { - // First, check for languages with country-specific plural rules. - switch langName { - case "pt-BR": - return PluralRuleFrench - - case "pt-PT": - return PluralRuleCatalan - - default: - break - } - - // Remove the country portion of the locale name. - langName = strings.Split(strings.Split(langName, "_")[0], "-")[0] - - // When adding a new language not in the list, add its plural rule definition here. - switch langName { - case "en", "aa", "ab", "abr", "ada", "ae", "aeb", "af", "afh", "aii", "ain", "akk", "ale", "aln", "alt", "ami", "an", "ang", "anp", "apc", "arc", "arp", "arq", "arw", "arz", "asa", "ast", "av", "avk", "awa", "ayc", "az", "azb", "ba", "bal", "ban", "bar", "bas", "bbc", "bci", "bej", "bem", "ber", "bew", "bez", "bg", "bgc", "bgn", "bhb", "bhi", "bi", "bik", "bin", "bjj", "bjn", "bla", "bnt", "bqi", "bra", "brb", "brh", "brx", "bua", "bug", "bum", "byn", "cad", "cak", "car", "ce", "cgg", "ch", "chb", "chg", "chk", "chm", "chn", "cho", "chp", "chr", "chy", "ckb", "co", "cop", "cpe", "cpf", "cr", "crp", "cu", "cv", "da", "dak", "dar", "dcc", "de", "del", "den", "dgr", "din", "dje", "dnj", "dnk", "dru", "dry", "dua", "dum", "dv", "dyu", "ee", "efi", "egl", "egy", "eka", "el", "elx", "enm", "eo", "et", "eu", "ewo", "ext", "fan", "fat", "fbl", "ffm", "fi", "fj", "fo", "fon", "frk", "frm", "fro", "frr", "frs", "fuq", "fur", "fuv", "fvr", "fy", "gaa", "gay", "gba", "gbm", "gez", "gil", "gl", "glk", "gmh", "gn", "goh", "gom", "gon", "gor", "got", "grb", "gsw", "guc", "gum", "gur", "guz", "gwi", "ha", "hai", "haw", "haz", "hil", "hit", "hmn", "hnd", "hne", "hno", "ho", "hoc", "hoj", "hrx", "ht", "hu", "hup", "hus", "hz", "ia", "iba", "ibb", "ie", "ik", "ilo", "inh", "io", "jam", "jgo", "jmc", "jpr", "jrb", "ka", "kaa", "kac", "kaj", "kam", "kaw", "kbd", "kcg", "kfr", "kfy", "kg", "kha", "khn", "kho", "ki", "kj", "kk", "kkj", "kl", "kln", "kmb", "kmr", "kok", "kpe", "kr", "krc", "kri", "krl", "kru", "ks", "ksb", "ku", "kum", "kut", "kv", "kxm", "ky", "la", "lad", "laj", "lam", "lb", "lez", "lfn", "lg", "li", "lij", "ljp", "lki", "lmn", "lmo", "lol", "loz", "lrc", "lu", "lua", "lui", "lun", "luo", "lus", "luy", "luz", "mad", "mag", "mai", "mak", "man", "mas", "mdf", "mdh", "mdr", "men", "mer", "mfa", "mga", "mgh", "mgo", "mh", "mhr", "mic", "min", "mjw", "ml", "mn", "mnc", "mni", "mnw", "moe", "moh", "mos", "mr", "mrh", "mtr", "mus", "mwk", "mwl", "mwr", "mxc", "myv", "myx", "mzn", "na", "nah", "nap", "nb", "nd", "ndc", "nds", "ne", "new", "ng", "ngl", "nia", "nij", "niu", "nl", "nn", "nnh", "nod", "noe", "nog", "non", "nr", "nuk", "nv", "nwc", "ny", "nym", "nyn", "nyo", "nzi", "oj", "om", "or", "os", "ota", "otk", "ovd", "pag", "pal", "pam", "pap", "pau", "pbb", "pdt", "peo", "phn", "pi", "pms", "pon", "pro", "ps", "pwn", "qu", "quc", "qug", "qya", "raj", "rap", "rar", "rcf", "rej", "rhg", "rif", "rkt", "rm", "rmt", "rn", "rng", "rof", "rom", "rue", "rup", "rw", "rwk", "sad", "sai", "sam", "saq", "sas", "sc", "sck", "sco", "sd", "sdh", "sef", "seh", "sel", "sga", "sgn", "sgs", "shn", "sid", "sjd", "skr", "sm", "sml", "sn", "snk", "so", "sog", "sou", "sq", "srn", "srr", "ss", "ssy", "st", "suk", "sus", "sux", "sv", "sw", "swg", "swv", "sxu", "syc", "syl", "syr", "szy", "ta", "tay", "tcy", "te", "tem", "teo", "ter", "tet", "tig", "tiv", "tk", "tkl", "tli", "tly", "tmh", "tn", "tog", "tr", "trv", "ts", "tsg", "tsi", "tsj", "tts", "tum", "tvl", "tw", "ty", "tyv", "tzj", "tzl", "udm", "ug", "uga", "umb", "und", "unr", "ur", "uz", "vai", "ve", "vls", "vmf", "vmw", "vo", "vot", "vro", "vun", "wae", "wal", "war", "was", "wbq", "wbr", "wep", "wtm", "xal", "xh", "xnr", "xog", "yao", "yap", "yi", "yua", "za", "zap", "zbl", "zen", "zgh", "zun", "zza": - return PluralRuleDefault - - case "ach", "ady", "ak", "am", "arn", "as", "bh", "bho", "bn", "csw", "doi", "fa", "ff", "frc", "frp", "gu", "gug", "gun", "guw", "hi", "hy", "kab", "kn", "ln", "mfe", "mg", "mi", "mia", "nso", "oc", "pa", "pcm", "pt", "qdt", "qtp", "si", "tg", "ti", "wa", "zu": - return PluralRuleBengali - - case "is": - return PluralRuleIcelandic - - case "fil": - return PluralRuleFilipino - - case "ace", "ay", "bm", "bo", "cdo", "cpx", "crh", "dz", "gan", "hak", "hnj", "hsn", "id", "ig", "ii", "ja", "jbo", "jv", "kde", "kea", "km", "ko", "kos", "lkt", "lo", "lzh", "ms", "my", "nan", "nqo", "osa", "sah", "ses", "sg", "son", "su", "th", "tlh", "to", "tok", "tpi", "tt", "vi", "wo", "wuu", "yo", "yue", "zh": - return PluralRuleOneForm - - case "cpp", "cs", "sk": - return PluralRuleCzech - - case "be", "bs", "cnr", "hr", "ru", "sr", "uk", "wen": - return PluralRuleRussian - - case "csb", "pl", "szl": - return PluralRulePolish - - case "lv", "prg": - return PluralRuleLatvian - - case "lt": - return PluralRuleLithuanian - - case "fr": - return PluralRuleFrench - - case "ca", "es", "it": - return PluralRuleCatalan - - case "sl": - return PluralRuleSlovenian - - case "ar": - return PluralRuleArabic - - default: - break - } - - log.Error("No plural rule defined for language %s", langName) - return PluralRuleDefault -} - -var PluralRules = []i18n.PluralFormRule{ - // [ 0] Common 2-form, e.g. English, German - func(n int64) i18n.PluralFormIndex { - if n != 1 { - return i18n.PluralFormOther - } - return i18n.PluralFormOne - }, - - // [ 1] Bengali - func(n int64) i18n.PluralFormIndex { - if n > 1 { - return i18n.PluralFormOther - } - return i18n.PluralFormOne - }, - - // [ 2] Icelandic - func(n int64) i18n.PluralFormIndex { - if n%10 != 1 || n%100 == 11 { - return i18n.PluralFormOther - } - return i18n.PluralFormOne - }, - - // [ 3] Filipino - func(n int64) i18n.PluralFormIndex { - if n != 1 && n != 2 && n != 3 && (n%10 == 4 || n%10 == 6 || n%10 == 9) { - return i18n.PluralFormOther - } - return i18n.PluralFormOne - }, - - // [ 4] OneForm - func(n int64) i18n.PluralFormIndex { - return i18n.PluralFormOther - }, - - // [ 5] Czech - func(n int64) i18n.PluralFormIndex { - if n == 1 { - return i18n.PluralFormOne - } - if n >= 2 && n <= 4 { - return i18n.PluralFormFew - } - return i18n.PluralFormOther - }, - - // [ 6] Russian - func(n int64) i18n.PluralFormIndex { - if n%10 == 1 && n%100 != 11 { - return i18n.PluralFormOne - } - if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) { - return i18n.PluralFormFew - } - return i18n.PluralFormMany - }, - - // [ 7] Polish - func(n int64) i18n.PluralFormIndex { - if n == 1 { - return i18n.PluralFormOne - } - if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) { - return i18n.PluralFormFew - } - return i18n.PluralFormMany - }, - - // [ 8] Latvian - func(n int64) i18n.PluralFormIndex { - if n%10 == 0 || n%100 >= 11 && n%100 <= 19 { - return i18n.PluralFormZero - } - if n%10 == 1 && n%100 != 11 { - return i18n.PluralFormOne - } - return i18n.PluralFormOther - }, - - // [ 9] Lithuanian - func(n int64) i18n.PluralFormIndex { - if n%10 == 1 && (n%100 < 11 || n%100 > 19) { - return i18n.PluralFormOne - } - if n%10 >= 2 && n%10 <= 9 && (n%100 < 11 || n%100 > 19) { - return i18n.PluralFormFew - } - return i18n.PluralFormMany - }, - - // [10] French - func(n int64) i18n.PluralFormIndex { - if n == 0 || n == 1 { - return i18n.PluralFormOne - } - if n != 0 && n%1000000 == 0 { - return i18n.PluralFormMany - } - return i18n.PluralFormOther - }, - - // [11] Catalan - func(n int64) i18n.PluralFormIndex { - if n == 1 { - return i18n.PluralFormOne - } - if n != 0 && n%1000000 == 0 { - return i18n.PluralFormMany - } - return i18n.PluralFormOther - }, - - // [12] Slovenian - func(n int64) i18n.PluralFormIndex { - if n%100 == 1 { - return i18n.PluralFormOne - } - if n%100 == 2 { - return i18n.PluralFormTwo - } - if n%100 == 3 || n%100 == 4 { - return i18n.PluralFormFew - } - return i18n.PluralFormOther - }, - - // [13] Arabic - func(n int64) i18n.PluralFormIndex { - if n == 0 { - return i18n.PluralFormZero - } - if n == 1 { - return i18n.PluralFormOne - } - if n == 2 { - return i18n.PluralFormTwo - } - if n%100 >= 3 && n%100 <= 10 { - return i18n.PluralFormFew - } - if n%100 >= 11 { - return i18n.PluralFormMany - } - return i18n.PluralFormOther - }, -} - -var UsedPluralForms = [][]i18n.PluralFormIndex{ - // [ 0] Common 2-form, e.g. English, German - {i18n.PluralFormOne, i18n.PluralFormOther}, - // [ 1] Bengali - {i18n.PluralFormOne, i18n.PluralFormOther}, - // [ 2] Icelandic - {i18n.PluralFormOne, i18n.PluralFormOther}, - // [ 3] Filipino - {i18n.PluralFormOne, i18n.PluralFormOther}, - // [ 4] OneForm - {i18n.PluralFormOther}, - // [ 5] Czech - {i18n.PluralFormOne, i18n.PluralFormFew, i18n.PluralFormOther}, - // [ 6] Russian - {i18n.PluralFormOne, i18n.PluralFormFew, i18n.PluralFormMany}, - // [ 7] Polish - {i18n.PluralFormOne, i18n.PluralFormFew, i18n.PluralFormOther}, - // [ 8] Latvian - {i18n.PluralFormZero, i18n.PluralFormOne, i18n.PluralFormOther}, - // [ 9] Lithuanian - {i18n.PluralFormOne, i18n.PluralFormFew, i18n.PluralFormMany}, - // [10] French - {i18n.PluralFormOne, i18n.PluralFormMany, i18n.PluralFormOther}, - // [11] Catalan - {i18n.PluralFormOne, i18n.PluralFormMany, i18n.PluralFormOther}, - // [12] Slovenian - {i18n.PluralFormOne, i18n.PluralFormTwo, i18n.PluralFormFew, i18n.PluralFormOther}, - // [13] Arabic - {i18n.PluralFormZero, i18n.PluralFormOne, i18n.PluralFormTwo, i18n.PluralFormFew, i18n.PluralFormMany, i18n.PluralFormOther}, -} diff --git a/modules/translation/translation.go b/modules/translation/translation.go index 17c7cc068b..16eb55e28e 100644 --- a/modules/translation/translation.go +++ b/modules/translation/translation.go @@ -10,11 +10,11 @@ import ( "strings" "sync" - "forgejo.org/modules/log" - "forgejo.org/modules/options" - "forgejo.org/modules/setting" - "forgejo.org/modules/translation/i18n" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/util" "github.com/dustin/go-humanize" "golang.org/x/text/language" @@ -27,27 +27,16 @@ type contextKey struct{} var ContextKey any = &contextKey{} // Locale represents an interface to translation -// -// If this gets modified, remember to also adjust -// build/lint-locale-usage/lint-locale-usage.go's InitLocaleTrFunctions(), -// which requires to know in what argument positions `trKey`'s are given. type Locale interface { Language() string TrString(string, ...any) string Tr(key string, args ...any) template.HTML - // New-style pluralized strings - TrPluralString(count any, trKey string, trArgs ...any) template.HTML - // Old-style pseudo-pluralized strings, deprecated TrN(cnt any, key1, keyN string, args ...any) template.HTML TrSize(size int64) ReadableSize - HasKey(trKey string) bool - PrettyNumber(v any) string - - TrPluralStringAllForms(trKey string) ([]string, []string) } // LangType represents a lang type @@ -110,19 +99,9 @@ func InitLocales(ctx context.Context) { } } - pluralRuleIndex := GetPluralRuleImpl(setting.Langs[i]) key := "locale_" + setting.Langs[i] + ".ini" - if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], PluralRules[pluralRuleIndex], UsedPluralForms[pluralRuleIndex], localeDataBase, localeData[key]); err != nil { - log.Error("Failed to set old-style messages to %s: %v", setting.Langs[i], err) - } - - key = "locale_next/locale_" + setting.Langs[i] + ".json" - if bytes, err := options.AssetFS().ReadFile(key); err == nil { - if err = i18n.DefaultLocales.AddToLocaleFromJSON(setting.Langs[i], bytes); err != nil { - log.Error("Failed to add new-style messages to %s: %v", setting.Langs[i], err) - } - } else { - log.Error("Failed to open new-style messages for %s: %v", setting.Langs[i], err) + if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localeDataBase, localeData[key]); err != nil { + log.Error("Failed to set messages to %s: %v", setting.Langs[i], err) } } if len(setting.Langs) != 0 { @@ -181,16 +160,6 @@ func NewLocale(lang string) Locale { defer lock.RUnlock() } - if lang == "dummy" { - l := &locale{ - Locale: &i18n.KeyLocale{}, - Lang: lang, - LangName: lang, - msgPrinter: message.NewPrinter(language.English), - } - return l - } - langName := "unknown" if l, ok := allLangMap[lang]; ok { langName = l.Name @@ -327,14 +296,6 @@ func (l *locale) PrettyNumber(v any) string { return l.msgPrinter.Sprintf("%v", number.Decimal(v)) } -func GetPluralRule(l Locale) int { - return GetPluralRuleImpl(l.Language()) -} - -func GetDefaultPluralRule() int { - return GetPluralRuleImpl(i18n.DefaultLocales.GetDefaultLang()) -} - func init() { // prepare a default matcher, especially for tests supportedTags = []language.Tag{language.English} diff --git a/modules/translation/translation_test.go b/modules/translation/translation_test.go index 7584490941..bffbb155ca 100644 --- a/modules/translation/translation_test.go +++ b/modules/translation/translation_test.go @@ -8,7 +8,7 @@ package translation import ( "testing" - "forgejo.org/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/stretchr/testify/assert" ) @@ -16,19 +16,19 @@ import ( func TestTrSize(t *testing.T) { l := NewLocale("") size := int64(1) - assert.Equal(t, "1 munits.data.b", l.TrSize(size).String()) + assert.EqualValues(t, "1 munits.data.b", l.TrSize(size).String()) size *= 2048 - assert.Equal(t, "2 munits.data.kib", l.TrSize(size).String()) + assert.EqualValues(t, "2 munits.data.kib", l.TrSize(size).String()) size *= 2048 - assert.Equal(t, "4 munits.data.mib", l.TrSize(size).String()) + assert.EqualValues(t, "4 munits.data.mib", l.TrSize(size).String()) size *= 2048 - assert.Equal(t, "8 munits.data.gib", l.TrSize(size).String()) + assert.EqualValues(t, "8 munits.data.gib", l.TrSize(size).String()) size *= 2048 - assert.Equal(t, "16 munits.data.tib", l.TrSize(size).String()) + assert.EqualValues(t, "16 munits.data.tib", l.TrSize(size).String()) size *= 2048 - assert.Equal(t, "32 munits.data.pib", l.TrSize(size).String()) + assert.EqualValues(t, "32 munits.data.pib", l.TrSize(size).String()) size *= 128 - assert.Equal(t, "4 munits.data.eib", l.TrSize(size).String()) + assert.EqualValues(t, "4 munits.data.eib", l.TrSize(size).String()) } func TestPrettyNumber(t *testing.T) { @@ -38,121 +38,13 @@ func TestPrettyNumber(t *testing.T) { allLangMap["id-ID"] = &LangType{Lang: "id-ID", Name: "Bahasa Indonesia"} l := NewLocale("id-ID") - assert.Equal(t, "1.000.000", l.PrettyNumber(1000000)) - assert.Equal(t, "1.000.000,1", l.PrettyNumber(1000000.1)) - assert.Equal(t, "1.000.000", l.PrettyNumber("1000000")) - assert.Equal(t, "1.000.000", l.PrettyNumber("1000000.0")) - assert.Equal(t, "1.000.000,1", l.PrettyNumber("1000000.1")) + assert.EqualValues(t, "1.000.000", l.PrettyNumber(1000000)) + assert.EqualValues(t, "1.000.000,1", l.PrettyNumber(1000000.1)) + assert.EqualValues(t, "1.000.000", l.PrettyNumber("1000000")) + assert.EqualValues(t, "1.000.000", l.PrettyNumber("1000000.0")) + assert.EqualValues(t, "1.000.000,1", l.PrettyNumber("1000000.1")) l = NewLocale("nosuch") - assert.Equal(t, "1,000,000", l.PrettyNumber(1000000)) - assert.Equal(t, "1,000,000.1", l.PrettyNumber(1000000.1)) -} - -func TestGetPluralRule(t *testing.T) { - assert.Equal(t, PluralRuleDefault, GetPluralRuleImpl("en")) - assert.Equal(t, PluralRuleDefault, GetPluralRuleImpl("en-US")) - assert.Equal(t, PluralRuleDefault, GetPluralRuleImpl("en_UK")) - assert.Equal(t, PluralRuleDefault, GetPluralRuleImpl("nds")) - assert.Equal(t, PluralRuleDefault, GetPluralRuleImpl("de-DE")) - - assert.Equal(t, PluralRuleOneForm, GetPluralRuleImpl("zh")) - assert.Equal(t, PluralRuleOneForm, GetPluralRuleImpl("ja")) - - assert.Equal(t, PluralRuleBengali, GetPluralRuleImpl("bn")) - - assert.Equal(t, PluralRuleIcelandic, GetPluralRuleImpl("is")) - - assert.Equal(t, PluralRuleFilipino, GetPluralRuleImpl("fil")) - - assert.Equal(t, PluralRuleCzech, GetPluralRuleImpl("cs")) - - assert.Equal(t, PluralRuleRussian, GetPluralRuleImpl("ru")) - - assert.Equal(t, PluralRulePolish, GetPluralRuleImpl("pl")) - - assert.Equal(t, PluralRuleLatvian, GetPluralRuleImpl("lv")) - - assert.Equal(t, PluralRuleLithuanian, GetPluralRuleImpl("lt")) - - assert.Equal(t, PluralRuleFrench, GetPluralRuleImpl("fr")) - - assert.Equal(t, PluralRuleCatalan, GetPluralRuleImpl("ca")) - - assert.Equal(t, PluralRuleSlovenian, GetPluralRuleImpl("sl")) - - assert.Equal(t, PluralRuleArabic, GetPluralRuleImpl("ar")) - - assert.Equal(t, PluralRuleCatalan, GetPluralRuleImpl("pt-PT")) - assert.Equal(t, PluralRuleFrench, GetPluralRuleImpl("pt-BR")) - - assert.Equal(t, PluralRuleDefault, GetPluralRuleImpl("invalid")) -} - -func TestApplyPluralRule(t *testing.T) { - testCases := []struct { - expect i18n.PluralFormIndex - pluralRule int - values []int64 - }{ - {i18n.PluralFormOne, PluralRuleDefault, []int64{1}}, - {i18n.PluralFormOther, PluralRuleDefault, []int64{0, 2, 10, 256}}, - - {i18n.PluralFormOther, PluralRuleOneForm, []int64{0, 1, 2}}, - - {i18n.PluralFormOne, PluralRuleBengali, []int64{0, 1}}, - {i18n.PluralFormOther, PluralRuleBengali, []int64{2, 10, 256}}, - - {i18n.PluralFormOne, PluralRuleIcelandic, []int64{1, 21, 31}}, - {i18n.PluralFormOther, PluralRuleIcelandic, []int64{0, 2, 11, 15, 256}}, - - {i18n.PluralFormOne, PluralRuleFilipino, []int64{0, 1, 2, 3, 5, 7, 8, 10, 11, 12, 257}}, - {i18n.PluralFormOther, PluralRuleFilipino, []int64{4, 6, 9, 14, 16, 19, 256}}, - - {i18n.PluralFormOne, PluralRuleCzech, []int64{1}}, - {i18n.PluralFormFew, PluralRuleCzech, []int64{2, 3, 4}}, - {i18n.PluralFormOther, PluralRuleCzech, []int64{5, 0, 12, 78, 254}}, - - {i18n.PluralFormOne, PluralRuleRussian, []int64{1, 21, 31}}, - {i18n.PluralFormFew, PluralRuleRussian, []int64{2, 23, 34}}, - {i18n.PluralFormMany, PluralRuleRussian, []int64{0, 5, 11, 37, 111, 256}}, - - {i18n.PluralFormOne, PluralRulePolish, []int64{1}}, - {i18n.PluralFormFew, PluralRulePolish, []int64{2, 23, 34}}, - {i18n.PluralFormMany, PluralRulePolish, []int64{0, 5, 11, 21, 37, 256}}, - - {i18n.PluralFormZero, PluralRuleLatvian, []int64{0, 10, 11, 17}}, - {i18n.PluralFormOne, PluralRuleLatvian, []int64{1, 21, 71}}, - {i18n.PluralFormOther, PluralRuleLatvian, []int64{2, 7, 22, 23, 256}}, - - {i18n.PluralFormOne, PluralRuleLithuanian, []int64{1, 21, 31}}, - {i18n.PluralFormFew, PluralRuleLithuanian, []int64{2, 5, 9, 23, 34, 256}}, - {i18n.PluralFormMany, PluralRuleLithuanian, []int64{0, 10, 11, 18}}, - - {i18n.PluralFormOne, PluralRuleFrench, []int64{0, 1}}, - {i18n.PluralFormMany, PluralRuleFrench, []int64{1000000, 2000000}}, - {i18n.PluralFormOther, PluralRuleFrench, []int64{2, 4, 10, 256}}, - - {i18n.PluralFormOne, PluralRuleCatalan, []int64{1}}, - {i18n.PluralFormMany, PluralRuleCatalan, []int64{1000000, 2000000}}, - {i18n.PluralFormOther, PluralRuleCatalan, []int64{0, 2, 4, 10, 256}}, - - {i18n.PluralFormOne, PluralRuleSlovenian, []int64{1, 101, 201, 501}}, - {i18n.PluralFormTwo, PluralRuleSlovenian, []int64{2, 102, 202, 502}}, - {i18n.PluralFormFew, PluralRuleSlovenian, []int64{3, 103, 203, 503, 4, 104, 204, 504}}, - {i18n.PluralFormOther, PluralRuleSlovenian, []int64{0, 5, 11, 12, 20, 256}}, - - {i18n.PluralFormZero, PluralRuleArabic, []int64{0}}, - {i18n.PluralFormOne, PluralRuleArabic, []int64{1}}, - {i18n.PluralFormTwo, PluralRuleArabic, []int64{2}}, - {i18n.PluralFormFew, PluralRuleArabic, []int64{3, 4, 9, 10, 103, 104}}, - {i18n.PluralFormMany, PluralRuleArabic, []int64{11, 12, 13, 14, 17, 111, 256}}, - {i18n.PluralFormOther, PluralRuleArabic, []int64{100, 101, 102}}, - } - - for _, tc := range testCases { - for _, n := range tc.values { - assert.Equal(t, tc.expect, PluralRules[tc.pluralRule](n), "Testcase for plural rule %d, value %d", tc.pluralRule, n) - } - } + assert.EqualValues(t, "1,000,000", l.PrettyNumber(1000000)) + assert.EqualValues(t, "1,000,000.1", l.PrettyNumber(1000000.1)) } diff --git a/modules/turnstile/turnstile.go b/modules/turnstile/turnstile.go index 31ba256195..38d0233446 100644 --- a/modules/turnstile/turnstile.go +++ b/modules/turnstile/turnstile.go @@ -11,8 +11,8 @@ import ( "net/url" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/setting" ) // Response is the structure of JSON returned from API diff --git a/modules/typesniffer/typesniffer.go b/modules/typesniffer/typesniffer.go index 262feb2b05..6aec5c285e 100644 --- a/modules/typesniffer/typesniffer.go +++ b/modules/typesniffer/typesniffer.go @@ -11,7 +11,7 @@ import ( "regexp" "strings" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/util" ) // Use at most this many bytes to determine Content Type. @@ -20,20 +20,8 @@ const sniffLen = 1024 const ( // SvgMimeType MIME type of SVG images. SvgMimeType = "image/svg+xml" - // AvifMimeType MIME type of AVIF images - AvifMimeType = "image/avif" // ApplicationOctetStream MIME type of binary files. ApplicationOctetStream = "application/octet-stream" - // GLTFMimeType MIME type of GLTF files. - GLTFMimeType = "model/gltf+json" - // GLBMimeType MIME type of GLB files. - GLBMimeType = "model/gltf-binary" - // OBJMimeType MIME type of OBJ files. - OBJMimeType = "model/obj" - // STLMimeType MIME type of STL files. - STLMimeType = "model/stl" - // 3MFMimeType MIME type of 3MF files. - ThreeMFMimeType = "model/3mf" ) var ( @@ -77,36 +65,6 @@ func (ct SniffedType) IsAudio() bool { return strings.Contains(ct.contentType, "audio/") } -// Is3DModel detects if data is a 3D format -func (ct SniffedType) Is3DModel() bool { - return strings.Contains(ct.contentType, "model/") -} - -// IsGLTFFile detects if data is an SVG image format -func (ct SniffedType) IsGLTF() bool { - return strings.Contains(ct.contentType, GLTFMimeType) -} - -// IsGLBFile detects if data is an GLB image format -func (ct SniffedType) IsGLB() bool { - return strings.Contains(ct.contentType, GLBMimeType) -} - -// IsOBJFile detects if data is an OBJ image format -func (ct SniffedType) IsOBJ() bool { - return strings.Contains(ct.contentType, OBJMimeType) -} - -// IsSTLTextFile detects if data is an STL text format -func (ct SniffedType) IsSTL() bool { - return strings.Contains(ct.contentType, STLMimeType) -} - -// Is3MFFile detects if data is an 3MF image format -func (ct SniffedType) Is3MF() bool { - return strings.Contains(ct.contentType, ThreeMFMimeType) -} - // IsRepresentableAsText returns true if file content can be represented as // plain text or is empty. func (ct SniffedType) IsRepresentableAsText() bool { @@ -115,7 +73,7 @@ func (ct SniffedType) IsRepresentableAsText() bool { // IsBrowsableBinaryType returns whether a non-text type can be displayed in a browser func (ct SniffedType) IsBrowsableBinaryType() bool { - return ct.IsImage() || ct.IsSvgImage() || ct.IsPDF() || ct.IsVideo() || ct.IsAudio() || ct.Is3DModel() + return ct.IsImage() || ct.IsSvgImage() || ct.IsPDF() || ct.IsVideo() || ct.IsAudio() } // GetMimeType returns the mime type @@ -148,12 +106,6 @@ func DetectContentType(data []byte) SniffedType { } } - // AVIF is unsupported by http.DetectContentType - // Signature taken from https://stackoverflow.com/a/68322450 - if bytes.Index(data, []byte("ftypavif")) == 4 { - ct = AvifMimeType - } - if strings.HasPrefix(ct, "audio/") && bytes.HasPrefix(data, []byte("ID3")) { // The MP3 detection is quite inaccurate, any content with "ID3" prefix will result in "audio/mpeg". // So remove the "ID3" prefix and detect again, if result is text, then it must be text content. @@ -175,13 +127,6 @@ func DetectContentType(data []byte) SniffedType { ct = "audio/ogg" // for most cases, it is used as an audio container } } - - // GLTF is unsupported by http.DetectContentType - // hexdump -n 4 -C glTF.glb - if bytes.HasPrefix(data, []byte("glTF")) { - ct = GLBMimeType - } - return SniffedType{ct} } diff --git a/modules/typesniffer/typesniffer_test.go b/modules/typesniffer/typesniffer_test.go index 176d3658bb..da662ab99d 100644 --- a/modules/typesniffer/typesniffer_test.go +++ b/modules/typesniffer/typesniffer_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestDetectContentTypeLongerThanSniffLen(t *testing.T) { @@ -117,51 +116,21 @@ func TestIsAudio(t *testing.T) { assert.True(t, DetectContentType([]byte("ID3Toy\n====\t* hi 🌞, ..."+"🌛"[0:2])).IsText()) // test ID3 tag with incomplete UTF8 char } -func TestIsGLB(t *testing.T) { - glb, _ := hex.DecodeString("676c5446") - assert.True(t, DetectContentType(glb).IsGLB()) - assert.True(t, DetectContentType(glb).Is3DModel()) - assert.False(t, DetectContentType([]byte("plain text")).IsGLB()) - assert.False(t, DetectContentType([]byte("plain text")).Is3DModel()) -} - func TestDetectContentTypeFromReader(t *testing.T) { mp3, _ := base64.StdEncoding.DecodeString("SUQzBAAAAAABAFRYWFgAAAASAAADbWFqb3JfYnJhbmQAbXA0MgBUWFhYAAAAEQAAA21pbm9yX3Zl") st, err := DetectContentTypeFromReader(bytes.NewReader(mp3)) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, st.IsAudio()) } func TestDetectContentTypeOgg(t *testing.T) { oggAudio, _ := hex.DecodeString("4f67675300020000000000000000352f0000000000007dc39163011e01766f72626973000000000244ac0000000000000071020000000000b8014f6767530000") st, err := DetectContentTypeFromReader(bytes.NewReader(oggAudio)) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, st.IsAudio()) oggVideo, _ := hex.DecodeString("4f676753000200000000000000007d9747ef000000009b59daf3012a807468656f7261030201001e00110001e000010e00020000001e00000001000001000001") st, err = DetectContentTypeFromReader(bytes.NewReader(oggVideo)) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, st.IsVideo()) } - -func TestDetectContentTypeAvif(t *testing.T) { - avifImage, err := hex.DecodeString("000000206674797061766966") - require.NoError(t, err) - - st, err := DetectContentTypeFromReader(bytes.NewReader(avifImage)) - require.NoError(t, err) - - assert.True(t, st.IsImage()) -} - -func TestDetectContentTypeModelGLB(t *testing.T) { - glb, err := hex.DecodeString("676c5446") - require.NoError(t, err) - - st, err := DetectContentTypeFromReader(bytes.NewReader(glb)) - require.NoError(t, err) - - // print st for debugging - assert.Equal(t, "model/gltf-binary", st.GetMimeType()) - assert.True(t, st.IsGLB()) -} diff --git a/modules/updatechecker/update_checker.go b/modules/updatechecker/update_checker.go index b0932ba663..0c93f08d21 100644 --- a/modules/updatechecker/update_checker.go +++ b/modules/updatechecker/update_checker.go @@ -11,10 +11,10 @@ import ( "net/http" "strings" - "forgejo.org/modules/json" - "forgejo.org/modules/proxy" - "forgejo.org/modules/setting" - "forgejo.org/modules/system" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/proxy" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/system" "github.com/hashicorp/go-version" ) diff --git a/modules/updatechecker/update_checker_test.go b/modules/updatechecker/update_checker_test.go index 5ac2603ca1..301afd95e4 100644 --- a/modules/updatechecker/update_checker_test.go +++ b/modules/updatechecker/update_checker_test.go @@ -7,11 +7,10 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestDNSUpdate(t *testing.T) { version, err := getVersionDNS("release.forgejo.org") - require.NoError(t, err) + assert.NoError(t, err) assert.NotEmpty(t, version) } diff --git a/modules/uri/uri_test.go b/modules/uri/uri_test.go index 71a8985cd7..11b915c261 100644 --- a/modules/uri/uri_test.go +++ b/modules/uri/uri_test.go @@ -7,13 +7,13 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" ) func TestReadURI(t *testing.T) { p, err := filepath.Abs("./uri.go") - require.NoError(t, err) + assert.NoError(t, err) f, err := Open("file://" + p) - require.NoError(t, err) + assert.NoError(t, err) defer f.Close() } diff --git a/modules/user/user.go b/modules/user/user.go index d153413c70..eee401a23f 100644 --- a/modules/user/user.go +++ b/modules/user/user.go @@ -6,6 +6,8 @@ package user import ( "os" "os/user" + "runtime" + "strings" ) // CurrentUsername return current login OS user name @@ -14,7 +16,12 @@ func CurrentUsername() string { if err != nil { return fallbackCurrentUsername() } - return userinfo.Username + username := userinfo.Username + if runtime.GOOS == "windows" { + parts := strings.Split(username, "\\") + username = parts[len(parts)-1] + } + return username } // Old method, used if new method doesn't work on your OS for some reason diff --git a/modules/user/user_test.go b/modules/user/user_test.go index c7eff85c90..9129ae79a1 100644 --- a/modules/user/user_test.go +++ b/modules/user/user_test.go @@ -4,7 +4,9 @@ package user import ( + "os" "os/exec" + "runtime" "strings" "testing" ) @@ -22,6 +24,10 @@ func TestCurrentUsername(t *testing.T) { if len(user) == 0 { t.Errorf("expected non-empty user, got: %s", user) } + // Windows whoami is weird, so just skip remaining tests + if runtime.GOOS == "windows" { + t.Skip("skipped test because of weird whoami on Windows") + } whoami, err := getWhoamiOutput() if err != nil { t.Errorf("failed to run whoami to test current user: %f", err) @@ -30,7 +36,7 @@ func TestCurrentUsername(t *testing.T) { if user != whoami { t.Errorf("expected %s as user, got: %s", whoami, user) } - t.Setenv("USER", "spoofed") + os.Setenv("USER", "spoofed") user = CurrentUsername() if user != whoami { t.Errorf("expected %s as user, got: %s", whoami, user) diff --git a/modules/util/color_test.go b/modules/util/color_test.go index abd5551218..be6e6b122a 100644 --- a/modules/util/color_test.go +++ b/modules/util/color_test.go @@ -27,9 +27,9 @@ func Test_HexToRBGColor(t *testing.T) { } for n, c := range cases { r, g, b := HexToRBGColor(c.colorString) - assert.InDelta(t, c.expectedR, r, 0, "case %d: error R should match: expected %f, but get %f", n, c.expectedR, r) - assert.InDelta(t, c.expectedG, g, 0, "case %d: error G should match: expected %f, but get %f", n, c.expectedG, g) - assert.InDelta(t, c.expectedB, b, 0, "case %d: error B should match: expected %f, but get %f", n, c.expectedB, b) + assert.Equal(t, c.expectedR, r, "case %d: error R should match: expected %f, but get %f", n, c.expectedR, r) + assert.Equal(t, c.expectedG, g, "case %d: error G should match: expected %f, but get %f", n, c.expectedG, g) + assert.Equal(t, c.expectedB, b, "case %d: error B should match: expected %f, but get %f", n, c.expectedB, b) } } diff --git a/modules/util/file_unix.go b/modules/util/file_unix.go index b722eee97d..79a29c8b3b 100644 --- a/modules/util/file_unix.go +++ b/modules/util/file_unix.go @@ -1,6 +1,8 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT +//go:build !windows + package util import ( diff --git a/modules/util/file_unix_test.go b/modules/util/file_unix_test.go index 228c64f980..87d6c2f09a 100644 --- a/modules/util/file_unix_test.go +++ b/modules/util/file_unix_test.go @@ -1,6 +1,8 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT +//go:build !windows + package util import ( @@ -8,17 +10,16 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestApplyUmask(t *testing.T) { f, err := os.CreateTemp(t.TempDir(), "test-filemode-") - require.NoError(t, err) + assert.NoError(t, err) err = os.Chmod(f.Name(), 0o777) - require.NoError(t, err) + assert.NoError(t, err) st, err := os.Stat(f.Name()) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 0o777, st.Mode().Perm()&0o777) oldDefaultUmask := defaultUmask @@ -27,8 +28,8 @@ func TestApplyUmask(t *testing.T) { defaultUmask = oldDefaultUmask }() err = ApplyUmask(f.Name(), os.ModePerm) - require.NoError(t, err) + assert.NoError(t, err) st, err = os.Stat(f.Name()) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, 0o740, st.Mode().Perm()&0o777) } diff --git a/modules/util/file_windows.go b/modules/util/file_windows.go new file mode 100644 index 0000000000..77a33d3c49 --- /dev/null +++ b/modules/util/file_windows.go @@ -0,0 +1,15 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build windows + +package util + +import ( + "os" +) + +func ApplyUmask(f string, newMode os.FileMode) error { + // do nothing for Windows, because Windows doesn't use umask + return nil +} diff --git a/modules/util/filebuffer/file_backed_buffer_test.go b/modules/util/filebuffer/file_backed_buffer_test.go index c56c1c64e9..16d5a1965f 100644 --- a/modules/util/filebuffer/file_backed_buffer_test.go +++ b/modules/util/filebuffer/file_backed_buffer_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestFileBackedBuffer(t *testing.T) { @@ -23,14 +22,14 @@ func TestFileBackedBuffer(t *testing.T) { for _, c := range cases { buf, err := CreateFromReader(strings.NewReader(c.Data), c.MaxMemorySize) - require.NoError(t, err) + assert.NoError(t, err) assert.EqualValues(t, len(c.Data), buf.Size()) data, err := io.ReadAll(buf) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, c.Data, string(data)) - require.NoError(t, buf.Close()) + assert.NoError(t, buf.Close()) } } diff --git a/modules/util/io.go b/modules/util/io.go index 4c99004c0c..1559b019a0 100644 --- a/modules/util/io.go +++ b/modules/util/io.go @@ -4,6 +4,7 @@ package util import ( + "bytes" "errors" "io" ) @@ -19,6 +20,42 @@ func ReadAtMost(r io.Reader, buf []byte) (n int, err error) { return n, err } +// ReadWithLimit reads at most "limit" bytes from r into buf. +// If EOF or ErrUnexpectedEOF occurs while reading, err will be nil. +func ReadWithLimit(r io.Reader, n int) (buf []byte, err error) { + return readWithLimit(r, 1024, n) +} + +func readWithLimit(r io.Reader, batch, limit int) ([]byte, error) { + if limit <= batch { + buf := make([]byte, limit) + n, err := ReadAtMost(r, buf) + if err != nil { + return nil, err + } + return buf[:n], nil + } + res := bytes.NewBuffer(make([]byte, 0, batch)) + bufFix := make([]byte, batch) + eof := false + for res.Len() < limit && !eof { + bufTmp := bufFix + if res.Len()+batch > limit { + bufTmp = bufFix[:limit-res.Len()] + } + n, err := io.ReadFull(r, bufTmp) + if err == io.EOF || err == io.ErrUnexpectedEOF { + eof = true + } else if err != nil { + return nil, err + } + if _, err = res.Write(bufTmp[:n]); err != nil { + return nil, err + } + } + return res.Bytes(), nil +} + // ErrNotEmpty is an error reported when there is a non-empty reader var ErrNotEmpty = errors.New("not-empty") diff --git a/modules/util/io_test.go b/modules/util/io_test.go new file mode 100644 index 0000000000..275575463a --- /dev/null +++ b/modules/util/io_test.go @@ -0,0 +1,66 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package util + +import ( + "bytes" + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +type readerWithError struct { + buf *bytes.Buffer +} + +func (r *readerWithError) Read(p []byte) (n int, err error) { + if r.buf.Len() < 2 { + return 0, errors.New("test error") + } + return r.buf.Read(p) +} + +func TestReadWithLimit(t *testing.T) { + bs := []byte("0123456789abcdef") + + // normal test + buf, err := readWithLimit(bytes.NewBuffer(bs), 5, 2) + assert.NoError(t, err) + assert.Equal(t, []byte("01"), buf) + + buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 5) + assert.NoError(t, err) + assert.Equal(t, []byte("01234"), buf) + + buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 6) + assert.NoError(t, err) + assert.Equal(t, []byte("012345"), buf) + + buf, err = readWithLimit(bytes.NewBuffer(bs), 5, len(bs)) + assert.NoError(t, err) + assert.Equal(t, []byte("0123456789abcdef"), buf) + + buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 100) + assert.NoError(t, err) + assert.Equal(t, []byte("0123456789abcdef"), buf) + + // test with error + buf, err = readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 10) + assert.NoError(t, err) + assert.Equal(t, []byte("0123456789"), buf) + + buf, err = readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 100) + assert.ErrorContains(t, err, "test error") + assert.Empty(t, buf) + + // test public function + buf, err = ReadWithLimit(bytes.NewBuffer(bs), 2) + assert.NoError(t, err) + assert.Equal(t, []byte("01"), buf) + + buf, err = ReadWithLimit(bytes.NewBuffer(bs), 9999999) + assert.NoError(t, err) + assert.Equal(t, []byte("0123456789abcdef"), buf) +} diff --git a/modules/util/keypair_test.go b/modules/util/keypair_test.go index 6c05db779a..c6f68c845a 100644 --- a/modules/util/keypair_test.go +++ b/modules/util/keypair_test.go @@ -10,26 +10,26 @@ import ( "crypto/sha256" "crypto/x509" "encoding/pem" + "regexp" "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestKeygen(t *testing.T) { priv, pub, err := GenerateKeyPair(2048) - require.NoError(t, err) + assert.NoError(t, err) assert.NotEmpty(t, priv) assert.NotEmpty(t, pub) - assert.Regexp(t, "^-----BEGIN RSA PRIVATE KEY-----.*", priv) - assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----.*", pub) + assert.Regexp(t, regexp.MustCompile("^-----BEGIN RSA PRIVATE KEY-----.*"), priv) + assert.Regexp(t, regexp.MustCompile("^-----BEGIN PUBLIC KEY-----.*"), pub) } func TestSignUsingKeys(t *testing.T) { priv, pub, err := GenerateKeyPair(2048) - require.NoError(t, err) + assert.NoError(t, err) privPem, _ := pem.Decode([]byte(priv)) if privPem == nil || privPem.Type != "RSA PRIVATE KEY" { @@ -37,7 +37,7 @@ func TestSignUsingKeys(t *testing.T) { } privParsed, err := x509.ParsePKCS1PrivateKey(privPem.Bytes) - require.NoError(t, err) + assert.NoError(t, err) pubPem, _ := pem.Decode([]byte(pub)) if pubPem == nil || pubPem.Type != "PUBLIC KEY" { @@ -45,7 +45,7 @@ func TestSignUsingKeys(t *testing.T) { } pubParsed, err := x509.ParsePKIXPublicKey(pubPem.Bytes) - require.NoError(t, err) + assert.NoError(t, err) // Sign msg := "activity pub is great!" @@ -53,9 +53,9 @@ func TestSignUsingKeys(t *testing.T) { h.Write([]byte(msg)) d := h.Sum(nil) sig, err := rsa.SignPKCS1v15(rand.Reader, privParsed, crypto.SHA256, d) - require.NoError(t, err) + assert.NoError(t, err) // Verify err = rsa.VerifyPKCS1v15(pubParsed.(*rsa.PublicKey), crypto.SHA256, d, sig) - require.NoError(t, err) + assert.NoError(t, err) } diff --git a/modules/util/legacy_test.go b/modules/util/legacy_test.go index 62c2f8af16..b7991bd365 100644 --- a/modules/util/legacy_test.go +++ b/modules/util/legacy_test.go @@ -10,7 +10,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestCopyFile(t *testing.T) { @@ -29,10 +28,10 @@ func TestCopyFile(t *testing.T) { }() err := os.WriteFile(srcFile, testContent, 0o777) - require.NoError(t, err) + assert.NoError(t, err) err = CopyFile(srcFile, dstFile) - require.NoError(t, err) + assert.NoError(t, err) dstContent, err := os.ReadFile(dstFile) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, testContent, dstContent) } diff --git a/modules/util/pack_test.go b/modules/util/pack_test.go index 42ada89b81..592c69cd0a 100644 --- a/modules/util/pack_test.go +++ b/modules/util/pack_test.go @@ -6,7 +6,7 @@ package util import ( "testing" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" ) func TestPackAndUnpackData(t *testing.T) { @@ -19,10 +19,10 @@ func TestPackAndUnpackData(t *testing.T) { var f2 float32 data, err := PackData(s, i, f) - require.NoError(t, err) + assert.NoError(t, err) - require.NoError(t, UnpackData(data, &s2, &i2, &f2)) - require.NoError(t, UnpackData(data, &s2)) - require.Error(t, UnpackData(data, &i2)) - require.Error(t, UnpackData(data, &s2, &f2)) + assert.NoError(t, UnpackData(data, &s2, &i2, &f2)) + assert.NoError(t, UnpackData(data, &s2)) + assert.Error(t, UnpackData(data, &i2)) + assert.Error(t, UnpackData(data, &s2, &f2)) } diff --git a/modules/util/paginate_test.go b/modules/util/paginate_test.go index 3dc5095071..6e69dd19cc 100644 --- a/modules/util/paginate_test.go +++ b/modules/util/paginate_test.go @@ -13,23 +13,23 @@ func TestPaginateSlice(t *testing.T) { stringSlice := []string{"a", "b", "c", "d", "e"} result, ok := PaginateSlice(stringSlice, 1, 2).([]string) assert.True(t, ok) - assert.Equal(t, []string{"a", "b"}, result) + assert.EqualValues(t, []string{"a", "b"}, result) result, ok = PaginateSlice(stringSlice, 100, 2).([]string) assert.True(t, ok) - assert.Equal(t, []string{}, result) + assert.EqualValues(t, []string{}, result) result, ok = PaginateSlice(stringSlice, 3, 2).([]string) assert.True(t, ok) - assert.Equal(t, []string{"e"}, result) + assert.EqualValues(t, []string{"e"}, result) result, ok = PaginateSlice(stringSlice, 1, 0).([]string) assert.True(t, ok) - assert.Equal(t, []string{"a", "b", "c", "d", "e"}, result) + assert.EqualValues(t, []string{"a", "b", "c", "d", "e"}, result) result, ok = PaginateSlice(stringSlice, 1, -1).([]string) assert.True(t, ok) - assert.Equal(t, []string{"a", "b", "c", "d", "e"}, result) + assert.EqualValues(t, []string{"a", "b", "c", "d", "e"}, result) type Test struct { Val int @@ -38,9 +38,9 @@ func TestPaginateSlice(t *testing.T) { testVar := []*Test{{Val: 2}, {Val: 3}, {Val: 4}} testVar, ok = PaginateSlice(testVar, 1, 50).([]*Test) assert.True(t, ok) - assert.Equal(t, []*Test{{Val: 2}, {Val: 3}, {Val: 4}}, testVar) + assert.EqualValues(t, []*Test{{Val: 2}, {Val: 3}, {Val: 4}}, testVar) testVar, ok = PaginateSlice(testVar, 2, 2).([]*Test) assert.True(t, ok) - assert.Equal(t, []*Test{{Val: 4}}, testVar) + assert.EqualValues(t, []*Test{{Val: 4}}, testVar) } diff --git a/modules/util/path.go b/modules/util/path.go index 3ef3925c49..185e7cf882 100644 --- a/modules/util/path.go +++ b/modules/util/path.go @@ -10,6 +10,8 @@ import ( "os" "path" "path/filepath" + "regexp" + "runtime" "strings" ) @@ -34,10 +36,9 @@ func PathJoinRel(elem ...string) string { elems[i] = path.Clean("/" + e) } p := path.Join(elems...) - switch p { - case "": + if p == "" { return "" - case "/": + } else if p == "/" { return "." } return p[1:] @@ -77,7 +78,11 @@ func FilePathJoinAbs(base string, sub ...string) string { // POSIX filesystem can have `\` in file names. Windows: `\` and `/` are both used for path separators // to keep the behavior consistent, we do not allow `\` in file names, replace all `\` with `/` - elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", pathSeparator)) + if isOSWindows() { + elems[0] = filepath.Clean(base) + } else { + elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", pathSeparator)) + } if !filepath.IsAbs(elems[0]) { // This shouldn't happen. If there is really necessary to pass in relative path, return the full path with filepath.Abs() instead panic(fmt.Sprintf("FilePathJoinAbs: %q (for path %v) is not absolute, do not guess a relative path based on current working directory", elems[0], elems)) @@ -86,7 +91,11 @@ func FilePathJoinAbs(base string, sub ...string) string { if s == "" { continue } - elems = append(elems, filepath.Clean(pathSeparator+strings.ReplaceAll(s, "\\", pathSeparator))) + if isOSWindows() { + elems = append(elems, filepath.Clean(pathSeparator+s)) + } else { + elems = append(elems, filepath.Clean(pathSeparator+strings.ReplaceAll(s, "\\", pathSeparator))) + } } // the elems[0] must be an absolute path, just join them together return filepath.Join(elems...) @@ -208,6 +217,12 @@ func StatDir(rootPath string, includeDir ...bool) ([]string, error) { return statDir(rootPath, "", isIncludeDir, false, false) } +func isOSWindows() bool { + return runtime.GOOS == "windows" +} + +var driveLetterRegexp = regexp.MustCompile("/[A-Za-z]:/") + // FileURLToPath extracts the path information from a file://... url. // It returns an error only if the URL is not a file URL. func FileURLToPath(u *url.URL) (string, error) { @@ -215,7 +230,17 @@ func FileURLToPath(u *url.URL) (string, error) { return "", errors.New("URL scheme is not 'file': " + u.String()) } - return u.Path, nil + path := u.Path + + if !isOSWindows() { + return path, nil + } + + // If it looks like there's a Windows drive letter at the beginning, strip off the leading slash. + if driveLetterRegexp.MatchString(path) { + return path[1:], nil + } + return path, nil } // HomeDir returns path of '~'(in Linux) on Windows, @@ -224,7 +249,14 @@ func HomeDir() (home string, err error) { // TODO: some users run Gitea with mismatched uid and "HOME=xxx" (they set HOME=xxx by environment manually) // TODO: when running gitea as a sub command inside git, the HOME directory is not the user's home directory // so at the moment we can not use `user.Current().HomeDir` - home = os.Getenv("HOME") + if isOSWindows() { + home = os.Getenv("USERPROFILE") + if home == "" { + home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") + } + } else { + home = os.Getenv("HOME") + } if home == "" { return "", errors.New("cannot get home directory") diff --git a/modules/util/path_test.go b/modules/util/path_test.go index b912b76f6e..6a38bf4ace 100644 --- a/modules/util/path_test.go +++ b/modules/util/path_test.go @@ -5,10 +5,10 @@ package util import ( "net/url" + "runtime" "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestFileURLToPath(t *testing.T) { @@ -16,6 +16,7 @@ func TestFileURLToPath(t *testing.T) { url string expected string haserror bool + windows bool }{ // case 0 { @@ -32,15 +33,24 @@ func TestFileURLToPath(t *testing.T) { url: "file:///path", expected: "/path", }, + // case 3 + { + url: "file:///C:/path", + expected: "C:/path", + windows: true, + }, } for n, c := range cases { + if c.windows && runtime.GOOS != "windows" { + continue + } u, _ := url.Parse(c.url) p, err := FileURLToPath(u) if c.haserror { - require.Error(t, err, "case %d: should return error", n) + assert.Error(t, err, "case %d: should return error", n) } else { - require.NoError(t, err, "case %d: should not return error", n) + assert.NoError(t, err, "case %d: should not return error", n) assert.Equal(t, c.expected, p, "case %d: should be equal", n) } } @@ -166,18 +176,35 @@ func TestCleanPath(t *testing.T) { assert.Equal(t, c.expected, PathJoinRelX(c.elems...), "case: %v", c.elems) } - cases = []struct { - elems []string - expected string - }{ - {[]string{`/..`}, `/`}, - {[]string{`/a`}, `/a`}, - {[]string{`/a/`}, `/a`}, - {[]string{`/../a/`, `../b`, `c/..`, `d`}, `/a/b/d`}, - {[]string{`/a\..\b`}, `/b`}, - {[]string{`/a`, ``, `b`}, `/a/b`}, - {[]string{`/a`, `..`, `b`}, `/a/b`}, - {[]string{`/lfs`, `repo/..`, `user/../path`}, `/lfs/path`}, + // for POSIX only, but the result is similar on Windows, because the first element must be an absolute path + if isOSWindows() { + cases = []struct { + elems []string + expected string + }{ + {[]string{`C:\..`}, `C:\`}, + {[]string{`C:\a`}, `C:\a`}, + {[]string{`C:\a/`}, `C:\a`}, + {[]string{`C:\..\a\`, `../b`, `c\..`, `d`}, `C:\a\b\d`}, + {[]string{`C:\a/..\b`}, `C:\b`}, + {[]string{`C:\a`, ``, `b`}, `C:\a\b`}, + {[]string{`C:\a`, `..`, `b`}, `C:\a\b`}, + {[]string{`C:\lfs`, `repo/..`, `user/../path`}, `C:\lfs\path`}, + } + } else { + cases = []struct { + elems []string + expected string + }{ + {[]string{`/..`}, `/`}, + {[]string{`/a`}, `/a`}, + {[]string{`/a/`}, `/a`}, + {[]string{`/../a/`, `../b`, `c/..`, `d`}, `/a/b/d`}, + {[]string{`/a\..\b`}, `/b`}, + {[]string{`/a`, ``, `b`}, `/a/b`}, + {[]string{`/a`, `..`, `b`}, `/a/b`}, + {[]string{`/lfs`, `repo/..`, `user/../path`}, `/lfs/path`}, + } } for _, c := range cases { assert.Equal(t, c.expected, FilePathJoinAbs(c.elems[0], c.elems[1:]...), "case: %v", c.elems) diff --git a/modules/util/remove.go b/modules/util/remove.go index b07a48bee4..265891b307 100644 --- a/modules/util/remove.go +++ b/modules/util/remove.go @@ -7,10 +7,13 @@ import ( "io/fs" "os" "path/filepath" + "runtime" "syscall" "time" ) +const windowsSharingViolationError syscall.Errno = 32 + // Remove removes the named file or (empty) directory with at most 5 attempts. func Remove(name string) error { var err error @@ -26,6 +29,12 @@ func Remove(name string) error { continue } + if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" { + // try again + <-time.After(100 * time.Millisecond) + continue + } + if unwrapped == syscall.ENOENT { // it's already gone return nil @@ -34,29 +43,6 @@ func Remove(name string) error { return err } -// MakeWritable recursively makes the named directory writable. -func MakeWritable(name string) error { - return filepath.WalkDir(name, func(path string, d fs.DirEntry, err error) error { - // NB: this is called WalkDir but it works on a single file too - if err == nil { - info, err := d.Info() - if err != nil { - return err - } - - // Don't try chmod'ing symlinks (will fail with broken symlinks) - if info.Mode()&os.ModeSymlink != os.ModeSymlink { - // 0200 == u+w, in octal unix permission notation - err = os.Chmod(path, info.Mode()|0o200) - if err != nil { - return err - } - } - } - return nil - }) -} - // RemoveAll removes the named file or directory with at most 5 attempts. func RemoveAll(name string) error { var err error @@ -69,7 +55,25 @@ func RemoveAll(name string) error { // > (The only bad consequence of this is that rm -rf .git // > doesn't work unless you first run chmod -R +w .git) - err = MakeWritable(name) + err = filepath.WalkDir(name, func(path string, d fs.DirEntry, err error) error { + // NB: this is called WalkDir but it works on a single file too + if err == nil { + info, err := d.Info() + if err != nil { + return err + } + + // Don't try chmod'ing symlinks (will fail with broken symlinks) + if info.Mode()&os.ModeSymlink != os.ModeSymlink { + // 0200 == u+w, in octal unix permission notation + err = os.Chmod(path, info.Mode()|0o200) + if err != nil { + return err + } + } + } + return nil + }) if err != nil { // try again <-time.After(100 * time.Millisecond) @@ -87,6 +91,12 @@ func RemoveAll(name string) error { continue } + if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" { + // try again + <-time.After(100 * time.Millisecond) + continue + } + if unwrapped == syscall.ENOENT { // it's already gone return nil @@ -110,6 +120,12 @@ func Rename(oldpath, newpath string) error { continue } + if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" { + // try again + <-time.After(100 * time.Millisecond) + continue + } + if i == 0 && os.IsNotExist(err) { return err } diff --git a/modules/util/rotatingfilewriter/writer.go b/modules/util/rotatingfilewriter/writer.go index ff234eea93..c595f49c49 100644 --- a/modules/util/rotatingfilewriter/writer.go +++ b/modules/util/rotatingfilewriter/writer.go @@ -14,8 +14,8 @@ import ( "sync" "time" - "forgejo.org/modules/graceful/releasereopen" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/graceful/releasereopen" + "code.gitea.io/gitea/modules/util" ) type Options struct { diff --git a/modules/util/rotatingfilewriter/writer_test.go b/modules/util/rotatingfilewriter/writer_test.go index 5b3b351667..88392797b3 100644 --- a/modules/util/rotatingfilewriter/writer_test.go +++ b/modules/util/rotatingfilewriter/writer_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestCompressOldFile(t *testing.T) { @@ -20,9 +19,9 @@ func TestCompressOldFile(t *testing.T) { nonGzip := filepath.Join(tmpDir, "test-nonGzip") f, err := os.OpenFile(fname, os.O_CREATE|os.O_WRONLY, 0o660) - require.NoError(t, err) + assert.NoError(t, err) ng, err := os.OpenFile(nonGzip, os.O_CREATE|os.O_WRONLY, 0o660) - require.NoError(t, err) + assert.NoError(t, err) for i := 0; i < 999; i++ { f.WriteString("This is a test file\n") @@ -32,18 +31,18 @@ func TestCompressOldFile(t *testing.T) { ng.Close() err = compressOldFile(fname, gzip.DefaultCompression) - require.NoError(t, err) + assert.NoError(t, err) _, err = os.Lstat(fname + ".gz") - require.NoError(t, err) + assert.NoError(t, err) f, err = os.Open(fname + ".gz") - require.NoError(t, err) + assert.NoError(t, err) zr, err := gzip.NewReader(f) - require.NoError(t, err) + assert.NoError(t, err) data, err := io.ReadAll(zr) - require.NoError(t, err) + assert.NoError(t, err) original, err := os.ReadFile(nonGzip) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, original, data) } diff --git a/modules/util/slice.go b/modules/util/slice.go index 80c8e62f6f..9c878c24be 100644 --- a/modules/util/slice.go +++ b/modules/util/slice.go @@ -4,6 +4,7 @@ package util import ( + "cmp" "slices" "strings" ) @@ -46,6 +47,13 @@ func SliceRemoveAll[T comparable](slice []T, target T) []T { return slices.DeleteFunc(slice, func(t T) bool { return t == target }) } +// Sorted returns the sorted slice +// Note: The parameter is sorted inline. +func Sorted[S ~[]E, E cmp.Ordered](values S) S { + slices.Sort(values) + return values +} + // TODO: Replace with "maps.Values" once available, current it only in golang.org/x/exp/maps but not in standard library func ValuesOfMap[K comparable, V any](m map[K]V) []V { values := make([]V, 0, len(m)) diff --git a/modules/util/string.go b/modules/util/string.go index ca3d43ec6e..cf50f591c6 100644 --- a/modules/util/string.go +++ b/modules/util/string.go @@ -95,25 +95,3 @@ func UnsafeBytesToString(b []byte) string { func UnsafeStringToBytes(s string) []byte { return unsafe.Slice(unsafe.StringData(s), len(s)) } - -// AsciiEqualFold is taken from Golang, but reimplemented here, since the original is not exposed to public -// Taken from: https://cs.opensource.google/go/go/+/refs/tags/go1.24.4:src/net/http/internal/ascii/print.go -func ASCIIEqualFold(s, t string) bool { - if len(s) != len(t) { - return false - } - for i := 0; i < len(s); i++ { - if ASCIILower(s[i]) != ASCIILower(t[i]) { - return false - } - } - return true -} - -// AsciiLower returns the ASCII lowercase version of b. -func ASCIILower(b byte) byte { - if 'A' <= b && b <= 'Z' { - return b + ('a' - 'A') - } - return b -} diff --git a/modules/util/string_test.go b/modules/util/string_test.go index 1012ab32a4..0a4a8bbcfb 100644 --- a/modules/util/string_test.go +++ b/modules/util/string_test.go @@ -45,29 +45,3 @@ func TestToSnakeCase(t *testing.T) { assert.Equal(t, expected, ToSnakeCase(input)) } } - -func TestASCIIEqualFold(t *testing.T) { - cases := map[string]struct { - First string - Second string - Expected bool - }{ - "Empty String": {First: "", Second: "", Expected: true}, - "Single Letter Ident": {First: "h", Second: "h", Expected: true}, - "Single Letter Equal": {First: "h", Second: "H", Expected: true}, - "Single Letter Unequal": {First: "h", Second: "g", Expected: false}, - "Simple Match Ident": {First: "someString", Second: "someString", Expected: true}, - "Simple Match Equal": {First: "someString", Second: "someSTRIng", Expected: true}, - "Simple Match Unequal": {First: "someString", Second: "sameString", Expected: false}, - "Different Length": {First: "abcdef", Second: "abcdefg", Expected: false}, - "Unicode Kelvin": {First: "ghijklm", Second: "GHIJ\u212ALM", Expected: false}, - } - - for name := range cases { - c := cases[name] - t.Run(name, func(t *testing.T) { - Actual := ASCIIEqualFold(c.First, c.Second) - assert.Equal(t, c.Expected, Actual) - }) - } -} diff --git a/modules/util/truncate.go b/modules/util/truncate.go index 7207a89177..77b116eeff 100644 --- a/modules/util/truncate.go +++ b/modules/util/truncate.go @@ -41,8 +41,6 @@ func SplitStringAtByteN(input string, n int) (left, right string) { // SplitTrimSpace splits the string at given separator and trims leading and trailing space func SplitTrimSpace(input, sep string) []string { - // Trim initial leading & trailing space - input = strings.TrimSpace(input) // replace CRLF with LF input = strings.ReplaceAll(input, "\r\n", "\n") @@ -54,12 +52,3 @@ func SplitTrimSpace(input, sep string) []string { return stringList } - -// TruncateRunes returns a truncated string with given rune limit, -// it returns input string if its rune length doesn't exceed the limit. -func TruncateRunes(str string, limit int) string { - if utf8.RuneCountInString(str) < limit { - return str - } - return string([]rune(str)[:limit]) -} diff --git a/modules/util/truncate_test.go b/modules/util/truncate_test.go index 8187b13eb2..dfe1230fd4 100644 --- a/modules/util/truncate_test.go +++ b/modules/util/truncate_test.go @@ -44,18 +44,3 @@ func TestSplitString(t *testing.T) { } test(tc, SplitStringAtByteN) } - -func TestTruncateRunes(t *testing.T) { - assert.Empty(t, TruncateRunes("", 0)) - assert.Empty(t, TruncateRunes("", 1)) - - assert.Empty(t, TruncateRunes("ab", 0)) - assert.Equal(t, "a", TruncateRunes("ab", 1)) - assert.Equal(t, "ab", TruncateRunes("ab", 2)) - assert.Equal(t, "ab", TruncateRunes("ab", 3)) - - assert.Empty(t, TruncateRunes("测试", 0)) - assert.Equal(t, "测", TruncateRunes("测试", 1)) - assert.Equal(t, "测试", TruncateRunes("测试", 2)) - assert.Equal(t, "测试", TruncateRunes("测试", 3)) -} diff --git a/modules/util/util.go b/modules/util/util.go index 548fd1e90b..b6ea283551 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -1,24 +1,31 @@ // Copyright 2017 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package util import ( "bytes" - "crypto/ed25519" "crypto/rand" - "encoding/pem" "fmt" "math/big" "strconv" "strings" - "golang.org/x/crypto/ssh" + "code.gitea.io/gitea/modules/optional" + "golang.org/x/text/cases" "golang.org/x/text/language" ) +// OptionalBoolParse get the corresponding optional.Option[bool] of a string using strconv.ParseBool +func OptionalBoolParse(s string) optional.Option[bool] { + v, e := strconv.ParseBool(s) + if e != nil { + return optional.None[bool]() + } + return optional.Some(v) +} + // IsEmptyString checks if the provided string is empty func IsEmptyString(s string) bool { return len(strings.TrimSpace(s)) == 0 @@ -88,16 +95,10 @@ func CryptoRandomString(length int64) (string, error) { // CryptoRandomBytes generates `length` crypto bytes // This differs from CryptoRandomString, as each byte in CryptoRandomString is generated by [0,61] range // This function generates totally random bytes, each byte is generated by [0,255] range -func CryptoRandomBytes(length int64) []byte { - // crypto/rand.Read is documented to never return a error. - // https://go.dev/issue/66821 +func CryptoRandomBytes(length int64) ([]byte, error) { buf := make([]byte, length) - n, err := rand.Read(buf) - if err != nil || n != int(length) { - panic(err) - } - - return buf + _, err := rand.Read(buf) + return buf, err } // ToUpperASCII returns s with all ASCII letters mapped to their upper case. @@ -220,34 +221,6 @@ func Iif[T any](condition bool, trueVal, falseVal T) T { return falseVal } -// IfZero returns "def" if "v" is a zero value, otherwise "v" -func IfZero[T comparable](v, def T) T { - var zero T - if v == zero { - return def - } - return v -} - -// OptionalArg helps the "optional argument" in Golang: -// -// func foo(optArg ...int) { return OptionalArg(optArg) } -// calling `foo()` gets zero value 0, calling `foo(100)` gets 100 -// func bar(optArg ...int) { return OptionalArg(optArg, 42) } -// calling `bar()` gets default value 42, calling `bar(100)` gets 100 -// -// Passing more than 1 item to `optArg` or `defaultValue` is undefined behavior. -// At the moment only the first item is used. -func OptionalArg[T any](optArg []T, defaultValue ...T) (ret T) { - if len(optArg) >= 1 { - return optArg[0] - } - if len(defaultValue) >= 1 { - return defaultValue[0] - } - return ret -} - func ReserveLineBreakForTextarea(input string) string { // Since the content is from a form which is a textarea, the line endings are \r\n. // It's a standard behavior of HTML. @@ -256,23 +229,3 @@ func ReserveLineBreakForTextarea(input string) string { // Other than this, we should respect the original content, even leading or trailing spaces. return strings.ReplaceAll(input, "\r\n", "\n") } - -// GenerateSSHKeypair generates a ed25519 SSH-compatible keypair. -func GenerateSSHKeypair() (publicKey, privateKey []byte, err error) { - public, private, err := ed25519.GenerateKey(nil) - if err != nil { - return nil, nil, fmt.Errorf("ed25519.GenerateKey: %w", err) - } - - privPEM, err := ssh.MarshalPrivateKey(private, "") - if err != nil { - return nil, nil, fmt.Errorf("ssh.MarshalPrivateKey: %w", err) - } - - sshPublicKey, err := ssh.NewPublicKey(public) - if err != nil { - return nil, nil, fmt.Errorf("ssh.NewPublicKey: %w", err) - } - - return ssh.MarshalAuthorizedKey(sshPublicKey), pem.EncodeToMemory(privPEM), nil -} diff --git a/modules/util/util_test.go b/modules/util/util_test.go index 21988fd0f8..de8f065cad 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -1,21 +1,16 @@ // Copyright 2018 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package util_test +package util import ( - "bytes" - "crypto/rand" "regexp" "strings" "testing" - "forgejo.org/modules/test" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/optional" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestURLJoin(t *testing.T) { @@ -47,7 +42,7 @@ func TestURLJoin(t *testing.T) { newTest("/a/b/c#hash", "/a", "b/c#hash"), } { - assert.Equal(t, test.Expected, util.URLJoin(test.Base, test.Elements...)) + assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...)) } } @@ -63,7 +58,7 @@ func TestIsEmptyString(t *testing.T) { } for _, v := range cases { - assert.Equal(t, v.expected, util.IsEmptyString(v.s)) + assert.Equal(t, v.expected, IsEmptyString(v.s)) } } @@ -104,80 +99,95 @@ func Test_NormalizeEOL(t *testing.T) { unix := buildEOLData(data1, "\n") mac := buildEOLData(data1, "\r") - assert.Equal(t, unix, util.NormalizeEOL(dos)) - assert.Equal(t, unix, util.NormalizeEOL(mac)) - assert.Equal(t, unix, util.NormalizeEOL(unix)) + assert.Equal(t, unix, NormalizeEOL(dos)) + assert.Equal(t, unix, NormalizeEOL(mac)) + assert.Equal(t, unix, NormalizeEOL(unix)) dos = buildEOLData(data2, "\r\n") unix = buildEOLData(data2, "\n") mac = buildEOLData(data2, "\r") - assert.Equal(t, unix, util.NormalizeEOL(dos)) - assert.Equal(t, unix, util.NormalizeEOL(mac)) - assert.Equal(t, unix, util.NormalizeEOL(unix)) + assert.Equal(t, unix, NormalizeEOL(dos)) + assert.Equal(t, unix, NormalizeEOL(mac)) + assert.Equal(t, unix, NormalizeEOL(unix)) - assert.Equal(t, []byte("one liner"), util.NormalizeEOL([]byte("one liner"))) - assert.Equal(t, []byte("\n"), util.NormalizeEOL([]byte("\n"))) - assert.Equal(t, []byte("\ntwo liner"), util.NormalizeEOL([]byte("\ntwo liner"))) - assert.Equal(t, []byte("two liner\n"), util.NormalizeEOL([]byte("two liner\n"))) - assert.Equal(t, []byte{}, util.NormalizeEOL([]byte{})) + assert.Equal(t, []byte("one liner"), NormalizeEOL([]byte("one liner"))) + assert.Equal(t, []byte("\n"), NormalizeEOL([]byte("\n"))) + assert.Equal(t, []byte("\ntwo liner"), NormalizeEOL([]byte("\ntwo liner"))) + assert.Equal(t, []byte("two liner\n"), NormalizeEOL([]byte("two liner\n"))) + assert.Equal(t, []byte{}, NormalizeEOL([]byte{})) - assert.Equal(t, []byte("mix\nand\nmatch\n."), util.NormalizeEOL([]byte("mix\r\nand\rmatch\n."))) + assert.Equal(t, []byte("mix\nand\nmatch\n."), NormalizeEOL([]byte("mix\r\nand\rmatch\n."))) } func Test_RandomInt(t *testing.T) { - randInt, err := util.CryptoRandomInt(255) - assert.GreaterOrEqual(t, randInt, int64(0)) - assert.LessOrEqual(t, randInt, int64(255)) - require.NoError(t, err) + randInt, err := CryptoRandomInt(255) + assert.True(t, randInt >= 0) + assert.True(t, randInt <= 255) + assert.NoError(t, err) } func Test_RandomString(t *testing.T) { - str1, err := util.CryptoRandomString(32) - require.NoError(t, err) + str1, err := CryptoRandomString(32) + assert.NoError(t, err) matches, err := regexp.MatchString(`^[a-zA-Z0-9]{32}$`, str1) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, matches) - str2, err := util.CryptoRandomString(32) - require.NoError(t, err) + str2, err := CryptoRandomString(32) + assert.NoError(t, err) matches, err = regexp.MatchString(`^[a-zA-Z0-9]{32}$`, str1) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, matches) assert.NotEqual(t, str1, str2) - str3, err := util.CryptoRandomString(256) - require.NoError(t, err) + str3, err := CryptoRandomString(256) + assert.NoError(t, err) matches, err = regexp.MatchString(`^[a-zA-Z0-9]{256}$`, str3) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, matches) - str4, err := util.CryptoRandomString(256) - require.NoError(t, err) + str4, err := CryptoRandomString(256) + assert.NoError(t, err) matches, err = regexp.MatchString(`^[a-zA-Z0-9]{256}$`, str4) - require.NoError(t, err) + assert.NoError(t, err) assert.True(t, matches) assert.NotEqual(t, str3, str4) } func Test_RandomBytes(t *testing.T) { - bytes1 := util.CryptoRandomBytes(32) - bytes2 := util.CryptoRandomBytes(32) + bytes1, err := CryptoRandomBytes(32) + assert.NoError(t, err) + + bytes2, err := CryptoRandomBytes(32) + assert.NoError(t, err) - assert.Len(t, bytes1, 32) - assert.Len(t, bytes2, 32) assert.NotEqual(t, bytes1, bytes2) - bytes3 := util.CryptoRandomBytes(256) - bytes4 := util.CryptoRandomBytes(256) + bytes3, err := CryptoRandomBytes(256) + assert.NoError(t, err) + + bytes4, err := CryptoRandomBytes(256) + assert.NoError(t, err) - assert.Len(t, bytes3, 256) - assert.Len(t, bytes4, 256) assert.NotEqual(t, bytes3, bytes4) } +func TestOptionalBoolParse(t *testing.T) { + assert.Equal(t, optional.None[bool](), OptionalBoolParse("")) + assert.Equal(t, optional.None[bool](), OptionalBoolParse("x")) + + assert.Equal(t, optional.Some(false), OptionalBoolParse("0")) + assert.Equal(t, optional.Some(false), OptionalBoolParse("f")) + assert.Equal(t, optional.Some(false), OptionalBoolParse("False")) + + assert.Equal(t, optional.Some(true), OptionalBoolParse("1")) + assert.Equal(t, optional.Some(true), OptionalBoolParse("t")) + assert.Equal(t, optional.Some(true), OptionalBoolParse("True")) +} + // Test case for any function which accepts and returns a single string. type StringTest struct { in, out string @@ -198,7 +208,7 @@ var upperTests = []StringTest{ func TestToUpperASCII(t *testing.T) { for _, tc := range upperTests { - assert.Equal(t, util.ToUpperASCII(tc.in), tc.out) + assert.Equal(t, ToUpperASCII(tc.in), tc.out) } } @@ -206,69 +216,27 @@ func BenchmarkToUpper(b *testing.B) { for _, tc := range upperTests { b.Run(tc.in, func(b *testing.B) { for i := 0; i < b.N; i++ { - util.ToUpperASCII(tc.in) + ToUpperASCII(tc.in) } }) } } func TestToTitleCase(t *testing.T) { - assert.Equal(t, `Foo Bar Baz`, util.ToTitleCase(`foo bar baz`)) - assert.Equal(t, `Foo Bar Baz`, util.ToTitleCase(`FOO BAR BAZ`)) + assert.Equal(t, ToTitleCase(`foo bar baz`), `Foo Bar Baz`) + assert.Equal(t, ToTitleCase(`FOO BAR BAZ`), `Foo Bar Baz`) } func TestToPointer(t *testing.T) { - assert.Equal(t, "abc", *util.ToPointer("abc")) - assert.Equal(t, 123, *util.ToPointer(123)) + assert.Equal(t, "abc", *ToPointer("abc")) + assert.Equal(t, 123, *ToPointer(123)) abc := "abc" - assert.NotSame(t, &abc, util.ToPointer(abc)) + assert.False(t, &abc == ToPointer(abc)) val123 := 123 - assert.NotSame(t, &val123, util.ToPointer(val123)) + assert.False(t, &val123 == ToPointer(val123)) } func TestReserveLineBreakForTextarea(t *testing.T) { - assert.Equal(t, "test\ndata", util.ReserveLineBreakForTextarea("test\r\ndata")) - assert.Equal(t, "test\ndata\n", util.ReserveLineBreakForTextarea("test\r\ndata\r\n")) -} - -const ( - testPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAOhB7/zzhC+HXDdGOdLwJln5NYwm6UNXx3chmQSVTG4\n" - testPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz -c2gtZWQyNTUxOQAAACADoQe/884Qvh1w3RjnS8CZZ+TWMJulDV8d3IZkElUxuAAA -AIggISIjICEiIwAAAAtzc2gtZWQyNTUxOQAAACADoQe/884Qvh1w3RjnS8CZZ+TW -MJulDV8d3IZkElUxuAAAAEAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0e -HwOhB7/zzhC+HXDdGOdLwJln5NYwm6UNXx3chmQSVTG4AAAAAAECAwQF ------END OPENSSH PRIVATE KEY-----` + "\n" -) - -func TestGeneratingEd25519Keypair(t *testing.T) { - defer test.MockProtect(&rand.Reader)() - - // Only 32 bytes needs to be provided to generate a ed25519 keypair. - // And another 32 bytes are required, which is included as random value - // in the OpenSSH format. - b := make([]byte, 64) - for i := 0; i < 64; i++ { - b[i] = byte(i) - } - rand.Reader = bytes.NewReader(b) - - publicKey, privateKey, err := util.GenerateSSHKeypair() - require.NoError(t, err) - assert.Equal(t, testPublicKey, string(publicKey)) - assert.Equal(t, testPrivateKey, string(privateKey)) -} - -func TestOptionalArg(t *testing.T) { - foo := func(other any, optArg ...int) int { - return util.OptionalArg(optArg) - } - bar := func(other any, optArg ...int) int { - return util.OptionalArg(optArg, 42) - } - assert.Equal(t, 0, foo(nil)) - assert.Equal(t, 100, foo(nil, 100)) - assert.Equal(t, 42, bar(nil)) - assert.Equal(t, 100, bar(nil, 100)) + assert.Equal(t, ReserveLineBreakForTextarea("test\r\ndata"), "test\ndata") + assert.Equal(t, ReserveLineBreakForTextarea("test\r\ndata\r\n"), "test\ndata\n") } diff --git a/modules/validation/binding.go b/modules/validation/binding.go index f4f82278bd..cb0a5063e5 100644 --- a/modules/validation/binding.go +++ b/modules/validation/binding.go @@ -8,11 +8,10 @@ import ( "regexp" "strings" - "forgejo.org/modules/auth" - "forgejo.org/modules/git" - "forgejo.org/modules/util" + "code.gitea.io/gitea/modules/auth" + "code.gitea.io/gitea/modules/git" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" "github.com/gobwas/glob" ) @@ -27,14 +26,11 @@ const ( ErrUsername = "UsernameError" // ErrInvalidGroupTeamMap is returned when a group team mapping is invalid ErrInvalidGroupTeamMap = "InvalidGroupTeamMap" - // ErrEmail is returned when an email address is invalid - ErrEmail = "Email" ) // AddBindingRules adds additional binding rules func AddBindingRules() { addGitRefNameBindingRule() - addValidURLListBindingRule() addValidURLBindingRule() addValidSiteURLBindingRule() addGlobPatternRule() @@ -42,14 +38,13 @@ func AddBindingRules() { addGlobOrRegexPatternRule() addUsernamePatternRule() addValidGroupTeamMapRule() - addEmailBindingRules() } func addGitRefNameBindingRule() { // Git refname validation rule binding.AddRule(&binding.Rule{ IsMatch: func(rule string) bool { - return rule == "GitRefName" + return strings.HasPrefix(rule, "GitRefName") }, IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) { str := fmt.Sprintf("%v", val) @@ -63,38 +58,11 @@ func addGitRefNameBindingRule() { }) } -func addValidURLListBindingRule() { - // URL validation rule - binding.AddRule(&binding.Rule{ - IsMatch: func(rule string) bool { - return rule == "ValidUrlList" - }, - IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) { - str := fmt.Sprintf("%v", val) - if len(str) == 0 { - errs.Add([]string{name}, binding.ERR_URL, "Url") - return false, errs - } - - ok := true - urls := util.SplitTrimSpace(str, "\n") - for _, u := range urls { - if !IsValidURL(u) { - ok = false - errs.Add([]string{name}, binding.ERR_URL, u) - } - } - - return ok, errs - }, - }) -} - func addValidURLBindingRule() { // URL validation rule binding.AddRule(&binding.Rule{ IsMatch: func(rule string) bool { - return rule == "ValidUrl" + return strings.HasPrefix(rule, "ValidUrl") }, IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) { str := fmt.Sprintf("%v", val) @@ -112,7 +80,7 @@ func addValidSiteURLBindingRule() { // URL validation rule binding.AddRule(&binding.Rule{ IsMatch: func(rule string) bool { - return rule == "ValidSiteUrl" + return strings.HasPrefix(rule, "ValidSiteUrl") }, IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) { str := fmt.Sprintf("%v", val) @@ -203,7 +171,7 @@ func addUsernamePatternRule() { func addValidGroupTeamMapRule() { binding.AddRule(&binding.Rule{ IsMatch: func(rule string) bool { - return rule == "ValidGroupTeamMap" + return strings.HasPrefix(rule, "ValidGroupTeamMap") }, IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) { _, err := auth.UnmarshalGroupTeamMapping(fmt.Sprintf("%v", val)) @@ -217,34 +185,6 @@ func addValidGroupTeamMapRule() { }) } -func addEmailBindingRules() { - binding.AddRule(&binding.Rule{ - IsMatch: func(rule string) bool { - return strings.HasPrefix(rule, "EmailWithAllowedDomain") - }, - IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) { - if err := ValidateEmail(fmt.Sprintf("%v", val)); err != nil { - errs.Add([]string{name}, ErrEmail, err.Error()) - return false, errs - } - return true, errs - }, - }) - - binding.AddRule(&binding.Rule{ - IsMatch: func(rule string) bool { - return strings.HasPrefix(rule, "EmailForAdmin") - }, - IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) { - if err := ValidateEmailForAdmin(fmt.Sprintf("%v", val)); err != nil { - errs.Add([]string{name}, ErrEmail, err.Error()) - return false, errs - } - return true, errs - }, - }) -} - func portOnly(hostport string) string { colon := strings.IndexByte(hostport, ':') if colon == -1 { diff --git a/modules/validation/binding_test.go b/modules/validation/binding_test.go index 5adcdf0289..01ff4e3435 100644 --- a/modules/validation/binding_test.go +++ b/modules/validation/binding_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" chi "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" ) @@ -27,7 +27,6 @@ type ( TestForm struct { BranchName string `form:"BranchName" binding:"GitRefName"` URL string `form:"ValidUrl" binding:"ValidUrl"` - URLs string `form:"ValidUrls" binding:"ValidUrlList"` GlobPattern string `form:"GlobPattern" binding:"GlobPattern"` RegexPattern string `form:"RegexPattern" binding:"RegexPattern"` } diff --git a/modules/validation/email.go b/modules/validation/email.go deleted file mode 100644 index 8e1ffc203d..0000000000 --- a/modules/validation/email.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2016 The Gogs Authors. All rights reserved. -// Copyright 2020 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved -// SPDX-License-Identifier: MIT - -package validation - -import ( - "fmt" - "net/mail" - "strings" - - "forgejo.org/modules/setting" - "forgejo.org/modules/util" - - "github.com/gobwas/glob" -) - -// ErrEmailNotActivated e-mail address has not been activated error -var ErrEmailNotActivated = util.NewInvalidArgumentErrorf("e-mail address has not been activated") - -// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322 -// or has a leading '-' character -type ErrEmailInvalid struct { - Email string -} - -// IsErrEmailInvalid checks if an error is an ErrEmailInvalid -func IsErrEmailInvalid(err error) bool { - _, ok := err.(ErrEmailInvalid) - return ok -} - -func (err ErrEmailInvalid) Error() string { - return fmt.Sprintf("e-mail invalid [email: %s]", err.Email) -} - -func (err ErrEmailInvalid) Unwrap() error { - return util.ErrInvalidArgument -} - -// check if email is a valid address with allowed domain -func ValidateEmail(email string) error { - if err := validateEmailBasic(email); err != nil { - return err - } - return validateEmailDomain(email) -} - -// check if email is a valid address when admins manually add or edit users -func ValidateEmailForAdmin(email string) error { - return validateEmailBasic(email) - // In this case we do not need to check the email domain -} - -// validateEmailBasic checks whether the email complies with the rules -func validateEmailBasic(email string) error { - if len(email) == 0 { - return ErrEmailInvalid{email} - } - - parsedAddress, err := mail.ParseAddress(email) - if err != nil { - return ErrEmailInvalid{email} - } - - if parsedAddress.Name != "" { - return ErrEmailInvalid{email} - } - - return nil -} - -func validateEmailDomain(email string) error { - if !IsEmailDomainAllowed(email) { - return ErrEmailInvalid{email} - } - - return nil -} - -func IsEmailDomainAllowed(email string) bool { - return isEmailDomainAllowedInternal( - email, - setting.Service.EmailDomainAllowList, - setting.Service.EmailDomainBlockList) -} - -func isEmailDomainAllowedInternal( - email string, - emailDomainAllowList []glob.Glob, - emailDomainBlockList []glob.Glob, -) bool { - var result bool - - if len(emailDomainAllowList) == 0 { - result = !isEmailDomainListed(emailDomainBlockList, email) - } else { - result = isEmailDomainListed(emailDomainAllowList, email) - } - return result -} - -// isEmailDomainListed checks whether the domain of an email address -// matches a list of domains -func isEmailDomainListed(globs []glob.Glob, email string) bool { - if len(globs) == 0 { - return false - } - - n := strings.LastIndex(email, "@") - if n <= 0 { - return false - } - - domain := strings.ToLower(email[n+1:]) - - for _, g := range globs { - if g.Match(domain) { - return true - } - } - - return false -} diff --git a/modules/validation/email_test.go b/modules/validation/email_test.go deleted file mode 100644 index b7ee766ddb..0000000000 --- a/modules/validation/email_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved -// SPDX-License-Identifier: MIT - -package validation - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestEmailAddressValidate(t *testing.T) { - kases := map[string]error{ - "abc@gmail.com": nil, - "132@hotmail.com": nil, - "1-3-2@test.org": nil, - "1.3.2@test.org": nil, - "a_123@test.org.cn": nil, - `first.last@iana.org`: nil, - `first!last@iana.org`: nil, - `first#last@iana.org`: nil, - `first$last@iana.org`: nil, - `first%last@iana.org`: nil, - `first&last@iana.org`: nil, - `first'last@iana.org`: nil, - `first*last@iana.org`: nil, - `first+last@iana.org`: nil, - `first/last@iana.org`: nil, - `first=last@iana.org`: nil, - `first?last@iana.org`: nil, - `first^last@iana.org`: nil, - "first`last@iana.org": nil, - `first{last@iana.org`: nil, - `first|last@iana.org`: nil, - `first}last@iana.org`: nil, - `first~last@iana.org`: nil, - `first;last@iana.org`: ErrEmailInvalid{`first;last@iana.org`}, - ".233@qq.com": ErrEmailInvalid{".233@qq.com"}, - "!233@qq.com": nil, - "#233@qq.com": nil, - "$233@qq.com": nil, - "%233@qq.com": nil, - "&233@qq.com": nil, - "'233@qq.com": nil, - "*233@qq.com": nil, - "+233@qq.com": nil, - "-233@qq.com": nil, - "/233@qq.com": nil, - "=233@qq.com": nil, - "?233@qq.com": nil, - "^233@qq.com": nil, - "_233@qq.com": nil, - "`233@qq.com": nil, - "{233@qq.com": nil, - "|233@qq.com": nil, - "}233@qq.com": nil, - "~233@qq.com": nil, - "\"~@ \"@famfo.xyz": nil, - "Foo ": ErrEmailInvalid{"Foo "}, - ";233@qq.com": ErrEmailInvalid{";233@qq.com"}, - string([]byte{0xE2, 0x84, 0xAA}): ErrEmailInvalid{string([]byte{0xE2, 0x84, 0xAA})}, - } - for kase, err := range kases { - t.Run(kase, func(t *testing.T) { - assert.Equal(t, err, ValidateEmail(kase)) - }) - } -} - -func TestEmailDomainAllowList(t *testing.T) { - res := IsEmailDomainAllowed("someuser@localhost.localdomain") - assert.True(t, res) -} diff --git a/modules/validation/glob_pattern_test.go b/modules/validation/glob_pattern_test.go index 42d86754e1..1bf622e61d 100644 --- a/modules/validation/glob_pattern_test.go +++ b/modules/validation/glob_pattern_test.go @@ -6,7 +6,7 @@ package validation import ( "testing" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" "github.com/gobwas/glob" ) diff --git a/modules/validation/helpers.go b/modules/validation/helpers.go index 4b28dead03..567ad867fe 100644 --- a/modules/validation/helpers.go +++ b/modules/validation/helpers.go @@ -9,7 +9,9 @@ import ( "regexp" "strings" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" + + "github.com/gobwas/glob" ) var externalTrackerRegex = regexp.MustCompile(`({?)(?:user|repo|index)+?(}?)`) @@ -48,6 +50,29 @@ func IsValidSiteURL(uri string) bool { return false } +// IsEmailDomainListed checks whether the domain of an email address +// matches a list of domains +func IsEmailDomainListed(globs []glob.Glob, email string) bool { + if len(globs) == 0 { + return false + } + + n := strings.LastIndex(email, "@") + if n <= 0 { + return false + } + + domain := strings.ToLower(email[n+1:]) + + for _, g := range globs { + if g.Match(domain) { + return true + } + } + + return false +} + // IsAPIURL checks if URL is current Gitea instance API URL func IsAPIURL(uri string) bool { return strings.HasPrefix(strings.ToLower(uri), strings.ToLower(setting.AppURL+"api")) @@ -75,11 +100,6 @@ func IsValidExternalURL(uri string) bool { return true } -// IsValidReleaseAssetURL checks if the URL is valid for external release assets -func IsValidReleaseAssetURL(uri string) bool { - return IsValidURL(uri) -} - // IsValidExternalTrackerURLFormat checks if URL matches required syntax for external trackers func IsValidExternalTrackerURLFormat(uri string) bool { if !IsValidExternalURL(uri) { diff --git a/modules/validation/helpers_test.go b/modules/validation/helpers_test.go index 7e32184691..a1bdf2a29c 100644 --- a/modules/validation/helpers_test.go +++ b/modules/validation/helpers_test.go @@ -6,8 +6,7 @@ package validation import ( "testing" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) @@ -48,7 +47,7 @@ func Test_IsValidURL(t *testing.T) { } func Test_IsValidExternalURL(t *testing.T) { - defer test.MockVariableValue(&setting.AppURL, "https://code.forgejo.org/")() + setting.AppURL = "https://try.gitea.io/" cases := []struct { description string @@ -57,7 +56,7 @@ func Test_IsValidExternalURL(t *testing.T) { }{ { description: "Current instance URL", - url: "https://code.forgejo.org/test", + url: "https://try.gitea.io/test", valid: true, }, { @@ -67,7 +66,7 @@ func Test_IsValidExternalURL(t *testing.T) { }, { description: "Current instance API URL", - url: "https://code.forgejo.org/api/v1/user/follow", + url: "https://try.gitea.io/api/v1/user/follow", valid: false, }, { @@ -90,7 +89,7 @@ func Test_IsValidExternalURL(t *testing.T) { } func Test_IsValidExternalTrackerURLFormat(t *testing.T) { - defer test.MockVariableValue(&setting.AppURL, "https://code.forgejo.org/")() + setting.AppURL = "https://try.gitea.io/" cases := []struct { description string @@ -157,8 +156,7 @@ func Test_IsValidExternalTrackerURLFormat(t *testing.T) { } func TestIsValidUsernameAllowDots(t *testing.T) { - defer test.MockVariableValue(&setting.Service.AllowDotsInUsernames, true)() - + setting.Service.AllowDotsInUsernames = true tests := []struct { arg string want bool @@ -190,7 +188,10 @@ func TestIsValidUsernameAllowDots(t *testing.T) { } func TestIsValidUsernameBanDots(t *testing.T) { - defer test.MockVariableValue(&setting.Service.AllowDotsInUsernames, false)() + setting.Service.AllowDotsInUsernames = false + defer func() { + setting.Service.AllowDotsInUsernames = true + }() tests := []struct { arg string diff --git a/modules/validation/refname_test.go b/modules/validation/refname_test.go index bb64cab51e..3af7387c47 100644 --- a/modules/validation/refname_test.go +++ b/modules/validation/refname_test.go @@ -6,7 +6,7 @@ package validation import ( "testing" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" ) var gitRefNameValidationTestCases = []validationTestCase{ diff --git a/modules/validation/regex_pattern_test.go b/modules/validation/regex_pattern_test.go index 90bd969c4f..efcb276734 100644 --- a/modules/validation/regex_pattern_test.go +++ b/modules/validation/regex_pattern_test.go @@ -7,7 +7,7 @@ import ( "regexp" "testing" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" ) func getRegexPatternErrorString(pattern string) string { diff --git a/modules/validation/validatable.go b/modules/validation/validatable.go index 4500f6e53d..94b5cc135c 100644 --- a/modules/validation/validatable.go +++ b/modules/validation/validatable.go @@ -1,4 +1,5 @@ -// Copyright 2023, 2024, 2025 The Forgejo Authors. All rights reserved. +// Copyright 2024 The Forgejo Authors. All rights reserved. +// Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package validation @@ -9,9 +10,7 @@ import ( "strings" "unicode/utf8" - "forgejo.org/modules/timeutil" - - ap "github.com/go-ap/activitypub" + "code.gitea.io/gitea/modules/timeutil" ) // ErrNotValid represents an validation error @@ -34,22 +33,15 @@ type Validateable interface { } func IsValid(v Validateable) (bool, error) { - if valdationErrors := v.Validate(); len(valdationErrors) > 0 { + if err := v.Validate(); len(err) > 0 { typeof := reflect.TypeOf(v) - errString := strings.Join(valdationErrors, "\n") + errString := strings.Join(err, "\n") return false, ErrNotValid{fmt.Sprint(typeof, ": ", errString)} } return true, nil } -func ValidateIDExists(value ap.Item, name string) []string { - if value == nil { - return []string{fmt.Sprintf("%v should not be nil", name)} - } - return ValidateNotEmpty(value.GetID().String(), name) -} - func ValidateNotEmpty(value any, name string) []string { isValid := true switch v := value.(type) { @@ -61,10 +53,6 @@ func ValidateNotEmpty(value any, name string) []string { if v.IsZero() { isValid = false } - case uint16: - if v == 0 { - isValid = false - } case int64: if v == 0 { isValid = false @@ -92,5 +80,5 @@ func ValidateOneOf(value any, allowed []any, name string) []string { return []string{} } } - return []string{fmt.Sprintf("Field %s contains the value %v, which is not in allowed subset %v", name, value, allowed)} + return []string{fmt.Sprintf("Value %v is not contained in allowed values %v", value, allowed)} } diff --git a/modules/validation/validatable_test.go b/modules/validation/validatable_test.go index 1fe407b343..919f5a3183 100644 --- a/modules/validation/validatable_test.go +++ b/modules/validation/validatable_test.go @@ -1,4 +1,4 @@ -// Copyright 2024, 2025 The Forgejo Authors. All rights reserved. +// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package validation @@ -6,10 +6,7 @@ package validation import ( "testing" - "forgejo.org/modules/timeutil" - - ap "github.com/go-ap/activitypub" - "github.com/stretchr/testify/assert" + "code.gitea.io/gitea/modules/timeutil" ) type Sut struct { @@ -40,50 +37,33 @@ func Test_IsValid(t *testing.T) { func Test_ValidateNotEmpty_ForString(t *testing.T) { sut := "" - res := ValidateNotEmpty(sut, "dummyField") - assert.Len(t, res, 1) - + if len(ValidateNotEmpty(sut, "dummyField")) == 0 { + t.Errorf("sut should be invalid") + } sut = "not empty" - res = ValidateNotEmpty(sut, "dummyField") - assert.Empty(t, res, 0) + if res := ValidateNotEmpty(sut, "dummyField"); len(res) > 0 { + t.Errorf("sut should be valid but was %q", res) + } } func Test_ValidateNotEmpty_ForTimestamp(t *testing.T) { sut := timeutil.TimeStamp(0) - res := ValidateNotEmpty(sut, "dummyField") - assert.Len(t, res, 1) - + if res := ValidateNotEmpty(sut, "dummyField"); len(res) == 0 { + t.Errorf("sut should be invalid") + } sut = timeutil.TimeStampNow() - res = ValidateNotEmpty(sut, "dummyField") - assert.Empty(t, res, 0) -} - -func Test_ValidateIDExists_ForItem(t *testing.T) { - sut := ap.Activity{ - Object: nil, + if res := ValidateNotEmpty(sut, "dummyField"); len(res) > 0 { + t.Errorf("sut should be valid but was %q", res) } - res := ValidateIDExists(sut.Object, "dummyField") - assert.Len(t, res, 1) - - sut = ap.Activity{ - Object: ap.IRI(""), - } - res = ValidateIDExists(sut.Object, "dummyField") - assert.Len(t, res, 1) - - sut = ap.Activity{ - Object: ap.IRI("https://dummy.link/id"), - } - res = ValidateIDExists(sut.Object, "dummyField") - assert.Empty(t, res, 0) } func Test_ValidateMaxLen(t *testing.T) { sut := "0123456789" - res := ValidateMaxLen(sut, 9, "dummyField") - assert.Len(t, res, 1) - + if len(ValidateMaxLen(sut, 9, "dummyField")) == 0 { + t.Errorf("sut should be invalid") + } sut = "0123456789" - res = ValidateMaxLen(sut, 11, "dummyField") - assert.Empty(t, res, 0) + if res := ValidateMaxLen(sut, 11, "dummyField"); len(res) > 0 { + t.Errorf("sut should be valid but was %q", res) + } } diff --git a/modules/validation/validurl_test.go b/modules/validation/validurl_test.go index 77fa7aa097..39f7fa5d65 100644 --- a/modules/validation/validurl_test.go +++ b/modules/validation/validurl_test.go @@ -6,7 +6,7 @@ package validation import ( "testing" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" ) var urlValidationTestCases = []validationTestCase{ diff --git a/modules/validation/validurllist_test.go b/modules/validation/validurllist_test.go deleted file mode 100644 index 506f96da69..0000000000 --- a/modules/validation/validurllist_test.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package validation - -import ( - "testing" - - "code.forgejo.org/go-chi/binding" -) - -// This is a copy of all the URL tests cases, plus additional ones to -// account for multiple URLs -var urlListValidationTestCases = []validationTestCase{ - { - description: "Empty URL", - data: TestForm{ - URLs: "", - }, - expectedErrors: binding.Errors{}, - }, - { - description: "URL without port", - data: TestForm{ - URLs: "http://test.lan/", - }, - expectedErrors: binding.Errors{}, - }, - { - description: "URL with port", - data: TestForm{ - URLs: "http://test.lan:3000/", - }, - expectedErrors: binding.Errors{}, - }, - { - description: "URL with IPv6 address without port", - data: TestForm{ - URLs: "http://[::1]/", - }, - expectedErrors: binding.Errors{}, - }, - { - description: "URL with IPv6 address with port", - data: TestForm{ - URLs: "http://[::1]:3000/", - }, - expectedErrors: binding.Errors{}, - }, - { - description: "Invalid URL", - data: TestForm{ - URLs: "http//test.lan/", - }, - expectedErrors: binding.Errors{ - binding.Error{ - FieldNames: []string{"URLs"}, - Classification: binding.ERR_URL, - Message: "http//test.lan/", - }, - }, - }, - { - description: "Invalid schema", - data: TestForm{ - URLs: "ftp://test.lan/", - }, - expectedErrors: binding.Errors{ - binding.Error{ - FieldNames: []string{"URLs"}, - Classification: binding.ERR_URL, - Message: "ftp://test.lan/", - }, - }, - }, - { - description: "Invalid port", - data: TestForm{ - URLs: "http://test.lan:3x4/", - }, - expectedErrors: binding.Errors{ - binding.Error{ - FieldNames: []string{"URLs"}, - Classification: binding.ERR_URL, - Message: "http://test.lan:3x4/", - }, - }, - }, - { - description: "Invalid port with IPv6 address", - data: TestForm{ - URLs: "http://[::1]:3x4/", - }, - expectedErrors: binding.Errors{ - binding.Error{ - FieldNames: []string{"URLs"}, - Classification: binding.ERR_URL, - Message: "http://[::1]:3x4/", - }, - }, - }, - { - description: "Multi URLs", - data: TestForm{ - URLs: "http://test.lan:3000/\nhttp://test.local/", - }, - expectedErrors: binding.Errors{}, - }, - { - description: "Multi URLs with newline", - data: TestForm{ - URLs: "http://test.lan:3000/\nhttp://test.local/\n", - }, - expectedErrors: binding.Errors{}, - }, - { - description: "List with invalid entry", - data: TestForm{ - URLs: "http://test.lan:3000/\nhttp://[::1]:3x4/", - }, - expectedErrors: binding.Errors{ - binding.Error{ - FieldNames: []string{"URLs"}, - Classification: binding.ERR_URL, - Message: "http://[::1]:3x4/", - }, - }, - }, - { - description: "List with two invalid entries", - data: TestForm{ - URLs: "ftp://test.lan:3000/\nhttp://[::1]:3x4/\n", - }, - expectedErrors: binding.Errors{ - binding.Error{ - FieldNames: []string{"URLs"}, - Classification: binding.ERR_URL, - Message: "ftp://test.lan:3000/", - }, - binding.Error{ - FieldNames: []string{"URLs"}, - Classification: binding.ERR_URL, - Message: "http://[::1]:3x4/", - }, - }, - }, -} - -func Test_ValidURLListValidation(t *testing.T) { - AddBindingRules() - - for _, testCase := range urlListValidationTestCases { - t.Run(testCase.description, func(t *testing.T) { - performValidationTest(t, testCase) - }) - } -} diff --git a/modules/web/handler.go b/modules/web/handler.go index 4a7f28b1fa..728cc5a160 100644 --- a/modules/web/handler.go +++ b/modules/web/handler.go @@ -9,9 +9,9 @@ import ( "net/http" "reflect" - "forgejo.org/modules/log" - "forgejo.org/modules/web/routing" - "forgejo.org/modules/web/types" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/web/routing" + "code.gitea.io/gitea/modules/web/types" ) var responseStatusProviders = map[reflect.Type]func(req *http.Request) types.ResponseStatusProvider{} diff --git a/modules/web/middleware/binding.go b/modules/web/middleware/binding.go index 123eb29015..8fa71a81bd 100644 --- a/modules/web/middleware/binding.go +++ b/modules/web/middleware/binding.go @@ -8,12 +8,12 @@ import ( "reflect" "strings" - "forgejo.org/modules/setting" - "forgejo.org/modules/translation" - "forgejo.org/modules/util" - "forgejo.org/modules/validation" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" ) // Form form binding interface @@ -79,11 +79,6 @@ func GetInclude(field reflect.StructField) string { return getRuleBody(field, "Include(") } -func GetRange(field reflect.StructField) (string, string) { - min, max, _ := strings.Cut(getRuleBody(field, "Range("), ",") - return min, max -} - // Validate populates the data with validation error (if any). func Validate(errs binding.Errors, data map[string]any, f any, l translation.Locale) binding.Errors { if errs.Len() == 0 { @@ -136,9 +131,6 @@ func Validate(errs binding.Errors, data map[string]any, f any, l translation.Loc data["ErrorMsg"] = trName + l.TrString("form.url_error", errs[0].Message) case binding.ERR_INCLUDE: data["ErrorMsg"] = trName + l.TrString("form.include_error", GetInclude(field)) - case binding.ERR_RANGE: - min, max := GetRange(field) - data["ErrorMsg"] = trName + l.TrString("alert.range_error", l.PrettyNumber(min), l.PrettyNumber(max)) case validation.ErrGlobPattern: data["ErrorMsg"] = trName + l.TrString("form.glob_pattern_error", errs[0].Message) case validation.ErrRegexPattern: @@ -151,8 +143,6 @@ func Validate(errs binding.Errors, data map[string]any, f any, l translation.Loc } case validation.ErrInvalidGroupTeamMap: data["ErrorMsg"] = trName + l.TrString("form.invalid_group_team_map_error", errs[0].Message) - case validation.ErrEmail: - data["ErrorMsg"] = trName + l.TrString("form.email_error") default: msg := errs[0].Classification if msg != "" && errs[0].Message != "" { diff --git a/modules/web/middleware/cookie.go b/modules/web/middleware/cookie.go index 3bfaeabe69..f2d25f5b1c 100644 --- a/modules/web/middleware/cookie.go +++ b/modules/web/middleware/cookie.go @@ -9,8 +9,8 @@ import ( "net/url" "strings" - "forgejo.org/modules/session" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/session" + "code.gitea.io/gitea/modules/setting" ) // SetRedirectToCookie convenience function to set the RedirectTo cookie consistently diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index 4603e64052..08d83f94be 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -7,7 +7,7 @@ import ( "context" "time" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // ContextDataStore represents a data store diff --git a/modules/web/middleware/locale.go b/modules/web/middleware/locale.go index 565fb2f502..34a16f04e7 100644 --- a/modules/web/middleware/locale.go +++ b/modules/web/middleware/locale.go @@ -6,8 +6,8 @@ package middleware import ( "net/http" - "forgejo.org/modules/translation" - "forgejo.org/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/translation/i18n" "golang.org/x/text/language" ) @@ -26,10 +26,8 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale { } } - if lang == "dummy" { - changeLang = false - } else if lang != "" && !i18n.DefaultLocales.HasLang(lang) { - // Check again in case someone changes the supported language list. + // Check again in case someone changes the supported language list. + if lang != "" && !i18n.DefaultLocales.HasLang(lang) { lang = "" changeLang = false } @@ -53,3 +51,9 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale { func SetLocaleCookie(resp http.ResponseWriter, lang string, maxAge int) { SetSiteCookie(resp, "lang", lang, maxAge) } + +// DeleteLocaleCookie convenience function to delete the locale cookie consistently +// Setting the lang cookie will trigger the middleware to reset the language to previous state. +func DeleteLocaleCookie(resp http.ResponseWriter) { + SetSiteCookie(resp, "lang", "", -1) +} diff --git a/modules/web/route.go b/modules/web/route.go index 046c9f4ba7..805fcb4411 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -7,9 +7,9 @@ import ( "net/http" "strings" - "forgejo.org/modules/web/middleware" + "code.gitea.io/gitea/modules/web/middleware" - "code.forgejo.org/go-chi/binding" + "gitea.com/go-chi/binding" "github.com/go-chi/chi/v5" ) diff --git a/modules/web/route_test.go b/modules/web/route_test.go index 44626ec141..cc0e26a12e 100644 --- a/modules/web/route_test.go +++ b/modules/web/route_test.go @@ -12,7 +12,6 @@ import ( chi "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestRoute1(t *testing.T) { @@ -23,17 +22,17 @@ func TestRoute1(t *testing.T) { r := NewRoute() r.Get("/{username}/{reponame}/{type:issues|pulls}", func(resp http.ResponseWriter, req *http.Request) { username := chi.URLParam(req, "username") - assert.Equal(t, "gitea", username) + assert.EqualValues(t, "gitea", username) reponame := chi.URLParam(req, "reponame") - assert.Equal(t, "gitea", reponame) + assert.EqualValues(t, "gitea", reponame) tp := chi.URLParam(req, "type") - assert.Equal(t, "issues", tp) + assert.EqualValues(t, "issues", tp) }) req, err := http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, http.StatusOK, recorder.Code) } func TestRoute2(t *testing.T) { @@ -48,23 +47,23 @@ func TestRoute2(t *testing.T) { r.Group("", func() { r.Get("/{type:issues|pulls}", func(resp http.ResponseWriter, req *http.Request) { username := chi.URLParam(req, "username") - assert.Equal(t, "gitea", username) + assert.EqualValues(t, "gitea", username) reponame := chi.URLParam(req, "reponame") - assert.Equal(t, "gitea", reponame) + assert.EqualValues(t, "gitea", reponame) tp := chi.URLParam(req, "type") - assert.Equal(t, "issues", tp) + assert.EqualValues(t, "issues", tp) hit = 0 }) r.Get("/{type:issues|pulls}/{index}", func(resp http.ResponseWriter, req *http.Request) { username := chi.URLParam(req, "username") - assert.Equal(t, "gitea", username) + assert.EqualValues(t, "gitea", username) reponame := chi.URLParam(req, "reponame") - assert.Equal(t, "gitea", reponame) + assert.EqualValues(t, "gitea", reponame) tp := chi.URLParam(req, "type") - assert.Equal(t, "issues", tp) + assert.EqualValues(t, "issues", tp) index := chi.URLParam(req, "index") - assert.Equal(t, "1", index) + assert.EqualValues(t, "1", index) hit = 1 }) }, func(resp http.ResponseWriter, req *http.Request) { @@ -77,39 +76,39 @@ func TestRoute2(t *testing.T) { r.Group("/issues/{index}", func() { r.Get("/view", func(resp http.ResponseWriter, req *http.Request) { username := chi.URLParam(req, "username") - assert.Equal(t, "gitea", username) + assert.EqualValues(t, "gitea", username) reponame := chi.URLParam(req, "reponame") - assert.Equal(t, "gitea", reponame) + assert.EqualValues(t, "gitea", reponame) index := chi.URLParam(req, "index") - assert.Equal(t, "1", index) + assert.EqualValues(t, "1", index) hit = 2 }) }) }) req, err := http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 0, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 0, hit) req, err = http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues/1", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 1, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 1, hit) req, err = http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues/1?stop=100", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 100, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 100, hit) req, err = http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues/1/view", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 2, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 2, hit) } func TestRoute3(t *testing.T) { @@ -148,32 +147,32 @@ func TestRoute3(t *testing.T) { }) req, err := http.NewRequest("GET", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 0, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 0, hit) req, err = http.NewRequest("POST", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code, http.StatusOK) - assert.Equal(t, 1, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code, http.StatusOK) + assert.EqualValues(t, 1, hit) req, err = http.NewRequest("GET", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections/master", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 2, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 2, hit) req, err = http.NewRequest("PATCH", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections/master", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 3, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 3, hit) req, err = http.NewRequest("DELETE", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections/master", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) - assert.Equal(t, http.StatusOK, recorder.Code) - assert.Equal(t, 4, hit) + assert.EqualValues(t, http.StatusOK, recorder.Code) + assert.EqualValues(t, 4, hit) } diff --git a/modules/web/routemock.go b/modules/web/routemock.go index 33d2ad06eb..cb41f63b91 100644 --- a/modules/web/routemock.go +++ b/modules/web/routemock.go @@ -6,7 +6,7 @@ package web import ( "net/http" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" ) // MockAfterMiddlewares is a general mock point, it's between middlewares and the handler diff --git a/modules/web/routemock_test.go b/modules/web/routemock_test.go index 46f0296046..04c6d1d82e 100644 --- a/modules/web/routemock_test.go +++ b/modules/web/routemock_test.go @@ -8,10 +8,9 @@ import ( "net/http/httptest" "testing" - "forgejo.org/modules/setting" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestRouteMock(t *testing.T) { @@ -32,12 +31,12 @@ func TestRouteMock(t *testing.T) { // normal request recorder := httptest.NewRecorder() req, err := http.NewRequest("GET", "http://localhost:8000/foo", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) assert.Len(t, recorder.Header(), 3) - assert.Equal(t, "m1", recorder.Header().Get("X-Test-Middleware1")) - assert.Equal(t, "m2", recorder.Header().Get("X-Test-Middleware2")) - assert.Equal(t, "h", recorder.Header().Get("X-Test-Handler")) + assert.EqualValues(t, "m1", recorder.Header().Get("X-Test-Middleware1")) + assert.EqualValues(t, "m2", recorder.Header().Get("X-Test-Middleware2")) + assert.EqualValues(t, "h", recorder.Header().Get("X-Test-Handler")) RouteMockReset() // mock at "mock-point" @@ -47,11 +46,11 @@ func TestRouteMock(t *testing.T) { }) recorder = httptest.NewRecorder() req, err = http.NewRequest("GET", "http://localhost:8000/foo", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) assert.Len(t, recorder.Header(), 2) - assert.Equal(t, "m1", recorder.Header().Get("X-Test-Middleware1")) - assert.Equal(t, "a", recorder.Header().Get("X-Test-MockPoint")) + assert.EqualValues(t, "m1", recorder.Header().Get("X-Test-Middleware1")) + assert.EqualValues(t, "a", recorder.Header().Get("X-Test-MockPoint")) RouteMockReset() // mock at MockAfterMiddlewares @@ -61,11 +60,11 @@ func TestRouteMock(t *testing.T) { }) recorder = httptest.NewRecorder() req, err = http.NewRequest("GET", "http://localhost:8000/foo", nil) - require.NoError(t, err) + assert.NoError(t, err) r.ServeHTTP(recorder, req) assert.Len(t, recorder.Header(), 3) - assert.Equal(t, "m1", recorder.Header().Get("X-Test-Middleware1")) - assert.Equal(t, "m2", recorder.Header().Get("X-Test-Middleware2")) - assert.Equal(t, "b", recorder.Header().Get("X-Test-MockPoint")) + assert.EqualValues(t, "m1", recorder.Header().Get("X-Test-Middleware1")) + assert.EqualValues(t, "m2", recorder.Header().Get("X-Test-Middleware2")) + assert.EqualValues(t, "b", recorder.Header().Get("X-Test-MockPoint")) RouteMockReset() } diff --git a/modules/web/routing/logger.go b/modules/web/routing/logger.go index 8fd24c9733..5f3a7592af 100644 --- a/modules/web/routing/logger.go +++ b/modules/web/routing/logger.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "forgejo.org/modules/log" - "forgejo.org/modules/web/types" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/web/types" ) // NewLoggerHandler is a handler that will log routing to the router log taking account of @@ -90,7 +90,7 @@ func logPrinter(logger log.Logger) func(trigger Event, record *requestRecord) { status = v.WrittenStatus() } logf := logger.Info - if strings.HasPrefix(req.RequestURI, "/assets/") || req.RequestURI == "/api/actions/runner.v1.RunnerService/FetchTask" || req.RequestURI == "/api/actions/runner.v1.RunnerService/UpdateLog" { + if strings.HasPrefix(req.RequestURI, "/assets/") { logf = logger.Trace } message := completedMessage diff --git a/modules/web/routing/logger_manager.go b/modules/web/routing/logger_manager.go index 4b12419b44..aa25ec3a27 100644 --- a/modules/web/routing/logger_manager.go +++ b/modules/web/routing/logger_manager.go @@ -9,8 +9,8 @@ import ( "sync" "time" - "forgejo.org/modules/graceful" - "forgejo.org/modules/process" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/process" ) // Event indicates when the printer is triggered diff --git a/modules/webhook/structs.go b/modules/webhook/structs.go index 6c0161bfc2..927a91a74c 100644 --- a/modules/webhook/structs.go +++ b/modules/webhook/structs.go @@ -4,7 +4,6 @@ package webhook // HookEvents is a set of web hook events -// update TestCreateWebhook in models/webhook/webhook_test.go when adding or changing values here type HookEvents struct { Create bool `json:"create"` Delete bool `json:"delete"` @@ -27,12 +26,9 @@ type HookEvents struct { Repository bool `json:"repository"` Release bool `json:"release"` Package bool `json:"package"` - ActionRunFailure bool `json:"action_run_failure"` - ActionRunRecover bool `json:"action_run_recover"` - ActionRunSuccess bool `json:"action_run_success"` } -// HookEvent represents events that will deliver a hook. +// HookEvent represents events that will delivery hook. type HookEvent struct { PushOnly bool `json:"push_only"` SendEverything bool `json:"send_everything"` diff --git a/modules/webhook/type.go b/modules/webhook/type.go index e833f90f58..244dc423c1 100644 --- a/modules/webhook/type.go +++ b/modules/webhook/type.go @@ -7,7 +7,6 @@ package webhook type HookEventType string // Types of hook events -// update TestCreateWebhook in models/webhook/webhook_test.go when adding or changing values here const ( HookEventCreate HookEventType = "create" HookEventDelete HookEventType = "delete" @@ -34,9 +33,6 @@ const ( HookEventPackage HookEventType = "package" HookEventSchedule HookEventType = "schedule" HookEventWorkflowDispatch HookEventType = "workflow_dispatch" - HookEventActionRunFailure HookEventType = "action_run_failure" - HookEventActionRunRecover HookEventType = "action_run_recover" - HookEventActionRunSuccess HookEventType = "action_run_success" ) // Event returns the HookEventType as an event string @@ -69,12 +65,6 @@ func (h HookEventType) Event() string { return "repository" case HookEventRelease: return "release" - case HookEventActionRunFailure: - return "action_run_failure" - case HookEventActionRunRecover: - return "action_run_recover" - case HookEventActionRunSuccess: - return "action_run_success" } return "" } diff --git a/modules/zstd/option.go b/modules/zstd/option.go deleted file mode 100644 index 916a390819..0000000000 --- a/modules/zstd/option.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package zstd - -import "github.com/klauspost/compress/zstd" - -type WriterOption = zstd.EOption - -var ( - WithEncoderCRC = zstd.WithEncoderCRC - WithEncoderConcurrency = zstd.WithEncoderConcurrency - WithWindowSize = zstd.WithWindowSize - WithEncoderPadding = zstd.WithEncoderPadding - WithEncoderLevel = zstd.WithEncoderLevel - WithZeroFrames = zstd.WithZeroFrames - WithAllLitEntropyCompression = zstd.WithAllLitEntropyCompression - WithNoEntropyCompression = zstd.WithNoEntropyCompression - WithSingleSegment = zstd.WithSingleSegment - WithLowerEncoderMem = zstd.WithLowerEncoderMem - WithEncoderDict = zstd.WithEncoderDict - WithEncoderDictRaw = zstd.WithEncoderDictRaw -) - -type EncoderLevel = zstd.EncoderLevel - -const ( - SpeedFastest EncoderLevel = zstd.SpeedFastest - SpeedDefault EncoderLevel = zstd.SpeedDefault - SpeedBetterCompression EncoderLevel = zstd.SpeedBetterCompression - SpeedBestCompression EncoderLevel = zstd.SpeedBestCompression -) - -type ReaderOption = zstd.DOption - -var ( - WithDecoderLowmem = zstd.WithDecoderLowmem - WithDecoderConcurrency = zstd.WithDecoderConcurrency - WithDecoderMaxMemory = zstd.WithDecoderMaxMemory - WithDecoderDicts = zstd.WithDecoderDicts - WithDecoderDictRaw = zstd.WithDecoderDictRaw - WithDecoderMaxWindow = zstd.WithDecoderMaxWindow - WithDecodeAllCapLimit = zstd.WithDecodeAllCapLimit - WithDecodeBuffersBelow = zstd.WithDecodeBuffersBelow - IgnoreChecksum = zstd.IgnoreChecksum -) diff --git a/modules/zstd/zstd.go b/modules/zstd/zstd.go deleted file mode 100644 index d2249447d6..0000000000 --- a/modules/zstd/zstd.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -// Package zstd provides a high-level API for reading and writing zstd-compressed data. -// It supports both regular and seekable zstd streams. -// It's not a new wheel, but a wrapper around the zstd and zstd-seekable-format-go packages. -package zstd - -import ( - "errors" - "io" - - seekable "github.com/SaveTheRbtz/zstd-seekable-format-go/pkg" - "github.com/klauspost/compress/zstd" -) - -type Writer zstd.Encoder - -var _ io.WriteCloser = (*Writer)(nil) - -// NewWriter returns a new zstd writer. -func NewWriter(w io.Writer, opts ...WriterOption) (*Writer, error) { - zstdW, err := zstd.NewWriter(w, opts...) - if err != nil { - return nil, err - } - return (*Writer)(zstdW), nil -} - -func (w *Writer) Write(p []byte) (int, error) { - return (*zstd.Encoder)(w).Write(p) -} - -func (w *Writer) Close() error { - return (*zstd.Encoder)(w).Close() -} - -type Reader zstd.Decoder - -var _ io.ReadCloser = (*Reader)(nil) - -// NewReader returns a new zstd reader. -func NewReader(r io.Reader, opts ...ReaderOption) (*Reader, error) { - zstdR, err := zstd.NewReader(r, opts...) - if err != nil { - return nil, err - } - return (*Reader)(zstdR), nil -} - -func (r *Reader) Read(p []byte) (int, error) { - return (*zstd.Decoder)(r).Read(p) -} - -func (r *Reader) Close() error { - (*zstd.Decoder)(r).Close() // no error returned - return nil -} - -type SeekableWriter struct { - buf []byte - n int - w seekable.Writer -} - -var _ io.WriteCloser = (*SeekableWriter)(nil) - -// NewSeekableWriter returns a zstd writer to compress data to seekable format. -// blockSize is an important parameter, it should be decided according to the actual business requirements. -// If it's too small, the compression ratio could be very bad, even no compression at all. -// If it's too large, it could cost more traffic when reading the data partially from underlying storage. -func NewSeekableWriter(w io.Writer, blockSize int, opts ...WriterOption) (*SeekableWriter, error) { - zstdW, err := zstd.NewWriter(nil, opts...) - if err != nil { - return nil, err - } - - seekableW, err := seekable.NewWriter(w, zstdW) - if err != nil { - return nil, err - } - - return &SeekableWriter{ - buf: make([]byte, blockSize), - w: seekableW, - }, nil -} - -func (w *SeekableWriter) Write(p []byte) (int, error) { - written := 0 - for len(p) > 0 { - n := copy(w.buf[w.n:], p) - w.n += n - written += n - p = p[n:] - - if w.n == len(w.buf) { - if _, err := w.w.Write(w.buf); err != nil { - return written, err - } - w.n = 0 - } - } - return written, nil -} - -func (w *SeekableWriter) Close() error { - if w.n > 0 { - if _, err := w.w.Write(w.buf[:w.n]); err != nil { - return err - } - } - return w.w.Close() -} - -type SeekableReader struct { - r seekable.Reader - c func() error -} - -var _ io.ReadSeekCloser = (*SeekableReader)(nil) - -// NewSeekableReader returns a zstd reader to decompress data from seekable format. -func NewSeekableReader(r io.ReadSeeker, opts ...ReaderOption) (*SeekableReader, error) { - zstdR, err := zstd.NewReader(nil, opts...) - if err != nil { - return nil, err - } - - seekableR, err := seekable.NewReader(r, zstdR) - if err != nil { - return nil, err - } - - ret := &SeekableReader{ - r: seekableR, - } - if closer, ok := r.(io.Closer); ok { - ret.c = closer.Close - } - - return ret, nil -} - -func (r *SeekableReader) Read(p []byte) (int, error) { - return r.r.Read(p) -} - -func (r *SeekableReader) Seek(offset int64, whence int) (int64, error) { - return r.r.Seek(offset, whence) -} - -func (r *SeekableReader) Close() error { - return errors.Join( - func() error { - if r.c != nil { - return r.c() - } - return nil - }(), - r.r.Close(), - ) -} diff --git a/modules/zstd/zstd_test.go b/modules/zstd/zstd_test.go deleted file mode 100644 index 9284ab0eb2..0000000000 --- a/modules/zstd/zstd_test.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package zstd - -import ( - "bytes" - "io" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestWriterReader(t *testing.T) { - testData := prepareTestData(t, 15_000_000) - - result := bytes.NewBuffer(nil) - - t.Run("regular", func(t *testing.T) { - result.Reset() - writer, err := NewWriter(result) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - - reader, err := NewReader(result) - require.NoError(t, err) - - data, err := io.ReadAll(reader) - require.NoError(t, err) - require.NoError(t, reader.Close()) - - assert.Equal(t, testData, data) - }) - - t.Run("with options", func(t *testing.T) { - result.Reset() - writer, err := NewWriter(result, WithEncoderLevel(SpeedBestCompression)) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - - reader, err := NewReader(result, WithDecoderLowmem(true)) - require.NoError(t, err) - - data, err := io.ReadAll(reader) - require.NoError(t, err) - require.NoError(t, reader.Close()) - - assert.Equal(t, testData, data) - }) -} - -func TestSeekableWriterReader(t *testing.T) { - testData := prepareTestData(t, 15_000_000) - - result := bytes.NewBuffer(nil) - - t.Run("regular", func(t *testing.T) { - result.Reset() - blockSize := 100_000 - - writer, err := NewSeekableWriter(result, blockSize) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - - reader, err := NewSeekableReader(bytes.NewReader(result.Bytes())) - require.NoError(t, err) - - data, err := io.ReadAll(reader) - require.NoError(t, err) - require.NoError(t, reader.Close()) - - assert.Equal(t, testData, data) - }) - - t.Run("seek read", func(t *testing.T) { - result.Reset() - blockSize := 100_000 - - writer, err := NewSeekableWriter(result, blockSize) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - - assertReader := &assertReadSeeker{r: bytes.NewReader(result.Bytes())} - - reader, err := NewSeekableReader(assertReader) - require.NoError(t, err) - - _, err = reader.Seek(10_000_000, io.SeekStart) - require.NoError(t, err) - - data := make([]byte, 1000) - _, err = io.ReadFull(reader, data) - require.NoError(t, err) - require.NoError(t, reader.Close()) - - assert.Equal(t, testData[10_000_000:10_000_000+1000], data) - - // Should seek 3 times, - // the first two times are for getting the index, - // and the third time is for reading the data. - assert.Equal(t, 3, assertReader.SeekTimes) - // Should read less than 2 blocks, - // even if the compression ratio is not good and the data is not in the same block. - assert.Less(t, assertReader.ReadBytes, blockSize*2) - // Should close the underlying reader if it is Closer. - assert.True(t, assertReader.Closed) - }) - - t.Run("tidy data", func(t *testing.T) { - testData := prepareTestData(t, 1000) // data size is less than a block - - result.Reset() - blockSize := 100_000 - - writer, err := NewSeekableWriter(result, blockSize) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - - reader, err := NewSeekableReader(bytes.NewReader(result.Bytes())) - require.NoError(t, err) - - data, err := io.ReadAll(reader) - require.NoError(t, err) - require.NoError(t, reader.Close()) - - assert.Equal(t, testData, data) - }) - - t.Run("tidy block", func(t *testing.T) { - result.Reset() - blockSize := 100 - - writer, err := NewSeekableWriter(result, blockSize) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - // A too small block size will cause a bad compression rate, - // even the compressed data is larger than the original data. - assert.Greater(t, result.Len(), len(testData)) - - reader, err := NewSeekableReader(bytes.NewReader(result.Bytes())) - require.NoError(t, err) - - data, err := io.ReadAll(reader) - require.NoError(t, err) - require.NoError(t, reader.Close()) - - assert.Equal(t, testData, data) - }) - - t.Run("compatible reader", func(t *testing.T) { - result.Reset() - blockSize := 100_000 - - writer, err := NewSeekableWriter(result, blockSize) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - - // It should be able to read the data with a regular reader. - reader, err := NewReader(bytes.NewReader(result.Bytes())) - require.NoError(t, err) - - data, err := io.ReadAll(reader) - require.NoError(t, err) - require.NoError(t, reader.Close()) - - assert.Equal(t, testData, data) - }) - - t.Run("wrong reader", func(t *testing.T) { - result.Reset() - - // Use a regular writer to compress the data. - writer, err := NewWriter(result) - require.NoError(t, err) - - _, err = io.Copy(writer, bytes.NewReader(testData)) - require.NoError(t, err) - require.NoError(t, writer.Close()) - - t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100) - - // But use a seekable reader to read the data, it should fail. - _, err = NewSeekableReader(bytes.NewReader(result.Bytes())) - require.Error(t, err) - }) -} - -// prepareTestData prepares test data to test compression. -// Random data is not suitable for testing compression, -// so it collects code files from the project to get enough data. -func prepareTestData(t *testing.T, size int) []byte { - // .../gitea/modules/zstd - dir, err := os.Getwd() - require.NoError(t, err) - // .../gitea/ - dir = filepath.Join(dir, "../../") - - textExt := []string{".go", ".tmpl", ".ts", ".yml", ".css"} // add more if not enough data collected - isText := func(info os.FileInfo) bool { - if info.Size() == 0 { - return false - } - for _, ext := range textExt { - if strings.HasSuffix(info.Name(), ext) { - return true - } - } - return false - } - - ret := make([]byte, size) - n := 0 - count := 0 - - queue := []string{dir} - for len(queue) > 0 && n < size { - file := queue[0] - queue = queue[1:] - info, err := os.Stat(file) - require.NoError(t, err) - if info.IsDir() { - entries, err := os.ReadDir(file) - require.NoError(t, err) - for _, entry := range entries { - queue = append(queue, filepath.Join(file, entry.Name())) - } - continue - } - if !isText(info) { // text file only - continue - } - data, err := os.ReadFile(file) - require.NoError(t, err) - n += copy(ret[n:], data) - count++ - } - - if n < size { - require.Failf(t, "Not enough data", "Only %d bytes collected from %d files", n, count) - } - return ret -} - -type assertReadSeeker struct { - r io.ReadSeeker - SeekTimes int - ReadBytes int - Closed bool -} - -func (a *assertReadSeeker) Read(p []byte) (int, error) { - n, err := a.r.Read(p) - a.ReadBytes += n - return n, err -} - -func (a *assertReadSeeker) Seek(offset int64, whence int) (int64, error) { - a.SeekTimes++ - return a.r.Seek(offset, whence) -} - -func (a *assertReadSeeker) Close() error { - a.Closed = true - return nil -} diff --git a/options/gitignore/Flutter b/options/gitignore/Flutter deleted file mode 100644 index 39b8814aec..0000000000 --- a/options/gitignore/Flutter +++ /dev/null @@ -1,119 +0,0 @@ -# Miscellaneous -*.class -*.lock -*.log -*.pyc -*.swp -.buildlog/ -.history - - - -# Flutter repo-specific -/bin/cache/ -/bin/internal/bootstrap.bat -/bin/internal/bootstrap.sh -/bin/mingit/ -/dev/benchmarks/mega_gallery/ -/dev/bots/.recipe_deps -/dev/bots/android_tools/ -/dev/devicelab/ABresults*.json -/dev/docs/doc/ -/dev/docs/flutter.docs.zip -/dev/docs/lib/ -/dev/docs/pubspec.yaml -/dev/integration_tests/**/xcuserdata -/dev/integration_tests/**/Pods -/packages/flutter/coverage/ -version -analysis_benchmark.json - -# packages file containing multi-root paths -.packages.generated - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -**/generated_plugin_registrant.dart -.packages -.pub-preload-cache/ -.pub/ -build/ -flutter_*.png -linked_*.ds -unlinked.ds -unlinked_spec.ds - -# Android related -**/android/**/gradle-wrapper.jar -.gradle/ -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java -**/android/key.properties -*.jks - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/.last_build_id -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/ephemeral -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# macOS -**/Flutter/ephemeral/ -**/Pods/ -**/macos/Flutter/GeneratedPluginRegistrant.swift -**/macos/Flutter/ephemeral -**/xcuserdata/ - -# Windows -**/windows/flutter/generated_plugin_registrant.cc -**/windows/flutter/generated_plugin_registrant.h -**/windows/flutter/generated_plugins.cmake - -# Linux -**/linux/flutter/generated_plugin_registrant.cc -**/linux/flutter/generated_plugin_registrant.h -**/linux/flutter/generated_plugins.cmake - -# Coverage -coverage/ - -# Symbols -app.*.symbols - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -!/dev/ci/**/Gemfile.lock \ No newline at end of file diff --git a/options/gitignore/Hexo b/options/gitignore/Hexo deleted file mode 100644 index 570a5e7b5d..0000000000 --- a/options/gitignore/Hexo +++ /dev/null @@ -1,14 +0,0 @@ -# gitignore template for Hexo sites -# website: https://hexo.io/ -# Recommended: Node.gitignore - -# Ignore generated directory -public/ - -# Ignore temp files -tmp/ -.tmp* - -# additional files -db.json -.deploy*/ diff --git a/options/gitignore/Nix b/options/gitignore/Nix index 912e6700f4..1fd04ef1f6 100644 --- a/options/gitignore/Nix +++ b/options/gitignore/Nix @@ -1,6 +1,3 @@ # Ignore build outputs from performing a nix-build or `nix build` command result result-* - -# Ignore automatically generated direnv output -.direnv diff --git a/options/gitignore/NotesAndCoreConfiguration b/options/gitignore/NotesAndCoreConfiguration deleted file mode 100644 index 4eff01dae1..0000000000 --- a/options/gitignore/NotesAndCoreConfiguration +++ /dev/null @@ -1,16 +0,0 @@ -# Excludes Obsidian workspace cache and plugins. All notes and core obsidian -# configuration files are tracked by Git. - -# The current application UI state (DOM layout, recently-opened files, etc.) is -# stored in these files (separate for desktop and mobile) so you can resume -# your session seamlessly after a restart. If you want to track UI state, use -# the Workspaces core plugin instead of relying on these files. -.obsidian/workspace.json -.obsidian/workspace-mobile.json - -# Obsidian plugins are stored under .obsidian/plugins/$plugin_name. They -# contain metadata (manifest.json), application code (main.js), stylesheets -# (styles.css), and user-configuration data (data.json). -# We want to exclude all plugin-related files, so we can exclude everything -# under this directory. -.obsidian/plugins/**/* diff --git a/options/gitignore/NotesAndExtendedConfiguration b/options/gitignore/NotesAndExtendedConfiguration deleted file mode 100644 index 3e0804f299..0000000000 --- a/options/gitignore/NotesAndExtendedConfiguration +++ /dev/null @@ -1,38 +0,0 @@ -# Excludes Obsidian workspace cache and plugin code, but retains plugin -# configuration. All notes and user-controlled configuration files are tracked -# by Git. -# -# !!! WARNING !!! -# -# Community plugins may store sensitive secrets in their data.json files. By -# including these files, those secrets may be tracked in your Git repository. -# -# To ignore configurations for specific plugins, add a line like this after the -# contents of this file (order is important): -# .obsidian/plugins/{{plugin_name}}/data.json -# -# Alternatively, ensure that you are treating your entire Git repository as -# sensitive data, since it may contain secrets, or may have contained them in -# past commits. Understand your threat profile, and make the decision -# appropriate for yourself. If in doubt, err on the side of not including -# plugin configuration. Use one of the alternative gitignore files instead: -# * NotesOnly.gitignore -# * NotesAndCoreConfiguration.gitignore - -# The current application UI state (DOM layout, recently-opened files, etc.) is -# stored in these files (separate for desktop and mobile) so you can resume -# your session seamlessly after a restart. If you want to track UI state, use -# the Workspaces core plugin instead of relying on these files. -.obsidian/workspace.json -.obsidian/workspace-mobile.json - -# Obsidian plugins are stored under .obsidian/plugins/$plugin_name. They -# contain metadata (manifest.json), application code (main.js), stylesheets -# (styles.css), and user-configuration data (data.json). -# We only want to track data.json, so we: -# 1. exclude everything under the plugins directory recursively, -# 2. unignore the plugin directories themselves, which then allows us to -# 3. unignore the data.json files -.obsidian/plugins/**/* -!.obsidian/plugins/*/ -!.obsidian/plugins/*/data.json diff --git a/options/gitignore/NotesOnly b/options/gitignore/NotesOnly deleted file mode 100644 index 2b3b76ee0e..0000000000 --- a/options/gitignore/NotesOnly +++ /dev/null @@ -1,4 +0,0 @@ -# Excludes all Obsidian-related configuration. All notes are tracked by Git. - -# All Obsidian configuration and runtime state is stored here -.obsidian/**/* diff --git a/options/gitignore/ReScript b/options/gitignore/ReScript deleted file mode 100644 index b7364c932a..0000000000 --- a/options/gitignore/ReScript +++ /dev/null @@ -1,3 +0,0 @@ -/node_modules/ -/lib/ -.bsb.lock diff --git a/options/gitignore/Terragrunt b/options/gitignore/Terragrunt deleted file mode 100644 index ea4808637f..0000000000 --- a/options/gitignore/Terragrunt +++ /dev/null @@ -1,3 +0,0 @@ -# Ignore the default terragrunt cache directory -# https://terragrunt.gruntwork.io/docs/features/caching/ -.terragrunt-cache diff --git a/options/gitignore/Zig b/options/gitignore/Zig index 748837a058..236ae6be8c 100644 --- a/options/gitignore/Zig +++ b/options/gitignore/Zig @@ -1,4 +1,4 @@ -.zig-cache/ +zig-cache/ zig-out/ build/ build-*/ diff --git a/options/license/DocBook-Stylesheet b/options/license/DocBook-Stylesheet deleted file mode 100644 index e986ed4235..0000000000 --- a/options/license/DocBook-Stylesheet +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2005 Norman Walsh, Sun Microsystems, -Inc., and the Organization for the Advancement -of Structured Information Standards (OASIS). - -Release: $Id: db4-upgrade.xsl 8905 2010-09-12 11:47:07Z bobstayton $ - -Permission to use, copy, modify and distribute this stylesheet -and its accompanying documentation for any purpose and -without fee is hereby granted in perpetuity, provided that -the above copyright notice and this paragraph appear in -all copies. The copyright holders make no representation -about the suitability of the schema for any purpose. It -is provided "as is" without expressed or implied warranty. diff --git a/options/license/GPL-3.0-389-ds-base-exception b/options/license/GPL-3.0-389-ds-base-exception deleted file mode 100644 index 52be470c10..0000000000 --- a/options/license/GPL-3.0-389-ds-base-exception +++ /dev/null @@ -1,10 +0,0 @@ -Additional permission under GPLv3 section 7: - -If you modify this Program, or any covered work, by -linking or combining it with OpenSSL, or a modified -version of OpenSSL licensed under the OpenSSL license -(https://www.openssl.org/source/license.html), the licensors of this -Program grant you additional permission to convey the resulting work. -Corresponding Source for a non-source form of such a combination -shall include the source code for the parts that are licensed -under the OpenSSL license as well as that of the covered work. diff --git a/options/license/MIT-Click b/options/license/MIT-Click deleted file mode 100644 index 82054edc39..0000000000 --- a/options/license/MIT-Click +++ /dev/null @@ -1,30 +0,0 @@ -Portions of this software are subject to the license below. The relevant -source files are clearly marked; they refer to this file using the phrase -"the Click LICENSE file". This license is an MIT license, plus a clause -(taken from the W3C license) requiring prior written permission to use our -names in publicity. - -=========================================================================== - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -The name and trademarks of copyright holders may NOT be used in advertising -or publicity pertaining to the Software without specific, written prior -permission. Title to copyright in this Software and any associated -documentation will at all times remain with copyright holders. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/options/license/TrustedQSL b/options/license/TrustedQSL deleted file mode 100644 index 982d4269f6..0000000000 --- a/options/license/TrustedQSL +++ /dev/null @@ -1,58 +0,0 @@ -Copyright (C) 2001-2015 American Radio Relay League, Inc. All rights -reserved. - -Portions (C) 2003-2023 The TrustedQSL Developers. Please see the AUTHORS.txt -file for contributors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Any redistribution of source code must retain the above copyright -notice, this list of conditions and the disclaimer shown in -Paragraph 5 (below). - -2. Redistribution in binary form must reproduce the above copyright -notice, this list of conditions and the disclaimer shown in -Paragraph 5 (below) in the documentation and/or other materials -provided with the distribution. - -3. Products derived from or including this software may not use -"Logbook of the World" or "LoTW" or any other American Radio Relay -League, Incorporated trademarks or servicemarks in their names -without prior written permission of the ARRL. See Paragraph 6 -(below) for contact information. - -4. Use of this software does not imply endorsement by ARRL of -products derived from or including this software and vendors may not -claim such endorsement. - -5. Disclaimer: This software is provided "as-is" without -representation, guarantee or warranty of any kind, either express or -implied, including but not limited to the implied warranties of -merchantability or of fitness for a particular purpose. The entire -risk as to the quality and performance of the software is solely -with you. Should the software prove defective, you (and not the -American Radio Relay League, its officers, directors, employees or -agents) assume the entire cost of all necessary servicing, repair or -correction. In no event will ARRL be liable to you or to any third -party for any damages, whether direct or indirect, including lost -profits, lost savings, or other incidental or consequential damages -arising out of the use or inability to use such software, regardless -of whether ARRL has been advised of the possibility of such damages. - -6. Contact information: - -American Radio Relay League, Inc. -Attn: Logbook of the World Manager -225 Main St -Newington, CT 06111 -voice: 860-594-0200 -fax: 860-594-0259 -email: logbook@arrl.org -Worldwide Web: www.arrl.org - -This software consists of voluntary contributions made by many -individuals on behalf of the ARRL. More information on the "Logbook -of The World" project and the ARRL is available from the ARRL Web -site at www.arrl.org. diff --git a/options/locale/locale_ar.ini b/options/locale/locale_ar.ini index ca74a477ce..3056bd5dd5 100644 --- a/options/locale/locale_ar.ini +++ b/options/locale/locale_ar.ini @@ -1,3 +1,6 @@ + + + [common] language = لغة passcode = رمز المرور @@ -10,7 +13,7 @@ preview = عاين disabled = معطّل go_back = عُد للوراء licenses = التراخيص -sign_in = تسجيل الدخول +sign_in = سجل الدخول activities = الأنشطة copy_content = انسخ المحتوى collaborative = مشترك @@ -50,7 +53,7 @@ concept_user_organization = المنظمة link_account = ربط الحساب rerun_all = أعِد تشغيل جميع الوظائف your_profile = الملف الشخصي -sign_out = سجّل الخروج +sign_out = سجل الخروج settings = الإعدادات locked = مقفول error = خطأ @@ -87,7 +90,7 @@ add_all = أضف الكل new_fork = اشتقاق جديد لمستودع new_project_column = عمود جديد add = أضف -active_stopwatch = متتبِّع وقت النشاط +active_stopwatch = تتبع وقت الإنجاز organization = منظمة new_migrate = ترحيل جديد save = احفظ @@ -114,7 +117,7 @@ twofa_scratch = الرمز الاحتياطي للمصادقة بعاملين home = الرئيسية email = عنوان البريد الإلكتروني issues = المسائل -error404 = الصفحة التي تحاول الوصول لها إما غير موجودو أو أنك غير مصرح لك بعرضها. +error404 = الصفحة التي تحاول الوصول لها إما لا توجد أو أنت لست مأذون لك بعرضها. powered_by = مدعوم بواسطة %s retry = أعد المحاولة tracked_time_summary = ملخص للتتبع الزمني وفقًا لنتائج تصفية قائمة المسائل @@ -127,8 +130,8 @@ toggle_menu = تبديل القائمة more_items = عناصر اضافية copy_generic = نسخ إلى الحافظة invalid_data = بيانات غير صالحة: %v -filter.clear = مسح عوامل التصفية -filter = عامل تصفية +filter.clear = مسح المرشحات +filter = مرشح filter.is_archived = مؤرشف filter.is_template = قوالب filter.not_mirror = ليست مرايا @@ -137,18 +140,8 @@ filter.is_mirror = مرايا filter.is_fork = الاشتقاقات filter.not_fork = ليست اشتقاقات filter.not_archived = ليس مؤرشف -filter.public = عام +filter.public = علني filter.private = خاص -new_repo.title = مستودع جديد -new_migrate.title = انتقال جديد -new_org.title = منظمة جديدة -new_repo.link = مستودع جديد -new_migrate.link = انتقال جديد - -new_org.link = منظمة جديدة -test = اختبار -copy_path = نسخ المسار -error413 = لقد استنفدت حصتك. [install] db_name = اسم قاعدة البيانات @@ -175,7 +168,7 @@ reinstall_confirm_check_2 = وقد يلزم إعادة تزامن المستود run_user = شغّل عبر مستخدم err_admin_name_is_invalid = اسم مستخدم المدير غير صالح reinstall_confirm_check_3 = أنتِ تؤكد أنكِ متأكد تماماً من أن فورجيو يعمل مع مسار app.ini الصحيح وأنك متأكد من أنه يجب عليك إعادة تثبيته. أنت تُؤكّدُ بأنّك تُقرّ بالمخاطر السالفة الذكر. -repo_path = المسار الجذر للمستودع +repo_path = المسار الجذري للمستودع err_empty_admin_email = عنوان بريد المدير لا يمكن أن يكون فارغ. no_admin_and_disable_registration = لا يمكنك تعطيل التسجيل الذاتي للمستخدمين بدون إنشاء حساب إداري. err_admin_name_pattern_not_allowed = اسم مستخدم المدير غير صالح، هذا الأسم يطابق نمطا محجوز @@ -184,10 +177,10 @@ repo_path_helper = ستُحفظ كلّ مستودعات جِت البعيدة ف general_title = الإعدادات العامة lfs_path_helper = الملفات التي تم تعقبها بواسطة Git LFS ستُخزن في هذا الدليل. اتركه فارغًا لتعطيله. err_empty_db_path = طريق قاعدة بيانات SQLite3 لا يمكن أن يكون فارغا. -lfs_path = مسار جذر Git LFS -app_name_helper = أدخل اسم المثيل هنا. سيظهر هذا الاسم في كل الصفحات. +lfs_path = مسار جذر جِت LFS +app_name_helper = يمكنك إدخال اسم شركتك هنا. err_admin_name_is_reserved = اسم مستخدم المدير غير صالح، هذا الأسم محجوز -app_name = عنوان المثيل +app_name = عنوان الموقع log_root_path = مسار السجل log_root_path_helper = ستُكتب ملفات السجل في هذا الدليل. smtp_addr = مضيف SMTP @@ -195,7 +188,7 @@ smtp_port = منفذ SMTP mailer_password = كلمة مرور SMTP app_url_helper = العنوان الأساسي لاستنساخ عناوين URL HTTP(S) وإشعارات البريد الإلكتروني. mailer_user = اسم مستخدم SMTP -disable_gravatar.description = عطل Gravatar والجهات الخارجية للصور الرمزية. ستُستخدم صورة رمزية مبدئية حتى يرفع المستخدم صورة. +disable_gravatar.description = عطل جرافاتار والجهات الخارجية للصور الرمزية. ستُستخدم صورة رمزية مبدئية حتى يرفع المستخدم صورة. offline_mode.description = عطل خدمات توصيل المحتوى من الجهات الخارجية، واخدم كل المحتوى محلياً. run_user_helper = اسم مستخدم نظام التشغيل الذي يشغل فورجيو. ملاحظة: هذا المستخدم يجب أن يكون له حق الوصول إلى المسار الجذري للمستودع. domain = نطاق الخادم @@ -204,28 +197,28 @@ smtp_from = أرسل البريد الإلكتروني كـ federated_avatar_lookup = تفعيل الصور الرمزية الاتحادية optional_title = إعدادات اختيارية domain_helper = نطاق أو عنوان المضيف لخادمك. -mail_notify = فعّل التنبيهات عبر البريد الإلكتروني -app_url = الرابط الأساس +mail_notify = فعّل التنبيه عبر البريد الإلكتروني +app_url = الرابط الأساس لفورجيو smtp_from_helper = عنوان البريد الإلكتروني الذي سيستخدمه فورجيو. أدخل عنوان بريد إلكتروني عادي أو استخدم صيغة"Name" . ssh_port_helper = رقم المنفذ الذي يستمع له خادم SSH. اتركه فارغاً لتعطيله. -http_port_helper = المنفذ الذي سيستمع إليه خادم ويب Forgejo. -http_port = منفذ استماع HTTP +http_port_helper = المنفذ الذي سيستمع إليه خادم الويب لفورجيو. +http_port = منفذ استماع HTTP لفورجيو ssh_port = منفذ خادم SSH email_title = إعدادات البريد الإلكتروني offline_mode = فعل الوضع المحلي server_service_title = إعدادات الخادم وخدمات الجهات الخارجية register_confirm = الزم تأكيد البريد الإلكتروني للتسجيل -allow_only_external_registration.description = لن يتمكن المستخدمون من إنشاء حسابات جديدة إلا باستخدام خدمات خارجية مهيأة. +allow_only_external_registration.description = لا يسمح بالتسجيل إلا من خلال الخدمات الخارجية disable_registration = عطّل التسجيل الذاتي -federated_avatar_lookup.description = تفعيل الصور الرمزية الاتحادية باستخدام Libravatar. +federated_avatar_lookup.description = تفعيل الصور الرمزية الاتحادية باستخدام ليبرافاتار. openid_signup = فعّل التسجيل الذاتي عبر OpenID -disable_registration.description = سيتمكن مسؤولو المثيل فقط من إنشاء حسابات مستخدمين جديدة. يوصى بشدة بإبقاء التسجيل معطلاً إلا إذا كنت تنوي استضافة مثيل عام للجميع ومستعد للتعامل مع كميات كبيرة من الحسابات غير المرغوب بها. +disable_registration.description = عطل التسجيل الذاتي. المديرون فقط سيكونون قادرين على إنشاء حسابات جديدة للمستخدمين. openid_signin = فعّل تسجيل الدخول عبر OpenID openid_signin.description = فعّل تسجيل دخول المستخدمين عبر OpenID. enable_captcha = فعّل كابتشا التسجيل -enable_captcha.description = مطالبة المستخدمين باجتياز اختبار CAPTCHA من أجل إنشاء حسابات. +enable_captcha.description = الزم وجود كابتشا للتسجيل الذاتي للمستخدمين. openid_signup.description = فعّل التسجيل الذاتي للمستخدمين عبر OpenID. -require_sign_in_view = يتطلب تسجيل الدخول لعرض محتوى المثيل +require_sign_in_view = الزم تسجيل الدخول لعرض الصفحات require_sign_in_view.description = مكّن وصول الصفحات للمستخدمين فقط. لن يرى الزائرون سوى صفحات التسجيل والتسجيل. admin_setting.description = إنشاء حساب إداري هو اختياري. أول مستخدم مُسجل سيصبح تلقائيا مديرا. admin_password = كلمة المرور @@ -238,7 +231,7 @@ test_git_failed = يتعذر اختبار أمر جِت: %v confirm_password = أكّد كلمة المرور invalid_admin_setting = إعداد حساب المدير غير صالح: %v invalid_log_root_path = مسار السجل غير صالح: %v -default_enable_timetracking = فعّل التتبع الزمني افتراضيًا +default_enable_timetracking = فعّل تتبع الوقت مبدئيا env_config_keys_prompt = ستطبق المتغيرات البيئية التالية أيضاً على ملف الإعدادات: admin_title = إعدادات حساب المدير no_reply_address_helper = النطاق للمستخدمين بعنوان بريد إلكتروني مخفي. مثلاً، اسم المستخدم "sarah" سوف يسجل في جِت كـ"sarah@noreply.example.org" لو كان نطاق البريد الإلكتروني الخفي مدخل كـ"noreply.example.org". @@ -247,9 +240,9 @@ default_enable_timetracking.description = فعل تتبع الوقت للمست run_user_not_match = مستخدم التشغيل غير مطابق لأسم المستخدم الحالي: %s -> %s invalid_db_setting = إعدادات قاعدة البيانات غير صالحة: %v invalid_db_table = جدول قاعدة البيانات "%s" غير صالح: %v -default_keep_email_private.description = قم بتمكين إخفاء عنوان البريد الإلكتروني للمستخدمين الجدد افتراضيًا حتى لا يتم تسريب هذه المعلومات فور التسجيل. +default_keep_email_private.description = أخفِ عناوين البريد الإلكتروني للحسابات الجديدة مبدئيا. env_config_keys = إعدادات بيئية -default_allow_create_organization = اسمح بإنشاء المنظمات بشكل افتراضي +default_allow_create_organization = اسمح بإنشاء المنظمات مبدئيا invalid_app_data_path = مسار بيانات التطبيق غير صالح: %v enable_update_checker_helper = يفحص لإيجاد اصدارات جديدة عن طريق الإتصال بسيرفرات فورجيو. invalid_repo_path = المسار الجزري للمستودع غير صالح: %v @@ -257,17 +250,11 @@ internal_token_failed = فشل توليد الرمز الداخلي: %v no_reply_address = نطاقات البريد الإلكتروني المخفية default_keep_email_private = أخفِ عناوين البريد الإلكتروني مبدئيا admin_name = اسم مستخدم المدير -default_allow_create_organization.description = السماح للمستخدمين الجدد بإنشاء منتديات المجموعة بشكل افتراضي. عند تعطيل هذا الخيار، سيتعين على المسؤول منح إذن لإنشاء منتديات المجموعة للمستخدمين الجدد. +default_allow_create_organization.description = اسمح بحسابات المستخدمين الجديدة بإنشاء المنظمات مبدئيا. password_algorithm = خوارزمية تجزئة كلمة المرور invalid_password_algorithm = خوارزمية بصمة كلمة المرور غير صالحة password_algorithm_helper = اختر خوارزمية بصمة كلمة المرور. تختلف الخوارزميات في متطلباتها وقوتها. خوارزمية argon2 آمنة لكن تتطلب الكثير من الذاكرة ولذلك قد تكون غير ملائمة للأنظمة الصغيرة. -app_slogan = شعار المثيل -app_slogan_helper = أدخل شعار المثيل الخاص بك هنا. اتركه فارغاً لتعطيله. -smtp_from_invalid = عنوان "،بريد الإرسال كـ" غير صالح -allow_only_external_registration = السماح بالتسجيل عبر الخدمات الخارجية فقط -config_location_hint = سيتم حفظ خيارات التهيئة هذه في: - [editor] buttons.list.ordered.tooltip = أضف قائمة مرقمة buttons.bold.tooltip = أضف نصًا عريضًا @@ -284,22 +271,9 @@ buttons.italic.tooltip = أضف نصًا مائلًا buttons.link.tooltip = اضف رابط buttons.disable_monospace_font = عطّل الخط الثابت العرض -buttons.indent.tooltip = تداخل العناصر بنفس المستوى -buttons.unindent.tooltip = ‪عناصر غير متساوية من نفس المستوى -buttons.new_table.tooltip = إضافة جدول -table_modal.header = إضافة جدول -table_modal.placeholder.header = الترويسة -table_modal.placeholder.content = المحتوى -table_modal.label.rows = الصفوف -table_modal.label.columns = الأعمدة -link_modal.header = إضافة رابط -link_modal.url = Url -link_modal.description = الوصف -link_modal.paste_reminder = تلميح: باستخدام عنوان URL في حافظتك، يمكنك اللصق مباشرةً في المحرر لإنشاء رابط. - [aria] navbar = شريط التنقل -footer.software = عن هذه البرمجية +footer.software = عن البرمجية footer.links = روابط footer = الذيل @@ -321,7 +295,7 @@ twofa_disabled = عُطِّل الاستيثاق الثنائي. theme_desc = ستكون هذه السمة المبدئية لك عبر الموقع. new_password = كلمة المرور الجديدة twofa_disable_desc = تعطيل الاستيثاق الثنائي سيجعل حسابك أقل أمانًا. أتريد الاستمرار؟ -manage_themes = الموضوع الافتراضي +manage_themes = اختر السمة المبدئية delete_prompt = هذه العملية ستحذف حسابك إلى الأبد. لا يمكن التراجع عنها بعد ذلك. cancel = ألغ repos_none = ليس لديك أي مستودع. @@ -414,7 +388,7 @@ account = الحساب uploaded_avatar_is_too_big = حجم الملف المرفوع (%d كي‌ب) يتخطى الحجم الأقصى (%d كي‌ب). biography_placeholder = أخبرنا شيئا عن نفسك! (يمكنك استخدام ماركداون) comment_type_group_reference = الإشارات -orgs = المنظمات +orgs = إدارة المنظمات update_profile = حدِّث الملف الشخصي profile = الملف الشخصي comment_type_group_dependency = الاعتماديات @@ -445,7 +419,7 @@ keep_email_private_popup = سيؤدي هذا إلى إخفاء عنوان بري ssh_key_name_used = هناك مفتاح SSH بنفس الاسم موجود بالفعل على حسابك. authorized_oauth2_applications = تطبيقات OAuth2 المأذونة uid = المعرّف الرمزي -manage_openid = عناوين OpenID +manage_openid = إدارة عناوين OpenID webauthn = استيثاق ثنائي (مفاتيح الأمان) comment_type_group_deadline = الموعد النهائي add_key = أضف مفتاح @@ -527,8 +501,6 @@ oauth2_redirect_uris = روابط إعادة التوجيه. نرجو وضع ك remove_account_link = أزل الحساب المربوط remove_account_link_success = أُزيل الحساب المربوط. -quota = كوتا - [org] follow_blocked_user = لا يمكنك إتباع هذه المنظمة لأن هذه المنظمة حظرتك. settings.delete_prompt = ستزال المنظمة إلى الأبد. لا يمكن التراجع عنها بعد ذلك! @@ -696,7 +668,7 @@ issues.unlock.notice_1 = - يستطيع أي مستخدم عندئذٍ أن يع issues.remove_assignee_at = `ألغى تكليفه %s %s` branch.warning_rename_default_branch = إنك تغيّر اسم الفرع المبدئي. trust_model_helper_default = المبدئي: اختر نموذج الثقة المبدئي لهذا الموقع -tag.create_tag = أنشئ الوسم %s +tag.create_tag = أنشئ الوسم %s release.title_empty = لا يمكن ترك العنوان فارغا. tag.create_tag_operation = أنشئ وسمًا issues.remove_request_review = ألغ طلب المراجعة @@ -725,7 +697,7 @@ issues.filter_milestone_all = كل الأهداف issues.unlock.notice_2 = - يمكنك دوما إقفال هذه المسألة من جديد في المستقبل. issues.num_participants_few = %d متحاور release.title = عنوان الإصدار -issues.closed_at = `أغلق هذه المسألة %s` +issues.closed_at = `أغلق هذه المسألة %[2]s` issues.lock.title = إقفال التحاور في هذه المسألة. issues.new.no_label = بلا تصنيف issues.filter_sort.mostforks = الأعلى اشتقاقا @@ -785,7 +757,7 @@ branch.renamed = غُيّر اسم الفرع %s إلى %s. delete_preexisting = احذف الملفات الموجودة سابقا branch.included_desc = هذا الفرع جزء من الفرع المبدئي trust_model_helper_collaborator_committer = مشترك+مودع: ثق بتوقيعات المشتركين التي تطابق المودع -issues.reopened_at = `أعاد فتح هذه المسألة %s` +issues.reopened_at = `أعاد فتح هذه المسألة %[2]s` issues.action_milestone = هدف issues.new.assignees = المكلَّفون release.tag_name_protected = اسم الوسم محمي. @@ -802,7 +774,7 @@ issues.save = احفظ migrate_items_labels = تصنيفات issues.add_assignee_at = `كلّفه %s بها %s` milestones.filter_sort.least_complete = الأقل اكتمالا -branch.create_branch = أنشئ الفرع %s +branch.create_branch = أنشئ الفرع %s issues.remove_self_assignment = `ألغى تكليف نفسه %s` issues.label_edit = عدّل release.download_count = التنزيلات: %s @@ -983,7 +955,7 @@ settings.recent_deliveries = التوصيل الأخيرة projects.new = مشروع جديد file_history = تاريخ editor.directory_is_a_file = اسم المجلد "%s" مستخدم فعلا لاسم ملف في هذا المستودع. -editor.commit_directly_to_this_branch = أودع مباشرةً إلى فرع %[1]s. +editor.commit_directly_to_this_branch = أودع مباشرةً إلى فرع %s. editor.unable_to_upload_files = تعذر رفع الملفات إلى "%s" برسالة الخطأ: %v settings.webhook.payload = المحتوى invisible_runes_header = `يحتوي هذا الملف على محارف يونيكود غير مرئية` @@ -1043,7 +1015,7 @@ commit.revert-header = إرجاع: %s editor.file_already_exists = يوجد فعلا في هذا المستودع ملف باسم "%s". settings.web_hook_name_matrix = متركس editor.filename_cannot_be_empty = لا يمكن ترك اسم الملف فارغا. -editor.add_tmpl = أضف '<%s>' +editor.add_tmpl = أضف '' editor.new_branch_name_desc = اسم الفرع الجديد… release = إصدار editor.delete_this_file = احذف الملف @@ -1128,7 +1100,7 @@ activity.git_stats_pushed_1 = دفع activity.git_stats_pushed_n = دفعوا activity.git_stats_commit_1 = %d إيداع activity.git_stats_commit_n = %d إيداعا -activity.git_stats_push_to_branch = `إلى %s و"` +activity.git_stats_push_to_branch = إلى %s و  activity.git_stats_push_to_all_branches = إلى كل الفروع. activity.git_stats_on_default_branch = في %s، activity.git_stats_file_1 = %d ملف @@ -1138,7 +1110,7 @@ activity.git_stats_files_changed_n = تغيّروا activity.git_stats_additions = وحدثت activity.git_stats_addition_1 = %d إضافة activity.git_stats_addition_n = %d إضافة -activity.git_stats_and_deletions = `و"` +activity.git_stats_and_deletions = و  activity.git_stats_deletion_1 = %d إزالة activity.git_stats_deletion_n = %d إزالة settings.mirror_settings.direction = الاتجاه @@ -1192,7 +1164,7 @@ pulls.status_checking = في انتظار بعض الفحوص pulls.status_checks_failure = بعض الفحوص فشلت pulls.status_checks_success = جميع الفحوص ناجحة pulls.status_checks_warning = بعض الفحوص تعطي تحذيرات -pulls.commit_ref_at = `أشار إلى طلب الدمج من إيداع %s` +pulls.commit_ref_at = `أشار إلى طلب الدمج من إيداع %[2]s` pulls.cmd_instruction_hint = `أظهر شرح استخدام سطر الأوامر.` pulls.cmd_instruction_checkout_title = اسحب pulls.cmd_instruction_checkout_desc = من مستودع مشروعك، اسحب (check out) فرعا جديدا واختبر التغييرات. @@ -1283,8 +1255,8 @@ pulls.status_checks_details = تفاصيل pulls.status_checks_hide_all = أخفِ كل الفحوص pulls.status_checks_show_all = أظهر كل الفحوص pulls.close = أغلق طلب الدمج -pulls.closed_at = `أغلق طلب الدمج %s` -pulls.reopened_at = `أعاد فتح طلب الدمج %s` +pulls.closed_at = `أغلق طلب الدمج %[2]s` +pulls.reopened_at = `أعاد فتح طلب الدمج %[2]s` milestones.title = العنوان milestones.desc = الوصف milestones.edit = عدّل الهدف @@ -1328,11 +1300,11 @@ issues.closed_by_fake = من %[2]s أُغلقت %[1]s issues.num_comments_1 = %d تعليق issues.num_comments = %d تعليقا issues.commented_at = `علّق %s` -issues.commit_ref_at = `أشار إلى هذه المسألة من إيداع %s` -issues.ref_issue_from = `أشار إلى هذه المسألة %[3]s %[1]s` -issues.ref_pull_from = `أشار إلى هذا الطلب %[3]s %[1]s` -issues.ref_closing_from = `أشار إلى طلب دمج %[3]s سيغلق هذه المسألة %[1]s` -issues.ref_reopening_from = `أشار إلى طلب دمج %[3]s سيعيد فتح هذه المسألة %[1]s` +issues.commit_ref_at = `أشار إلى هذه المسألة من إيداع %[2]s` +issues.ref_issue_from = `أشار إلى هذه المسألة %[4]s %[2]s` +issues.ref_pull_from = `أشار إلى هذا الطلب %[4]s %[2]s` +issues.ref_closing_from = `أشار إلى طلب دمج %[4]s سيغلق هذه المسألة %[2]s` +issues.ref_reopening_from = `أشار إلى طلب دمج %[4]s سيعيد فتح هذه المسألة %[2]s` issues.ref_closed_from = `أغلق هذه المسألة %[4]s %[2]s` issues.ref_reopened_from = `أعاد فتح هذه المسألة %[4]s %[2]s` issues.reference_issue.body = المحتوى @@ -1359,7 +1331,7 @@ admin.new_user.text = من فضلك اضغط هنا لإدار admin.new_user.subject = مستخدم جديد: %s سجل حالاً admin.new_user.user_info = معلومات المستخدم activate_account.text_1 = أهلا يا %[1]s، شكرا لك للتسجيل في %[2]s! -register_notify = أهلا بك في فورجيو +register_notify_prev9 = أهلا بك في فورجيو activate_account = نرجو تفعيل حسابك activate_account.title = يا %s، نرجو منك تفعيل حسابك issue.x_mentioned_you = ذكرك @%s: @@ -1412,25 +1384,9 @@ issue.action.ready_for_review = @%[1]s علّم هذا الطلب للس issue_assigned.pull = @%[1]s عيّنك إلى طلب سحب %[2]s في مستودع %[3]s. issue.action.review_dismissed = @%[1]s أستبعد آخر مراجعة من %[2]s لهذا الطلب للسحب. -password_change.subject = تم تغيير كلمة مرورك -password_change.text_1 = تم تغيير كلمة مرور حسابك للتو. -primary_mail_change.subject = تم تغيير البريد الأساسي الخاص بك -primary_mail_change.text_1 = تم تغيير البريد الإلكتروني الأساسي لحسابك إلى %[1]s. هذا يعني أن عنوان البريد الإلكتروني هذا لن يتلقى إشعارات البريد لحسابك بعد الآن. -totp_disabled.subject = تم تعطيل TOTP -totp_disabled.text_1 = تم تعطيل كلمة المرور لمرة واحدة المستندة إلى الوقت (TOTP) على حسابك للتو. -totp_disabled.no_2fa = لم تعد هناك طرق أُخرى للمصادقة الثنائية (2FA) قيد التهيئة عد الآن ، أي أنه لم يعد من الضروري تسجيل الدخول إلى حسابك باستخدام المصادقة الثنائية (2FA). -removed_security_key.subject = تمت إزالة مفتاح الأمان -removed_security_key.text_1 = تم إزالة مفتاح الأمان ”%[1] s“ للتو من حسابك. -removed_security_key.no_2fa = لم تعد هناك طرق أخرى للمصادقة الثنائية (2FA) قيد التهيئة بعد الآن، أي لم يعد من الضروري تسجيل الدخول إلى حسابك باستخدام المصادقة الثنائية (2FA). -account_security_caution.text_1 = إذا كان هذا أنت، فيمكنك تجاهل هذا البريد بأمان. -account_security_caution.text_2 = إذا لم تكن أنت، فهذا يعني أن حسابك مخترق. يرجى الاتصال بمسؤولي هذا الموقع. -totp_enrolled.subject = لقد قمت بتشيط TOTP كطريقة 2FA -totp_enrolled.text_1.no_webauthn = لقد قمت للتو بتمكين TOTP لحسابك. هذا يعني أنه بالنسبة لجميع عمليات تسجيل الدخول المستقبلية إلى حسابك، يجب عليك استخدام TOTP كطريقة للمصادقة الثنائية. -totp_enrolled.text_1.has_webauthn = لقد قمت للتو بتمكين TOTP لحسابك. هذا يعني أنه بالنسبة لجميع عمليات تسجيل الدخول المستقبلية إلى حسابك، يمكنك استخدام TOTP كطريقة للمصادقة الثنائية ، أو استخدام أي من مفاتيح الأمان الخاصة بك. - [error] not_found = تعذر العثور على الهدف. -report_message = إن كنت متيقِّنًا أن هذه علة في فورجيو، رجاءً ابحث في كودبيرج أو افتح مسأله جديدة إذا لزم الأمر. +report_message = إن كنت متيقِّنًا أن هذه علة في فورجيو، رجاءً ابحث في كودبيرج أو افتح مسأله جديدة إذا لزم الأمر. network_error = خطأ في الشبكة invalid_csrf = طلب سيئ: رمز CSRF غير صالح occurred = حدث خطأ @@ -1441,10 +1397,10 @@ server_internal = خطأ داخلي في الخادم install = سهلة التثبيت lightweight = خفيف license = مفتوح المصدر -platform_desc = فورجيو يعمل في أي مكان جو يعمل على ويندوز، ماك، لينكس، ARM، إلخ. اختر ما تحب! -install_desc = ببساطة شغل الملف الملائم لمنصتك، أو أستخدم دوكر، او نزله كحزمة. +platform_desc = فورجيو يعمل في أي مكان جو يعمل على ويندوز، ماك، لينكس، ARM، إلخ. اختر ما تحب! +install_desc = ببساطة شغل الملف الملائم لمنصتك، أو أستخدم دوكر، او نزله كحزمة. lightweight_desc = فورجيو لديه متطلبات منخفضة ويمكن أن يعمل على أجهزة Raspberry Pi الغير مكلفة. احفظ موارد جهازك! -license_desc = احصل على فورجيو! إنضم لنا عن طريق المساهمة لتحسين المشروع. لا تكن خجولاً للمساهمة! +license_desc = احصل على فورجيو! إنضم لنا عن طريق المساهمة لتحسين المشروع. لا تكن خجولاً للمساهمة! app_desc = خدمة جِت غير مؤلمة مستضافة ذاتياً platform = متعدد المنصات @@ -1462,7 +1418,7 @@ joined_on = انضم في %s user_bio = السيرة الذاتية repositories = المستودعات activity = النشاط العام -projects = المشاريع +projects = مشاريع unfollow = إلغِ المتابعة settings = إعدادات المستخدم following_few = %d يتابع @@ -1470,7 +1426,7 @@ follow = تابع followers_few = %d متابعين form.name_reserved = اسم المستخدم "%s" محجوز. email_visibility.limited = عنوان بريدك الإلكتروني ظاهر لكل المستخدمين المُستَوثَقين -code = الكود +code = البرمجية overview = نظرة عامة watched = المستودعات المشاهدة disabled_public_activity = هذا المستخدم عطّل الظهور العام للنشاط. @@ -1480,18 +1436,6 @@ starred = المستودعات المميّزة بنجمة form.name_chars_not_allowed = اسم المستخدم "%s" يحتوي على رموز غير صالحة. form.name_pattern_not_allowed = النمط "s%" غير مسموح به في إسم المستخدم. -followers.title.one = متابِع -followers.title.few = متابعين -following.title.one = متابعة -following.title.few = متابعة -followers_one = %d متابِع -following_one = %d يُتابع -public_activity.visibility_hint.self_public = نشاطك مرئي للجميع، باستثناء التفاعلات في المساحات الخاصة. اضبط الإعدادات. -public_activity.visibility_hint.admin_public = هذا النشاط مرئي للجميع، ولكن بصفتك مسؤولاً يمكنك أيضًا رؤية التفاعلات في المساحات الخاصة. -public_activity.visibility_hint.self_private = نشاطك مرئي لك ولسُعاة المثيل فقط. تعديل الإعدادات. -public_activity.visibility_hint.admin_private = هذا النشاط مرئي لك لأنك مسؤول، ولكن المستخدم يريد أن يظل خاصاً. -public_activity.visibility_hint.self_private_profile = نشاطك مرئي لك ولسُعاة المثيل فقط لأن ملفك الشخصي خاص. تعديل الإعدادات. - [auth] change_unconfirmed_email_error = تعذر تغيير البريد الإلكتروني: %v change_unconfirmed_email_summary = تغيير البريد الإلكتروني الذي يُرسل التفعيل له. @@ -1511,11 +1455,11 @@ active_your_account = فعّل حسابك register_helper_msg = هل لديك حساب بالفعل؟ سجل الدخول! manual_activation_only = تواصل مع مدير موقعك لإكمال التفعيل. must_change_password = حدّث كلمة المرور الخاصة بك -send_reset_mail = أرسل بريد الاستعادة +send_reset_mail = أرسل رسالة استعادة حساب resend_mail = اضغط هنا لإعادة إرسالة رسالة تفعيل حسابك has_unconfirmed_mail = أهلا يا %s، لديك عنوان بريد إلكتروني غير مؤكَّد (%s). إن لم تستلم رسالة تأكيد أو تريد إرسال واحدة جديدة، فنرجو الضغط على الزر الذي بالأسفل. email_not_associate = عنوان البريد هذا غير مرتبط بأي حساب. -reset_password = استعادة الحساب +reset_password = استعادة حساب oauth_signin_tab = أربط بحساب موجود invalid_password = كلمة المرور الخاصة بك لا تطابق كلمة المرور التي استخدمت لتسجيل الحساب. oauth_signin_title = سجّل الدخول لتأذن للحساب المربوط @@ -1536,13 +1480,13 @@ reset_password_wrong_user = أنت مُسجل كـ %s، لكن رابط أعاد openid_connect_title = اتصل بحساب موجود confirmation_mail_sent_prompt = تم إرسال بريد تأكيد جديد إلى %s. يرجى التأكد من صندوق بريدك في خلال %s حتى تكتمل عملية التسجيل. إذا كان عنوان البريد خاطئ، يمكنك تسجيل الدخول وطلب بريد تأكيد جديد يُرسل إلى عنوان آخر. scratch_code = رمز الخدش -invalid_code_forgot_password = رمز تأكيدك غير صحيح أو انتهت صلاحيته. اضغط هنا للإعادة. +invalid_code_forgot_password = رمز تأكيدك غير صحيح أو انتهى اضغط هنا للإعادة. openid_register_title = أنشئ حسابًا جديدًا verify = تحقق twofa_scratch_used = لقد استخدمت رمز الخدش الخاص بك. لقد تم إعادة توجيهك إلى إعدادات المصادقة الثنائية حتى يمكنك إزالة تسجيل جهازك أو توليد رمز خدش جديد. oauth_signup_submit = أكمل الحساب oauth.signin.error = كان هناك خطأ في تجهيز طلب الإذن إذا استمر هذا الخطأ، يرجى الاتصال بالمدير. -invalid_code = رمز تأكيدك غير صحيح أو انتهت صلاحيته. +invalid_code = رمز تأكيدك غير صحيح أو انتهى. oauth_signup_title = أكمل حساب جديد resent_limit_prompt = لقد طلبت بالفعل بريداً إلكترونياً للتفعيل مؤخراً من فضلك انتظر 3 دقائق وحاول مرة أخرى. reset_password_mail_sent_prompt = تم إرسال بريد تأكيد جديد إلى %s. يرجى التأكد من صندوق بريدك في خلال %s حتى تكتمل عملية استعادة الحساب. @@ -1555,7 +1499,7 @@ prohibit_login = تسجيل الدخول ممنوع prohibit_login_desc = حسابك ممنوع من تسجيل الدخول، يرجى التواصل مع مدير الموقع. disable_forgot_password_mail_admin = استرداد الحساب متاح فقط عند إعداد البريد الإلكتروني. يُرجى إعداد البريد الإلكتروني لتفعيل استرداد الحساب. password_pwned_err = تعذر الوصول إلى HaveIBeenPwned -password_pwned = الكلمة المرور المُختارة هي على قائمة كلمات مرور مسروقة تم كشفها في تسريبات عامة للبيانات. يُرجى المحاولة مرة أخرى بكلمة مرور أخرى، وضع في اعتبارك تغيير تلك الكلمة في الأماكن الأخرى. +password_pwned = الكلمة المرور المُختارة هي على قائمة كلمات مرور مسروقة تم كشفها في تسريبات عامة للبيانات. يُرجى المحاولة مرة أخرى بكلمة مرور أخرى، وضع في اعتبارك تغيير تلك الكلمة في الأماكن الأخرى. authorization_failed = فشل الإذن authorize_redirect_notice = ستتم إعادة توجيهك إلى %s إذا أذنت للتطبيق. authorize_application = ائذن للتطبيق @@ -1567,14 +1511,6 @@ remember_me = تذكر هذا الجهاز remember_me.compromised = رمز الاحتفاظ بتسجيل الدخول لم يعد صالحا، مما قد يعني اختراق الحساب. نرجو مراجعة حسابك لرؤية أي نشاط غير مألوف. authorization_failed_desc = فشل التفويض لأننا اكتشفنا طلبًا غير صالح. يرجى الاتصال بمشرف التطبيق الذي حاولت ترخيصه. -hint_login = لديك حساب بالفعل؟ سجّل الدخول الآن! -hint_register = يلزمك حساب ؟ سجِّل الآن. -sign_up_button = سجِّل الآن. -unauthorized_credentials = بيانات الاعتماد غير صحيحة أو انتهت صلاحيتها. أعد محاولة تنفيذ الأمر أو راجع %s لمزيد من المعلومات -use_onetime_code = استخدم رمزًا لمرة واحدة -back_to_sign_in = العودة إلى تسجيل الدخول -sign_in_openid = المتابعة باستخدام OpenID - [packages] rpm.repository.multiple_groups = هذه الحزمة متوفرة في مجموعات متعددة. rpm.repository.architectures = بنيات @@ -1618,10 +1554,6 @@ number_of_contributions_in_the_last_12_months = %s مساهم في آخر 12 ش contributions_zero = بلا مساهمات more = أكثر -contributions_format = {contributions} مساهمة في {day} {month} {year} -contributions_one = المساهمة -contributions_few = المساهمات - [admin] self_check.database_fix_mysql = لمستخدمين ميسكول/ماريا دي بي، يمكنك استخدام أمر "forgejo doctor convert" لإصلاح مشاكل التجمّع، أو يمكنك أيضاً إصلاح المشكلة عن طريق تعديل السيكول يدوياً. self_check.database_collation_mismatch = توقع قاعدة البيانات لتستعمل تجميع: %s @@ -1772,7 +1704,7 @@ enterred_invalid_org_name = اسم المنظمة التي أدخلته خطأ. lang_select_error = اختر لغة من القائمة. alpha_dash_error = ` لا يجب أن يحتوي إلا على الحروف الإنجليزية والأرقام والشرطة ("-") والشرطة السفلية ("_").` alpha_dash_dot_error = ` لا يجب أن يحتوي إلا على الحروف الإنجليزية والأرقام والشرطة ("-") والشرطة السفلية ("_") والنقطة (".").` -repo_name_been_taken = اسم المستودع مستخدم بالفعل. +repo_name_been_taken = اسم المستودع مستعمل بالفعل. Email = البريد الإلكتروني auth_failed = فشل الاستيثاق: %v email_error = ` ليس عنوان بريد إلكتروني صالح.` @@ -1792,10 +1724,10 @@ still_has_org = "حسابك عضو في منظمة أو أكثر؛ غادرهم repository_files_already_exist.adopt_or_delete = الملفات موجودة بالفعل لهذا المستودع. إما اعتمادها أو حذفها. repository_files_already_exist.delete = الملفات موجودة بالفعل لهذا المستودع. يجب عليك حذفها. repository_files_already_exist.adopt = الملفات موجودة بالفعل لهذا المستودع ويمكن اعتمادها فقط. -repository_files_already_exist = الملفات موجودة بالفعل لهذا المستودع. اتصل بمدير النظام. +repository_files_already_exist = الملفات موجودة بالفعل لهذا المستودع. تواصل مع مدير النظام. TeamName = اسم الفريق username_has_not_been_changed = لم يتم تغيير اسم المستخدم -username_change_not_local_user = المستخدمين غير المحليين غير مسموح لهم بتغيير أسمائهم. +username_change_not_local_user = المستخدمين غير المحليين غير مسموح لهم بتغيير أسماؤهم. captcha_incorrect = الكابتشا خاطئة. AdminEmail = عنوان البريد الإلكتروني للمدير team_no_units_error = اسمح بالوصول إلى قسم واحد على الأقل في المستودعات. @@ -1823,24 +1755,6 @@ CommitChoice = إختيار الإداع regex_pattern_error = ` نمط التعبير النمطي غير صالح: %s.` username_error = ` يُمكنه أن يحتوي على حروف إنجليزية وأرقام وشرطة ("-") وشرطة سفلية ("_") و نقطة (".") فقط. ويمكنه ان يبدأ وينتهي بحرف او برقم.` -FullName = الاسم الكامل -Description = الوصف -Pronouns = الضمائر -Biography = النبذة -Website = موقع الويب -Location = الموقع -To = اسم الفرع -AccessToken = رمز الوصول -invalid_group_team_map_error = ` التعيين غير صالح: %s ` -username_claiming_cooldown = لا يمكن المطالبة باسم المستخدم، لأن فترة تباطؤه لم تنتهِ بعد. يمكن المطالبة به عند %[1]s. -repository_force_private = وضع الخاص الإجباري مفعّل: لا يمكن تحويل المستودعات الخاصة إلى عامة. -visit_rate_limit = تناولت الزيارة عن بُعد الحد من معدلها. -email_domain_is_not_allowed = نطاق البريد الإلكتروني للمستخدم %s يتعارض مع قائمة النطاقات المسموحة ، أو الممنوعة. يرجى التأكد من إدخال عنوان البريد الإلكتروني بشكل صحيح. -unset_password = المستخدم المسجل لم يقم بتعيين كلمة مرور. -unsupported_login_type = نوع تسجيل الدخول غير مدعوم لحذف الحساب. -invalid_ssh_principal = أصل غير صالح: %s -required_prefix = المُدخل يجب أن يبدأ مع "%s" - [home] filter = تصفيات أخرى show_archived = مؤرشف @@ -1887,11 +1801,6 @@ relevant_repositories_tooltip = تم أخفاء المستودعات التي ه relevant_repositories = يتم اظهار المستودعات المتعلقة فقط. أظهر النتائج غير المصفاة. code_last_indexed_at = فُهرس آخر مرة %s -stars_one = %d نجمة -stars_few = %d نجوم -forks_one = %d نسخة -forks_few = %d نُسَخ - [actions] variables.none = لا توجد متغيرات بعد. variables.deletion = أزل المتغير @@ -2062,30 +1971,15 @@ component_failed_to_load = حدث خطأ غير متوقع. [search] -org_kind = بحث في المنظمات… +org_kind = بحث في المنظمات... code_search_unavailable = البحث في الكود غير متوفر حاليًا. يرجى الاتصال بمدير الموقع. -search = البحث… +search = ابحث... type_tooltip = نوع البحث fuzzy = أجعد fuzzy_tooltip = قم بتضمين النتائج التي تتطابق أيضًا مع مصطلح البحث بشكل وثيق match = تتناسب match_tooltip = قم بتضمين النتائج التي تطابق مصطلح البحث المحدد فقط -repo_kind = بحث في المستودعات… -user_kind = بحث عن المستخدمين… -team_kind = بحث عن الفرق… -code_kind = بحث ضمن الكود… -project_kind = البحث ضمن المشاريع… -branch_kind = البحث ضمن الفروع… -no_results = لا توجد نتائج مطابقة. -issue_kind = البحث ضمن الأعطال… -pull_kind = البحث ضمن طلبات السحب… -keyword_search_unavailable = البحث من خلال الكلمات المفتاحية ليس متوفر حالياً. رجاءاً تواصل مع مشرف الموقع. -union = مطابقة عامة -union_tooltip = عرض النتائج التي تطابق أي من الكلمات المفتاحية المفصولة بمسافات -exact = مطابق -exact_tooltip = عرض النتائج التي تطابق مصطلح البحث بالضبط فقط -regexp = RegExp -regexp_tooltip = تعامل مع عبارة البحث على أنها تعبير نمطي -package_kind = البحث ضمن الحزم… -commit_kind = البحث ضمن الإيداعات… -runner_kind = البحث ضمن المشغِّلات… +repo_kind = بحث في المستودعات... +user_kind = بحث عن المستخدمين... +team_kind = بحث عن الفرق ... +code_kind = بحث في الكود... \ No newline at end of file diff --git a/options/locale/locale_be.ini b/options/locale/locale_be.ini index fe04dadc3e..f9d8e738c3 100644 --- a/options/locale/locale_be.ini +++ b/options/locale/locale_be.ini @@ -1,3 +1,6 @@ + + + [common] dashboard = Панэль кіравання explore = Агляд diff --git a/options/locale/locale_bg.ini b/options/locale/locale_bg.ini index 35e33f4430..4ee716c037 100644 --- a/options/locale/locale_bg.ini +++ b/options/locale/locale_bg.ini @@ -1,148 +1,5 @@ -[common] -language = Език -cancel = Отказ -captcha = CAPTCHA -create_new = Създаване… -preview = Преглеждане -disabled = Изключено -licenses = Лицензи -sign_in = Вход -copy_content = Копиране на съдържанието -user_profile_and_more = Профил и настройки… -view = Преглед -your_settings = Настройки -mirrors = Огледални -explore = Разглеждане -write = Писане -twofa = Двуфакторно удостоверяване -version = Версия -copy_success = Копирано! -help = Помощ -loading = Зареждане… -name = Име -sign_in_or = или -edit = Редактиране -concept_code_repository = Хранилище -page = Страница -forks = Разклонения -concept_user_organization = Организация -link_account = Свързване на акаунт -your_profile = Профил -sign_out = Изход -settings = Настройки -locked = Заключено -error = Грешка -dashboard = Табло -logo = Лого -toc = Съдържание -copy_url = Копиране на URL -new_mirror = Ново огледално -re_type = Потвърдете паролата -copy = Копиране -enabled = Включено -new_org = Нова организация -milestones = Етапи -rss_feed = RSS емисия -never = Никога -new_project = Нов проект -your_starred = Отбелязани -value = Стойност -sources = Източници -notifications = Известия -repository = Хранилище -add_all = Добавяне на всичко -new_project_column = Нова колона -add = Добавяне -organization = Организация -new_migrate = Нова миграция -save = Запазване -sign_in_with_provider = Влизане с %s -ok = Добре -manage_org = Управление на организациите -new_repo = Ново хранилище -register = Регистрация -mirror = Огледално -username = Потребителско име -password = Парола -template = Шаблон -signed_in_as = Влезли сте като -sign_up = Регистриране -enable_javascript = Този сайт изисква JavaScript. -home = Начало -email = Адрес за ел. поща -issues = Задачи -retry = Повторен опит -remove = Премахване -admin_panel = Управление на сайта -account_settings = Настройки на акаунта -powered_by = Осъществено от %s -pull_requests = Заявки за сливане -collaborative = Съвместни -all = Всички -activities = Дейности -new_fork = Ново разклонение на хранилище -unpin = Откачване -pin = Закачване -filter = Филтър -filter.clear = Изчистване на филтрите -filter.is_archived = Архивирани -filter.not_archived = Не архивирани -filter.is_fork = Разклонения -filter.public = Публични -filter.not_fork = Не разклонения -filter.is_template = Шаблони -filter.not_template = Не шаблони -filter.private = Частни -filter.is_mirror = Огледални -filter.not_mirror = Не огледални -copy_hash = Копиране на контролната сума -artifacts = Артефакти -show_log_seconds = Показване на секундите -remove_all = Премахване на всичко -test = Проба -remove_label_str = Премахване на елемента „%s“ -copy_branch = Копиране на името на клона -error404 = Страницата, която се опитвате да отворите, или не съществува, или е премахната, или не сте упълномощени да я видите. -new_repo.link = Ново хранилище -new_migrate.title = Нова миграция -new_repo.title = Ново хранилище -new_org.title = Нова организация -new_migrate.link = Нова миграция -new_org.link = Нова организация -copy_generic = Копиране в клипборда -copy_error = Неуспешно копиране -copy_path = Копиране на пътя -toggle_menu = Превключване на менюто -confirm_delete_artifact = Сигурни ли сте, че искате да изтриете артефакта „%s“? -more_items = Още елементи -twofa_scratch = Резервен код за двуфакторно удостоверяване -webauthn_use_twofa = Използвайте двуфакторен код от телефона си -webauthn_error_insecure = WebAuthn поддържа само сигурни връзки. За тестване през HTTP можете да използвате произход „localhost“ или „127.0.0.1“ -error413 = Изчерпали сте квотата си. -go_back = Връщане -invalid_data = Невалидни данни: %v -archived = Архивирано -concept_system_global = Глобално -concept_user_individual = Индивидуално -show_full_screen = Показване на цял екран -show_timestamps = Показване на времеви отпечатъци -rerun = Повторно изпълнение -copy_type_unsupported = Този тип файл не може да бъде копиран -webauthn_error_unknown = Възникна неизвестна грешка. Моля, опитайте отново. -webauthn_error_unable_to_process = Сървърът не можа да обработи заявката ви. -webauthn_error_empty = Трябва да зададете име за този ключ. -webauthn_error_timeout = Времето за изчакване изтече преди ключът ви да бъде прочетен. Моля, презаредете страницата и опитайте отново. -return_to_forgejo = Връщане към Forgejo -unknown = Неизвестно -confirm_delete_selected = Потвърждавате ли изтриването на всички избрани елементи? -webauthn_insert_key = Поставете вашия ключ за сигурност -webauthn_press_button = Моля, натиснете бутона на вашия ключ за сигурност… -webauthn_sign_in = Натиснете бутона на вашия ключ за сигурност. Ако ключът ви за сигурност няма бутон, поставете го отново. -webauthn_error = Неуспешно прочитане на вашия ключ за сигурност. -webauthn_unsupported_browser = Вашият браузър в момента не поддържа WebAuthn. -webauthn_error_duplicated = Ключът за сигурност не е разрешен за тази заявка. Моля, уверете се, че ключът не е вече регистриран. -tracked_time_summary = Обобщение на проследеното време въз основа на филтрите в списъка със задачи + [settings] ui = Тема @@ -188,10 +45,10 @@ account = Акаунт update_avatar = Обновяване на профилната снимка ssh_gpg_keys = SSH / GPG ключове comment_type_group_milestone = Етап -manage_emails = Управление на адресите за ел. поща +manage_emails = Управление на адресите на ел. поща permission_read = Четене update_password = Обновяване на паролата -biography_placeholder = Разкажете на другите малко за себе си! (Можете да използвате Маркдаун) +biography_placeholder = Разкажете ни малко за себе си! (Можете да използвате Markdown) orgs = Организации continue = Продължаване blocked_users = Блокирани потребители @@ -207,14 +64,14 @@ permission_no_access = Без достъп ssh_key_deletion_success = SSH ключът е премахнат. comment_type_group_project = Проект update_language_success = Езикът е обновен. -add_key_success = SSH ключът „%s“ е добавен. -add_gpg_key_success = GPG ключът „%s“ е добавен. +add_key_success = SSH ключът "%s" е добавен. +add_gpg_key_success = GPG ключът "%s" е добавен. user_unblock_success = Потребителят е отблокиран успешно. user_block_success = Потребителят е блокиран успешно. update_profile_success = Профилът ви е обновен. update_user_avatar_success = Профилната снимка на потребителя е обновена. remove_oauth2_application_success = Приложението е изтрито. -email_deletion_success = Адресът за ел. поща е премахнат. +email_deletion_success = Адресът на ел. поща е премахнат. update_avatar_success = Профилната ви снимка е обновена. change_username = Потребителското ви име е променено. comment_type_group_assignee = Изпълнител @@ -222,25 +79,25 @@ enable_custom_avatar = Използване на персонализирана requires_activation = Изисква активиране activated = Активиран primary = Основен -email_deletion = Премахване на адреса за ел. поща -add_new_email = Добавяне на нов адрес за ел. поща -add_email = Добавяне на адрес за ел. поща -key_content_gpg_placeholder = Започва с „-----BEGIN PGP PUBLIC KEY BLOCK-----“ +email_deletion = Премахване на адреса на ел. поща +add_new_email = Добавяне на нов адрес на ел. поща +add_email = Добавяне на адрес на ел. поща +key_content_gpg_placeholder = Започва с "-----BEGIN PGP PUBLIC KEY BLOCK-----" comment_type_group_title = Заглавие comment_type_group_label = Етикет -change_username_prompt = Бележка: Промяната на потребителското ви име променя също URL на вашия акаунт. -update_language_not_found = Езикът „%s“ не е наличен. +change_username_prompt = Забележка: Промяната на потребителското ви име променя също URL на вашия акаунт. +update_language_not_found = Езикът "%s" не е наличен. keep_activity_private_popup = Вашата дейност ще бъде видима само за вас и администраторите на сайта uploaded_avatar_not_a_image = Каченият файл не е изображение. uploaded_avatar_is_too_big = Размерът на качения файл (%d KiB) надвишава максималния размер (%d KiB). -change_password_success = Паролата ви е обновена. Отсега нататък използвайте новата си парола, за да влезете. +change_password_success = Паролата ви е обновена. Влизайте с новата си парола от сега нататък. manage_themes = Тема по подразбиране manage_openid = OpenID адреси primary_email = Да е основен -keep_email_private = Скриване на адреса за ел. поща +keep_email_private = Скриване на адреса на ел. поща theme_update_error = Избраната тема не съществува. theme_update_success = Темата ви е обновена. -key_content_ssh_placeholder = Започва с „ssh-ed25519“, „ssh-rsa“, „ecdsa-sha2-nistp256“, „ecdsa-sha2-nistp384“, „ecdsa-sha2-nistp521“, „sk-ecdsa-sha2-nistp256@openssh.com“, или „sk-ssh-ed25519@openssh.com“ +key_content_ssh_placeholder = Започва с "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com", или "sk-ssh-ed25519@openssh.com" hide_openid = Скриване от профила key_content = Съдържание ssh_key_deletion = Премахване на SSH ключ @@ -252,13 +109,13 @@ visibility.public = Публична visibility.limited = Ограничена visibility.private = Частна location_placeholder = Споделете приблизителното си местоположение с другите -key_signature_gpg_placeholder = Започва с „-----BEGIN PGP SIGNATURE-----“ -key_signature_ssh_placeholder = Започва с „-----BEGIN SSH SIGNATURE-----“ +key_signature_gpg_placeholder = Започва с "-----BEGIN PGP SIGNATURE-----" +key_signature_ssh_placeholder = Започва с "-----BEGIN SSH SIGNATURE-----" saved_successfully = Настройките бяха запазени успешно. no_activity = Няма скорошна дейност -theme_desc = Тази тема ще се използва за уеб интерфейса, когато сте влезли. +theme_desc = Това ще бъде вашата тема по подразбиране в целия сайт. keep_activity_private = Скриване на дейността от профилната страница -lookup_avatar_by_mail = Търсене на профилна снимка по адреса за ел. поща +lookup_avatar_by_mail = Търсене на профилна снимка по адреса на ел. поща password_incorrect = Текущата парола е неправилна. change_username_redirect_prompt = Старото потребителско име ще се пренасочва, докато някой не го вземе. principal_content = Съдържание @@ -267,7 +124,7 @@ twofa_disabled = Двуфакторното удостоверяване е из orgs_none = Не сте участник в никакви организации. repos_none = Не притежавате никакви хранилища. blocked_users_none = Няма блокирани потребители. -profile_desc = Вашият профил +profile_desc = Контролирайте как вашият профил се показва на другите потребители. Вашият основен адрес на ел. поща ще се използва за известия, възстановяване на паролата и уеб базирани Git операции. permission_write = Четене и писане twofa_disable = Изключване на двуфакторното удостоверяване twofa_enroll = Включване на двуфакторно удостоверяване @@ -277,125 +134,11 @@ delete_prompt = Тази операция ще изтрие перманентн email_notifications.disable = Изключване на известията по ел. поща delete_account = Изтриване на акаунта ви confirm_delete_account = Потвърждаване на изтриването -email_notifications.onmention = Ел. писмо само при споменаване +email_notifications.onmention = Ел. поща само при споменаване pronouns_unspecified = Непосочени pronouns = Местоимения gpg_token_code = echo "%s" | gpg -a --default-key %s --detach-sig language.title = Език по подразбиране -language.localization_project = Помогнете ни да преведем Forgejo на вашия език! Научете повече. -language.description = Този език ще бъде запазен във вашия акаунт и ще се използва като език по подразбиране, след като влезете. -pronouns_custom = Персонализирани -visibility.limited_tooltip = Видим само за влезли потребители -pronouns_custom_label = Персонализирани местоимения -comment_type_group_review_request = Искане за рецензия -ssh_key_been_used = Този SSH ключ вече е добавен към сървъра. -create_oauth2_application = Създаване на ново OAuth2 приложение -update_oauth2_application_success = Успешно обновихте OAuth2 приложението. -authorized_oauth2_applications = Упълномощени OAuth2 приложения -manage_account_links = Свързани акаунти -revoke_oauth2_grant = Отнемане на достъпа -added_on = Добавен на %s -comment_type_group_dependency = Зависимост -update_hints_success = Подсказките са обновени. -manage_oauth2_applications = Управление на OAuth2 приложения -gpg_key_id_used = Вече съществува публичен GPG ключ със същото ID. -oauth2_applications_desc = OAuth2 приложенията позволяват на вашето приложение от трета страна да удостоверява сигурно потребители в тази инстанция на Forgejo. -blocked_since = Блокиран от %s -hidden_comment_types.ref_tooltip = Коментари, в които тази задача е спомената от друга задача/подаване/… -create_oauth2_application_success = Успешно създадохте ново OAuth2 приложение. -quota.applies_to_org = Следните правила за квота се прилагат за тази организация -keep_activity_private.description = Вашата публична дейност ще бъде видима само за вас и администраторите на инстанцията. -ssh_helper = Нуждаете се от помощ? Разгледайте ръководството за създаване на собствени SSH ключове или за решаване на често срещани проблеми, които може да срещнете при използване на SSH. -twofa_desc = За да защитите акаунта си от кражба на парола, можете да използвате смартфон или друго устройство за получаване на еднократни пароли, базирани на време („TOTP“). -scan_this_image = Сканирайте това изображение с вашето приложение за удостоверяване: -quota.rule.exceeded.helper = Общият размер на обектите за това правило надвиши квотата. -password_change_disabled = Нелокални потребители не могат да обновяват паролата си през уеб интерфейса на Forgejo. -twofa_disable_note = Можете да изключите двуфакторното удостоверяване, ако е необходимо. -hooks.desc = Добавете уеб-куки, които ще се задействат за всички хранилища, които притежавате. -delete_account_desc = Сигурни ли сте, че искате да изтриете перманентно този потребителски акаунт? -last_used = Последно използван на -revoke_oauth2_grant_description = Отнемането на достъпа за това приложение от трета страна ще му попречи да има достъп до вашите данни. Сигурни ли сте? -password_username_disabled = Нелокални потребители не могат да променят потребителското си име. Моля, свържете се с администратора на сайта за повече подробности. -change_username_redirect_prompt.with_cooldown.one = Старото потребителско име ще бъде достъпно за всички след период на изчакване от %[1]d ден. Все още можете да си върнете старото потребителско име по време на периода на изчакване. -change_username_redirect_prompt.with_cooldown.few = Старото потребителско име ще бъде достъпно за всички след период на изчакване от %[1]d дни. Все още можете да си върнете старото потребителско име по време на периода на изчакване. -generate_token_name_duplicate = %s вече е използвано като име на приложение. Моля, използвайте ново. -quota.rule.exceeded = Надвишена -repo_and_org_access = Достъп до хранилища и организации -permissions_public_only = Само публични -permissions_list = Разрешения: -edit_oauth2_application = Редактиране на OAuth2 приложение -remove_oauth2_application = Премахване на OAuth2 приложение -twofa_recovery_tip = Ако загубите устройството си, ще можете да използвате ключ за еднократно възстановяване, за да си върнете достъпа до акаунта. -visibility.private_tooltip = Видим само за участници в организации, в които участвате -quota.applies_to_user = Следните правила за квота се прилагат за вашия акаунт -quota.rule.no_limit = Неограничена -hints = Подсказки -comment_type_group_issue_ref = Препратка към задача -activate_email = Изпращане на активация -ssh_disabled = SSH е изключен -twofa_disable_desc = Изключването на двуфакторното удостоверяване ще направи акаунта ви по-малко сигурен. Продължаване? -keep_pronouns_private = Показване на местоименията само на удостоверени потребители -keep_pronouns_private.description = Това ще скрие вашите местоимения от посетители, които не са влезли в системата. -gpg_helper = Нуждаете се от помощ? Разгледайте ръководството относно GPG. -valid_until_date = Валиден до %s -ssh_externally_managed = Този SSH ключ се управлява външно за този потребител -regenerate_scratch_token_desc = Ако сте загубили ключа си за възстановяване или вече сте го използвали, за да влезете, можете да го нулирате тук. -create_oauth2_application_button = Създаване на приложение -revoke_oauth2_grant_success = Достъпът е отнет успешно. -comment_type_group_deadline = Краен срок -comment_type_group_time_tracking = Проследяване на времето -activations_pending = Чакащи активации -valid_forever = Валиден завинаги -key_state_desc = Този ключ е използван през последните 7 дни -revoke_key = Отнемане -delete_account_title = Изтриване на потребителския акаунт -update_hints = Обновяване на подсказките -permissions_access_all = Всички (публични, частни и ограничени) -oauth2_application_name = Име на приложението -visibility.public_tooltip = Видим за всички -user_block_yourself = Не можете да блокирате себе си. -hidden_comment_types.issue_ref_tooltip = Коментари, в които потребителят променя клона/маркера, свързан със задачата -comment_type_group_reference = Препратка -comment_type_group_branch = Клон -comment_type_group_pull_request_push = Добавени подавания -quota = Квота -webauthn_delete_key = Премахване на ключ за сигурност -webauthn_register_key = Добавяне на ключ за сигурност -webauthn_nickname = Прякор -webauthn_delete_key_desc = Ако премахнете ключ за сигурност, вече няма да можете да влизате с него. Продължаване? -additional_repo_units_hint = Предлагане за включване на допълнителни елементи на хранилището -twofa_is_enrolled = Вашият акаунт в момента е включен в двуфакторно удостоверяване. -twofa_not_enrolled = Вашият акаунт в момента не е включен в двуфакторно удостоверяване. -webauthn_key_loss_warning = Ако загубите ключовете си за сигурност, ще загубите достъп до акаунта си. -email_desc = Вашият основен адрес за ел. поща ще се използва за известия, възстановяване на парола и, при условие че не е скрит, за уеб-базирани Git операции. -email_preference_set_success = Предпочитанията за ел. поща са зададени успешно. -add_email_confirmation_sent = Изпратено е ел. писмо за потвърждение до „%s“. За да потвърдите адреса си за ел. поща, моля, проверете входящата си кутия и последвайте предоставената връзка в рамките на следващите %s. -additional_repo_units_hint_description = Показване на подсказка „Включване на повече“ за хранилища, които нямат включени всички налични елементи. -email_notifications.submit = Задаване на предпочит. за ел. поща -email_notifications.andyourown = И вашите собствени известия -email_deletion_desc = Адресът за ел. поща и свързаната информация ще бъдат премахнати от вашия акаунт. Git подаванията от този адрес за ел. поща ще останат непроменени. Продължаване? -add_email_success = Новият адрес за ел. поща е добавен. -remove_account_link = Премахване на свързан акаунт -webauthn_alternative_tip = Може да искате да конфигурирате допълнителен метод за удостоверяване. -hidden_comment_types_description = Типовете коментари, отметнати тук, няма да се показват в страниците на задачите. Например, отмятането на „Етикет“ премахва всички коментари от типа „<потребител> добави/премахна <етикет>“. -hidden_comment_types = Скрити типове коментари -comment_type_group_lock = Състояние на заключване -can_not_add_email_activations_pending = Има чакаща активация, опитайте отново след няколко минути, ако искате да добавите нова ел. поща. -storage_overview = Преглед на съхранението - -webauthn = Двуфакторно удостоверяване (Ключове за сигурност) -quota.sizes.all = Всички -quota.sizes.repos.all = Хранилища -quota.sizes.repos.public = Публични хранилища -quota.sizes.repos.private = Частни хранилища -quota.sizes.git.all = Git съдържание -quota.sizes.git.lfs = Git LFS -quota.sizes.assets.attachments.all = Прикачени файлове -quota.sizes.assets.attachments.issues = Прикачени файлове към задачи -quota.sizes.assets.attachments.releases = Прикачени файлове към издания -quota.sizes.assets.artifacts = Артефакти -quota.sizes.assets.packages.all = Пакети -quota.sizes.wiki = Уики [packages] container.labels.value = Стойност @@ -419,148 +162,6 @@ settings.delete = Изтриване на пакета container.details.platform = Платформа settings.delete.error = Неуспешно изтриване на пакет. installation = Инсталация -versions.view_all = Вижте всички -dependencies = Зависимости -published_by_in = Публикуван %[1]s от %[3]s в %[5]s -published_by = Публикуван %[1]s от %[3]s -generic.download = Изтеглете пакета от командния ред: -container.details.type = Тип образ -alpine.repository = За хранилището -container.images.title = Образи -arch.version.description = Описание -search_in_external_registry = Търсене в %s -filter.type = Тип -filter.container.untagged = Без маркер -filter.type.all = Всички -registry.documentation = За повече информация относно регистъра %s, вижте документацията. -filter.no_result = Вашият филтър не даде резултати. -filter.container.tagged = С маркер -arch.pacman.repo.multi = %s има същата версия в различни дистрибуции. -arch.pacman.helper.gpg = Добавете доверителен сертификат за pacman: -alpine.repository.architectures = Архитектури -arch.version.provides = Доставя -arch.version.groups = Група -details.project_site = Уебсайт на проекта -arch.pacman.conf = Добавете сървър със свързаната дистрибуция и архитектура към /etc/pacman.conf : -arch.pacman.sync = Синхронизирайте пакета с pacman: -details.repository_site = Уебсайт на хранилището -arch.version.depends = Зависимости -arch.version.optdepends = Допълнителни зависимости -arch.version.replaces = Заменя -go.install = Инсталирайте пакета от командния ред: -cargo.registry = Настройте този регистър в конфигурационния файл на Cargo (например ~/.cargo/config.toml): -cargo.install = За да инсталирате пакета с Cargo, изпълнете следната команда: -details.documentation_site = Уебсайт на документацията -arch.version.conflicts = В конфликт -alpine.repository.branches = Клонове -arch.pacman.repo.multi.item = Конфигурация за %s - -desc = Управление на пакетите на хранилището. -alpine.registry = Настройте този регистър, като добавите URL адреса във вашия файл /etc/apk/repositories: -alpine.registry.key = Изтеглете публичния RSA ключ на регистъра в папката /etc/apk/keys/, за да проверите подписа на индекса: -alpine.registry.info = Изберете $branch и $repository от списъка по-долу. -alpine.install = За да инсталирате пакета, изпълнете следната команда: -arch.version.properties = Свойства на версията -arch.version.makedepends = Зависимости за изграждането -arch.version.checkdepends = Зависимости за проверката -chef.registry = Настройте този регистър във вашия файл ~/.chef/config.rb: -chef.install = За да инсталирате пакета, изпълнете следната команда: -composer.registry = Настройте този регистър във вашия файл ~/.composer/config.json: -composer.install = За да инсталирате пакета с Composer, изпълнете следната команда: -composer.dependencies = Зависимости -conan.details.repository = Хранилище -conan.registry = Настройте този регистър от командния ред: -conan.install = За да инсталирате пакета с Conan, изпълнете следната команда: -conda.registry = Настройте този регистър като Conda хранилище във вашия файл .condarc: -conda.install = За да инсталирате пакета с Conda, изпълнете следната команда: -container.pull = Издърпайте образа от командния ред: -container.multi_arch = ОС / Архитектура -container.layers = Слоеве на образа -cran.registry = Настройте този регистър във вашия файл Rprofile.site: -cran.install = За да инсталирате пакета, изпълнете следната команда: -debian.registry = Настройте този регистър от командния ред: -debian.registry.info = Изберете $distribution и $component от списъка по-долу. -debian.install = За да инсталирате пакета, изпълнете следната команда: -debian.repository = Информация за хранилището -debian.repository.distributions = Дистрибуции -debian.repository.components = Компоненти -debian.repository.architectures = Архитектури -helm.registry = Настройте този регистър от командния ред: -helm.install = За да инсталирате пакета, изпълнете следната команда: -maven.registry = Настройте този регистър във файла на вашия проект pom.xml: -maven.install = За да използвате пакета, включете следното в блока dependencies във файла pom.xml: -maven.install2 = Изпълнете през командния ред: -maven.download = За да изтеглите зависимостта, изпълнете през командния ред: -nuget.registry = Настройте този регистър от командния ред: -nuget.install = За да инсталирате пакета с NuGet, изпълнете следната команда: -nuget.dependency.framework = Целева платформа -npm.registry = Настройте този регистър във файла на вашия проект .npmrc: -npm.install = За да инсталирате пакета с npm, изпълнете следната команда: -npm.install2 = или го добавете във файла package.json: -npm.dependencies.optional = Опционални зависимости -npm.details.tag = Маркер -pub.install = За да инсталирате пакета с Dart, изпълнете следната команда: -pypi.requires = Изисква Python -pypi.install = За да инсталирате пакета с pip, изпълнете следната команда: -rpm.registry = Настройте този регистър от командния ред: -rpm.distros.redhat = на дистрибуции, базирани на RedHat -rpm.distros.suse = на дистрибуции, базирани на SUSE -rpm.install = За да инсталирате пакета, изпълнете следната команда: -rpm.repository = Информация за хранилището -rpm.repository.architectures = Архитектури -rpm.repository.multiple_groups = Този пакет е наличен в няколко групи. -alt.registry = Настройте този регистър от командния ред: -alt.registry.install = За да инсталирате пакета, изпълнете следната команда: -alt.install = Инсталиране на пакет -alt.setup = Добавете хранилище към списъка със свързани хранилища (изберете необходимата архитектура вместо „_arch_“): -alt.repository = Информация за хранилището -alt.repository.architectures = Архитектури -alt.repository.multiple_groups = Този пакет е наличен в няколко групи. -swift.registry = Настройте този регистър от командния ред: -swift.install = Добавете пакета във вашия файл Package.swift: -swift.install2 = и изпълнете следната команда: -vagrant.install = За да добавите Vagrant box, изпълнете следната команда: -settings.link = Свързване на този пакет с хранилище -settings.link.description = Ако свържете пакет с хранилище, пакетът се изброява в списъка с пакети на хранилището. -settings.link.select = Изберете хранилище -settings.link.button = Обновяване на връзката на хранилището -settings.link.success = Връзката на хранилището беше успешно обновена. -settings.link.error = Неуспешно обновяване на връзката на хранилището. -settings.delete.description = Изтриването на пакет е трайно и не може да бъде отменено. -settings.delete.notice = На път сте да изтриете %s (%s). Тази операция е необратима, сигурни ли сте? -owner.settings.cargo.title = Индекс на регистъра на Cargo -owner.settings.cargo.initialize = Инициализиране на индекс -owner.settings.cargo.initialize.description = Необходимо е специално Git хранилище за индекс, за да се използва регистърът на Cargo. Използването на тази опция ще (пре)създаде хранилището и ще го конфигурира автоматично. -owner.settings.cargo.initialize.error = Неуспешно инициализиране на индекса на Cargo: %v -owner.settings.cargo.initialize.success = Индексът на Cargo беше успешно създаден. -owner.settings.cargo.rebuild = Преизграждане на индекс -owner.settings.cargo.rebuild.description = Преизграждането може да бъде полезно, ако индексът не е синхронизиран със съхранените Cargo пакети. -owner.settings.cargo.rebuild.error = Неуспешно преизграждане на индекса на Cargo: %v -owner.settings.cargo.rebuild.success = Индексът на Cargo беше успешно преизграден. -owner.settings.cargo.rebuild.no_index = Не може да се преизгради, няма инициализиран индекс. -owner.settings.cleanuprules.title = Правила за почистване -owner.settings.cleanuprules.add = Добавяне на правило за почистване -owner.settings.cleanuprules.edit = Редактиране на правилото за почистване -owner.settings.cleanuprules.none = Все още няма правила за почистване. -owner.settings.cleanuprules.preview = Преглед на правило за почистване -owner.settings.cleanuprules.preview.overview = %d пакета са насрочени за премахване. -owner.settings.cleanuprules.preview.none = Правилото за почистване не съвпада с нито един пакет. -owner.settings.cleanuprules.enabled = Включено -owner.settings.cleanuprules.pattern_full_match = Прилагане на шаблона към пълното име на пакета -owner.settings.cleanuprules.keep.title = Версиите, които съответстват на тези правила, се запазват, дори ако съответстват на правило за премахване по-долу. -owner.settings.cleanuprules.keep.count = Запазване на най-новите -owner.settings.cleanuprules.keep.count.1 = 1 версия на пакет -owner.settings.cleanuprules.keep.count.n = %d версии на пакет -owner.settings.cleanuprules.keep.pattern = Запазване на версии, съответстващи на -owner.settings.cleanuprules.keep.pattern.container = Версията latest винаги се запазва за Container пакети. -owner.settings.cleanuprules.remove.title = Версиите, които съответстват на тези правила, се премахват, освен ако правило по-горе не казва да се запазят. -owner.settings.cleanuprules.remove.days = Премахване на версии, по-стари от -owner.settings.cleanuprules.remove.pattern = Премахване на версии, съответстващи на -owner.settings.cleanuprules.success.update = Правилото за почистване е обновено. -owner.settings.cleanuprules.success.delete = Правилото за почистване е изтрито. -owner.settings.chef.title = Регистър на Chef -owner.settings.chef.keypair = Генериране на двойка ключове -owner.settings.chef.keypair.description = Заявките, изпратени до регистъра на Chef, трябва да бъдат криптографски подписани като средство за удостоверяване. При генериране на двойка ключове, само публичният ключ се съхранява във Forgejo. Частният ключ ви се предоставя, за да се използва с knife. Генерирането на нова двойка ключове ще презапише предишната. [tool] hours = %d часа @@ -582,6 +183,109 @@ minutes = %d минути future = бъдеще raw_minutes = минути +[common] +language = Език +cancel = Отказ +captcha = CAPTCHA +create_new = Създаване… +preview = Преглеждане +disabled = Изключено +licenses = Лицензи +sign_in = Вход +copy_content = Копиране на съдържанието +user_profile_and_more = Профил и настройки… +view = Преглед +your_settings = Настройки +mirrors = Огледала +explore = Разглеждане +write = Писане +twofa = Двуфакторно удостоверяване +version = Версия +copy_success = Копирано! +help = Помощ +loading = Зареждане… +name = Име +sign_in_or = или +edit = Редактиране +concept_code_repository = Хранилище +page = Страница +forks = Разклонения +concept_user_organization = Организация +link_account = Свързване на акаунт +your_profile = Профил +sign_out = Изход +settings = Настройки +locked = Заключено +error = Грешка +dashboard = Табло +logo = Лого +toc = Съдържание +copy_url = Копиране на URL +new_mirror = Ново огледало +re_type = Потвърдете паролата +copy = Копиране +enabled = Включено +new_org = Нова организация +milestones = Етапи +rss_feed = RSS емисия +never = Никога +new_project = Нов проект +your_starred = Отбелязани +value = Стойност +sources = Източници +notifications = Известия +repository = Хранилище +add_all = Добавяне на всичко +new_project_column = Нова колона +add = Добавяне +organization = Организация +new_migrate = Нова миграция +save = Запазване +sign_in_with_provider = Влизане с %s +ok = Добре +manage_org = Управление на организациите +new_repo = Ново хранилище +register = Регистрация +mirror = Огледало +username = Потребителско име +password = Парола +template = Шаблон +signed_in_as = Влезли сте като +sign_up = Регистриране +enable_javascript = Този сайт изисква JavaScript. +home = Начало +email = Адрес на ел. поща +issues = Задачи +retry = Повторен опит +remove = Премахване +admin_panel = Управление на сайта +account_settings = Настройки на акаунта +powered_by = Осъществено от %s +pull_requests = Заявки за сливане +collaborative = Съвместни +all = Всички +activities = Дейности +new_fork = Ново разклонение на хранилище +unpin = Откачване +pin = Закачване +filter = Филтър +filter.clear = Изчистване на филтрите +filter.is_archived = Архивирани +filter.not_archived = Не архивирани +filter.is_fork = Разклонения +filter.public = Публични +filter.not_fork = Не разклонения +filter.is_template = Шаблони +filter.not_template = Не шаблони +filter.private = Частни +filter.is_mirror = Огледала +filter.not_mirror = Не огледала +copy_hash = Копиране на контролната сума +artifacts = Артефакти +show_log_seconds = Показване на секундите +remove_all = Премахване на всичко +test = Проба + [repo] issues.context.edit = Редактиране stargazers = Отбелязали със звезда @@ -678,15 +382,15 @@ issues.keyword_search_unavailable = В момента търсенето по к repo_desc_helper = Въведете кратко описание (опционално) mirror_address = Клониране от URL owner_helper = Някои организации може да не се показват в падащото меню поради ограничение за максимален брой хранилища. -new_repo_helper = Хранилището съдържа всички файлове на проекта, включително хронологията на ревизиите. Вече хоствате хранилище другаде? Мигрирайте хранилище. +new_repo_helper = Хранилището съдържа всички файлове на проекта, включително хронологията на ревизиите. Вече хоствате хранилище другаде? Мигрирайте хранилище. repo_name_helper = Добрите имена на хранилища използват кратки, запомнящи се и уникални ключови думи. migrated_from = Мигрирано от %[2]s visibility_description = Само притежателят или участниците в организацията, ако имат права, ще могат да го видят. projects.description = Описание (опционално) -template_select = Изберете шаблон +template_select = Изберете шаблон. visibility_helper = Хранилището да е частно license = Лиценз -license_helper = Изберете лицензионен файл +license_helper = Изберете лицензионен файл. readme = README migrate.clone_address = Мигриране / Клониране от URL migrated_from_fake = Мигрирано от %[1]s @@ -703,16 +407,16 @@ milestones.filter_sort.least_issues = Най-малко задачи milestones.filter_sort.most_issues = Най-много задачи settings.add_webhook = Добавяне на уеб-кука template.webhooks = Уеб-куки -issues.label_templates.info = Все още няма етикети. Създайте етикет с „Нов етикет“ или използвайте предварително зададен набор от етикети: +issues.label_templates.info = Все още няма етикети. Създайте етикет с "Нов етикет" или използвайте предварително зададен набор от етикети: labels = Етикети -license_helper_desc = Лицензът определя какво могат и какво не могат да правят другите с вашия код. Не сте сигурни кой е подходящ за вашия проект? Вижте Избиране на лиценз. +license_helper_desc = Лицензът определя какво могат и какво не могат да правят другите с вашия код. Не сте сигурни кой е подходящ за вашия проект? Вижте Избиране на лиценз. issues.choose.blank = По подразбиране settings.hooks = Уеб-куки -issue_labels = Етикети -issue_labels_helper = Изберете набор от етикети +issue_labels = Етикети за задачите +issue_labels_helper = Изберете набор от етикети за задачите. readme_helper_desc = Това е мястото, където можете да напишете пълно описание на вашия проект. -repo_gitignore_helper = Изберете .gitignore шаблони -auto_init = Да се инициализира хранилище +repo_gitignore_helper = Изберете .gitignore шаблони. +auto_init = Да се инициализира хранилище (Добавя .gitignore, License и README) template.issue_labels = Етикети за задачите migrate_items_labels = Етикети issues.label_templates.title = Зареждане на предв. зададен набор от етикети @@ -721,13 +425,13 @@ projects.template.desc = Шаблон projects.card_type.text_only = Само текст projects.card_type.images_and_text = Изображения и текст wiki = Уики -wiki.welcome = Добре дошли в уикито. +wiki.welcome = Добре дошли в Уикито. wiki.create_first_page = Създаване на първата страница editor.upload_file = Качване на файл projects.column.color = Цвят editor.cancel_lower = Отказ pulls = Заявки за сливане -editor.upload_files_to_dir = Качване на файлове в „%s“ +editor.upload_files_to_dir = Качване на файлове в "%s" settings.slack_color = Цвят issues.label_color = Цвят create_new_repo_command = Създаване на ново хранилище в командния ред @@ -739,7 +443,7 @@ issues.cancel = Отказ settings.transfer_owner = Нов притежател wiki.new_page_button = Нова страница commit_graph.color = Цвят -projects.create_success = Проектът „%s“ е създаден. +projects.create_success = Проектът "%s" е създаден. projects.type.none = Няма projects.new_subheader = Координирайте, проследявайте и обновявайте работата си на едно място, така че проектите да останат прозрачни и по график. projects.open = Отваряне @@ -810,10 +514,10 @@ wiki.back_to_wiki = Обратно към уики страницата wiki.wiki_page_revisions = Ревизии на страницата wiki.file_revision = Ревизия на страницата activity.title.issues_created_by = %s създадени от %s -wiki.delete_page_notice_1 = Изтриването на уики страницата „%s“ не може да бъде отменено. Продължаване? +wiki.delete_page_notice_1 = Изтриването на уики страницата "%s" не може да бъде отменено. Продължаване? wiki.page_name_desc = Въведете име за тази уики страница. Някои специални имена са: "Home", "_Sidebar" и "_Footer". wiki.page_already_exists = Вече съществува уики страница със същото име. -wiki.reserved_page = Името на уики страницата „%s“ е резервирано. +wiki.reserved_page = Името на уики страницата "%s" е резервирано. wiki.last_updated = Последно обновяване %s settings.event_release = Издание wiki.desc = Пишете и споделяйте документация със сътрудници. @@ -872,7 +576,7 @@ settings.admin_settings = Администраторски настройки issues.role.owner = Притежател settings.transfer.title = Прехвърляне на притежанието issues.author = Автор -issues.closed_at = `затвори тази задача %s` +issues.closed_at = `затвори тази задача %[2]s` settings.collaborator_deletion_desc = Премахването на сътрудник ще отнеме достъпа му до това хранилище. Продължаване? commits.message = Съобщение issues.due_date_not_set = Няма зададен краен срок. @@ -896,29 +600,29 @@ issues.filter_type.all_issues = Всички задачи issues.filter_poster_no_select = Всички автори issues.opened_by = отворена %[1]s от %[3]s issues.action_open = Отваряне -pulls.closed_at = `затвори тази заявка за сливане %s` -pulls.reopened_at = `отвори наново тази заявка за сливане %s` -issues.reopened_at = `отвори наново тази задача %s` +pulls.closed_at = `затвори тази заявка за сливане %[2]s` +pulls.reopened_at = `отвори наново тази заявка за сливане %[2]s` +issues.reopened_at = `отвори наново тази задача %[2]s` projects.column.edit = Редактиране на колоната issues.close = Затваряне на задачата issues.ref_reopened_from = `отвори наново тази задача %[4]s %[2]s` projects.deletion = Изтриване на проекта -projects.edit_success = Проектът „%s“ е обновен. +projects.edit_success = Проектът "%s" е обновен. projects.deletion_success = Проектът е изтрит. issues.create_comment = Коментиране unescape_control_characters = Отекраниране -editor.file_delete_success = Файлът „%s“ е изтрит. +editor.file_delete_success = Файлът "%s" е изтрит. projects.type.uncategorized = Некатегоризирано projects.column.set_default = Задаване по подразбиране projects.column.assigned_to = Възложено на -issues.reopen_comment_issue = Отваряне наново с коментар +issues.reopen_comment_issue = Коментиране и отваряне issues.reopen_issue = Отваряне наново -issues.close_comment_issue = Затваряне с коментар +issues.close_comment_issue = Коментиране и Затваряне milestones.filter_sort.latest_due_date = Най-далечен краен срок diff.view_file = Преглед на файла release.deletion_success = Изданието е изтрито. projects.column.delete = Изтриване на колоната -migrate.migrating = Мигриране от %s … +migrate.migrating = Мигриране от %s ... escape_control_characters = Екраниране issues.label_deletion_success = Етикетът е изтрит. pulls.is_closed = Заявката за сливане е затворена. @@ -961,11 +665,11 @@ activity.title.prs_opened_by = %s предложени от %s issues.action_milestone_no_select = Без етап issues.action_assignee_no_select = Без изпълнител milestones.edit = Редактиране на етапа -milestones.create_success = Етапът „%s“ е създаден. +milestones.create_success = Етапът "%s" е създаден. milestones.create = Създаване на етап milestones.clear = Изчистване milestones.deletion = Изтриване на етапа -milestones.edit_success = Етапът „%s“ е обновен. +milestones.edit_success = Етапът "%s" е обновен. milestones.modify = Обновяване на етапа milestones.deletion_success = Етапът е изтрит. milestones.filter_sort.most_complete = Най-много завършен @@ -1048,7 +752,7 @@ pulls.compare_changes = Нова заявка за сливане activity.title.releases_published_by = %s публикувани от %s topic.manage_topics = Управление на темите topic.done = Готово -find_file.go_to_file = Намиране на файл +find_file.go_to_file = Отиване към файл reactions_more = и още %d issues.unpin_comment = откачи това %s lines = реда @@ -1058,14 +762,14 @@ editor.preview_changes = Преглеждане на промените default_branch = Стандартен клон default_branch_label = стандартен template.topics = Теми -editor.branch_does_not_exist = Клонът „%s“ не съществува в това хранилище. +editor.branch_does_not_exist = Клонът "%s" не съществува в това хранилище. editor.no_changes_to_show = Няма промени за показване. issues.choose.get_started = Първи стъпки issues.change_milestone_at = `промени етапа от %s на %s %s` issues.change_project_at = `промени проекта от %s на %s %s` -issues.self_assign_at = `си самовъзложи това %s` +issues.self_assign_at = `си само-възложи това %s` issues.remove_assignee_at = `е премахнат като изпълнител от %s %s` -issues.remove_self_assignment = `се самопремахна като изпълнител %s` +issues.remove_self_assignment = `се само-премахна като изпълнител %s` issues.add_assignee_at = `му бе възложено това от %s %s` pulls.merged_by = от %[3]s бе слята %[1]s pulls.merged_by_fake = от %[2]s бе слята %[1]s @@ -1089,18 +793,18 @@ file_view_source = Преглед на изходния код diff.parent = родител issues.unlock_comment = отключи това обсъждане %s release.edit_subheader = Изданията ви позволяват да управлявате версиите на проекта. -branch.already_exists = Вече съществува клон на име „%s“. +branch.already_exists = Вече съществува клон на име "%s". contributors.contribution_type.deletions = Изтривания contributors.contribution_type.additions = Добавяния diff.browse_source = Разглеждане на изходния код file_view_rendered = Преглед на визуализация issues.lock_with_reason = заключи като %s и ограничи обсъждането до сътрудници %s milestones.new_subheader = Етапите ви помагат да управлявате задачите и да проследявате напредъка им. -release.edit = Редактиране -activity.published_release_label = Издание +release.edit = редактиране +activity.published_release_label = Публикувано activity.navbar.contributors = Допринесли pulls.recently_pushed_new_branches = Изтласкахте в клона %[1]s %[2]s -branch.branch_name_conflict = Името на клона „%s“ е в конфликт с вече съществуващия клон „%s“. +branch.branch_name_conflict = Името на клон "%s" е в конфликт с вече съществуващия клон "%s". all_branches = Всички клонове file_raw = Директно file_history = История @@ -1112,8 +816,7 @@ file_too_large = Файлът е твърде голям, за да бъде п commits = Подавания commit = Подаване editor.commit_changes = Подаване на промените -editor.add_tmpl = Добавяне на "<%s>" -editor.add_tmpl.filename = име на файла +editor.add_tmpl = Добавяне на "<име на файла>" editor.add = Добавяне на %s editor.delete = Изтриване на %s editor.update = Обновяване на %s @@ -1124,14 +827,14 @@ editor.new_branch_name_desc = Име на новия клон… editor.propose_file_change = Предлагане на промяна на файла editor.create_new_branch = Създаване на нов клон за това подаване и започване на заявка за сливане. editor.create_new_branch_np = Създаване на нов клон за това подаване. -editor.filename_is_invalid = Името на файла е невалидно: „%s“. -editor.commit_directly_to_this_branch = Подаване директно към клона %[1]s. -editor.branch_already_exists = Клонът „%s“ вече съществува в това хранилище. -editor.file_already_exists = Файл с име „%s“ вече съществува в това хранилище. +editor.filename_is_invalid = Името на файла е невалидно: "%s". +editor.commit_directly_to_this_branch = Подаване директно към клона %s. +editor.branch_already_exists = Клонът "%s" вече съществува в това хранилище. +editor.file_already_exists = Файл с име "%s" вече съществува в това хранилище. editor.commit_empty_file_header = Подаване на празен файл editor.commit_empty_file_text = Файлът, който сте на път да подадете, е празен. Продължаване? editor.fail_to_update_file_summary = Съобщение за грешка: -editor.fail_to_update_file = Неуспешно обновяване/създаване на файл „%s“. +editor.fail_to_update_file = Неуспешно обновяване/създаване на файл "%s". editor.add_subdir = Добавяне на директория… commits.commits = Подавания commits.find = Търсене @@ -1169,7 +872,7 @@ release.download_count = Изтегляния: %s release.tag_name_invalid = Името на маркера не е валидно. diff.stats_desc = %d променени файла с %d добавяния и %d изтривания release.tag_name_already_exist = Вече съществува издание с това име на маркер. -branch.branch_already_exists = Клонът „%s“ вече съществува в това хранилище. +branch.branch_already_exists = Клонът "%s" вече съществува в това хранилище. diff.download_patch = Изтегляне на файл-кръпка diff.show_diff_stats = Показване на статистика diff.commit = подаване @@ -1220,22 +923,22 @@ pulls.approve_count_1 = %d одобрение pulls.can_auto_merge_desc = Тази заявка за сливане може да бъде слята автоматично. pulls.num_conflicting_files_1 = %d конфликтен файл activity.git_stats_commit_n = %d подавания -settings.event_issues = Изменение +settings.event_issues = Задачи branch.delete_head = Изтриване -branch.delete = Изтриване на клона „%s“ +branch.delete = Изтриване на клона "%s" branch.delete_html = Изтриване на клона -tag.create_success = Маркерът „%s“ е създаден. -branch.new_branch_from = Създаване на нов клон от „%s“ +tag.create_success = Маркерът "%s" е създаден. +branch.new_branch_from = Създаване на нов клон от "%s" branch.new_branch = Създаване на нов клон branch.confirm_rename_branch = Преименуване на клона -branch.create_from = от „%s“ +branch.create_from = от "%s" settings.add_team_duplicate = Екипът вече разполага с това хранилище settings.slack_domain = Домейн -editor.directory_is_a_file = Името на директорията „%s“ вече се използва като име на файл в това хранилище. -editor.filename_is_a_directory = Името на файла „%s“ вече се използва като име на директория в това хранилище. -editor.file_editing_no_longer_exists = Файлът, който се редактира, „%s“, вече не съществува в това хранилище. -editor.file_deleting_no_longer_exists = Файлът, който се изтрива, „%s“, вече не съществува в това хранилище. -editor.unable_to_upload_files = Неуспешно качване на файлове в „%s“ с грешка: %v +editor.directory_is_a_file = Името на директорията "%s" вече се използва като име на файл в това хранилище. +editor.filename_is_a_directory = Името на файла "%s" вече се използва като име на директория в това хранилище. +editor.file_editing_no_longer_exists = Файлът, който се редактира, "%s", вече не съществува в това хранилище. +editor.file_deleting_no_longer_exists = Файлът, който се изтрива, "%s", вече не съществува в това хранилище. +editor.unable_to_upload_files = Неуспешно качване на файлове в "%s" с грешка: %v settings.web_hook_name_slack = Slack settings.web_hook_name_discord = Discord settings.web_hook_name_telegram = Telegram @@ -1247,10 +950,10 @@ settings.web_hook_name_larksuite_only = Lark Suite settings.web_hook_name_wechatwork = WeCom (Wechat Work) settings.web_hook_name_packagist = Packagist diff.file_byte_size = Размер -branch.create_success = Клонът „%s“ е създаден. -branch.deletion_success = Клонът „%s“ е изтрит. -branch.deletion_failed = Неуспешно изтриване на клона „%s“. -branch.rename_branch_to = Преименуване от „%s“ на: +branch.create_success = Клонът "%s" е създаден. +branch.deletion_success = Клонът "%s" е изтрит. +branch.deletion_failed = Неуспешно изтриване на клон "%s". +branch.rename_branch_to = Преименуване от "%s" на: settings.web_hook_name_msteams = Microsoft Teams settings.web_hook_name_dingtalk = DingTalk issues.error_removing_due_date = Неуспешно премахване на крайния срок. @@ -1262,9 +965,9 @@ settings.web_hook_name_forgejo = Forgejo release.tag_already_exist = Вече съществува маркер с това име. branch.name = Име на клона settings.rename_branch = Преименуване на клона -branch.restore_failed = Неуспешно възстановяване на клона „%s“. -branch.download = Изтегляне на клона „%s“ -branch.rename = Преименуване на клона „%s“ +branch.restore_failed = Неуспешно възстановяване на клон "%s". +branch.download = Изтегляне на клона "%s" +branch.rename = Преименуване на клона "%s" empty_message = В това хранилище няма съдържание. open_with_editor = Отваряне с %s search.search_repo = Търсене в хранилището @@ -1272,11 +975,11 @@ search.results = Резултати от търсенето на "%s" в %[2]s
    в %[3]s +pulls.title_desc_few = иска да слее %[1]d подавания от %[2]s в %[3]s issues.content_history.deleted = изтрито activity.git_stats_exclude_merges = С изключение на сливанията, activity.navbar.pulse = Последна дейност @@ -1296,11 +999,11 @@ pulls.collapse_files = Свиване на всички файлове pulls.show_all_commits = Показване на всички подавания diff.whitespace_button = Празни знаци issues.content_history.edited = редактирано -pulls.title_desc_one = иска да слее %[1]d подаване от %[2]s в %[3]s +pulls.title_desc_one = иска да слее %[1]d подаване от %[2]s в %[3]s pulls.showing_specified_commit_range = Показани са само промените между %[1]s..%[2]s pulls.merged_title_desc_one = сля %[1]d подаване от %[2]s в %[3]s %[4]s -pulls.no_merge_access = Не сте упълномощени да слеете тази заявка за сливане. -activity.navbar.code_frequency = Честота на промените +pulls.no_merge_access = Не сте упълномощени за сливане на тази заявка за сливане. +activity.navbar.code_frequency = Честота на кода activity.git_stats_pushed_1 = е изтласкал activity.git_stats_push_to_branch = към %s и contributors.contribution_type.commits = Подавания @@ -1328,7 +1031,7 @@ issues.dependency.cancel = Отказ issues.dependency.add_error_dep_exists = Зависимостта вече съществува. issues.dependency.add_error_dep_not_exist = Зависимостта не съществува. issues.remove_ref_at = `премахна препратката %s %s` -issues.ref_pull_from = `спомена тази заявка за сливане %[3]s %[1]s` +issues.ref_pull_from = `спомена тази заявка за сливане %[4]s %[2]s` issues.dependency.pr_no_dependencies = Няма зададени зависимости. issues.dependency.remove_info = Премахване на тази зависимост issues.dependency.removed_dependency = `премахна зависимостта %s` @@ -1353,19 +1056,19 @@ issues.dependency.title = Зависимости issues.dependency.issue_no_dependencies = Няма зададени зависимости. issues.dependency.pr_close_blocked = Трябва да затворите всички задачи, блокиращи тази заявка за сливане, преди да можете да я слеете. issues.dependency.pr_close_blocks = Тази заявка за сливане блокира затварянето на следните задачи -issues.ref_issue_from = `спомена тази задача %[3]s %[1]s` -issues.commit_ref_at = `спомена тази задача в подаване %s` +issues.ref_issue_from = `спомена тази задача %[4]s %[2]s` +issues.commit_ref_at = `спомена тази задача в подаване %[2]s` issues.add_ref_at = `добави препратка %s %s` pulls.merged_info_text = Клонът %s вече може да бъде изтрит. -pulls.commit_ref_at = `спомена тази заявка за сливане в подаване %s` +pulls.commit_ref_at = `спомена тази заявка за сливане в подаване %[2]s` issues.change_ref_at = `промени препратката от %s на %s %s` diff.review.reject = Поискване на промени diff.bin_not_shown = Двоичният файл не е показан. -settings.units.units = Елементи +settings.units.units = Елементи на хранилището settings.delete_notices_fork_1 = - Разклоненията на това хранилище ще станат независими след изтриване. settings.actions_desc = Включване на интегрираните CI/CD pipelines с Forgejo Actions settings.packages_desc = Включване на регистъра на пакетите за хранилището -settings.units.add_more = Включване на повече +settings.units.add_more = Добавяне... settings.use_external_issue_tracker = Използване на външен тракер за задачи settings.releases_desc = Включване на изданията за хранилището settings.projects_desc = Включване на проектите за хранилището @@ -1394,8 +1097,8 @@ pulls.reject_count_1 = %d поискана промяна issues.review.show_resolved = Показване на решено issues.review.hide_resolved = Скриване на решено issues.review.resolve_conversation = Решаване на обсъждането -diff.comment.markdown_info = Поддържа се стилизиране с Маркдаун. -diff.file_suppressed = Разликите във файла са потиснати, защото са твърде много +diff.comment.markdown_info = Поддържа се стилизиране с markdown. +diff.file_suppressed = Разликите не са показани, защото са твърде много pulls.reject_count_n = %d поискани промени settings.pulls.default_allow_edits_from_maintainers = Позволяване на редакции от поддържащите по подразбиране fork_branch = Клон за клониране в разклонението @@ -1412,25 +1115,25 @@ issues.filter_type.review_requested = Поискани рецензии issues.review.review = Рецензия issues.review.comment = рецензира %s branch.deleted_by = Изтрит от %s -branch.restore = Възстановяване на клона „%s“ -archive.title_date = Това хранилище е архивирано на %s. Можете да преглеждате файлове и да го клонирате, но не можете да правите промени в състоянието му, като изтласкване и създаване на нови задачи, заявки за сливане или коментари. +branch.restore = Възстановяване на клона "%s" +archive.title_date = Това хранилище е архивирано на %s. Можете да преглеждате файлове и да го клонирате, но не можете да изтласквате или отваряте задачи или заявки за сливане. release.download_count_one = %s изтегляне release.download_count_few = %s изтегляния -branch.restore_success = Клонът „%s“ е възстановен. -tag.create_tag_from = Създаване на нов маркер от „%s“ +branch.restore_success = Клонът "%s" е възстановен. +tag.create_tag_from = Създаване на нов маркер от "%s" branch.create_new_branch = Създаване на клон от клон: pulls.status_checks_show_all = Показване на всички проверки size_format = %[1]s: %[2]s; %[3]s: %[4]s pulls.filter_changes_by_commit = Филтриране по подаване -issues.ref_closing_from = `спомена тази задача в заявка за сливане %[3]s, която ще я затвори, %[1]s` +issues.ref_closing_from = `спомена заявка за сливане %[4]s, която ще затвори тази задача %[2]s` issues.ref_from = `от %[1]s` -issues.ref_reopening_from = `спомена тази задача в заявка за сливане %[3]s, която ще я отвори наново , %[1]s` +issues.ref_reopening_from = `спомена заявка за сливане %[4]s, която ще отвори наново тази задача %[2]s` issues.draft_title = Чернова pulls.reopen_to_merge = Моля, отворете наново тази заявка за сливане, за да извършите сливане. pulls.cant_reopen_deleted_branch = Тази заявка за сливане не може да бъде отворена наново, защото клонът е изтрит. pulls.status_checks_hide_all = Скриване на всички проверки pulls.status_checks_failure = Някои проверки са неуспешни -issues.review.add_review_request = поиска рецензия от %[1]s %[2]s +issues.review.add_review_request = поиска рецензия от %s %s wiki.no_search_results = Няма резултати wiki.search = Търсене в уикито issues.author.tooltip.pr = Този потребител е авторът на тази заявка за сливане. @@ -1443,433 +1146,6 @@ project = Проекти issues.content_history.delete_from_history = Изтриване от историята n_release_few = %s издания n_release_one = %s издание -editor.cannot_edit_non_text_files = Двоични файлове не могат да се редактират през уеб интерфейса. -settings.mirror_settings.push_mirror.copy_public_key = Копиране на публичния ключ -activity.published_tag_label = Маркер -activity.published_prerelease_label = Предв. издание -branch.create_branch = Създаване на клон %s -no_eol.text = Липсва EOL -no_eol.tooltip = Този файл не съдържа финален знак за край на реда. -tag.create_tag = Създаване на маркер %s -milestones.filter_sort.name = Име -mirror_public_key = Публичен SSH ключ -diff.file_after = След -find_tag = Намиране на маркер -diff.file_before = Преди -diff.file_image_height = Височина -contributors.contribution_type.filter_label = Тип принос: -diff.show_file_tree = Показване на файловото дърво -diff.hide_file_tree = Скриване на файловото дърво -tag.ahead.target = в %s след този маркер -diff.file_image_width = Широчина -activity.unresolved_conv_label = Отворено -invisible_runes_line = `Този ред съдържа невидими Уникод знаци` -code.desc = Достъп до програмния код, файловете, подаванията и клоновете. -settings.branches.update_default_branch = Обновяване на стандартния клон -settings.default_branch_desc = Изберете стандартен клон за хранилището, за заявки за сливане и подавания на код: -settings.transfer.button = Прехвърляне на притежанието -settings.transfer.modal.title = Прехвърляне на притежанието -ambiguous_runes_line = `Този ред съдържа двусмислени Уникод знаци` -ambiguous_character = `%[1]c [U+%04[1]X] може да бъде объркан със %[2]c [U+%04[2]X]` -invisible_runes_header = `Този файл съдържа невидими Уникод знаци` -issues.all_title = Общо -issues.new.assign_to_me = Възлагане на мен -ext_wiki = Външно уики -ext_issues = Външни задачи -readme_helper = Изберете шаблон за файл README -settings.event_pull_request_review_desc = Заявка за сливане е одобрена, отхвърлена или са добавени рецензионни коментари. -settings.event_pull_request_review = Рецензии -issues.filter_sort.relevance = Съответствие -settings.confirm_wiki_branch_rename = Преименуване на клона на уикито -settings.webhook.request = Заявка -settings.webhook.response = Отговор -settings.event_create = Създаване -settings.event_push_only = Събития при изтласкване -settings.event_delete = Изтриване -settings.event_header_repository = Събития за хранилището -settings.event_fork_desc = Хранилище е разклонено. -settings.event_fork = Разклоняване -settings.event_wiki_desc = Уики страница е създадена, преименувана, редактирана или изтрита. -settings.event_issue_milestone = Етапи -settings.event_pull_request_milestone_desc = Етап е добавен, премахнат или изменен. -settings.event_pull_request_label_desc = Етикети на заявка за сливане са добавени или премахнати. -settings.event_pull_request_merge = Сливане на заявка за сливане -settings.archive.tagsettings_unavailable = Настройките за маркери не са налични в архивирани хранилища. -settings.event_desc = Задействане при: -settings.event_create_desc = Клон или маркер е създаден. -generate_from = Генериране от -settings.event_push_desc = Git изтласкване към хранилище. -settings.event_package = Пакет -settings.event_pull_request_label = Етикети -settings.event_pull_request_assign_desc = Заявка за сливане е възложена или отвъзложена. -settings.event_choose = Персонализирани събития… -settings.event_header_issue = Събития при задачи -fork_no_valid_owners = Това хранилище не може да бъде разклонено, защото няма валидни притежатели. -settings.unarchive.text = Разархивирането на хранилище ще възстанови способността му да получава подавания и изтласквания, както и нови задачи и заявки за сливане. -settings.archive.branchsettings_unavailable = Настройките за клонове не са налични в архивирани хранилища. -settings.event_send_everything = Всички събития -settings.event_pull_request_approvals = Одобрения на заявка за сливане -release.invalid_external_url = Невалиден външен URL адрес: "%s" -settings.event_delete_desc = Клон или маркер е изтрит. -settings.discord_icon_url = URL адрес на иконка -settings.discord_icon_url.exceeds_max_length = URL адресът на иконката трябва да е по-малък или равен на 2048 знака -settings.event_push = Изтласкване -settings.event_repository_desc = Хранилище е създадено или изтрито. -settings.slack_icon_url = URL адрес на иконка -settings.event_issue_comment = Коментари -settings.event_pull_request_desc = Заявка за сливане е отворена, затворена, отворена наново или редактирана. -settings.event_issue_comment_desc = Коментар на задача е създаден, редактиран или изтрит. -settings.event_release_desc = Издание е публикувано, обновено или изтрито в хранилище. -settings.event_pull_request_review_request = Искания за рецензия -settings.event_pull_request_enforcement = Принудително изпълнение -diff.git-notes.remove-header = Премахване на бележката -diff.git-notes.add = Добавяне на бележка -settings.event_pull_request_assign = Възлагане -new_advanced_expand = Щракнете за разгъване -new_advanced = Разширени настройки -new_from_template = Използване на шаблон -new_from_template_description = Можете да изберете съществуващо шаблонно хранилище в тази инстанция и да приложите неговите настройки. -settings.event_pull_request_comment = Коментари -repo_gitignore_helper_desc = Изберете кои файлове да не се проследяват от списък с шаблони за обичайните езици. Типичните артефакти, генерирани от инструментите за изграждане, са включени в .gitignore по подразбиране. -object_format_helper = Формат на обектите на хранилището. Не може да се променя по-късно. SHA1 е най-съвместим. -issues.num_reviews_one = %d рецензия -settings.event_pull_request = Изменение -settings.event_issue_label = Етикети -settings.event_issue_assign = Възлагане -settings.event_header_pull_request = Събития при заявка за сливане -settings.event_issue_milestone_desc = Етап е добавен, премахнат или изменен. -settings.event_issue_label_desc = Етикети на задача са добавени или премахнати. -settings.event_issues_desc = Задача е отворена, затворена, отворена наново или редактирана. -settings.webhook.headers = Заглавки -settings.webhook.body = Тяло -settings.event_pull_request_sync = Синхронизирано -settings.event_pull_request_sync_desc = Клонът е обновен автоматично с целевия клон. -settings.event_package_desc = Пакет е създаден или изтрит в хранилище. -template_description = Шаблонните хранилища позволяват на потребителите да генерират нови хранилища със същата структура на директориите, файлове и опционални настройки. -auto_init_description = Поставете началото на Git историята с README и по избор добавете файлове License и .gitignore. -pulls.sign_in_require = Влезте, за да създадете нова заявка за сливане. -issues.num_reviews_few = %d рецензии -diff.git-notes.remove-body = Тази бележка ще бъде премахната. -issues.review.add_remove_review_requests = поиска рецензии от %[1]s и премахна заявки за рецензия за %[2]s %[3]s -form.name_pattern_not_allowed = Шаблонът "%s" не е разрешен в име на хранилище. -settings.wiki_rename_branch_main_notices_2 = Това ще преименува перманентно вътрешния клон на уикито на хранилището %s. Съществуващите изтегляния ще трябва да бъдат обновени. -settings.event_pull_request_milestone = Етапи -settings.event_pull_request_comment_desc = Заявка за сливане е създадена, редактирана или изтрита. -settings.event_issue_assign_desc = Задача е възложена или отвъзложена. -settings.event_pull_request_review_request_desc = Рецензия на заявка за сливане е поискана или е премахната. -generate_repo = Генериране на хранилище -default_branch_helper = Стандартният клон е основния клон за заявки за сливане и подавания на код. -issues.reaction.add = Добавяне на реакция -issues.reaction.alt_few = %[1]s реагира с %[2]s. -issues.reaction.alt_many = %[1]s и още %[2]d реагираха с %[3]s. -issues.reaction.alt_add = Добавяне на реакция %[1]s към коментара. -issues.reaction.alt_remove = Премахване на реакция %[1]s от коментара. -already_forked = Вече сте разклонили %s -generated_from = генерирано от -clear_ref = `Изчистване на текущата препратка` -file_follow = Последване на символната връзка -commitstatus.failure = Неуспех -issues.filter_label_exclude = Използвайте Alt + Click, за да изключите етикети -migrate.migrating_failed = Мигрирането от %s е неуспешно. -migrate.migrating_issues = Мигриране на задачи -mirror_from = огледално на -fork_from_self = Не можете да разклоните хранилище, което притежавате. -commit_graph.hide_pr_refs = Скриване на заявките за сливане -generated = Генерирано -broken_message = Git данните, лежащи в основата на това хранилище, не могат да бъдат прочетени. Свържете се с администратора на тази инстанция или изтрийте това хранилище. -editor.file_is_a_symlink = `„%s“ е символна връзка. Символните връзки не могат да се редактират в уеб редактора` -commits.browse_further = Разглеждане нататък -commits.older = По-стари -form.reach_limit_of_creation_n = Притежателят вече е достигнал лимита от %d хранилища. -issues.edit.already_changed = Неуспешно запазване на промените в задачата. Изглежда съдържанието вече е променено от друг потребител. Моля, презаредете страницата и опитайте да редактирате отново, за да избегнете презаписването на техните промени -transfer.accept_desc = Прехвърляне към „%s“ -archive.title = Това хранилище е архивирано. Можете да преглеждате файлове и да го клонирате, но не можете да правите промени в състоянието му, като изтласкване и създаване на нови задачи, заявки за сливане или коментари. -form.reach_limit_of_creation_1 = Притежателят вече е достигнал лимита от %d хранилище. -editor.patching = Прилагане на кръпка: -editor.fail_to_apply_patch = Неуспешно прилагане на кръпка „%s“ -commits.no_commits = Няма общи подавания. „%s“ и „%s“ имат напълно различни истории. -migrate.migrating_pulls = Мигриране на заявки за сливане -migrate.migrating_topics = Мигриране на теми -projects.desc = Управлявайте задачи и заявки за сливане в проектни табла. -issues.choose.invalid_templates = %v невалидни шаблона са намерени -pulls.edit.already_changed = Неуспешно запазване на промените в заявката за сливане. Изглежда съдържанието вече е променено от друг потребител. Моля, презаредете страницата и опитайте да редактирате отново, за да избегнете презаписването на техните промени -migrate.gitbucket.description = Мигриране на данни от GitBucket инстанции. -migrate.migrating_git = Мигриране на Git данни -commits.newer = По-нови -issues.choose.blank_about = Създаване на задача от стандартен шаблон. -issues.filter_no_results = Няма резултати -issues.filter_no_results_placeholder = Опитайте да коригирате филтрите си за търсене. -archive.nocomment = Коментирането не е възможно, тъй като хранилището е архивирано. -migrate.gitlab.description = Мигриране на данни от gitlab.com или други GitLab инстанции. -transfer.no_permission_to_accept = Нямате разрешение да приемете това прехвърляне. -transfer.no_permission_to_reject = Нямате разрешение да отхвърлите това прехвърляне. -editor.file_changed_while_editing = Съдържанието на файла е променено, откакто сте го отворили. Щракнете тук, за да го видите, или Подайте промените отново, за да ги презапишете. -sync_fork.button = Синхронизиране -migrate.onedev.description = Мигриране на данни от code.onedev.io или други OneDev инстанции. -migrate.codebase.description = Мигриране на данни от codebasehq.com. -migrate.migrating_labels = Мигриране на етикети -migrate.migrating_releases = Мигриране на издания -editor.push_rejected_no_message = Промяната беше отхвърлена от сървъра без съобщение. Моля, проверете Git куките. -issues.choose.open_external_link = Отваряне -comments.edit.already_changed = Неуспешно запазване на промените в коментара. Изглежда съдържанието вече е променено от друг потребител. Моля, презаредете страницата и опитайте да редактирате отново, за да избегнете презаписването на техните промени -commits.nothing_to_compare = Тези клонове са равни. -transfer.reject_desc = Отказ от прехвърляне към „%s“ -subscribe.pull.guest.tooltip = Влезте, за да се абонирате за тази заявка за сливане. -commit.contained_in_default_branch = Това подаване е част от стандартния клон -normal_view = Нормален изглед -issues.context.menu = Меню за коментара -form.name_reserved = Името на хранилището „%s“ е резервирано. -need_auth = Упълномощаване -subscribe.issue.guest.tooltip = Влезте, за да се абонирате за тази задача. -commitstatus.pending = В очакване -commitstatus.success = Успех -editor.cannot_commit_to_protected_branch = Не може да се подава в защитения клон „%s“. -editor.no_commit_to_branch = Не може да се подава директно в клона, защото: -editor.push_rejected = Промяната беше отхвърлена от сървъра. Моля, проверете Git куките. -cite_this_repo = Цитиране на това хранилище -migrate.gitea.description = Мигриране на данни от gitea.com или други Gitea инстанции. -editor.push_rejected_summary = Пълно съобщение на отхвърлянето: -sync_fork.branch_behind_one = Този клон е %[1]d подаване зад %[2]s -sync_fork.branch_behind_few = Този клон е %[1]d подавания зад %[2]s -form.string_too_long = Даденият низ е по-дълъг от %d знака. -editor.commit_id_not_matching = Файлът е променен, докато сте го редактирали. Подайте в нов клон и след това слейте. -editor.user_no_push_to_branch = Потребителят не може да изтласква в клона -archive.pull.noreview = Това хранилище е архивирано. Не можете да рецензирате заявки за сливане. -migrate.migrating_failed.error = Неуспешно мигриране: %s -migrate.github.description = Мигриране на данни от github.com или GitHub Enterprise сървър. -migrate.forgejo.description = Мигриране на данни от codeberg.org или други Forgejo инстанции. -migrate.gogs.description = Мигриране на данни от notabug.org или други Gogs инстанции. -migrate.migrating_milestones = Мигриране на етапи -migrate.failed = Мигрирането е неуспешно: %v -pulls.nothing_to_compare_and_allow_empty_pr = Тези клонове са равни. Тази заявка за сливане ще бъде празна. -pulls.has_pull_request = `Вече съществува заявка за сливане между тези клонове: %[2]s#%[3]d` -pulls.is_checking = Проверката за конфликти при сливане е в ход. Опитайте отново след няколко минути. -pulls.cannot_merge_work_in_progress = Тази заявка за сливане е отбелязана като в процес на работа. -pulls.blocked_by_approvals = Тази заявка за сливане все още няма достатъчно одобрения. Дадени са %d от %d одобрения. -pulls.blocked_by_rejection = Тази заявка за сливане има поискани промени от официален рецензент. -pulls.waiting_count_1 = %d чакаща рецензия -pulls.status_checks_requested = Задължително -pulls.update_branch_success = Обновяването на клона е успешно -pulls.cannot_auto_merge_helper = Слейте ръчно, за да разрешите конфликтите. -migrate.clone_address_desc = HTTP(S) или Git „clone“ URL на съществуващо хранилище -pulls.add_prefix = Добавете префикс %s -pulls.merge_pull_request = Създаване на подаване със сливане -pulls.waiting_count_n = %d чакащи рецензии -pulls.is_ancestor = Този клон вече е включен в целевия клон. Няма какво да се слива. -pulls.required_status_check_missing = Някои задължителни проверки липсват. -pulls.change_target_branch_at = `промени целевия клон от %s на %s %s` -issues.time_spent_total = Общо изразходвано време -issues.del_time_history = `изтри изразходваното време %s` -pulls.nothing_to_compare_have_tag = Избраните клон/маркер са равни. -pulls.cannot_auto_merge_desc = Тази заявка за сливане не може да бъде слята автоматично поради конфликти. -issues.tracker_auto_close = Таймерът ще бъде спрян автоматично, когато тази задача бъде затворена -issues.force_push_codes = `изтласка принудително %[1]s от %[2]s към %[4]s %[6]s` -pulls.blocked_by_official_review_requests = Тази заявка за сливане е блокирана, защото липсва одобрение от един или повече официални рецензенти. -issues.tracker = Проследяване на времето -issues.add_time_history = `добави изразходвано време %s` -migrate.repo_desc_helper = Оставете празно, за да внесете съществуващото описание -migrate.git.description = Мигриране само на хранилище от всяка Git услуга. -mirror_sync = синхронизирано -migrate_repo = Мигриране на хранилище -migrate_options = Опции за мигрирането -editor.fork_before_edit = Трябва да разклоните това хранилище, за да направите или предложите промени в този файл. -editor.must_have_write_access = Трябва да имате право на запис, за да правите или предлагате промени в този файл. -editor.new_branch_name = Дайте име на новия клон за това подаване -editor.invalid_commit_mail = Невалидна ел. поща за създаване на подаване. -pulls.required_status_check_failed = Някои задължителни проверки не са успешни. -issues.time_spent_from_all_authors = `Общо изразходвано време: %s` -issues.attachment.download = `Щракнете, за да изтеглите „%s“` -issues.attachment.open_tab = `Щракнете, за да видите „%s“ в нов раздел` -pulls.update_branch = Обновяване на клона чрез сливане -migrate_items = Елементи за мигриране -commit.load_referencing_branches_and_tags = Зареждане на клонове и маркери, препращащи към това подаване -pulls.files_conflicted = Тази заявка за сливане има промени, които са в конфликт с целевия клон. -pulls.still_in_progress = Все още е в процес на работа? -pulls.ready_for_review = Готово е за рецензиране? -pulls.is_empty = Промените в този клон вече са в целевия клон. Това ще бъде празно подаване. -issues.start_tracking = Започване на проследяване на времето -migrate_options_mirror_helper = Това хранилище ще бъде огледално -migrate_options_lfs = Мигриране на LFS файлове -editor.upload_file_is_locked = Файлът „%s“ е заключен от %s. -issues.tracking_already_started = `Вече сте започнали проследяване на времето по друга задача!` -pulls.remove_prefix = Премахнете префикса %s -author_search_tooltip = Показва максимум 30 потребители -migrate.migrating_failed_no_addr = Мигрирането е неуспешно. -issues.force_push_compare = Сравняване -pulls.status_checking = Някои проверки са в очакване -pulls.nothing_to_compare = Тези клонове са равни. Не е нужно да създавате заявка за сливане. - -rss.must_be_on_branch = Трябва да сте на клон, за да имате RSS емисия. -admin.manage_flags = Управление на флаговете -admin.enabled_flags = Флагове, включени за хранилището: -admin.update_flags = Обновяване на флаговете -admin.failed_to_replace_flags = Неуспешна замяна на флаговете на хранилището -admin.flags_replaced = Флаговете на хранилището са заменени -fork_to_different_account = Разклоняване в друг акаунт -mirror_interval = Интервал на огледалото (валидни единици за време са „h“, „m“, „s“). 0 за изключване на периодичната синхронизация. (Минимален интервал: %s) -mirror_interval_invalid = Интервалът на огледалото не е валиден. -mirror_use_ssh.text = Използване на SSH удостоверяване -mirror_use_ssh.helper = Forgejo ще създаде огледало на хранилището чрез Git през SSH и ще генерира двойка ключове за вас, когато изберете тази опция. Трябва да се уверите, че генерираният публичен ключ е упълномощен да изтласква към целевото хранилище. Не можете да използвате удостоверяване, базирано на парола, когато избирате това. -mirror_use_ssh.not_available = SSH удостоверяването не е налично. -mirror_denied_combination = Не може да се използва удостоверяване с публичен ключ и парола едновременно. -mirror_sync_on_commit = Синхронизиране при изтласкване на подавания -mirror_address_desc = Поставете всички необходими данни за удостоверяване в секцията „Упълномощаване“. -mirror_address_url_invalid = Предоставеният URL е невалиден. Трябва да екранирате правилно всички компоненти на URL адреса. -mirror_address_protocol_invalid = Предоставеният URL е невалиден. Само http(s):// или git:// адреси могат да се използват за огледални хранилища. -mirror_lfs = Съхранение на големи файлове (LFS) -mirror_password_help = Променете потребителското име, за да изтриете запазена парола. -unit_disabled = Администраторът на сайта е изключил тази секция на хранилището. -summary_card_alt = Карта с обобщение на хранилище %s -template.items = Елементи на шаблона -template.git_content = Git съдържание (стандартен клон) -template.git_hooks = Git куки -template.git_hooks_tooltip = В момента не можете да променяте или премахвате Git куки, след като са добавени. Изберете това само ако се доверявате на шаблонното хранилище. -template.one_item = Трябва да изберете поне един елемент от шаблона -template.invalid = Трябва да изберете шаблонно хранилище -migrate.cancel_migrating_title = Отказ от миграцията -migrate.cancel_migrating_confirm = Искате ли да откажете тази миграция? -invisible_runes_description = `Този файл съдържа невидими Уникод знаци, които са неразличими за хората, но могат да бъдат обработени по различен начин от компютър. Ако смятате, че това е умишлено, можете спокойно да пренебрегнете това предупреждение. Използвайте бутона „Екраниране“, за да ги разкриете.` -ambiguous_runes_header = `Този файл съдържа двусмислени Уникод знаци` -ambiguous_runes_description = `Този файл съдържа Уникод знаци, които могат да бъдат объркани с други знаци. Ако смятате, че това е умишлено, можете спокойно да пренебрегнете това предупреждение. Използвайте бутона „Екраниране“, за да ги разкриете.` -file_copy_permalink = Копиране на постоянна връзка -view_git_blame = Преглед на git blame -video_not_supported_in_browser = Вашият браузър не поддържа HTML5 тага „video“. -audio_not_supported_in_browser = Вашият браузър не поддържа HTML5 тага „audio“. -stored_lfs = Съхранено с Git LFS -commit_graph.select = Изберете клонове -editor.cannot_edit_lfs_files = LFS файлове не могат да се редактират в уеб интерфейса. -editor.filename_help = Добавете директория, като въведете името ѝ, последвано от наклонена черта („/“). Премахнете директория, като натиснете backspace в началото на полето за въвеждане. -editor.commit_signed_changes = Подаване на подписани промени -editor.require_signed_commit = Клонът изисква подписано подаване -editor.commit_email = Ел. поща на подаването -commits.desc = Разглеждане на историята на промените в програмния код. -commits.search.tooltip = Можете да добавите префикс към ключовите думи с „author:“, „committer:“, „after:“ или „before:“, напр. „revert author:Alice before:2019-01-13“. -commits.signed_by = Подписано от -commits.signed_by_untrusted_user = Подписано от недоверен потребител -commits.signed_by_untrusted_user_unmatched = Подписано от недоверен потребител, който не съвпада с подаващия -commits.ssh_key_fingerprint = Отпечатък на SSH ключ -commits.view_single_diff = Преглед на промените в този файл, въведени в това подаване -commit.revert = Връщане -commit.revert-header = Връщане: %s -commit.revert-content = Изберете клон, върху който да се върне: -issues.desc = Организирайте доклади за грешки, задачи и етапи. -issues.choose.ignore_invalid_templates = Невалидните шаблони са игнорирани -issues.choose.invalid_config = Конфигурацията на задачите съдържа грешки: -issues.filter_type.all_pull_requests = Всички заявки за сливане -issues.role.member_helper = Този потребител е участник в организацията, притежаваща това хранилище. -issues.lock.unknown_reason = Не може да се заключи задача с неизвестна причина. -issues.lock_duplicate = Задача не може да бъде заключена два пъти. -issues.unlock_error = Не може да се отключи задача, която не е заключена. -issues.lock.notice_1 = - Други потребители не могат да добавят нови коментари към тази задача. -issues.lock.notice_2 = - Вие и други сътрудници с достъп до това хранилище все още можете да оставяте коментари, които другите да виждат. -issues.lock.notice_3 = - Винаги можете да отключите тази задача отново в бъдеще. -issues.unlock.notice_1 = - Всеки ще може отново да коментира тази задача. -issues.unlock.notice_2 = - Винаги можете да заключите тази задача отново в бъдеще. -issues.lock.title = Заключване на обсъждането по тази задача. -issues.unlock.title = Отключване на обсъждането по тази задача. -issues.comment_on_locked = Не можете да коментирате заключена задача. -issues.delete.text = Наистина ли искате да изтриете тази задача? (Това ще премахне трайно цялото съдържание. Помислете дали вместо това да не я затворите, ако възнамерявате да я запазите архивирана) -issues.cancel_tracking_history = `отмени проследяването на времето %s` -issues.add_time_sum_to_small = Не е въведено време. -issues.due_date_form = гггг-мм-дд -issues.due_date_invalid = Крайният срок е невалиден или извън обхвата. Моля, използвайте формата „гггг-мм-дд“. -issues.dependency.no_permission_1 = Нямате разрешение да прочетете %d зависимост -issues.dependency.no_permission_n = Нямате разрешение да прочетете %d зависимости -issues.dependency.no_permission.can_remove = Нямате разрешение да прочетете тази зависимост, но можете да я премахнете -issues.dependency.issue_batch_close_blocked = Не могат да бъдат затворени групово избраните задачи, защото задача #%d все още има отворени зависимости -issues.dependency.blocked_by_short = Зависи от -issues.dependency.setting = Включване на зависимости за задачи и заявки за сливане -issues.dependency.add_error_same_issue = Не можете да направите задача зависима от самата нея. -issues.dependency.add_error_dep_issue_not_exist = Зависимата задача не съществува. -issues.dependency.add_error_cannot_create_circular = Не можете да създадете зависимост с две задачи, които се блокират взаимно. -issues.dependency.add_error_dep_not_same_repo = И двете задачи трябва да са в едно и също хранилище. -issues.review.self.rejection = Не можете да поискате промени в собствената си заявка за сливане. -issues.review.dismissed = отхвърли рецензията на %s %s -issues.review.content.empty = Трябва да оставите коментар, посочващ исканите промени. -issues.review.add_review_requests = поиска рецензии от %[1]s %[2]s -issues.review.remove_review_request = премахна заявката за рецензия за %[1]s %[2]s -issues.review.remove_review_requests = премахна заявките за рецензия за %[1]s %[2]s -issues.review.remove_review_request_self = отказа да рецензира %s -issues.review.pending.tooltip = Този коментар в момента не е видим за други потребители. За да изпратите изчакващите си коментари, изберете „%s“ -> „%s/%s/%s“ в горната част на страницата. -issues.review.outdated = Остарял -issues.review.outdated_description = Съдържанието е променено, след като е направен този коментар -issues.review.show_outdated = Показване на остарели -issues.review.hide_outdated = Скриване на остарели -issues.content_history.options = Опции -issues.blocked_by_user = Не можете да създавате задачи в това хранилище, защото сте блокирани от притежателя на хранилището. -comment.blocked_by_user = Коментирането не е възможно, защото сте блокирани от притежателя на хранилището или от автора. -issues.reopen.blocked_by_user = Не можете да отворите наново тази задача, защото сте блокирани от притежателя на хранилището или от автора на тази задача. -compare.compare_base = основа -compare.compare_head = сравняване -pulls.desc = Включване на заявки за сливане и рецензии на код. -pulls.view = Преглед на заявката за сливане -pulls.allow_edits_from_maintainers_desc = Потребители с право на запис в основния клон могат също да изтласкват към този клон -pulls.allow_edits_from_maintainers_err = Обновяването е неуспешно -pulls.has_changed_since_last_review = Променено след последната ви рецензия -pulls.switch_comparison_type = Превключване на типа сравнение -pulls.filter_branch = Филтриране на клон -pulls.review_only_possible_for_full_diff = Рецензирането е възможно само при преглед на пълните разлики -pulls.wrong_commit_id = ID на подаването трябва да бъде ID на подаване в целевия клон -pulls.blocked_by_user = Не можете да създадете заявка за сливане в това хранилище, защото сте блокирани от притежателя на хранилището. -pulls.no_merge_desc = Тази заявка за сливане не може да бъде слята, защото всички опции за сливане в хранилището са изключени. -pulls.no_merge_helper = Включете опциите за сливане в настройките на хранилището или слейте заявката за сливане ръчно. -pulls.no_merge_wip = Тази заявка за сливане не може да бъде слята, защото е отбелязана като в процес на работа. -pulls.squash_merge_pull_request = Създаване на сплескано подаване -pulls.merge_manually = Ръчно слята -pulls.merge_commit_id = ID на подаването със сливане -pulls.require_signed_wont_sign = Клонът изисква подписани подавания, но това сливане няма да бъде подписано -pulls.merge_conflict = Сливането е неуспешно: Възникна конфликт по време на сливането. Подсказка: Опитайте различна стратегия -pulls.merge_conflict_summary = Съобщение за грешка -pulls.rebase_conflict_summary = Съобщение за грешка -pulls.has_merged = Неуспешно: Заявката за сливане е слята, не можете да слеете отново или да промените целевия клон. -pulls.push_rejected = Изтласкването е неуспешно: Изтласкването е отхвърлено. Прегледайте Git куките за това хранилище. -pulls.push_rejected_no_message = Изтласкването е неуспешно: Изтласкването е отхвърлено, но няма отдалечено съобщение. Прегледайте Git куките за това хранилище -pulls.update_not_allowed = Нямате разрешение да обновявате клона -pulls.outdated_with_base_branch = Този клон е остарял спрямо основния клон -pulls.cmd_instruction_merge_warning = Предупреждение: Настройката „Автоматично откриване на ръчно сливане“ не е включена за това хранилище, ще трябва да отбележите тази заявка за сливане като ръчно слята след това. -pulls.editable_explanation = Тази заявка за сливане позволява редакции от поддържащите. Можете да допринесете директно към нея. -pulls.auto_merge_button_when_succeed = (Когато проверките са успешни) -pulls.auto_merge_when_succeed = Автоматично сливане, когато всички проверки са успешни -pulls.auto_merge_newly_scheduled = Заявката за сливане е насрочена за сливане, когато всички проверки са успешни. -pulls.auto_merge_has_pending_schedule = %[1]s насрочи тази заявка за сливане за автоматично сливане, когато всички проверки са успешни %[2]s. -pulls.auto_merge_cancel_schedule = Отмяна на автоматичното сливане -pulls.auto_merge_not_scheduled = Тази заявка за сливане не е насрочена за автоматично сливане. -pulls.auto_merge_canceled_schedule = Автоматичното сливане е отменено за тази заявка за сливане. -pulls.auto_merge_newly_scheduled_comment = `насрочи тази заявка за сливане за автоматично сливане, когато всички проверки са успешни %[1]s` -pulls.auto_merge_canceled_schedule_comment = `отмени автоматичното сливане на тази заявка за сливане, когато всички проверки са успешни %[1]s` -pulls.delete.title = Да се изтрие ли тази заявка за сливане? -pulls.delete.text = Наистина ли искате да изтриете тази заявка за сливане? (Това ще премахне трайно цялото съдържание. Помислете дали вместо това да не я затворите, ако възнамерявате да я запазите архивирана) -diff.data_not_available = Съдържанието на разликите не е налично -diff.bin = ДВОИЧЕН -diff.file_suppressed_line_too_long = Разликите във файла са потиснати, защото един или повече редове са твърде дълги -diff.too_many_files = Някои файлове не бяха показани, защото твърде много файлове имат промени в тези разлики -diff.show_more = Показване на още -diff.generated = генериран -diff.comment.add_line_comment = Добавяне на коментар към ред -diff.comment.add_review_comment = Добавяне на коментар -diff.review.self_reject = Авторите на заявки за сливане не могат да поискват промени в собствените си заявки -diff.review.self_approve = Авторите на заявки за сливане не могат да одобряват собствените си заявки -diff.image.side_by_side = Едно до друго -diff.image.swipe = Плъзгане -diff.image.overlay = Наслагване -diff.has_escaped = Този ред има скрити Уникод знаци -release.tag_name_protected = Името на маркера е защитено. -release.add_tag_msg = Използване на заглавието и съдържанието на изданието като съобщение на маркера. -release.hide_archive_links = Скриване на автоматично генерираните архиви -release.hide_archive_links_helper = Скрийте автоматично генерираните архиви с програмен код за това издание. Например, ако качвате свои собствени. -release.asset_external_url = Външен URL адрес -release.summary_card_alt = Карта с обобщение на издание със заглавие „%s“ в хранилище %s -branch.protected_deletion_failed = Клонът „%s“ е защитен. Не може да бъде изтрит. -branch.default_deletion_failed = Клонът „%s“ е стандартният клон. Не може да бъде изтрит. -branch.included_desc = Този клон е част от стандартния клон -branch.included = Включен -branch.warning_rename_default_branch = Преименувате стандартния клон. -topic.count_prompt = Не можете да изберете повече от 25 теми -find_file.no_matching = Не е намерен съвпадащ файл -error.csv.too_large = Не може да се визуализира този файл, защото е твърде голям. -error.csv.unexpected = Не може да се визуализира този файл, защото съдържа неочакван знак на ред %d и колона %d. -error.csv.invalid_field_count = Не може да се визуализира този файл, защото има грешен брой полета на ред %d. -error.broken_git_hook = Git куките на това хранилище изглеждат повредени. Моля, последвайте документацията, за да ги поправите, след което изтласкайте подавания, за да обновите статуса. [modal] confirm = Потвърждаване @@ -1893,17 +1169,6 @@ buttons.italic.tooltip = Добавяне на курсив текст buttons.link.tooltip = Добавяне на връзка buttons.disable_monospace_font = Изключване на равноширокия шрифт buttons.ref.tooltip = Препратка към задача или заявка за сливане -table_modal.label.columns = Колони -table_modal.label.rows = Редове -table_modal.placeholder.content = Съдържание -table_modal.placeholder.header = Заглавка -buttons.new_table.tooltip = Добавяне на таблица -table_modal.header = Добавяне на таблица -link_modal.description = Описание -link_modal.header = Добавяне на връзка -buttons.indent.tooltip = Вмъкване на елементи с едно ниво -buttons.unindent.tooltip = Изваждане на елементи с едно ниво -link_modal.paste_reminder = Подсказка: С URL адрес в клипборда можете да поставите директно в редактора, за да създадете връзка. [org] teams.write_access = Писане @@ -1917,7 +1182,7 @@ settings = Настройки members.remove.detail = Премахване на %[1]s от %[2]s? settings.visibility = Видимост settings.options = Организация -teams.leave.detail = Сигурни ли сте, че искате да напуснете екипа „%s“? +teams.leave.detail = Напускане на %s? teams.can_create_org_repo = Създаване на хранилища teams.settings = Настройки settings.website = Уебсайт @@ -1927,7 +1192,7 @@ teams.all_repositories = Всички хранилища teams.update_settings = Обновяване на настройките settings.full_name = Пълно име members.leave = Напускане -members.leave.detail = Сигурни ли сте, че искате да напуснете организацията „%s“? +members.leave.detail = Напускане на %s? teams.read_access = Четене org_name_holder = Име на организацията create_org = Създаване на организация @@ -1935,7 +1200,7 @@ settings.visibility.public = Публична settings.visibility.limited_shortname = Ограничена settings.visibility.private_shortname = Частна settings.permission = Разрешения -settings.visibility.limited = Ограничена (видима само за влезли потребители) +settings.visibility.limited = Ограничена (видима само за удостоверени потребители) settings.visibility.private = Частна (видима само за участниците в организацията) org_name_helper = Имената на организациите е добре да са кратки и запомнящи се. org_full_name_holder = Пълно име на организацията @@ -1958,18 +1223,18 @@ follow_blocked_user = Не можете да следвате тази орга settings.delete_prompt = Организацията ще бъде премахната завинаги. Това НЕ МОЖЕ да бъде отменено! settings.labels_desc = Добавете етикети, които могат да се използват за задачи за всички хранилища в тази организация. teams.none_access = Без достъп -teams.members.none = Няма участници в този екип. +teams.members.none = Няма членове в този екип. repo_updated = Обновено %s teams.delete_team_success = Екипът е изтрит. teams.search_repo_placeholder = Потърсете хранилище… teams.delete_team_title = Изтриване на екипа -teams.add_team_member = Добавяне на участник в екипа +teams.add_team_member = Добавяне на член на екипа teams.read_access_helper = Членовете могат да преглеждат и клонират хранилищата на екипа. teams.invite.description = Моля, щракнете върху бутона по-долу, за да се присъедините към екипа. teams.invite.title = Поканени сте да се присъедините към екип %s в организация %s. team_permission_desc = Разрешение members.public_helper = Да е скрит -teams.members = Участници в екипа +teams.members = Членове на екипа teams.delete_team = Изтриване на екипа members.owner = Притежател members.member_role = Роля на участника: @@ -1977,45 +1242,11 @@ members.member = Участник members.private_helper = Да е видим teams.no_desc = Този екип няма описание settings.delete_org_desc = Тази организация ще бъде изтрита перманентно. Продължаване? -open_dashboard = Отваряне на таблото -settings.change_orgname_prompt = Бележка: Промяната на името на организацията ще промени и URL адреса на вашата организация и ще освободи старото име. - -team_access_desc = Достъп до хранилище -team_unit_desc = Разрешаване на достъп до секции на хранилището -team_unit_disabled = (Изключено) -form.name_reserved = Името на организацията „%s“ е резервирано. -form.name_pattern_not_allowed = Шаблонът „%s“ не е разрешен в име на организация. -form.create_org_not_allowed = Нямате разрешение да създавате организация. -settings.update_setting_success = Настройките на организацията са обновени. -settings.change_orgname_redirect_prompt = Старото име ще се пренасочва, докато не бъде взето. -settings.change_orgname_redirect_prompt.with_cooldown.one = Старото име на организацията ще бъде достъпно за всички след период на изчакване от %[1]d ден. Все още можете да си върнете старото име по време на периода на изчакване. -settings.change_orgname_redirect_prompt.with_cooldown.few = Старото име на организацията ще бъде достъпно за всички след период на изчакване от %[1]d дни. Все още можете да си върнете старото име по време на периода на изчакване. -settings.update_avatar_success = Профилната снимка на организацията е обновена. -settings.hooks_desc = Добавете уеб-куки, които ще се задействат за всички хранилища в тази организация. -members.membership_visibility = Видимост на участничеството: -members.public = Видим -members.private = Скрит -members.invite_desc = Добавяне на нов участник към %s: -members.invite_now = Поканване сега -teams.admin_access = Администраторски достъп -teams.invite_team_member = Поканване в %s -teams.invite_team_member.list = Чакащи покани -teams.delete_team_desc = Изтриването на екип отнема достъпа до хранилището от неговите участници. Продължаване? -teams.remove_all_repos_desc = Това ще премахне всички хранилища от екипа. -teams.add_all_repos_title = Добавяне на всички хранилища -teams.add_all_repos_desc = Това ще добави всички хранилища на организацията към екипа. -teams.add_nonexistent_repo = Хранилището, което се опитвате да добавите, не съществува, моля, първо го създайте. -teams.add_duplicate_users = Потребителят вече е участник в екипа. -teams.repos.none = Няма хранилища, до които този екип да има достъп. -teams.specific_repositories = Конкретни хранилища -teams.specific_repositories_helper = Участниците ще имат достъп само до хранилища, изрично добавени към екипа. Избирането на това няма автоматично да премахне хранилища, вече добавени с Всички хранилища. -teams.all_repositories_helper = Екипът има достъп до всички хранилища. Избирането на това ще добави всички съществуващи хранилища към екипа. -teams.invite.by = Поканен от %s [install] admin_password = Парола user = Потребителско име -admin_email = Адрес за ел. поща +admin_email = Адрес на ел. поща path = Път password = Парола host = Хост @@ -2045,17 +1276,10 @@ admin_title = Настройки на администраторския ака err_empty_admin_password = Администраторската парола не може да бъде празна. docker_helper = Ако стартирате Forgejo в Docker, моля, прочетете документацията преди да промените настройки. sqlite_helper = Път на файла за SQLite3 базата данни.
    Въведете абсолютен път, ако стартирате Forgejo като service. -err_empty_admin_email = Администраторският адрес за ел. поща не може да бъде празен. +err_empty_admin_email = Администраторският адрес на ел. поща не може да бъде празен. password_algorithm = Алгоритъм за хеш. на паролите -default_keep_email_private = Скриване на адресите за ел. поща по подразбиране +default_keep_email_private = Скриване на адресите на ел. поща по подразбиране invalid_password_algorithm = Невалиден алгоритъм за хеш. на паролите -err_admin_name_is_reserved = Потребителското име на администратора е невалидно, потребителското име е резервирано -err_admin_name_pattern_not_allowed = Потребителското име на администратора е невалидно, потребителското име съответства с резервиран шаблон -err_admin_name_is_invalid = Потребителското име на администратора е невалидно -db_schema_helper = Оставете празно за схемата по подразбиране на базата данни („public“). -reinstall_error = Опитвате се да инсталирате върху съществуваща Forgejo база данни -reinstall_confirm_message = Преинсталирането със съществуваща Forgejo база данни може да причини множество проблеми. В повечето случаи трябва да използвате съществуващия си „app.ini“, за да стартирате Forgejo. Ако знаете какво правите, потвърдете следното: -app_slogan = Слоган на инстанцията [filter] string.asc = А - Я @@ -2073,50 +1297,13 @@ issue.in_tree_path = В %s: release.note = Бележка: hi_user_x = Здравейте %s, admin.new_user.user_info = Информация за потребителя -register_notify = Добре дошли във %s +register_notify_prev9 = Добре дошли във Forgejo issue.action.new = @%[1]s създаде #%[2]d. issue.action.review = @%[1]s коментира в тази заявка за сливане. issue.action.reopen = @%[1]s отвори наново #%[2]d. issue.action.approve = @%[1]s одобри тази заявка за сливане. issue.action.reject = @%[1]s поиска промени в тази заявка за сливане. register_notify.title = %[1]s, добре дошли в %[2]s -link_not_working_do_paste = Ако връзката не работи, опитайте да я копирате и поставите в URL лентата на вашия браузър. -activate_account = Моля, активирайте своя акаунт -admin.new_user.subject = Нов потребител %s току-що се регистрира -activate_account.text_1 = Здравейте, %[1]s, благодарим ви за регистрацията в %[2]s! -activate_email.text = Моля, щракнете върху следната връзка, за да потвърдите своя адрес за ел. поща в рамките на %s: -activate_email = Потвърдете своя адрес за ел. поща -activate_account.text_2 = Моля, щракнете върху следната връзка, за да активирате своя акаунт в рамките на %s: -issue_assigned.issue = @%[1]s ви възложи задача %[2]s в хранилище %[3]s. -issue.action.push_n = @%[1]s изтласка %[3]d подавания към %[2]s -issue.action.push_1 = @%[1]s изтласка %[3]d подаване към %[2]s -repo.transfer.subject_to_you = %s иска да прехвърли хранилище "%s" към вас -issue.action.merge = @%[1]s сля #%[2]d в %[3]s. -issue_assigned.pull = @%[1]s ви възложи заявката за сливане %[2]s в хранилище %[3]s. -issue.action.ready_for_review = @%[1]s отбеляза тази заявка за сливане като готова за рецензиране. -repo.transfer.subject_to = %s иска да прехвърли хранилище "%s" към %s -password_change.subject = Вашата парола е променена -admin.new_user.text = Моля, щракнете тук, за да управлявате този потребител от администраторския панел. -password_change.text_1 = Паролата за вашия акаунт току-що беше променена. -reset_password = Възстановете своя акаунт -account_security_caution.text_1 = Ако това сте били вие, можете спокойно да игнорирате това ел. писмо. -issue.action.force_push = %[1]s изтласка принудително %[2]s от %[3]s към %[4]s. -team_invite.text_3 = Бележка: Тази покана е предназначена за %[1]s. Ако не сте очаквали тази покана, можете да игнорирате това ел. писмо. -view_it_on = Вижте го на %s -register_notify.text_1 = това е ел. писмо за потвърждение на вашата регистрация в %s! -register_notify.text_2 = Можете да влезете в акаунта си с потребителско име: %s -register_notify.text_3 = Ако някой друг е създал този акаунт за вас, първо ще трябва да зададете парола. -repo.collaborator.added.subject = %s ви добави към %s като сътрудник -primary_mail_change.text_1 = Основният адрес за ел. поща на вашия акаунт току-що беше променен на %[1]s. Това означава, че този адрес за ел. поща повече няма да получава известия по ел. поща за вашия акаунт. -team_invite.text_2 = Моля, щракнете върху следната връзка, за да се присъедините към екипа: -repo.transfer.body = За да го приемете или отхвърлите, посетете %s или просто го игнорирайте. -repo.collaborator.added.text = Бяхте добавени като сътрудник в хранилище: -team_invite.subject = %[1]s ви покани да се присъедините към организацията %[2]s -team_invite.text_1 = %[1]s ви покани да се присъедините към екип %[2]s в организация %[3]s. -reply = или отговорете директно на това ел. писмо -reset_password.text = Ако това сте вие, моля, щракнете върху следната връзка, за да възстановите акаунта си в рамките на %s: -primary_mail_change.subject = Основният ви адрес за ел. поща е променен -account_security_caution.text_2 = Ако това не сте били вие, акаунтът ви е компрометиран. Моля, свържете се с администраторите на този сайт. [user] joined_on = Присъединени на %s @@ -2137,7 +1324,7 @@ follow = Последване followers_few = %d последователи block_user = Блокиране на потребителя change_avatar = Променете профилната си снимка… -email_visibility.limited = Вашият адрес за ел. поща е видим за всички удостоверени потребители +email_visibility.limited = Вашият адрес на ел. поща е видим за всички удостоверени потребители disabled_public_activity = Този потребител е изключил публичната видимост на дейността. email_visibility.private = Вашият адрес на ел. поща е видим само за вас и администраторите show_on_map = Показване на това място на картата @@ -2147,19 +1334,6 @@ followers.title.few = Последователи followers.title.one = Последовател following.title.one = Следван following.title.few = Следвани -public_activity.visibility_hint.self_public = Вашата дейност е видима за всички, с изключение на взаимодействията в частни пространства. Конфигуриране. -form.name_pattern_not_allowed = Шаблонът "%s" не е разрешен в потребителско име. -form.name_reserved = Потребителското име "%s" е резервирано. -public_activity.visibility_hint.self_private_profile = Вашата дейност е видима само за вас и администраторите на инстанцията, тъй като вашият профил е частен. Конфигуриране. -block_user.detail = Моля, имайте предвид, че блокирането на потребител има и други ефекти, като например: -block_user.detail_2 = Този потребител няма да може да взаимодейства с хранилищата, които притежавате, или със задачите и коментарите, които сте създали. -block_user.detail_3 = Няма да можете да се добавяте един друг като сътрудници на хранилище. -public_activity.visibility_hint.self_private = Вашата дейност е видима само за вас и администраторите на инстанцията. Конфигуриране. -form.name_chars_not_allowed = Потребителското име „%s“ съдържа невалидни знаци. -public_activity.visibility_hint.admin_private = Тази дейност е видима за вас, защото сте администратор, но потребителят иска тя да остане частна. -public_activity.visibility_hint.admin_public = Тази дейност е видима за всички, но като администратор можете да виждате и взаимодействия в частни пространства. -follow_blocked_user = Не можете да последвате този потребител, защото сте го блокирали или той ви е блокирал. -block_user.detail_1 = Ще спрете да се следвате един друг и няма да можете да се последвате отново. [home] filter = Други филтри @@ -2169,7 +1343,7 @@ my_orgs = Организации uname_holder = Потребителско име или ел. поща my_repos = Хранилища show_both_archived_unarchived = Показване на и архивирани и неархивирани -feed_of = Емисия на „%s“ +feed_of = Емисия на "%s" issues.in_your_repos = Във вашите хранилища show_both_private_public = Показване на и публични и частни show_only_private = Показване само на частни @@ -2183,7 +1357,6 @@ view_home = Преглед на %s collaborative_repos = Съвместни хранилища switch_dashboard_context = Превключване на контекста на таблото show_only_public = Показване само на публични -filter_by_team_repositories = Филтриране по хранилища на екипа [admin] packages.version = Версия @@ -2214,7 +1387,7 @@ systemhooks = Системни уеб-куки orgs.new_orga = Нова организация config.https_only = Само HTTPS users.update_profile_success = Потребителският акаунт е обновен. -users.new_success = Потребителският акаунт „%s“ е създаден. +users.new_success = Потребителският акаунт "%s" е създаден. users.deletion_success = Потребителският акаунт е изтрит. last_page = Последна config.test_email_placeholder = Ел. поща (напр. test@example.com) @@ -2241,7 +1414,7 @@ config.server_config = Сървърна конфигурация packages.size = Размер settings = Админ. настройки users = Потребителски акаунти -emails.duplicate_active = Този адрес за ел. поща вече е активен за друг потребител. +emails.duplicate_active = Този адрес на ел. поща вече е активен за друг потребител. config.app_ver = Forgejo версия config.custom_conf = Път на конфигурационния файл config.git_version = Git версия @@ -2258,22 +1431,16 @@ orgs.members = Участници config_settings = Настройки users.details = Потребителски данни packages.total_size = Общ размер: %s -dashboard.new_version_hint = Forgejo %s вече е наличен, вие изпълнявате %s. Проверете блога за повече подробности. -total = Общо: %d -config.db_type = Тип -monitor.queue.type = Тип -notices.type = Тип [error] not_found = Целта не може да бъде намерена. -report_message = Ако смятате, че това е грешка на Forgejo, моля, потърсете в задачите на Codeberg или отворете нова задача, ако е необходимо. +report_message = Ако смятате, че това е грешка на Forgejo, моля, потърсете в задачите на Codeberg или отворете нова задача, ако е необходимо. network_error = Мрежова грешка occurred = Възникна грешка -server_internal = Вътрешна грешка на сървъра [form] UserName = Потребителско име -Email = Адрес за ел. поща +Email = Адрес на ел. поща Password = Парола RepoName = Име на хранилището username_been_taken = Потребителското име вече е заето. @@ -2287,12 +1454,12 @@ lang_select_error = Изберете език от списъка. HttpsUrl = HTTPS URL require_error = ` не може да бъде празно.` Retype = Потвърдете паролата -url_error = `„%s“ не е валиден URL.` +url_error = `"%s" не е валиден URL.` Content = Съдържание team_not_exist = Екипът не съществува. TeamName = Име на екипа -email_error = ` не е валиден адрес за ел. поща.` -email_invalid = Адресът за ел. поща е невалиден. +email_error = ` не е валиден адрес на ел. поща.` +email_invalid = Адресът на ел. поща е невалиден. SSHTitle = Име на SSH ключ repo_name_been_taken = Името на хранилището вече е използвано. team_name_been_taken = Името на екипа вече е заето. @@ -2305,56 +1472,6 @@ Pronouns = Местоимения Biography = Биография Website = Уебсайт Location = Местоположение -cannot_add_org_to_team = Организация не може да бъде добавена като участник в екип. -auth_failed = Неуспешно удостоверяване: %v -team_no_units_error = Разрешете достъп до поне една секция на хранилището. -password_uppercase_one = Поне един голям знак -CommitSummary = Обобщение на подаването -username_error = ` може да съдържа само буквено-цифрови знаци („0-9“, „a-z“, „A-Z“), тире („-“), долна черта („_“) и точка („.“). Не може да започва или завършва с не-буквено-цифрови знаци, като също така са забранени и последователни не-буквено-цифрови знаци.` -username_error_no_dots = ` може да съдържа само буквено-цифрови знаци („0-9“, „a-z“, „A-Z“), тире („-“) и долна черта („_“). Не може да започва или завършва с не-буквено-цифрови знаци, като също така са забранени и последователни не-буквено-цифрови знаци.` -duplicate_invite_to_team = Потребителят вече е поканен като участник в екипа. -must_use_public_key = Ключът, който предоставихте, е частен ключ. Моля, не качвайте частния си ключ никъде. Вместо това използвайте публичния си ключ. -org_still_own_packages = Тази организация все още притежава един или повече пакети, първо ги изтрийте. -admin_cannot_delete_self = Не можете да изтриете себе си, когато сте администратор. Моля, първо премахнете администраторските си привилегии. -To = Име на клон -CommitMessage = Съобщение на подаването -include_error = ` трябва да съдържа подниз „%s“.` -alpha_dash_error = ` трябва да съдържа само буквено-цифрови знаци, тире („-“) и долна черта („_“).` -alpha_dash_dot_error = ` трябва да съдържа само буквено-цифрови знаци, тире („-“), долна черта („_“) и точка („.“).` -size_error = ` трябва да е с размер %s.` -min_size_error = ` трябва да съдържа поне %s знака.` -max_size_error = ` трябва да съдържа най-много %s знака.` -invalid_group_team_map_error = ` съпоставянето е невалидно: %s` -password_complexity = Паролата не отговаря на изискванията за сложност: -password_lowercase_one = Поне един малък знак -password_digit_one = Поне една цифра -password_special_one = Поне един специален знак (препинателни знаци, скоби, кавички и др.) -enterred_invalid_repo_name = Името на хранилището, което въведохте, е неправилно. -enterred_invalid_org_name = Името на организацията, което въведохте, е неправилно. -enterred_invalid_password = Паролата, която въведохте, е неправилна. -organization_leave_success = Успешно напуснахте организацията %s. -still_has_org = Вашият акаунт е участник в една или повече организации, първо ги напуснете. -org_still_own_repo = Тази организация все още притежава едно или повече хранилища, първо ги изтрийте или прехвърлете. -target_branch_not_exist = Целевият клон не съществува. -glob_pattern_error = ` glob шаблонът е невалиден: %s.` -openid_been_used = OpenID адресът „%s“ вече е използван. -unknown_error = Неизвестна грешка: -TreeName = Път до файла -AdminEmail = Администраторски адрес за ел. поща -email_domain_is_not_allowed = Домейнът на адреса за ел. поща на потребителя %s е в конфликт с EMAIL_DOMAIN_ALLOWLIST или EMAIL_DOMAIN_BLOCKLIST. Уверете се, че сте въвели правилно адреса за ел. поща. -email_been_used = Адресът за ел. поща вече се използва. - -NewBranchName = Име на новия клон -git_ref_name_error = ` трябва да е правилно форматирано име на Git препратка.` -regex_pattern_error = ` шаблонът на регулярния израз е невалиден: %s.` -repository_files_already_exist = Вече съществуват файлове за това хранилище. Свържете се със системния администратор. -repository_files_already_exist.delete = Вече съществуват файлове за това хранилище. Трябва да ги изтриете. -enterred_invalid_owner_name = Името на новия притежател не е валидно. -last_org_owner = Не можете да премахнете последния потребител от екипа на „притежателите“. Трябва да има поне един притежател за организация. -invalid_ssh_key = Не може да се потвърди вашият SSH ключ: %s -invalid_gpg_key = Не може да се потвърди вашият GPG ключ: %s -unable_verify_ssh_key = Не може да се потвърди SSH ключът, проверете го отново за грешки. -required_prefix = Въведеният текст трябва да започва с „%s“ [action] close_issue = `затвори задача %[3]s#%[2]s` @@ -2381,14 +1498,6 @@ push_tag = изтласка маркер %[3]s към %[3]s#%[2]s` reject_pull_request = `предложи промени за %[3]s#%[2]s` compare_branch = Сравняване -compare_commits_general = Сравняване на подавания -compare_commits = Сравнете %d подавания - -transfer_repo = прехвърли хранилище %s към %s -mirror_sync_push = синхронизира подавания към %[3]s на %[4]s от огледало -mirror_sync_create = синхронизира нова препратка %[3]s към %[4]s от огледало -mirror_sync_delete = синхронизира и изтри препратка %[2]s на %[3]s от огледало -review_dismissed = `отхвърли рецензия от %[4]s за %[3]s#%[2]s` [auth] tab_openid = OpenID @@ -2415,57 +1524,22 @@ must_change_password = Обновете паролата си password_too_short = Дължината на паролата не може да бъде по-малка от %d знака. tab_signin = Влизане tab_signup = Регистриране -password_pwned = Паролата, която сте избрали, е в списък с откраднати пароли, разкрити преди това при публични пробиви на данни. Моля, опитайте отново с различна парола. -confirmation_mail_sent_prompt = Ново ел. писмо за потвърждение е изпратено до %s. За да завършите процеса на регистрация, моля, проверете входящата си кутия и последвайте предоставената връзка в рамките на следващите %s. Ако адресът за ел. поща е неправилен, можете да влезете и да поискате друго ел. писмо за потвърждение да бъде изпратено на различен адрес. -hint_login = Вече имате акаунт? Влезте! -hint_register = Нуждаете се от акаунт? Регистрирайте се. -sign_up_button = Регистрирайте се. -back_to_sign_in = Назад към Вход -sign_in_openid = Продължаване с OpenID -send_reset_mail = Изпращане на ел. писмо за възстановяване -authorize_application = Упълномощаване на приложение -password_pwned_err = Неуспешно завършване на заявката към HaveIBeenPwned -last_admin = Не можете да премахнете последния администратор. Трябва да има поне един администратор. -allow_password_change = Изискване потребителят да смени паролата си (препоръчително) -authorize_title = Упълномощавате ли „%s“ да има достъп до вашия акаунт? -reset_password_mail_sent_prompt = Изпратено е ел. писмо за потвърждение до %s. За да завършите процеса по възстановяване на акаунта, моля, проверете входящата си поща и последвайте предоставената връзка в рамките на следващите %s. -reset_password_wrong_user = Вие сте влезли като %s, но връзката за възстановяване на акаунта е предназначена за %s -authorize_redirect_notice = Ще бъдете пренасочени към %s, ако упълномощите това приложение. -authorize_application_description = Ако предоставите достъп, то ще може да осъществява достъп и да записва цялата информация за вашия акаунт, включително частни хранилища и организации. -twofa_scratch_used = Използвали сте своя резервен код. Пренасочени сте към страницата с настройки за двуфакторно удостоверяване, за да можете да премахнете регистрацията на устройството си или да генерирате нов резервен код. -reset_password_helper = Възстановяване на акаунт -invalid_password = Вашата парола не съвпада с паролата, използвана за създаване на акаунта. -invalid_code = Вашият код за потвърждение е невалиден или е изтекъл. -invalid_code_forgot_password = Вашият код за потвърждение е невалиден или е изтекъл. Щракнете тук, за да започнете нова сесия. -scratch_code = Резервен код -use_scratch_code = Използвайте резервен код -use_onetime_code = Използвайте еднократен код -twofa_scratch_token_incorrect = Вашият резервен код е неправилен. -authorize_application_created_by = Това приложение е създадено от %s. -authorization_failed = Неуспешно упълномощаване -resent_limit_prompt = Вече сте поискали ел. писмо за активация наскоро. Моля, изчакайте 3 минути и опитайте отново. -has_unconfirmed_mail = Здравейте, %s, имате непотвърден адрес за ел. поща (%s). Ако не сте получили ел. писмо за потвърждение или трябва да изпратите ново, моля, щракнете върху бутона по-долу. -change_unconfirmed_email_error = Неуспешна промяна на адреса за ел. поща: %v -resend_mail = Щракнете тук, за повторно изпращане на ел. писмо за активация -change_unconfirmed_email_summary = Промяна на адреса, на който се изпраща ел. писмо за активация. -change_unconfirmed_email = Ако сте въвели грешен адрес за ел. поща по време на регистрацията, можете да го промените по-долу и потвърждение ще бъде изпратено на новия адрес. [aria] footer.software = Относно този софтуер footer.links = Връзки footer = Долен колонтитул -navbar = Навигационна лента [startpage] install = Лесен за инсталиране lightweight = Лек license = Отворен код -install_desc = Просто стартирайте двоичния файл за вашата платформа, използвайте Docker, или го получете пакетиран. +install_desc = Просто стартирайте двоичния файл за вашата платформа, използвайте Docker, или го получете пакетирано. app_desc = Безпроблемна Git услуга със самостоятелен хостинг platform = Междуплатформен lightweight_desc = Forgejo има ниски минимални изисквания и може да работи на икономичен Raspberry Pi. Спестете енергията на вашата машина! -platform_desc = Forgejo работи на свободни операционни системи като Linux и FreeBSD, както и на различни CPU архитектури. Изберете тази, която предпочитате! -license_desc = Вземете Forgejo! Присъединете се към нас, допринасяйки, за да направите този проект още по-добър. Не се колебайте да сътрудничите! +platform_desc = Forgejo работи навсякъде, където Go може да се компилира: Windows, macOS, Linux, ARM, и т.н. Изберете, което харесвате! +license_desc = Вземете Forgejo! Присъединете се към нас, допринасяйки, за да направите този проект още по-добър. Не се колебайте да сътрудничите! [notification] subscriptions = Абонаменти @@ -2508,7 +1582,7 @@ actions = Действия variables.none = Все още няма променливи. variables.creation.failed = Неуспешно добавяне на променлива. variables.update.failed = Неуспешно редактиране на променлива. -variables.creation.success = Променливата „%s“ е добавена. +variables.creation.success = Променливата "%s" е добавена. variables.deletion.success = Променливата е премахната. variables.edit = Редактиране на променливата variables.deletion = Премахване на променливата @@ -2517,20 +1591,6 @@ variables.creation = Добавяне на променлива variables.deletion.failed = Неуспешно премахване на променлива. runners.task_list.repository = Хранилище runners.description = Описание -runs.no_workflows.help_no_write_access = За да научите повече за Forgejo Actions, вижте документацията. -variables.management = Управление на променливи -variables.not_found = Променливата не е открита. -variables.id_not_exist = Променлива с идентификатор %d не съществува. -runners.owner_type = Тип - -unit.desc = Управление на интегрирани CI/CD pipelines с Forgejo Actions. -status.unknown = Неизвестно -status.waiting = Изчаква се -status.running = Изпълнява се -status.success = Успешно -status.failure = Неуспешно -status.cancelled = Отменено -status.skipped = Пропуснато [heatmap] less = По-малко @@ -2560,41 +1620,29 @@ invalid_input_type = Не можете да качвате файлове от component_loading_failed = Неуспешно зареждане на %s contributors.what = приноси recent_commits.what = скорошни подавания -component_loading = Зареждане на %s… +component_loading = Зареждане на %s... component_loading_info = Това може да отнеме известно време… -code_frequency.what = честота на промените -component_failed_to_load = Възникна неочаквана грешка. [projects] type-1.display_name = Индивидуален проект -deleted.display_name = Изтрит проект [search] no_results = Няма намерени съответстващи резултати. -team_kind = Търсене на екипи… -repo_kind = Търсене на хранилища… -org_kind = Търсене на организации… -user_kind = Търсене на потребители… -code_kind = Търсене на код… -commit_kind = Търсене на подавания… -project_kind = Търсене на проекти… -package_kind = Търсене на пакети… -search = Търсене… -branch_kind = Търсене на клонове… -pull_kind = Търсене на заявки за сливане… -issue_kind = Търсене на задачи… +team_kind = Търсене на екипи... +repo_kind = Търсене на хранилища... +org_kind = Търсене на организации... +user_kind = Търсене на потребители... +code_kind = Търсене на код... +commit_kind = Търсене на подавания... +project_kind = Търсене на проекти... +package_kind = Търсене на пакети... +search = Търсене... +branch_kind = Търсене на клонове... +pull_kind = Търсене на заявки за сливане... +issue_kind = Търсене на задачи... fuzzy = Приблизително exact = Прецизно -regexp = Регекс -regexp_tooltip = Третиране на термина за търсене като регулярен израз -fuzzy_tooltip = Включване на резултати, които също съвпадат приблизително с термина за търсене -exact_tooltip = Включване само на резултати, които съвпадат точно с термина за търсене -code_search_unavailable = Търсенето на код в момента не е достъпно. Моля, свържете се с администратора на сайта. -keyword_search_unavailable = Търсенето по ключова дума в момента не е достъпно. Моля, свържете се с администратора на сайта. -union_tooltip = Включване на резултати, които съвпадат с някоя от ключовите думи, разделени с интервал -union = Обединение -type_tooltip = Тип търсене [markup] filepreview.lines = Редове от %[1]d до %[2]d в %[3]s @@ -2608,36 +1656,3 @@ gib = ГиБ tib = ТиБ pib = ПиБ eib = ЕиБ - - -[translation_meta] -test = окей - -[repo.permissions] -code.read = Четене: Достъп и клониране на кода на хранилището. -code.write = Писане: Изтласкване към хранилището, създаване на клонове и маркери. -issues.read = Четене: Четене и създаване на задачи и коментари. -issues.write = Писане: Затваряне на задачи и управление на метаданни като етикети, етапи, изпълнители, крайни срокове и зависимости. -pulls.read = Четене: Четене и създаване на заявки за сливане. -pulls.write = Писане: Затваряне на заявки за сливане и управление на метаданни като етикети, етапи, изпълнители, крайни срокове и зависимости. -releases.read = Четене: Преглед и изтегляне на издания. -wiki.read = Четене: Четене на интегрираното уики и неговата история. -wiki.write = Писане: Създаване, обновяване и изтриване на страници в интегрираното уики. -projects.read = Четене: Достъп до проектните табла на хранилището. -projects.write = Писане: Създаване и редактиране на проекти и колони. - -[gpg] -default_key = Подписано с ключ по подразбиране -error.extract_sign = Неуспешно извличане на подпис -error.generate_hash = Неуспешно генериране на хеш на подаването -error.no_committer_account = Няма акаунт, свързан с адреса за ел. поща на подаващия -error.no_gpg_keys_found = Не е намерен известен ключ за този подпис в базата данни -error.not_signed_commit = Не е подписано подаване -error.failed_retrieval_gpg_keys = Неуспешно извличане на ключ, свързан с акаунта на подаващия -error.probable_bad_signature = ВНИМАНИЕ! Въпреки че има ключ с това ID в базата данни, той не потвърждава това подаване! Това подаване е ПОДОЗРИТЕЛНО. -error.probable_bad_default_signature = ВНИМАНИЕ! Въпреки че ключът по подразбиране има това ID, той не потвърждава това подаване! Това подаване е ПОДОЗРИТЕЛНО. - -[units] -unit = Елемент -error.no_unit_allowed_repo = Нямате разрешение за достъп до никоя секция на това хранилище. -error.unit_not_allowed = Нямате разрешение за достъп до тази секция на хранилището. diff --git a/options/locale/locale_bn.ini b/options/locale/locale_bn.ini index 2155f9073c..8741fee98c 100644 --- a/options/locale/locale_bn.ini +++ b/options/locale/locale_bn.ini @@ -1,8 +1,6 @@ + + + [common] help = সাহায্য -dashboard = ড্যাশবোর্ড -home = বাড়ি -explore = দেখোণ -logo = লোগো -sign_in = সাইণ ইণ -sign_in_or = বা \ No newline at end of file +dashboard = ড্যাশবোর্ড \ No newline at end of file diff --git a/options/locale/locale_bs.ini b/options/locale/locale_bs.ini index 78eb7daa33..bec7a65005 100644 --- a/options/locale/locale_bs.ini +++ b/options/locale/locale_bs.ini @@ -1,3 +1,6 @@ + + + [common] tracked_time_summary = Sažetak praćenog vremena bazirano na filterima liste problema language = Jezik diff --git a/options/locale/locale_ca.ini b/options/locale/locale_ca.ini index ea2af3b645..e917e214ac 100644 --- a/options/locale/locale_ca.ini +++ b/options/locale/locale_ca.ini @@ -1,10 +1,13 @@ + + + [common] -home = Inici +home = inici dashboard = Panell de control explore = Explorar help = Ajuda logo = Logo -sign_in = Iniciar sessió +sign_in = Entrar sign_in_with_provider = Entra amb %s sign_in_or = o sign_out = Sortir @@ -15,9 +18,9 @@ page = Pàgina template = Plantilla language = Idioma notifications = Notificacions -active_stopwatch = Registre de temps actiu +active_stopwatch = Registre de Temps Actiu create_new = Crear… -user_profile_and_more = Perfil i Configuració… +user_profile_and_more = Perfil i configuració… signed_in_as = Entrat com enable_javascript = Aquest lloc web requereix Javascript. toc = Taula de Continguts @@ -25,462 +28,4 @@ licenses = Llicències sign_up = Registrar-se link_account = Vincular un compte tracked_time_summary = Resum del temps registrat basat en filtres del llistat de temes -return_to_forgejo = Tornar a Forgejo -toggle_menu = Commuta el menú -more_items = Més elements -username = Nom d'usuari -email = Direcció de correu -password = Contrasenya -access_token = Testimoni d'accés -re_type = Confirmar contrasenya -captcha = CAPTCHA -twofa = Autenticació de doble factor -twofa_scratch = Codi de rascar de doble-factor -passcode = Codi de pas -webauthn_insert_key = Inseriu la vostra clau de seguretat -webauthn_sign_in = Premeu el botó a la vostra clau de seguretat. Si no en té, torneu-la a inserir. -webauthn_press_button = Siusplau, premeu el botó a la vostra clau de seguretat… -webauthn_use_twofa = Utilitza un codi de doble factor des del teu mòbil -webauthn_error = No s'ha pogut llegir la clau de seguretat. -webauthn_unsupported_browser = El teu navegador no suprta WebAuthn. -webauthn_error_unknown = Hi ha hagut un error desconegut. Si us plau torneu-ho a intentar. -webauthn_error_insecure = WebAuthn només suporta connexions segures. Per provar sobre HTTP, podeu utilitzar l'origen "localhost" o "127.0.0.1" -webauthn_error_unable_to_process = El servidor no ha pogut processar la vostra petició. -webauthn_error_duplicated = La clau de seguretat no és permesa per aquesta petició. Si us plau, assegureu-vos que la clau encara no ha estat registrada. -webauthn_error_empty = S'ha d'anomenar aquesta clau. -webauthn_reload = Recarrega -repository = Repositori -organization = Organització -mirror = Mirall -new_repo = Nou repositori -new_migrate = Nova migració -new_mirror = Nou mirall -new_fork = Nou fork d'un repositori -new_org = Nova organització -new_project = Nou projecte -new_project_column = Nova columna -admin_panel = Administració del lloc -settings = Configuració -your_profile = Perfil -your_starred = Preferits -your_settings = Configuració -all = Tots -sources = Fonts -mirrors = Miralls -collaborative = Coŀlaboratiu -forks = Forks -activities = Activitats -pull_requests = Pull requests -issues = Problemes -milestones = Fites -ok = OK -retry = Reintentar -rerun = Torna a executar -rerun_all = Torna a executar tots els treballs -save = Guardar -add = Afegir -add_all = Afegeix-los tots -remove = Esborrar -remove_all = Esborral's tots -edit = Editar -view = Mirar -enabled = Habilitat -disabled = Deshabilitat -filter.public = Públic -filter.private = Privat -show_full_screen = Mostra a pantalla completa -webauthn_error_timeout = Temps d'espera finalitzar abans que la seva clau pogués ser llegida. Siusplau recarregueu la pàgina i torneu-ho a intentar. -remove_label_str = Esborra l'element "%s" -error413 = Ha exhaurit la quota. -cancel = Canceŀlar -download_logs = Baixa els registres -never = Mai -concept_user_individual = Individual -concept_code_repository = Repositori -concept_user_organization = Organització -show_timestamps = Mostra les marques temporals -show_log_seconds = Mostra els segons -test = Test -locked = Bloquejat -copy = Copiar -copy_generic = Copiar al porta-retalls -copy_url = Copiar l'URL -copy_hash = Copiar l'empremta -copy_content = Copiar continguts -copy_branch = Copiar el nom de la branca -copy_success = Copiat! -copy_error = Ha fallat el copiar -copy_type_unsupported = Aquest tipus de fitxer no pot ser copiat -write = Escriure -preview = Previsualitzar -loading = Carregant… -error = Error -error404 = La pàgina a la qual estàs intentant arribar no existeix, ha sigut eliminada o no estàs autoritzat a veure-la. -go_back = Tornar Enrere -invalid_data = Dades invalides: %v -unknown = Desconegut -rss_feed = Agregador RSS -pin = Fixar -unpin = Desfixar -artifacts = Artefactes -confirm_delete_artifact = Està segur de voler esborrar l'artefacte "%s"? -archived = Arxivat -concept_system_global = Global -confirm_delete_selected = Confirmar esborrar tots els elements seleccionats? -name = Nom -value = Valor -filter.is_mirror = És mirall -filter.not_mirror = No és mirall -filter.is_template = És plantilla -filter.not_template = No és plantilla -filter = Filtre -filter.clear = Netejar filtes -filter.is_archived = Arxivats -filter.not_archived = No arxivats -filter.not_fork = No és fork -filter.is_fork = Són forks -copy_path = Copiar ruta -new_repo.title = Nou repositori -new_migrate.title = Nova migració -new_org.title = Nova organització -new_repo.link = Nou repositori -new_migrate.link = Nova migració -new_org.link = Nova organització - -[search] -milestone_kind = Cerca fites... -fuzzy = Difusa -search = Cerca... -type_tooltip = Tipus de cerca -fuzzy_tooltip = Inclou resultats que s'assemblen al terme de la cerca -repo_kind = Cerca repos… -user_kind = Cerca usuaris… -code_search_unavailable = La cerca de codi no està disponible actualment. Si us plau concteu amb l'administrador del lloc. -code_search_by_git_grep = Els resultats actuals de la cerca de codi són proporcionats per "git grep". Podríen haver-hi millors resultats si l'administrador del lloc habilita l'indexador de codi. -package_kind = Cerca paquets… -project_kind = Cerca projectes… -branch_kind = Cerca branques… -commit_kind = Cerca commits… -runner_kind = Cerca executors… -no_results = Cap resultat coincident trobat. -keyword_search_unavailable = La cerca per paraula clau no està disponible ara mateix. Si us plau contacteu amb l'administrador del lloc. -union = Paraules clau -union_tooltip = Inclou resultats que encaixen amb qualsevol paraula clau separada per espais -org_kind = Cerca organitzacions… -team_kind = Cerca teams… -code_kind = Cerca codi… -pull_kind = Cerca "pulls"… -exact = Exacte -exact_tooltip = Inclou només resultats que són exactament el terme de cerca -issue_kind = Cerca problemes… -regexp = RegExp -regexp_tooltip = Interpreta el terme de cerca com una expressió regular - -[heatmap] -number_of_contributions_in_the_last_12_months = %s contribucions en els últims 12 mesos -contributions_zero = Cap contribució -contributions_format = {contribucions} a {day} de {month} de {year} -contributions_one = contribució -contributions_few = contribucions -less = Menys -more = Més - -[filter] -string.asc = A - Z -string.desc = Z - A - -[error] -occurred = Hi ha hagut un error -report_message = Si creus que això es un bug de Forgejo, si us plau cerca problemes a Codeberg i obre'n un de nou si cal. -not_found = L'objectiu no s'ha pogut trobar. -server_internal = Error intern del servidor -missing_csrf = Petició Dolenta: falta el testimoni CSRF -invalid_csrf = Petició Dolenta: testimoni CSRF invàlid -network_error = Error de xarxa - -[install] -title = Configuració inicial -docker_helper = Si executes Forgejo a Docker, si us plau llegeis la documentació abans de canviar qualsevol configuració. -require_db_desc = Forgejo requereix de MySQL, PostreSQL, SQLite3 o TiDB (protocol MySQL). -db_title = Configuració de la base de dades -path = Ruta -sqlite_helper = Ruta al fitxer de la base de dades SQLite3.
    Introduex la ruta absoluta si executes Forgejo com a servei. -user = Nom d'usuari -db_schema = Esquema -ssl_mode = SSL -err_empty_admin_email = El correu de l'administrador no pot ser buit. -reinstall_error = Estas intentant instaŀlar sobre una base de dades existent de Forgejo -reinstall_confirm_message = Reinstaŀlar amb una base de dades existent de Forgejo pot causar diferents problemes. En la majoria de casos, s'hauria d'utilitzar l'"app.ini" existent per executar Forgejo. Si saps el que estàs fent, confirma el seguent: -no_admin_and_disable_registration = No pot deshabilitar l'autoregistre d'usuaris sense crear un compte d'administrador. -err_admin_name_is_reserved = El nom d'usuari "Administrador" no es vàlid: està reservat -smtp_addr = Hoste SMTP -smtp_port = Port SMPT -smtp_from = Enviar correu com a -mailer_user = Nom d'usuari SMTP -err_admin_name_pattern_not_allowed = El nom d'usuari de l'administrador no es vàlid: coincideix amb un patró reservat -err_admin_name_is_invalid = El nom d'usuari "Administrador" no és vàlid -general_title = Configuració general -app_name = Títol de la instància -app_url = URL base -email_title = Configuració del correu -server_service_title = Configuracions del servidor i de serveis de tercers -offline_mode = Habilitar el mode local -mail_notify = Habilita les notificacions per correu -federated_avatar_lookup = Habilitar avatars federats -admin_title = Configuració del compte d'administrador -invalid_admin_setting = Configuració del compte d'administrador invalida: %v -invalid_log_root_path = La ruta dels registres es invalida: %v -save_config_failed = Error al guardar la confifuració: %v -enable_update_checker_helper_forgejo = Comprovarà periodicament si hi ha una nova versió de Forgejo comprovant un registre DNS TXT a release.forgejo.org. -password_algorithm = Funció resum per a contrasenyes -install = Instaŀlació -db_schema_helper = Deixa en blanc per la base de dades per defecte ("public"). -domain = Domini del servidor -mailer_password = Contrasenya SMTP -admin_email = Direcció de correu -invalid_db_setting = La configuració de la base de dades és invalida: %v -run_user_not_match = El nom d'usuari a executar com no és l'actual: %s -> %s -internal_token_failed = Error al generar testimoni intern: %v -secret_key_failed = Error al generar clau secreta: %v -test_git_failed = No s'ha pogut provar l'ordre "git": %v -sqlite3_not_available = Aquesta versióó de Forgejo no suporta SQLite3. Si us plau baixeu el binari de la versió oficial de %s (no la versió "gobuild"). -invalid_db_table = La taula "%s" de la base de dades es invalida: %v -invalid_repo_path = L'arrel del repositori es invalida: %v -invalid_app_data_path = La ruta de dades de l'aplicació es invalida: %v -env_config_keys_prompt = Les seguents variables d'entorns tambe s'aplicaràn al teu fitxer de configuració: -offline_mode.description = Deshabilitar les CDNs de tercers i servir tot el contingut de forma local. -disable_registration.description = Només els administradors de la instància podràn crear nous usuaris. És altament recomanat deixar el registre deshabilitat excepte si s'està hostatjant una instància pública per a tothom i està llesta per a assolir grans quantitats de comptes spam. -admin_password = Contrasenya -err_empty_admin_password = La contrasenya de l'administrador no por ser buida. -ssh_port = Por del servidor SSH -disable_gravatar = Deshabilitar Gravatar -disable_registration = Deshabilitar l'auto-registre -openid_signin = Habilita l'inici de sessió amb OpenID -enable_captcha = Habilita el CAPTCHA al registre -default_keep_email_private = Amaga les direccions de correu per defecte -app_slogan = Eslogan de la instància -app_slogan_helper = Escriu l'eslogan de la teva instància aquí. Deixa buit per deshabilitar. -repo_path = Ruta de l'arrel del repositori -log_root_path_helper = Els arxius dels registres es s'escriuran en aquest directori. -optional_title = Configuracions opcionals -host = Hoste -lfs_path = Ruta arreal de Git LFS -run_user = Executar com a usuari -domain_helper = Domini o adreça de l'hosta per al servidor. -http_port = Port d'escolta HTTP -app_url_helper = Adreces base per a clonació HTTP(S) i notificacions per correu. -log_root_path = Ruta dels registres -smtp_from_invalid = L'adreça d'"Enviar correu com a" és invalida -smtp_from_helper = L'adreça de correu que Forgejo utilitzarà. Entri el correu en pla o en format "Nom" . -register_confirm = Requereix confirmació de correu per a registrar-se -disable_gravatar.description = Deshabilitar l'ús de Gravatar o d'altres serveis d'avatars de tercers. S'utilitzaran imatges per defecte per als avatars dels uauris fins que pujin el seu propi a la instància. -federated_avatar_lookup.description = Cerca d'avatars amb Libravatar. -allow_only_external_registration = Permet el registre només amb serveis externs -allow_only_external_registration.description = Els usuaris nomes podràn crear nous comptes utilitzant els serveis externs configurats. -enable_captcha.description = Requereix als usuaris passar el CAPTCHA per a poder-se crear comptes. -require_sign_in_view = Requereix inciar sessió per a veure el contingut de la instància -default_keep_email_private.description = Habilita l'ocultament de les direccions de correu per a nous usuaris per defecte, amb tal que aquesta informació no sigui filtrada immediatament despres de registrar-se. -default_allow_create_organization = Per defecte permet crear organitzacions -default_enable_timetracking = Per defecta habilita el seguiment de temps -default_enable_timetracking.description = Per defecte activa el de seguiment de temps als nous repositoris. -admin_name = Nom d'usuari de l'administrador -install_btn_confirm = Instaŀlar Forgejo -allow_dots_in_usernames = Permet als usuaris utilitzar punts en els seus noms d'usuari. No afecta als comptes existents. -no_reply_address = Domini del correu ocult -no_reply_address_helper = Nom del domini per a usuaris amb l'adreça de correu oculta. Per exemple, el nom d'usuari "pep" tindrà la sessió inciada com a "pep@noreply.example.org" si el domini per a adreces ocultes es configurat a "noreply.example.org". -password_algorithm_helper = Configura la funció resum per a contrasenyes. Els algorismes difereixen en requeriments i seguretat. L'algorisme "argon2" es bastant segur, però utilitza molta memòria i podría ser inapropiat per a sistemes petits. -invalid_password_algorithm = Funció resum invalida per a contrasenyes -enable_update_checker = Habilita la comprovació d'actualitzacions -env_config_keys = configuració de l'entorn -db_type = Tipus de base de dades -lfs_path_helper = Els arxius seguits per Git LFS es desaran en aquest directory. Deixa buit per deshabilitar. -http_port_helper = Numero de port que utilitzarà el servidor web de Forgejo. -repo_path_helper = Els repositoris Git remotes es desaran en aquest diectori. -run_user_helper = El nom d'usuari del sistema operatiu sota el que Forgejo s'executa. Notis que aquest usuari ha de tenir accés a la ruta arrel del repositori. -ssh_port_helper = Numero del port que utilitzarà el servidor SSH. Deixa buit per deshablitar el servidor SSH. -require_sign_in_view.description = Limita l'accès al contingut per als usuaris connectats. Els visitatnts només podran veure les pàgines d'autenticació. -default_allow_create_organization.description = Per defecte permet als nous usuaris crear organitzacions. Quan aquesta opció està deshabilitada, un administrador haurà de concedir permisos per a crear organitzacions als nous usuaris. -reinstall_confirm_check_3 = Confirma que està completament segur que Forgejo s'està executant amb l'app.ini correcte i que està segur que ha de tornar a instaŀlar. Confirma que coneix els riscos anteriors. -err_empty_db_path = La ruta a la base de dades SQLite3 no por ser buida. -reinstall_confirm_check_1 = Les dades xifrades per la SECRET_KEY a l'app.ini podrien perdre's: es posible que els usuaris no puguin iniciar sessió amb 2FA/OTP i que els miralls no funcionin correctament. Marcant aquesta casella confirmes que l'arxiu app.ini conté la SECRET_KEY correcta. -reinstall_confirm_check_2 = És possibles que els repositoris i les configuracions hagin de tornar-se a sincronitzar. Marcant aquesta casella confirmes que resincronitzaras els ganxos dels respositoris i l'arxiu authorized_keys manualment. Confirma que comprovarà que les configuracions dels repositoris i els miralls són correctes. -openid_signin.description = Permet als usuaris iniciar sessió amb OpenID. -openid_signup = Habilita l'auto-registre amb OpenID -openid_signup.description = Permet als usuaris crear-se comptes amb OpenID si l'auto-registre està habilitat. -config_location_hint = Aquestes opcions de configuració es desaràn a: -admin_setting.description = Crear un compte d'aministrador és opcional. El primer usuari registrat automàticament serà un adminstrador. -confirm_password = Confirmar contrasenya -password = Contrasenya -db_name = Nom de la base de dades -app_name_helper = Escriu el nom de la teva instància aquí. Es mostrarà a totes les pàgines. - -[startpage] -license_desc = Aconsegueix Forgejo! Uneix-te contribuint per a millorar aquest projecte. No et fagi vergonya ser un contribuent! -platform_desc = Està confirmat que Forgejo s'executa en sistemes operatius lliures com Linux o FreeBSD, així com diferentes arquitectures de CPU. Tria la que més t'agradi! -lightweight_desc = Forgejo te uns requeriments minims baixos i pot executar-se en una Raspberry Pi. Estalvia energia a la teva màquina! -license = Codi Obert -app_desc = Un servei de Git autohostatjat i indolor -install = Fàcil d'instaŀlar -platform = Multiplataforma -lightweight = Lleuger -install_desc = Simplement executa el binari per a la teva plataforma, carrega'l amb Docker, o aconsegueix-lo empaquetat. - -[explore] -code_last_indexed_at = Indexat oer últim cop a %s -relevant_repositories_tooltip = Els repositoris que són forks o que no tenen tòpic, icona o descripció estàn amagats. -relevant_repositories = Només és mostren repositoris rellevants, mostra resultats sense filtrar. -repos = Repositoris -organizations = Organitzacions -code = Codi -stars_few = %d estrelles -forks_one = %d fork -forks_few = %d forks -go_to = Ves a -users = Usuaris -stars_one = %d estrella - -[auth] -disable_register_prompt = El registre està deshabilitat. Si us plau contacti l'administrador del lloc. -disable_register_mail = Registre amb confirmació per correu deshabilitat. -manual_activation_only = Contacti amb l'administrador de lloc per a completar l'activació. -remember_me = Recordar aquest dispositiu -create_new_account = Registrar compte -reset_password = Recuperació del compte -reset_password_wrong_user = Heu iniciat sessió com a %s, però l'enllaç de recuperació pertany a %s -allow_password_change = Requereix a l'usuari canviar la contrasenya (recomanat) -invalid_code_forgot_password = El codi de confirmació és invàlid o ha caducat. Feu click aquí per a iniciar una sessió nova. -twofa_scratch_used = Ja heu utilitzat el vostre codi de recuperació. Se us ha redirigit a la pàgina de configuració de l'autenticació de doble factor per tal d'eliminar el dispositiu o generar un codi de recuperació nou. -login_userpass = Entra -oauth.signin.error.temporarily_unavailable = Ha fallat l'autorització perquè el servidor d'autenticació no està disponible temporalment. Intenteu-ho de nou més tard. -authorization_failed_desc = Ha fallat l'autorització perquè s'ha detectat una sol·licitud invàlida. Si us plau, contacteu amb el responsable de l'aplicació que heu intentat autoritzar. -authorization_failed = Ha fallat l'autorització -last_admin = No podeu eliminar l'últim usuari administrador. Com a mínim n'hi ha d'haver un. -password_pwned_err = No s'ha pogut completar la sol·licitud a HaveIBeenPwned -forgot_password = Contrasenya oblidada? -reset_password_mail_sent_prompt = S'ha enviat un correu electrònic de confirmació a %s. Per tal de completar el procés de recuperació del compte, reviseu la safata d'entrada i seguiu l'enllaç que se us ha enviat en els següents %s. -prohibit_login = El compte està en suspensió -resent_limit_prompt = Fa poc que heu sol·licitat un correu electrònic d'activació. Si us plau, espereu 3 minuts i torneu a intentar-ho. -has_unconfirmed_mail = Hola %s, la vostra adreça de correu no s'ha confirmat (%s). Si no heu rebut un correu de confirmació o necessiteu que l'enviem de nou, feu clic al botó següent. -change_unconfirmed_email_summary = Canvieu l'adreça de correu on s'envia el correu d'activació. -invalid_code = El codi de confirmació no és vàlid o ha caducat. -invalid_password = La contrasenya no coincideix amb la que es va utilitzar per a crear el compte. -reset_password_helper = Recuperar compte -verify = Verificar -unauthorized_credentials = Les credencials són incorrectes o han caducat. Torneu a executar l'ordre o visiteu %s per a més informació -scratch_code = Codi de recuperació -use_scratch_code = Utilitzar un codi de recuperació -twofa_scratch_token_incorrect = El codi de recuperació és incorrecte. -oauth_signup_title = Completar compte nou -oauth_signup_submit = Completar compte -oauth.signin.error.access_denied = S'ha denegat la sol·licitud d'autorització. -openid_connect_submit = Connectar -openid_connect_title = Entreu a un compte existent -openid_register_title = Crear un compte nou -authorize_application = Autoritzar aplicació -authorize_redirect_notice = Sereu redirigits a %s si autoritzeu aquesta aplicació. -authorize_application_description = Si li concediu l'accés podrà accedir i escriure a tota la informació del vostre compte, inclòs repositoris privats i organitzacions. -authorize_title = Autoritzeu "%s" a accedir al vostre compte? -active_your_account = Activeu el compte -sign_up_successful = S'ha creat el compte correctament. Benvingut! -account_activated = El compte s'ha activat -send_reset_mail = Enviar correu electrònic de recuperació del compte -password_too_short = La longitud de la contrasenya no pot ser inferior a %d caràcters. -oauth_signin_title = Entreu per a autoritzar el compte vinculat -oauth_signin_submit = Vincular compte -disable_forgot_password_mail = La recuperació de comptes està deshabilitada perquè no hi ha configuració de correu electrònic. Si us plau, contacteu amb l'administrador del lloc. -email_domain_blacklisted = No podeu registrar-vos amb el correu electrònic. -hint_login = Ja tens compte? Entra ara! -hint_register = Necessites un compte? Registra't ara. -sign_up_button = Registra't ara. -must_change_password = Actualitza la contrasenya -change_unconfirmed_email_error = No s'ha pogut canviar l'adreça de correu: %v -oauth_signup_tab = Registrar compte nou -back_to_sign_in = Torneu a entrar -openid_signin_desc = Introduïu la URI OpenID. Per exemple: alice.openid.example.org o https://openid.example.org/alice. -authorize_application_created_by = Aquesta aplicació l'ha creat %s. -password_pwned = La contrasenya que heu introduït es troba en una llista de contrasenyes robades exposades en dades filtrades públicament. Si us plau, intenteu-ho de nou amb una contrasenya diferent i considereu modificar aquesta contrasenya a tot arreu on la utilitzeu. -use_onetime_code = Utilitzar un codi d'un sol ús -forgot_password_title = Contrasenya oblidada -confirmation_mail_sent_prompt = S'ha enviat un correu electrònic de confirmació a %s. Per tal de completar el registre, reviseu la safata d'entrada i seguiu l'enllaç que se us ha enviat en els següents %s. Si l'adreça de correu és incorrecta, podreu accedir al compte i demanar d'enviar un altre correu de confirmació a una altra adreça. -prohibit_login_desc = S'ha suspès la interacció del vostre compte amb la instància. Contacteu amb l'administrador per a recuperar-ne l'accés. -change_unconfirmed_email = Si heu proporcionat una direcció de correu incorrecta durant el registre, la podeu canviar aquí baix i se us enviarà una confirmació a l'adreça nova. -resend_mail = Feu clic aquí per tornar a enviar el correu electrònic d'activació -twofa_passcode_incorrect = El codi d'accés és incorrecte. Si heu perdut el dispositiu, useu el codi de recuperació per a entrar. -oauth_signin_tab = Vincular a un compte existent -oauth.signin.error = Hi ha hagut un error processant la sol·licitud d'autorització. Si persisteix, poseu-vos en contacte amb l'administrador del lloc. -disable_forgot_password_mail_admin = La recuperació de comptes només està disponible quan s'ha configurat el correu electrònic. Si us plau, configureu el correu electrònic per a habilitar la recuperació de comptes. -non_local_account = Els usuaris no locals no poden actualitzar la seva contrasenya mitjançant l'interfície web de Forgejo -openid_register_desc = No s'ha reconegut la URI OpenID. Vinculeu-la amb un compte nou aquí. -openid_connect_desc = No s'ha reconegut la URI OpenID. Vinculeu-la amb un compte nou aquí. -sign_in_openid = Accediu amb OpenID - -[editor] -buttons.indent.tooltip = Aniua els elements un nivell -buttons.unindent.tooltip = Desaniuna els elements un nivell -buttons.ref.tooltip = Referenciar un problema o una "pull request" -buttons.heading.tooltip = Afegir capçalera -buttons.bold.tooltip = Afegir text ressaltat -buttons.italic.tooltip = Afegir text en cursiva -buttons.switch_to_legacy.tooltip = En el seu lloc, utilitzar l'editor de codi antic -buttons.quote.tooltip = Citar text -buttons.enable_monospace_font = Habilitar la font monoespai -buttons.disable_monospace_font = Deshabilita la font monoespai -buttons.code.tooltip = Afegir codi -buttons.link.tooltip = Afegir un enllaç -buttons.list.unordered.tooltip = Afegir un llista de punts -buttons.list.ordered.tooltip = Afegir una llista enumerada -buttons.list.task.tooltip = Afegir una llista de tasques -buttons.mention.tooltip = Mencionar un usuari o equip -buttons.new_table.tooltip = Afegir taula -table_modal.header = Afegir taula -table_modal.placeholder.header = Capçalera -table_modal.placeholder.content = Contingut -table_modal.label.rows = Files -table_modal.label.columns = Columnes -link_modal.header = Afegeix un enllaç -link_modal.url = URL -link_modal.description = Descripció -link_modal.paste_reminder = Pista: Amb un enllaç en el teu porta-retalls, pots enganxar-la directament a l'editor per a crear un enllaç. - -[home] -my_orgs = Organitzacions -show_more_repos = Mostra més repositoris… -show_both_archived_unarchived = Mostrant ambdós arxivats i no-arxivats -show_only_public = Mostrant només publics -issues.in_your_repos = En els teus repositoris -show_only_unarchived = Mostrant només no-arxivats -show_private = Privat -show_both_private_public = Mostrant amdós publics i privats -show_only_private = Mostrant només privats -filter_by_team_repositories = Filtra per respostirois d'equip -feed_of = Canal de "%s" -collaborative_repos = Respositoris coŀlaboratius -show_archived = Arxivat -view_home = Veure %s -password_holder = Contrasenya -switch_dashboard_context = Commuta el contexte del tauler -my_repos = Repositoris -show_only_archived = Mostrant només arxivats -uname_holder = Nom d'usuari o direcció de correu -filter = Altres filtres - -[aria] -footer.software = Sobre aquest software -footer.links = Enllaços -navbar = Barra de navegació -footer = Peu de pàgina - -[mail] -hi_user_x = Hola %s, -view_it_on = Veure a %s -link_not_working_do_paste = No funciona l'enllaç? Proveu a copiar-lo i enganxar-lo al navegador web. -activate_account = Si us plau, activeu el compte -reply = o responeu directament a aquest correu -activate_account.text_1 = Hola %[1]s, gràcies per registrar-te a %[2]s! -register_notify = Benvinguts a %s -admin.new_user.text = Si us plau, cliqueu aui per administrar aquest usuari des del panell d'administració. -admin.new_user.user_info = Informació d'usuari -admin.new_user.subject = Nou usuari %s s'acaba d'enregistrar -activate_email.text = Si us plau, cliqueu el següent enllaç per verificar la vostra adreça de correu electrònic en %s -activate_email = Verifica la teva adreça de correu electrònic -activate_account.text_2 = Si us plau, cliqueu l'enllaç següent per activar el vostre compte en %s: \ No newline at end of file +return_to_forgejo = Tornar a Forgejo \ No newline at end of file diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 5c4bbbd87d..236de83d4d 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -4,8 +4,8 @@ dashboard=Přehled explore=Procházet help=Nápověda logo=Logo -sign_in=Přihlásit se -sign_in_with_provider = Přihlásit se přes %s +sign_in=Přihlášení +sign_in_with_provider=Přihlásit se pomocí %s sign_in_or=nebo sign_out=Odhlásit se sign_up=Registrace @@ -23,7 +23,7 @@ create_new=Vytvořit… user_profile_and_more=Profil a nastavení… signed_in_as=Přihlášen/a jako enable_javascript=Tato stránka vyžaduje JavaScript. -toc=Tabulka obsahu +toc=Obsah licenses=Licence return_to_forgejo=Vrátit se do Forgejo @@ -33,7 +33,7 @@ password=Heslo access_token=Přístupový token re_type=Potvrzení hesla captcha=CAPTCHA -twofa=Dvoufázové ověření +twofa=Dvoufaktorové ověřování twofa_scratch=Dvoufaktorový kód passcode=Přístupový kód @@ -112,19 +112,20 @@ preview=Náhled loading=Načítání… error=Chyba -error404=Stránka, kterou se snažíte zobrazit, buď neexistuje, byla odstraněna nebo nemáte oprávnění ji zobrazit. +error404=Stránka, kterou se snažíte zobrazit, buď neexistuje, nebo nemáte oprávnění ji zobrazit. go_back=Zpět never=Nikdy unknown=Neznámý -rss_feed=Kanál RSS +rss_feed=RSS kanál pin=Připnout unpin=Odepnout artifacts=Artefakty -confirm_delete_artifact = Opravdu chcete odstranit artefakt „%s“? +confirm_delete_artifact=Jste si jisti, že chcete odstranit artefakt „%s“? + archived=Archivováno concept_system_global=Globální @@ -141,6 +142,8 @@ confirm_delete_selected=Potvrdit odstranění všech vybraných položek? name=Název value=Hodnota +sign_in_with_provider = Přihlásit se přes %s +confirm_delete_artifact = Opravdu chcete odstranit artefakt „%s“? toggle_menu = Přepnout nabídku filter = Filtr filter.is_fork = Forky @@ -158,14 +161,6 @@ more_items = Další položky invalid_data = Neplatná data: %v copy_generic = Kopírovat do schránky test = Test -error413 = Vyčerpali jste svou kvótu. -new_repo.title = Nový repozitář -new_migrate.title = Nová migrace -new_org.title = Nová organizace -new_repo.link = Nový repozitář -new_migrate.link = Nová migrace -new_org.link = Nová organizace -copy_path = Kopírovat cestu [aria] navbar=Navigační lišta @@ -199,16 +194,6 @@ buttons.enable_monospace_font=Zapnout neproporcionální písmo buttons.disable_monospace_font=Vypnout neproporcionální písmo buttons.unindent.tooltip = Zrušit vnoření položek pod jednu úroveň buttons.indent.tooltip = Vnořit položky pod jednu úroveň -buttons.new_table.tooltip = Přidat tabulku -table_modal.header = Přidat tabulku -table_modal.placeholder.header = Záhlaví -table_modal.placeholder.content = Obsah -table_modal.label.rows = Řádky -table_modal.label.columns = Sloupce -link_modal.header = Přidat odkaz -link_modal.url = URL -link_modal.description = Popis -link_modal.paste_reminder = Tip: pokud máte adresu zkopírovanou ve schránce, můžete vytvořit odkaz jejím vložením přímo do editoru. [filter] string.asc=A – Z @@ -216,7 +201,7 @@ string.desc=Z – A [error] occurred=Došlo k chybě -report_message=Pokud jste si jisti, že se jedná o chybu software Forgejo, vyhledejte prosím problémy ve službě Codeberg a v případě potřeby založte nový problém. +report_message=Pokud jste si jisti, že se jedná o chybu software Forgejo, vyhledejte prosím problémy ve službě Codeberg a v případě potřeby založte nový problém. missing_csrf=Nesprávný požadavek: nenalezen token CSRF invalid_csrf=Nesprávný požadavek: neplatný token CSRF not_found=Cíl nebyl nalezen. @@ -224,15 +209,15 @@ network_error=Chyba sítě server_internal = Interní chyba serveru [startpage] -app_desc=Jednoduchá, samostatně hostovatelná služba Git +app_desc=Bezproblémová samostatně hostovatelná služba Git install=Jednoduché na instalaci -install_desc=Jednoduše spusťte binární soubor pro vaši platformu, nasaďte jej pomocí Dockeru nebo si jej stáhněte jako balíček. +install_desc=Jednoduše spusťte binární soubor pro vaši platformu, nasaďte jej pomocí Dockeru nebo si jej stáhněte jako balíček. platform=Multiplatformní -platform_desc=Forgejo běží na svobodných operačních systémech, jako je Linux a FreeBSD, stejně jako na různých architekturách CPU. Vyberte si takovou kombinaci, jakou máte rádi! +platform_desc=Forgejo běží na všech platformách, na které dokáže kompilovat jazyk Go: Windows, macOS, Linux, ARM, atd. Výběr je opravdu velký! lightweight=Lehké lightweight_desc=Forgejo má nízké minimální požadavky a dokáže běžet i na levném Raspberry Pi. Šetřete energii vašeho stroje! license=Open Source -license_desc=Vyzkoušejte Forgejo! Připojte se k nám, přispějte a vylepšete tento projekt. Nebojte se přispět! +license_desc=Vyzkoušejte Forgejo! Připojte se k nám, přispějte a vylepšete tento projekt. Nebojte se přispět! [install] install=Instalace @@ -259,7 +244,7 @@ err_empty_db_path=Cesta k databázi SQLite3 nemůže být prázdná. no_admin_and_disable_registration=Nelze vypnout registraci účtů bez vytvoření účtu administrátora. err_empty_admin_password=Heslo administrátora nemůže být prázdné. err_empty_admin_email=E-mail administrátora nemůže být prázdný. -err_admin_name_is_reserved=Uživatelské jméno administrátora není platné, jméno je rezervované +err_admin_name_is_reserved=Uživatelské jméno administrátora není platné, uživatelské jméno je rezervované err_admin_name_pattern_not_allowed=Uživatelské jméno administrátora je neplatné, uživatelské jméno odpovídá vyhrazenému vzoru err_admin_name_is_invalid=Uživatelské jméno administrátora není platné @@ -418,14 +403,14 @@ forgot_password_title=Zapomenuté heslo forgot_password=Zapomenuté heslo? sign_up_now=Nemáte účet? Zaregistrujte se. sign_up_successful=Účet byl úspěšně vytvořen. Vítejte! -confirmation_mail_sent_prompt=Na adresu %s byl zaslán nový potvrzovací e-mail. Pro dokončení procesu registrace prosím zkontrolujte svou schránku a klikněte na poskytnutý odkaz do %s. Pokud jste zadali nesprávný e-mail, můžete se přihlásit a požádat o poslání nového potvrzovacího e-mailu na jinou adresu. +confirmation_mail_sent_prompt=Na adresu %s byl zaslán nový potvrzovací e-mail. Zkontrolujte prosím vaši doručenou poštu během následujících %s, abyste dokončili proces registrace. Pokud jste zadali nesprávný e-mail, můžete se přihlásit a požádat o poslání nového potvrzovacího e-mailu na jinou adresu. must_change_password=Změňte své heslo allow_password_change=Vyžádat od uživatele změnu hesla (doporučeno) -reset_password_mail_sent_prompt=Na adresu %s byl zaslán potvrzovací e-mail. Pro dokončení procesu obnovy účtu prosím zkontrolujte vaši schránku a následujte poskytnutý odkaz během dalších %s. +reset_password_mail_sent_prompt=Na adresu %s byl zaslán potvrzovací e-mail. Zkontrolujte prosím vaši doručenou poštu během následujících %s pro dokončení procesu obnovení účtu. active_your_account=Aktivujte si váš účet account_activated=Účet byl aktivován -prohibit_login=Účet je pozastaven -prohibit_login_desc=Váš účet byl pozastaven z interakcí s instancí. Pro opětovné získání přístupu kontaktujte správce instance. +prohibit_login=Přihlašování je zakázáno +prohibit_login_desc=Vašemu účtu je zakázáno se přihlásit, kontaktujte prosím správce webu. resent_limit_prompt=Omlouváme se, ale nedávno jste již požádali o zaslání aktivačního e-mailu. Počkejte prosím 3 minuty a zkuste to znovu. has_unconfirmed_mail=Zdravíme, %s, máte nepotvrzenou e-mailovou adresu (%s). Pokud jste nedostali e-mail pro potvrzení nebo potřebujete zaslat nový, klikněte prosím na tlačítko níže. resend_mail=Klikněte sem pro opětovné odeslání aktivačního e-mailu @@ -442,7 +427,7 @@ non_local_account=Externě ověřovaní uživatelé nemohou změnit své heslo p verify=Ověřit scratch_code=Záložní kód use_scratch_code=Použít záložní kód -twofa_scratch_used=Použili jste svůj záložní kód. Byli jste přesměrování na stránku s nastavením dvoufázového ověření, kde můžete odstranit registraci vašeho zařízení nebo vygenerovat nový záložní kód. +twofa_scratch_used=Použili jste váš záložní kód. Byli jste přesměrování na stránku s nastavením dvoufaktorového ověřování, kde můžete odstranit registraci vašeho zařízení nebo vygenerovat nový záložní kód. twofa_passcode_incorrect=Vaše heslo je neplatné. Pokud jste ztratili vaše zařízení, použijte záložní kód k přihlášení. twofa_scratch_token_incorrect=Váš záložní kód není správný. login_userpass=Přihlásit se @@ -473,7 +458,7 @@ authorize_title=Autorizovat „%s“ pro přístup k vašemu účtu? authorization_failed=Autorizace selhala authorization_failed_desc=Autorizace selhala, protože jsme detekovali neplatný požadavek. Kontaktujte prosím správce aplikace, kterou jste se pokoušeli autorizovat. sspi_auth_failed=SSPI autentizace selhala -password_pwned=Heslo, které jste zvolili, je na seznamu odcizených hesel, která byla dříve odhalena při narušení veřejných dat. Zkuste to prosím znovu s jiným heslem. +password_pwned=Heslo, které jste zvolili, je na seznamu odcizených hesel, která byla dříve odhalena při narušení veřejných dat. Zkuste to prosím znovu s jiným heslem. password_pwned_err=Nelze dokončit požadavek na HaveIBeenPwned change_unconfirmed_email = Pokud jste při registraci zadali nesprávnou e-mailovou adresu, můžete ji změnit níže. Potvrzovací e-mail bude místo toho odeslán na novou adresu. change_unconfirmed_email_error = Nepodařilo se změnit e-mailovou adresu: %v @@ -486,25 +471,23 @@ hint_register = Nemáte účet? Zaregistrujte se nyní. sign_up_button = Zaregistrujte se nyní. back_to_sign_in = Zpět na přihlášení sign_in_openid = Pokračovat s OpenID -unauthorized_credentials = Údaje jsou nesprávné nebo vypršely. Opakujte svůj příkaz nebo se podívejte na %s pro více informací -use_onetime_code = Použít jednorázový kód [mail] view_it_on=Zobrazit na %s reply=nebo přímo odpovědět na tento e-mail link_not_working_do_paste=Odkaz nefunguje? Zkuste jej zkopírovat a vložit do adresního řádku svého prohlížeče. -hi_user_x=Dobrý den, uživateli %s, +hi_user_x=Ahoj %s, activate_account=Prosíme, aktivujte si váš účet activate_account.title=%s, prosím aktivujte si váš účet -activate_account.text_1=Dobrý den, uživateli %[1]s, děkujeme za registraci ve službě %[2]s! -activate_account.text_2=Pro aktivaci vašeho účtu klikněte %s na následující odkaz : +activate_account.text_1=Ahoj %[1]s, děkujeme za registraci na %[2]s! +activate_account.text_2=Pro aktivaci vašeho účtu do %s klikněte na následující odkaz: activate_email=Ověřte vaši e-mailovou adresu activate_email.title=%s, prosím ověřte vaši e-mailovou adresu -activate_email.text=Pro ověření vaší e-mailové adresy klikněte do %s na následující odkaz: +activate_email.text=Pro aktivaci vašeho účtu do %s klikněte na následující odkaz: -register_notify=Vítejte v %s +register_notify_prev9=Vítejte v Forgejo register_notify.title=%[1]s vítejte v %[2]s register_notify.text_1=toto je váš potvrzovací e-mail pro %s! register_notify.text_2=Do svého účtu se můžete přihlásit svým uživatelským jménem: %s @@ -521,8 +504,8 @@ issue_assigned.issue=@%[1]s vás přiřadil/a k problému %[2]s v repozitáři % issue.x_mentioned_you=@%s vás zmínil/a: issue.action.force_push=%[1]s vynutil/a nahrání %[2]s z %[3]s do %[4]s. -issue.action.push_1=Uživatel @%[1]s nahrál %[3]d revizi do %[2]s -issue.action.push_n=Uživatel @%[1]s nahrál %[3]d revizí do %[2]s +issue.action.push_1=@%[1]s nahrál/a %[3]d commit do %[2]s +issue.action.push_n=@%[1]s nahrál/a %[3]d commity do %[2]s issue.action.close=@%[1]s uzavřel/a #%[2]d. issue.action.reopen=@%[1]s znovu otevřel/a #%[2]d. issue.action.merge=@%[1]s sloučil/a #%[2]d do %[3]s. @@ -557,21 +540,6 @@ team_invite.text_3=Poznámka: Tato pozvánka byla určena pro %[1]s. Pokud jste admin.new_user.user_info = Informace o uživateli admin.new_user.text = Klikněte sem pro správu tohoto uživatele z administrátorského panelu. admin.new_user.subject = Právě se zaregistroval nový uživatel %s -totp_disabled.subject = TOTP bylo zakázáno -password_change.subject = Vaše heslo bylo změněno -password_change.text_1 = Heslo vašeho účtu bylo právě změněno. -primary_mail_change.subject = Váš primární e-mail byl změněn -primary_mail_change.text_1 = Primární e-mail vašeho účtu byl právě změněn na %[1]s. To znamená, že tato e-mailová adresa již nebude získávat e-mailová oznámení z vašeho účtu. -totp_disabled.text_1 = Časově založené jednorázové heslo (TOTP) u vašeho účtu bylo právě zakázáno. -totp_disabled.no_2fa = Nemáte nastavené žádné další 2FA metody, takže se již nemusíte přihlašovat do svého účtu pomocí 2FA. -removed_security_key.subject = Byl odstraněn bezpečnostní klíč -removed_security_key.text_1 = Bezpečnostní klíč „%[1]s“ byl právě odstraněn z vašeho účtu. -removed_security_key.no_2fa = Nemáte nastavené žádné další 2FA metody, takže se již nemusíte přihlašovat do svého účtu pomocí 2FA. -account_security_caution.text_1 = Pokud jste to byli vy, můžete tento e-mail v klidu ignorovat. -account_security_caution.text_2 = Pokud jste to nebyli vy, váš účet byl kompromitován. Kontaktujte prosím správce tohoto webu. -totp_enrolled.subject = Aktivovali jste TOTP jako metodu 2FA -totp_enrolled.text_1.no_webauthn = Právě jste povolili TOTP u vašeho účtu. To znamená, že pro všechna budoucí přihlášení do vašeho účtu budete muset použít TOTP jako metodu 2FA. -totp_enrolled.text_1.has_webauthn = Právě jste povolili TOTP u vašeho účtu. To znamená, že pro všechna budoucí přihlášení do vašeho účtu můžete použít TOTP jako metodu 2FA nebo použít jakýkoli z vašich bezpečnostních klíčů. [modal] yes=Ano @@ -594,9 +562,9 @@ AuthName=Název ověření AdminEmail=E-mailová adresa správce NewBranchName=Název nové větve -CommitSummary=Shrnutí revize -CommitMessage=Zpráva revize -CommitChoice=Výběr revize +CommitSummary=Shrnutí commity +CommitMessage=Zpráva commitu +CommitChoice=Výběr commitu TreeName=Cesta k souboru Content=Obsah @@ -632,7 +600,7 @@ repository_files_already_exist.adopt=Soubory pro tento repozitář již existuj repository_files_already_exist.delete=Soubory pro tento repozitář již existují. Musíte je odstranit. repository_files_already_exist.adopt_or_delete=Soubory pro tento repozitář již existují. Přijměte je, nebo je odstraňte. visit_rate_limit=Dosaženo limitu rychlosti dotazů při vzdáleném přístupu. -2fa_auth_required=Vzdálený přístup vyžaduje dvoufázové ověření. +2fa_auth_required=Vzdálený přístup vyžaduje dvoufaktorové ověřování. org_name_been_taken=Název organizace je již použit. team_name_been_taken=Název týmu je již použit. team_no_units_error=Povolit přístup alespoň do jedné sekce repozitáře. @@ -656,8 +624,8 @@ cannot_add_org_to_team=Organizace nemůže být přidána jako člen týmu. duplicate_invite_to_team=Uživatel byl již pozván jako člen týmu. organization_leave_success=Úspěšně jste opustili organizaci %s. -invalid_ssh_key=Nepodařilo se ověřit váš klíč SSH: %s -invalid_gpg_key=Nepodařilo se ověřit váš klíč GPG: %s +invalid_ssh_key=Nelze ověřit váš SSH klíč: %s +invalid_gpg_key=Nelze ověřit váš GPG klíč: %s invalid_ssh_principal=Neplatný SSH Principal certifikát: %s must_use_public_key=Zadaný klíč je soukromý klíč. Nenahrávejte svůj soukromý klíč nikde. Místo toho použijte váš veřejný klíč. unable_verify_ssh_key=Nepodařilo se ověřit klíč SSH, zkontrolujte, zda neobsahuje chyby. @@ -670,9 +638,10 @@ org_still_own_repo=Organizace stále vlastní jeden nebo více repozitářů. Ne org_still_own_packages=Organizace stále vlastní jeden nebo více balíčků. Nejdříve je odstraňte. target_branch_not_exist=Cílová větev neexistuje. -admin_cannot_delete_self=Nemůžete se smazat, dokud jste správce. Nejdříve prosím odeberte svá administrátorská oprávnění. +admin_cannot_delete_self = Nemůžete odstranit sami sebe, když jste administrátorem. Nejprve prosím odeberte svá práva administrátora. username_error_no_dots = ` může obsahovat pouze alfanumerické znaky („0-9“, „a-z“, „A-Z“), pomlčky („-“) a podtržítka („_“). Nemůže začínat nebo končit nealfanumerickými znaky. Jsou také zakázány po sobě jdoucí nealfanumerické znaky.` +admin_cannot_delete_self=Nemůžete se smazat, dokud jste správce. Nejdříve prosím odeberte svá administrátorská oprávnění. unset_password = Tento uživatel nemá nastavené heslo. unsupported_login_type = U tohoto typu účtu není funkce odstranění účtu podporována. required_prefix = Vstup musí začínat textem „%s“ @@ -684,8 +653,6 @@ Location = Umístění To = Název větve Biography = Životopis AccessToken = Přístupový token -username_claiming_cooldown = Uživatelské jméno nelze získat, protože ještě neskončila doba jeho platnosti. Půjde jej získat %[1]s. -email_domain_is_not_allowed = Doména uživatelské e-mailové adresy %s je v rozporu se seznamem EMAIL_DOMAIN_ALLOWLIST nebo EMAIL_DOMAIN_BLOCKLIST. Ujistěte se, že je vaše adresa správně nastavena. [user] change_avatar=Změnit váš avatar… @@ -698,7 +665,7 @@ watched=Sledované repozitáře code=Kód projects=Projekty overview=Přehled -following_few=%d sledovaných +following_few=%d sledovaní follow=Sledovat unfollow=Přestat sledovat user_bio=Životopis @@ -720,7 +687,7 @@ follow_blocked_user = Tohoto uživatele nemůžete sledovat, protože jste si je block = Zablokovat unblock = Odblokovat followers_one = %d sledující -following_one = %d sledovaný +following_one = %d následuje followers.title.one = Sledující followers.title.few = Sledující following.title.one = Sleduje @@ -729,7 +696,6 @@ public_activity.visibility_hint.self_private = Vaše aktivita je viditelná pouz public_activity.visibility_hint.admin_private = Tato aktivita je pro vás viditelná, protože jste administrátor, ale uživatel chce, aby zůstala soukromá. public_activity.visibility_hint.self_public = Vaše aktivita je viditelná všem, mimo interakcí v soukromých prostorech. Nastavení. public_activity.visibility_hint.admin_public = Tato aktivita je viditelná všem, ale jako administrátor také můžete vidět interakce v soukromých prostorech. -public_activity.visibility_hint.self_private_profile = Vaše aktivita je viditelná pouze vám a správcům instance, protože váš profil je soukromý. Nastavit. [settings] profile=Profil @@ -744,16 +710,16 @@ applications=Aplikace orgs=Organizace repos=Repozitáře delete=Smazat účet -twofa=Dvoufázové ověření (TOTP) +twofa=Dvoufaktorové ověřování (TOTP) account_link=Propojené účty organization=Organizace uid=UID -webauthn=Dvoufázové ověření (bezpečnostní klíče) +webauthn=Dvoufaktorové ověřování (bezpečnostní klíče) public_profile=Veřejný profil -biography_placeholder=Řekněte ostatním něco o sobě! (Je podporován Markdown) +biography_placeholder=Řekněte nám něco o sobě! (Můžete použít Markdown) location_placeholder=Sdílejte svou přibližnou polohu s ostatními -profile_desc=O vás +profile_desc=Nastavte, jak bude váš profil zobrazen ostatním uživatelům. Vaše hlavní e-mailová adresa bude použita pro oznámení, obnovení hesla a operace Git. password_username_disabled=Externí uživatelé nemohou měnit svoje uživatelské jméno. Kontaktujte prosím svého administrátora pro více detailů. full_name=Celé jméno website=Web @@ -773,7 +739,7 @@ language=Jazyk ui=Motiv vzhledu hidden_comment_types=Skryté typy komentářů hidden_comment_types_description=Zde zkontrolované typy komentářů nebudou zobrazeny na stránkách problémů. Zaškrtnutí „Štítek“ například odstraní všechny komentáře „ přidal/odstranil
-

{{ctx.Locale.Tr "org.settings.permission"}}

- {{if (eq .Team.AccessMode 3)}} + {{if (eq .Team.AccessMode 2)}} +

{{ctx.Locale.Tr "org.settings.permission"}}

+ {{ctx.Locale.Tr "org.teams.write_permission_desc"}} + {{else if (eq .Team.AccessMode 3)}} +

{{ctx.Locale.Tr "org.settings.permission"}}

{{ctx.Locale.Tr "org.teams.admin_permission_desc"}} {{else}} diff --git a/templates/package/content/alt.tmpl b/templates/package/content/alt.tmpl deleted file mode 100644 index 0a5c328e6d..0000000000 --- a/templates/package/content/alt.tmpl +++ /dev/null @@ -1,49 +0,0 @@ -{{if eq .PackageDescriptor.Package.Type "alt"}} -

{{ctx.Locale.Tr "packages.installation"}}

-
-
-
- -
{{- if gt (len .Groups) 1 -}}
-# {{ctx.Locale.Tr "packages.alt.repository.multiple_groups"}}
-
-{{end -}}
-# {{ctx.Locale.Tr "packages.alt.setup"}}
-{{- range $group := .Groups}}
-	{{- if $group}}{{$group = print "/" $group}}{{end}}
-apt-repo add rpm  _arch_ classic
-
-{{- end}}
-
-
- -
-
# {{ctx.Locale.Tr "packages.alt.registry.install"}}
-apt-get update
-apt-get install {{$.PackageDescriptor.Package.Name}}
-
-
-
- -
-
-
- -

{{ctx.Locale.Tr "packages.alt.repository"}}

-
-
- - - - - - -
{{ctx.Locale.Tr "packages.alt.repository.architectures"}}
{{StringUtils.Join .Architectures ", "}}
- - - {{if or .PackageDescriptor.Metadata.Summary .PackageDescriptor.Metadata.Description}} -

{{ctx.Locale.Tr "packages.about"}}

- {{if .PackageDescriptor.Metadata.Summary}}
{{.PackageDescriptor.Metadata.Summary}}
{{end}} - {{if .PackageDescriptor.Metadata.Description}}
{{.PackageDescriptor.Metadata.Description}}
{{end}} - {{end}} -{{end}} diff --git a/templates/package/content/arch.tmpl b/templates/package/content/arch.tmpl deleted file mode 100644 index 6a041d323b..0000000000 --- a/templates/package/content/arch.tmpl +++ /dev/null @@ -1,143 +0,0 @@ -{{if eq .PackageDescriptor.Package.Type "arch"}} -

{{ctx.Locale.Tr "packages.installation"}}

-
-
-
- -
-
wget -O sign.gpg 
-pacman-key --add sign.gpg
-pacman-key --lsign-key '{{$.SignMail}}'
-
-
-
- -
-

-{{- if gt (len $.Groups) 1 -}}
-# {{ctx.Locale.Tr "packages.arch.pacman.repo.multi" $.PackageDescriptor.Package.LowerName}}
-
-{{end -}}
-{{- $GroupSize := (len .Groups) -}}
-{{-  range $i,$v := .Groups -}}
-{{- if gt $i 0}}
-{{end -}}{{- if gt $GroupSize 1 -}}
-# {{ctx.Locale.Tr "packages.arch.pacman.repo.multi.item" .}}
-{{end -}}
-[{{$.PackageDescriptor.Owner.LowerName}}.{{$.PackageRegistryHost}}]
-SigLevel = Required
-Server = 
-{{end -}}
-
-
-
-
- -
-
pacman -Sy {{.PackageDescriptor.Package.LowerName}}
-
-
-
- -
-
-
- -

{{ctx.Locale.Tr "packages.arch.version.properties"}}

-
- - - - - - - - {{if .PackageDescriptor.Metadata.Groups}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.Provides}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.Depends}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.OptDepends}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.MakeDepends}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.CheckDepends}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.Conflicts}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.Replaces}} - - - - - {{end}} - - {{if .PackageDescriptor.Metadata.Backup}} - - - - - {{end}} - -
-
{{ctx.Locale.Tr "packages.arch.version.description"}}
-
{{.PackageDescriptor.Metadata.Description}}
-
{{ctx.Locale.Tr "packages.arch.version.groups"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.Groups ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.provides"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.Provides ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.depends"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.Depends ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.optdepends"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.OptDepends ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.makedepends"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.MakeDepends ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.checkdepends"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.CheckDepends ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.conflicts"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.Conflicts ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.replaces"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.Replaces ", "}}
-
{{ctx.Locale.Tr "packages.arch.version.backup"}}
-
{{StringUtils.Join $.PackageDescriptor.Metadata.Backup ", "}}
-
- -{{end}} diff --git a/templates/package/content/container.tmpl b/templates/package/content/container.tmpl index dd1c24269b..b5fdcfeb1b 100644 --- a/templates/package/content/container.tmpl +++ b/templates/package/content/container.tmpl @@ -5,13 +5,13 @@
{{if eq .PackageDescriptor.Metadata.Type "helm"}} -
helm pull oci://{{.PackageRegistryHost}}/{{.PackageDescriptor.Owner.LowerName}}/{{.PackageDescriptor.Package.LowerName}} --version {{.PackageDescriptor.Version.LowerVersion}}
+
helm pull oci://{{.RegistryHost}}/{{.PackageDescriptor.Owner.LowerName}}/{{.PackageDescriptor.Package.LowerName}} --version {{.PackageDescriptor.Version.LowerVersion}}
{{else}} {{$separator := ":"}} {{if not .PackageDescriptor.Metadata.IsTagged}} {{$separator = "@"}} {{end}} -
docker pull {{.PackageRegistryHost}}/{{.PackageDescriptor.Owner.LowerName}}/{{.PackageDescriptor.Package.LowerName}}{{$separator}}{{.PackageDescriptor.Version.LowerVersion}}
+
docker pull {{.RegistryHost}}/{{.PackageDescriptor.Owner.LowerName}}/{{.PackageDescriptor.Package.LowerName}}{{$separator}}{{.PackageDescriptor.Version.LowerVersion}}
{{end}}
@@ -24,7 +24,7 @@
{{if .PackageDescriptor.Metadata.Manifests}} -

{{ctx.Locale.Tr "packages.container.images.title"}}

+

{{ctx.Locale.Tr "packages.container.multi_arch"}}

@@ -36,13 +36,11 @@ {{range .PackageDescriptor.Metadata.Manifests}} - {{if ne .Platform "unknown/unknown"}} - + - - {{end}} + {{end}}
{{.Digest}} {{.Platform}} {{ctx.Locale.TrSize .Size}}
diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl index c8568845f1..ea665c7bbc 100644 --- a/templates/package/content/nuget.tmpl +++ b/templates/package/content/nuget.tmpl @@ -35,12 +35,11 @@ - {{$tooltipSearchInNuget := ctx.Locale.Tr "packages.search_in_external_registry" "nuget.org"}} {{range $framework, $dependencies := .PackageDescriptor.Metadata.Dependencies}} {{range $dependencies}} - {{.ID}} {{svg "octicon-link-external"}} - {{.Version}} {{svg "octicon-link-external"}} + {{.ID}} + {{.Version}} {{$framework}} {{end}} diff --git a/templates/package/metadata/alt.tmpl b/templates/package/metadata/alt.tmpl deleted file mode 100644 index 16fb52e9b1..0000000000 --- a/templates/package/metadata/alt.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -{{if eq .PackageDescriptor.Package.Type "alt"}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
{{svg "octicon-link-external" 16 "tw-mr-2"}} {{ctx.Locale.Tr "packages.details.project_site"}}
{{end}} - {{if .PackageDescriptor.Metadata.License}}
{{svg "octicon-law" 16 "tw-mr-2"}} {{.PackageDescriptor.Metadata.License}}
{{end}} -{{end}} diff --git a/templates/package/metadata/arch.tmpl b/templates/package/metadata/arch.tmpl deleted file mode 100644 index 89001b979c..0000000000 --- a/templates/package/metadata/arch.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -{{if eq .PackageDescriptor.Package.Type "arch"}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
{{svg "octicon-link-external" 16 "tw-mr-2"}} {{ctx.Locale.Tr "packages.details.project_site"}}
{{end}} - {{range .PackageDescriptor.Metadata.License}}
{{svg "octicon-law" 16 "tw-mr-2"}} {{.}}
{{end}} -{{end}} diff --git a/templates/package/shared/cargo.tmpl b/templates/package/shared/cargo.tmpl index 8e158d60d8..5b0f63965d 100644 --- a/templates/package/shared/cargo.tmpl +++ b/templates/package/shared/cargo.tmpl @@ -3,25 +3,25 @@
-
- -
{{if .CargoIndexExists}} +
+ +
{{.CsrfTokenHtml}} -
- -
{{else}} +
+ +
{{.CsrfTokenHtml}}
-
- -
{{end}} +
+ +
diff --git a/templates/package/shared/cleanup_rules/preview.tmpl b/templates/package/shared/cleanup_rules/preview.tmpl index da034fec7a..0d9c4b0d46 100644 --- a/templates/package/shared/cleanup_rules/preview.tmpl +++ b/templates/package/shared/cleanup_rules/preview.tmpl @@ -22,7 +22,7 @@ {{.Version.Version}} {{.Creator.Name}} {{ctx.Locale.TrSize .CalculateBlobSize}} - {{DateUtils.AbsoluteShort .Version.CreatedUnix}} + {{DateTime "short" .Version.CreatedUnix}} {{else}} diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 19b41d0bc8..36f8bc1522 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -24,7 +24,7 @@ {{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}
- {{$timeStr := DateUtils.TimeSince .Version.CreatedUnix}} + {{$timeStr := TimeSinceUnix .Version.CreatedUnix ctx.Locale}} {{$hasRepositoryAccess := false}} {{if .Repository}} {{$hasRepositoryAccess = index $.RepositoryAccessMap .Repository.ID}} diff --git a/templates/package/shared/versionlist.tmpl b/templates/package/shared/versionlist.tmpl index 7a1059e262..e5c568e059 100644 --- a/templates/package/shared/versionlist.tmpl +++ b/templates/package/shared/versionlist.tmpl @@ -25,7 +25,7 @@
{{.Version.LowerVersion}}
- {{ctx.Locale.Tr "packages.published_by" (DateUtils.TimeSince .Version.CreatedUnix) .Creator.HomeLink .Creator.GetDisplayName}} + {{ctx.Locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix ctx.Locale) .Creator.HomeLink .Creator.GetDisplayName}}
diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl index 18220e904b..1d87f4d3af 100644 --- a/templates/package/view.tmpl +++ b/templates/package/view.tmpl @@ -8,7 +8,7 @@

{{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})

- {{$timeStr := DateUtils.TimeSince .PackageDescriptor.Version.CreatedUnix}} + {{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix ctx.Locale}} {{if .HasRepositoryAccess}} {{ctx.Locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink .PackageDescriptor.Creator.GetDisplayName .PackageDescriptor.Repository.Link .PackageDescriptor.Repository.FullName}} {{else}} @@ -19,7 +19,6 @@
{{template "package/content/alpine" .}} - {{template "package/content/arch" .}} {{template "package/content/cargo" .}} {{template "package/content/chef" .}} {{template "package/content/composer" .}} @@ -37,7 +36,6 @@ {{template "package/content/pub" .}} {{template "package/content/pypi" .}} {{template "package/content/rpm" .}} - {{template "package/content/alt" .}} {{template "package/content/rubygems" .}} {{template "package/content/swift" .}} {{template "package/content/vagrant" .}} @@ -49,10 +47,9 @@ {{if .HasRepositoryAccess}}
{{svg "octicon-repo" 16 "tw-mr-2"}} {{.PackageDescriptor.Repository.FullName}}
{{end}} -
{{svg "octicon-calendar" 16 "tw-mr-2"}} {{DateUtils.TimeSince .PackageDescriptor.Version.CreatedUnix}}
+
{{svg "octicon-calendar" 16 "tw-mr-2"}} {{TimeSinceUnix .PackageDescriptor.Version.CreatedUnix ctx.Locale}}
{{svg "octicon-download" 16 "tw-mr-2"}} {{.PackageDescriptor.Version.DownloadCount}}
{{template "package/metadata/alpine" .}} - {{template "package/metadata/arch" .}} {{template "package/metadata/cargo" .}} {{template "package/metadata/chef" .}} {{template "package/metadata/composer" .}} @@ -69,7 +66,6 @@ {{template "package/metadata/pub" .}} {{template "package/metadata/pypi" .}} {{template "package/metadata/rpm" .}} - {{template "package/metadata/alt" .}} {{template "package/metadata/rubygems" .}} {{template "package/metadata/swift" .}} {{template "package/metadata/vagrant" .}} @@ -96,7 +92,7 @@ {{range .LatestVersions}}
{{.Version}} - {{DateUtils.AbsoluteShort .CreatedUnix}} + {{DateTime "short" .CreatedUnix}}
{{end}}
diff --git a/templates/projects/list.tmpl b/templates/projects/list.tmpl index 8c9b7c6e6f..b892cff996 100644 --- a/templates/projects/list.tmpl +++ b/templates/projects/list.tmpl @@ -1,12 +1,12 @@ {{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
-
+ @@ -41,21 +41,19 @@
{{range .Projects}}
  • -
    -

    - {{svg .IconName 16}} - {{.Title}} -

    -
    +

    + {{svg .IconName 16}} + {{.Title}} +

    {{svg "octicon-issue-opened" 14}} - {{ctx.Locale.PrettyNumber (index $.NumOpenIssuesInProject .ID)}} {{ctx.Locale.Tr "repo.issues.open_title"}} + {{ctx.Locale.PrettyNumber (.NumOpenIssues ctx)}} {{ctx.Locale.Tr "repo.issues.open_title"}}
    {{svg "octicon-check" 14}} - {{ctx.Locale.PrettyNumber (index $.NumClosedIssuesInProject .ID)}} {{ctx.Locale.Tr "repo.issues.closed_title"}} + {{ctx.Locale.PrettyNumber (.NumClosedIssues ctx)}} {{ctx.Locale.Tr "repo.issues.closed_title"}}
    {{if and $.CanWriteProjects (not $.Repository.IsArchived)}} diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 0e2fc87958..564ec1b13d 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -1,7 +1,7 @@ {{$canWriteProject := and .CanWriteProjects (or (not .Repository) (not .Repository.IsArchived))}}
    -
    +

    {{.Project.Title}}

    {{if $canWriteProject}} \ No newline at end of file diff --git a/templates/repo/actions/list.tmpl b/templates/repo/actions/list.tmpl index d973e6f3b2..263530f9a7 100644 --- a/templates/repo/actions/list.tmpl +++ b/templates/repo/actions/list.tmpl @@ -4,38 +4,89 @@
    {{template "base/alert" .}} - {{/* Refresh the list every interval (30s) unless the document isn't visible or a dropdown is open; refresh - if visibility changes as well. simulate-polling-interval is a custom event used for e2e tests to mimic - the polling interval and should be defined identically to the `every` clause for accurate testing. */}} -
    - {{template "repo/actions/list_inner" .}} + {{if .HasWorkflowsOrRuns}} +
    + +
    + + + {{if $.CurWorkflowDispatch}} + {{template "repo/actions/dispatch" .}} + {{end}} + + {{template "repo/actions/runs_list" .}} +
    + {{else}} + {{template "repo/actions/no_workflows" .}} + {{end}}
    - - - {{template "base/footer" .}} diff --git a/templates/repo/actions/list_inner.tmpl b/templates/repo/actions/list_inner.tmpl deleted file mode 100644 index 088d7d8454..0000000000 --- a/templates/repo/actions/list_inner.tmpl +++ /dev/null @@ -1,85 +0,0 @@ -{{if .HasWorkflowsOrRuns}} -
    - -
    - - - {{if $.CurWorkflowDispatch}} - {{template "repo/actions/dispatch" .}} - {{end}} - - {{template "repo/actions/runs_list" .}} -
    -
    -{{else}} - {{template "repo/actions/no_workflows" .}} -{{end}} diff --git a/templates/repo/actions/no_workflows.tmpl b/templates/repo/actions/no_workflows.tmpl index fb3a77fb9a..88d6e513ef 100644 --- a/templates/repo/actions/no_workflows.tmpl +++ b/templates/repo/actions/no_workflows.tmpl @@ -2,8 +2,7 @@ {{svg "octicon-no-entry" 48}}

    {{ctx.Locale.Tr "actions.runs.no_workflows"}}

    {{if and .CanWriteCode .CanWriteActions}} -

    {{ctx.Locale.Tr "actions.runs.no_workflows.help_write_access" "https://forgejo.org/docs/latest/user/actions/#quick-start" "https://forgejo.org/docs/latest/admin/runner-installation/"}}

    - {{else}} -

    {{ctx.Locale.Tr "actions.runs.no_workflows.help_no_write_access" "https://forgejo.org/docs/latest/user/actions/"}}

    +

    {{ctx.Locale.Tr "actions.runs.no_workflows.quick_start" "https://forgejo.org/docs/latest/admin/actions/"}}

    {{end}} +

    {{ctx.Locale.Tr "actions.runs.no_workflows.documentation" "https://forgejo.org/docs/latest/admin/actions/"}}

    diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 060fc1b66a..e37f3d7dc3 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -15,7 +15,7 @@ {{if .Title}}{{.Title}}{{else}}{{ctx.Locale.Tr "actions.runs.empty_commit_message"}}{{end}}
    - {{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}} - + {{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}} - {{- if .ScheduleID -}} {{ctx.Locale.Tr "actions.runs.scheduled"}} {{- else -}} @@ -27,13 +27,13 @@
    - {{if .IsRefDeleted}} - {{.PrettyRef}} + {{if .RefLink}} + {{.PrettyRef}} {{else}} - {{.PrettyRef}} + {{.PrettyRef}} {{end}}
    -
    {{svg "octicon-calendar" 16}}{{DateUtils.TimeSince .Updated}}
    +
    {{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}
    {{svg "octicon-stopwatch" 16}}{{.Duration}}
    diff --git a/templates/repo/actions/status.tmpl b/templates/repo/actions/status.tmpl index 99fa74ac17..a0e02cf8d7 100644 --- a/templates/repo/actions/status.tmpl +++ b/templates/repo/actions/status.tmpl @@ -17,15 +17,13 @@ {{svg "octicon-check-circle-fill" $size (printf "text green %s" $className)}} {{else if eq .status "skipped"}} {{svg "octicon-skip" $size (printf "text grey %s" $className)}} -{{else if eq .status "cancelled"}} - {{svg "octicon-stop" $size (printf "text grey %s" $className)}} {{else if eq .status "waiting"}} {{svg "octicon-clock" $size (printf "text yellow %s" $className)}} {{else if eq .status "blocked"}} {{svg "octicon-blocked" $size (printf "text yellow %s" $className)}} {{else if eq .status "running"}} {{svg "octicon-meter" $size (printf "text yellow job-status-rotate %s" $className)}} -{{else}}{{/*failure, unknown*/}} +{{else if or (eq .status "failure") or (eq .status "cancelled") or (eq .status "unknown")}} {{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}} {{end}} diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index fe945324ea..6a0b726b67 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -20,17 +20,15 @@
    + {{if .DefaultBranchBranch.IsProtected}}{{svg "octicon-shield-lock"}}{{end}} {{.DefaultBranchBranch.DBBranch.Name}} - {{if .DefaultBranchBranch.IsProtected}} - {{svg "octicon-shield-lock"}} - {{end}} - + {{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}}
    -

    {{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage (.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (DateUtils.TimeSince .DefaultBranchBranch.DBBranch.CommitTime)}}{{if .DefaultBranchBranch.DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}

    +

    {{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage (.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (TimeSince .DefaultBranchBranch.DBBranch.CommitTime.AsTime ctx.Locale)}} {{if .DefaultBranchBranch.DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}

    - {{if and $.IsWriter (not $.Repository.IsArchived) (not $.Repository.IsMirror) (not .IsDeleted)}} + {{if and $.IsWriter (not $.Repository.IsArchived) (not .IsDeleted)}} +
    -

    {{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{DateUtils.TimeSince .DBBranch.DeletedUnix}}

    +

    {{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{TimeSinceUnix .DBBranch.DeletedUnix ctx.Locale}}

    {{else}}
    + {{if .IsProtected}}{{svg "octicon-shield-lock"}}{{end}} {{.DBBranch.Name}} - {{if .IsProtected}} - {{svg "octicon-shield-lock"}} - {{end}} - + {{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DBBranch.CommitID)}}
    -

    {{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DBBranch.CommitMessage ($.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (DateUtils.TimeSince .DBBranch.CommitTime)}}{{if .DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}}  {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}

    +

    {{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DBBranch.CommitMessage ($.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (TimeSince .DBBranch.CommitTime.AsTime ctx.Locale)}} {{if .DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}}  {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}

    {{end}} @@ -142,16 +138,14 @@ {{if .LatestPullRequest.HasMerged}} {{svg "octicon-git-merge" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.pulls.merged"}} {{else if .LatestPullRequest.Issue.IsClosed}} - {{svg "octicon-git-pull-request-closed" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.issues.closed_title"}} - {{else if .LatestPullRequest.IsWorkInProgress ctx}} - {{svg "octicon-git-pull-request-draft" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.issues.draft_title"}} + {{svg "octicon-git-pull-request" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.issues.closed_title"}} {{else}} {{svg "octicon-git-pull-request" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.issues.open_title"}} {{end}} {{end}} - {{if and $.IsWriter (not $.Repository.IsArchived) (not $.Repository.IsMirror) (not .DBBranch.IsDeleted)}} + {{if and $.IsWriter (not $.Repository.IsArchived) (not .DBBranch.IsDeleted)}} - -
    -{{end}} diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index dd663762db..d996acc5b2 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -1,7 +1,7 @@ {{range .RecentlyPushedNewBranches}}
    - {{$timeSince := DateUtils.TimeSince .CommitTime}} + {{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}} {{$repo := .GetRepo $.Context}} {{$name := .Name}} {{if ne $repo.ID $.Repository.ID}} diff --git a/templates/repo/commit_header.tmpl b/templates/repo/commit_header.tmpl deleted file mode 100644 index 9604daf2b0..0000000000 --- a/templates/repo/commit_header.tmpl +++ /dev/null @@ -1,355 +0,0 @@ -{{$class := ""}} -{{if .Commit.Signature}} - {{$class = (print $class " isSigned")}} - {{if .Verification.Verified}} - {{if eq .Verification.TrustStatus "trusted"}} - {{$class = (print $class " isVerified")}} - {{else if eq .Verification.TrustStatus "untrusted"}} - {{$class = (print $class " isVerifiedUntrusted")}} - {{else}} - {{$class = (print $class " isVerifiedUnmatched")}} - {{end}} - {{else if .Verification.Warning}} - {{$class = (print $class " isWarning")}} - {{end}} -{{end}} -
    -
    -

    {{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}

    -
    - {{if .PageIsPullFiles}} - - {{else if not $.PageIsWiki}} - - {{ctx.Locale.Tr "repo.diff.browse_source"}} - - {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}} - - {{end}} - {{end}} -
    -
    - {{if IsMultilineCommitMessage .Commit.Message}} -
    {{RenderCommitBody $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}
    - {{end}} - {{template "repo/commit_load_branches_and_tags" .}} -
    -
    -
    - {{if .Author}} - {{ctx.AvatarUtils.Avatar .Author 28 "tw-mr-2"}} - {{if .Author.FullName}} - {{.Author.FullName}} - {{else}} - {{.Commit.Author.Name}} - {{end}} - {{else}} - {{ctx.AvatarUtils.AvatarByEmail .Commit.Author.Email .Commit.Author.Email 28 "tw-mr-2"}} - {{.Commit.Author.Name}} - {{end}} - {{DateUtils.TimeSince .Commit.Author.When}} - {{if or (ne .Commit.Committer.Name .Commit.Author.Name) (ne .Commit.Committer.Email .Commit.Author.Email)}} - - {{ctx.Locale.Tr "repo.diff.committed_by"}} - {{if ne .Verification.CommittingUser.ID 0}} - {{ctx.AvatarUtils.Avatar .Verification.CommittingUser 28 "tw-mr-2"}} - {{.Commit.Committer.Name}} - {{else}} - {{ctx.AvatarUtils.AvatarByEmail .Commit.Committer.Email .Commit.Committer.Name 28 "tw-mr-2"}} - {{.Commit.Committer.Name}} - {{end}} - {{end}} -
    -
    - {{if .Parents}} -
    - {{ctx.Locale.Tr "repo.diff.parent"}} - {{range .Parents}} - {{if $.PageIsWiki}} - - {{ShortSha .}} - - {{else}} - - {{ShortSha .}} - - {{end}} - {{end}} -
    - {{end}} -
    - {{ctx.Locale.Tr "repo.diff.commit"}} - {{if .PageIsPullFiles}} - {{$commitShaLink := (printf "%s/commit/%s" $.RepoLink (PathEscape .CommitID))}} - - {{ShortSha .CommitID}} - - {{else}} - - {{ShortSha .CommitID}} - - {{end}} -
    -
    -
    -{{if .Commit.Signature}} -
    -
    - {{if .Verification.Verified}} - {{if ne .Verification.SigningUser.ID 0}} - {{svg "gitea-lock" 16 "tw-mr-2"}} - {{if eq .Verification.TrustStatus "trusted"}} - {{ctx.Locale.Tr "repo.commits.signed_by"}}: - {{else if eq .Verification.TrustStatus "untrusted"}} - {{ctx.Locale.Tr "repo.commits.signed_by_untrusted_user"}}: - {{else}} - {{ctx.Locale.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}: - {{end}} - {{ctx.AvatarUtils.Avatar .Verification.SigningUser 28 "tw-mr-2"}} - {{.Verification.SigningUser.GetDisplayName}} - {{else}} - {{svg "gitea-lock-cog" 16 "tw-mr-2"}} - {{ctx.Locale.Tr "repo.commits.signed_by"}}: - {{ctx.AvatarUtils.AvatarByEmail .Verification.SigningEmail "" 28 "tw-mr-2"}} - {{.Verification.SigningUser.GetDisplayName}} - {{end}} - {{else}} - {{svg "gitea-unlock" 16 "tw-mr-2"}} - {{ctx.Locale.Tr .Verification.Reason}} - {{end}} -
    -
    - {{if .Verification.Verified}} - {{svg "octicon-verified" 16 "tw-mr-2"}} - {{if ne .Verification.SigningUser.ID 0}} - {{if .Verification.SigningSSHKey}} - {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: - {{.Verification.SigningSSHKey.Fingerprint}} - {{else}} - {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: - {{.Verification.SigningKey.PaddedKeyID}} - {{end}} - {{else}} - {{if .Verification.SigningSSHKey}} - {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: - {{.Verification.SigningSSHKey.Fingerprint}} - {{else}} - {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: - {{.Verification.SigningKey.PaddedKeyID}} - {{end}} - {{end}} - {{else if .Verification.Warning}} - {{svg "octicon-unverified" 16 "tw-mr-2"}} - {{if .Verification.SigningSSHKey}} - {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: - {{.Verification.SigningSSHKey.Fingerprint}} - {{else}} - {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: - {{.Verification.SigningKey.PaddedKeyID}} - {{end}} - {{else}} - {{if .Verification.SigningKey}} - {{if ne .Verification.SigningKey.KeyID ""}} - {{svg "octicon-verified" 16 "tw-mr-2"}} - {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: - {{.Verification.SigningKey.PaddedKeyID}} - {{end}} - {{end}} - {{if .Verification.SigningSSHKey}} - {{if ne .Verification.SigningSSHKey.Fingerprint ""}} - {{svg "octicon-verified" 16 "tw-mr-2"}} - {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: - {{.Verification.SigningSSHKey.Fingerprint}} - {{end}} - {{end}} - {{end}} -
    -
    -{{end}} -{{if .NoteRendered}} -
    - {{svg "octicon-note" 16 "tw-mr-2"}} - {{ctx.Locale.Tr "repo.diff.git-notes"}}: - {{if .NoteAuthor}} - - {{if .NoteAuthor.FullName}} - {{.NoteAuthor.FullName}} - {{else}} - {{.NoteCommit.Author.Name}} - {{end}} - - {{else}} - {{.NoteCommit.Author.Name}} - {{end}} - {{DateUtils.TimeSince .NoteCommit.Author.When}} - {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}} -
    - - -
    - - {{end}} -
    -
    -
    {{.NoteRendered | SanitizeHTML}}
    -
    - {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}} -
    -
    - {{.CsrfTokenHtml}} - -
    - -
    - -
    - -
    -
    -
    - {{end}} -{{else if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}} -
    -
    - {{.CsrfTokenHtml}} - -
    - -
    - -
    - -
    -
    -
    -{{end}} - diff --git a/templates/repo/commit_load_branches_and_tags.tmpl b/templates/repo/commit_load_branches_and_tags.tmpl index 25402ca2f4..ffa0e530e8 100644 --- a/templates/repo/commit_load_branches_and_tags.tmpl +++ b/templates/repo/commit_load_branches_and_tags.tmpl @@ -1,4 +1,4 @@ -{{if not (or .PageIsWiki .PageIsPullFiles)}} +{{if not .PageIsWiki}}
    + +
    +
    + + +
    +
  • + {{end}} +
    + {{end}} +
    + {{if IsMultilineCommitMessage .Commit.Message}} +
    {{RenderCommitBody $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}
    + {{end}} + {{template "repo/commit_load_branches_and_tags" .}} +
    +
    +
    + {{if .Author}} + {{ctx.AvatarUtils.Avatar .Author 28 "tw-mr-2"}} + {{if .Author.FullName}} + {{.Author.FullName}} + {{else}} + {{.Commit.Author.Name}} + {{end}} + {{else}} + {{ctx.AvatarUtils.AvatarByEmail .Commit.Author.Email .Commit.Author.Email 28 "tw-mr-2"}} + {{.Commit.Author.Name}} + {{end}} + {{TimeSince .Commit.Author.When ctx.Locale}} + {{if or (ne .Commit.Committer.Name .Commit.Author.Name) (ne .Commit.Committer.Email .Commit.Author.Email)}} + {{ctx.Locale.Tr "repo.diff.committed_by"}} + {{if ne .Verification.CommittingUser.ID 0}} + {{ctx.AvatarUtils.Avatar .Verification.CommittingUser 28 "tw-mx-2"}} + {{.Commit.Committer.Name}} + {{else}} + {{ctx.AvatarUtils.AvatarByEmail .Commit.Committer.Email .Commit.Committer.Name 28 "tw-mr-2"}} + {{.Commit.Committer.Name}} + {{end}} + {{end}} +
    +
    + {{if .Parents}} +
    + {{ctx.Locale.Tr "repo.diff.parent"}} + {{range .Parents}} + {{if $.PageIsWiki}} + {{ShortSha .}} + {{else}} + {{ShortSha .}} + {{end}} + {{end}} +
    + {{end}} +
    + {{ctx.Locale.Tr "repo.diff.commit"}} + {{ShortSha .CommitID}} +
    +
    +
    + {{if .Commit.Signature}} +
    +
    + {{if .Verification.Verified}} + {{if ne .Verification.SigningUser.ID 0}} + {{svg "gitea-lock" 16 "tw-mr-2"}} + {{if eq .Verification.TrustStatus "trusted"}} + {{ctx.Locale.Tr "repo.commits.signed_by"}}: + {{else if eq .Verification.TrustStatus "untrusted"}} + {{ctx.Locale.Tr "repo.commits.signed_by_untrusted_user"}}: + {{else}} + {{ctx.Locale.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}: + {{end}} + {{ctx.AvatarUtils.Avatar .Verification.SigningUser 28 "tw-mr-2"}} + {{.Verification.SigningUser.GetDisplayName}} + {{else}} + {{svg "gitea-lock-cog" 16 "tw-mr-2"}} + {{ctx.Locale.Tr "repo.commits.signed_by"}}: + {{ctx.AvatarUtils.AvatarByEmail .Verification.SigningEmail "" 28 "tw-mr-2"}} + {{.Verification.SigningUser.GetDisplayName}} + {{end}} + {{else}} + {{svg "gitea-unlock" 16 "tw-mr-2"}} + {{ctx.Locale.Tr .Verification.Reason}} + {{end}} +
    +
    + {{if .Verification.Verified}} + {{if ne .Verification.SigningUser.ID 0}} + {{svg "octicon-verified" 16 "tw-mr-2"}} + {{if .Verification.SigningSSHKey}} + {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: + {{.Verification.SigningSSHKey.Fingerprint}} + {{else}} + {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: + {{.Verification.SigningKey.PaddedKeyID}} + {{end}} + {{else}} + {{svg "octicon-unverified" 16 "tw-mr-2"}} + {{if .Verification.SigningSSHKey}} + {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: + {{.Verification.SigningSSHKey.Fingerprint}} + {{else}} + {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: + {{.Verification.SigningKey.PaddedKeyID}} + {{end}} + {{end}} + {{else if .Verification.Warning}} + {{svg "octicon-unverified" 16 "tw-mr-2"}} + {{if .Verification.SigningSSHKey}} + {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: + {{.Verification.SigningSSHKey.Fingerprint}} + {{else}} + {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: + {{.Verification.SigningKey.PaddedKeyID}} + {{end}} + {{else}} + {{if .Verification.SigningKey}} + {{if ne .Verification.SigningKey.KeyID ""}} + {{svg "octicon-verified" 16 "tw-mr-2"}} + {{ctx.Locale.Tr "repo.commits.gpg_key_id"}}: + {{.Verification.SigningKey.PaddedKeyID}} + {{end}} + {{end}} + {{if .Verification.SigningSSHKey}} + {{if ne .Verification.SigningSSHKey.Fingerprint ""}} + {{svg "octicon-verified" 16 "tw-mr-2"}} + {{ctx.Locale.Tr "repo.commits.ssh_key_fingerprint"}}: + {{.Verification.SigningSSHKey.Fingerprint}} + {{end}} + {{end}} + {{end}} +
    +
    + {{end}} + {{if .NoteRendered}} +
    + {{svg "octicon-note" 16 "tw-mr-2"}} + {{ctx.Locale.Tr "repo.diff.git-notes"}}: + {{if .NoteAuthor}} + + {{if .NoteAuthor.FullName}} + {{.NoteAuthor.FullName}} + {{else}} + {{.NoteCommit.Author.Name}} + {{end}} + + {{else}} + {{.NoteCommit.Author.Name}} + {{end}} + {{TimeSince .NoteCommit.Author.When ctx.Locale}} +
    +
    +
    {{.NoteRendered | SanitizeHTML}}
    +
    + {{end}} {{template "repo/diff/box" .}}
    diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index 69837bfc1a..c8c695e332 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -28,6 +28,21 @@ + {{$class := "ui sha label"}} + {{if .Signature}} + {{$class = (print $class " isSigned")}} + {{if .Verification.Verified}} + {{if eq .Verification.TrustStatus "trusted"}} + {{$class = (print $class " isVerified")}} + {{else if eq .Verification.TrustStatus "untrusted"}} + {{$class = (print $class " isVerifiedUntrusted")}} + {{else}} + {{$class = (print $class " isVerifiedUnmatched")}} + {{end}} + {{else if .Verification.Warning}} + {{$class = (print $class " isWarning")}} + {{end}} + {{end}} {{$commitShaLink := ""}} {{if $.PageIsWiki}} {{$commitShaLink = (printf "%s/wiki/commit/%s" $commitRepoLink (PathEscape .ID.String))}} @@ -36,12 +51,10 @@ {{else if $.Reponame}} {{$commitShaLink = (printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String))}} {{end}} - {{template "repo/shabox" (dict - "sha1" .ID.String - "commitLink" $commitShaLink - "signature" .Signature - "verification" .Verification - )}} + + {{ShortSha .ID.String}} + {{if .Signature}}{{template "repo/shabox_badge" dict "root" $ "verification" .Verification}}{{end}} + @@ -49,9 +62,6 @@ {{.Summary | RenderEmoji $.Context}} {{else}} {{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} - {{if $.PageIsPullCommits}} - {{$commitLink = (printf "%s/pulls/%d/commits/%s" $commitRepoLink $.Issue.Index (PathEscape .ID.String))}} - {{end}} {{RenderCommitMessageLinkSubject $.Context .Message $commitLink ($.Repository.ComposeMetas ctx)}} {{end}} @@ -64,21 +74,13 @@ {{end}} {{if .Committer}} - {{DateUtils.TimeSince .Committer.When}} + {{TimeSince .Committer.When ctx.Locale}} {{else}} - {{DateUtils.TimeSince .Author.When}} + {{TimeSince .Author.When ctx.Locale}} {{end}} {{if not $.PageIsWiki}} - {{if $.FileName}} - - {{svg "octicon-file-diff"}} - - {{end}} {{- RenderCommitMessageLinkSubject $.root.Context .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx) -}} @@ -28,14 +21,29 @@ {{end}} - + {{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}} - {{template "repo/shabox" (dict - "sha1" .ID.String - "commitLink" $commitLink - "signature" .Signature - "verification" .Verification - )}} + {{$class := "ui sha label"}} + {{if .Signature}} + {{$class = (print $class " isSigned")}} + {{if .Verification.Verified}} + {{if eq .Verification.TrustStatus "trusted"}} + {{$class = (print $class " isVerified")}} + {{else if eq .Verification.TrustStatus "untrusted"}} + {{$class = (print $class " isVerifiedUntrusted")}} + {{else}} + {{$class = (print $class " isVerifiedUnmatched")}} + {{end}} + {{else if .Verification.Warning}} + {{$class = (print $class " isWarning")}} + {{end}} + {{end}} + + {{ShortSha .ID.String}} + {{if .Signature}} + {{template "repo/shabox_badge" dict "root" $.root "verification" .Verification}} + {{end}} +
    {{if IsMultilineCommitMessage .Message}} diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index 621fc44bf5..7249becbab 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -10,13 +10,9 @@ {{if .IsDiffCompare}} {{end}} diff --git a/templates/repo/contributors.tmpl b/templates/repo/contributors.tmpl index c71312fc6c..f7f5d796f4 100644 --- a/templates/repo/contributors.tmpl +++ b/templates/repo/contributors.tmpl @@ -1,7 +1,6 @@ {{if .Permission.CanRead $.UnitTypeCode}}
    {{.CsrfTokenHtml}}

    - {{ctx.Locale.Tr "new_repo.title"}} + {{ctx.Locale.Tr "new_repo"}}

    - {{if or .CanCreateRepo .Orgs}} - {{template "base/alert" .}} - {{template "repo/create_helper" .}} + {{template "base/alert" .}} + {{template "repo/create_helper" .}} - {{if and (not .CanCreateRepo) (ne .MaxCreationLimit 0)}} -
    -

    {{ctx.Locale.TrN .MaxCreationLimit "repo.form.reach_limit_of_creation_1" "repo.form.reach_limit_of_creation_n" .MaxCreationLimit}}

    -
    - {{end}} -
    - {{template "repo/create_basic" .}} -
    - -
    - - {{ctx.Locale.Tr "repo.new_from_template"}} - {{ctx.Locale.Tr "repo.new_from_template_description"}} - - {{template "repo/create_from_template" .}} -
    - -
    -
    - {{ctx.Locale.Tr "repo.auto_init"}} - {{template "repo/create_init" .}} -
    - -
    - {{ctx.Locale.Tr "repo.new_advanced"}} -
    {{ctx.Locale.Tr "repo.new_advanced_expand"}} - {{template "repo/create_advanced" .}} -
    -
    -
    - - {{else}} + {{if not .CanCreateRepo}}
    - {{ctx.Locale.Tr "repo.form.cannot_create"}} +

    {{ctx.Locale.TrN .MaxCreationLimit "repo.form.reach_limit_of_creation_1" "repo.form.reach_limit_of_creation_n" .MaxCreationLimit}}

    {{end}} +
    + + + {{ctx.Locale.Tr "repo.owner_helper"}} +
    + +
    + + + {{ctx.Locale.Tr "repo.repo_name_helper"}} +
    +
    + +
    + + +
    + {{if .IsForcedPrivate}} + {{ctx.Locale.Tr "repo.visibility_helper_forced"}} + {{end}} + {{ctx.Locale.Tr "repo.visibility_description"}} +
    +
    + + +
    +
    + + +
    + +
    +
    + +
    + + +
    +
    + + +
    +
    +
    + +
    + + +
    +
    + + +
    +
    +
    + +
    + + +
    +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    +
    + + +
    + +
    + +
    + + + {{ctx.Locale.Tr "repo.repo_gitignore_helper_desc"}} +
    +
    + + + {{ctx.Locale.Tr "repo.license_helper_desc" "https://choosealicense.com/"}} +
    + +
    + + + {{ctx.Locale.Tr "repo.readme_helper_desc"}} +
    +
    +
    + + +
    +
    +
    + + + {{ctx.Locale.Tr "repo.default_branch_helper"}} +
    +
    + + + {{ctx.Locale.Tr "repo.object_format_helper"}} +
    +
    + +
    + + +
    +
    +
    +
    +
    + + +
    diff --git a/templates/repo/create_advanced.tmpl b/templates/repo/create_advanced.tmpl deleted file mode 100644 index c0274701f8..0000000000 --- a/templates/repo/create_advanced.tmpl +++ /dev/null @@ -1,45 +0,0 @@ - - -{{$supportedFormatsLength := len .SupportedObjectFormats}} -{{/* Only offer object format selection if there is an actual choice */}} -{{if ge $supportedFormatsLength 2}} - -{{else}} - -{{end}} - - - - diff --git a/templates/repo/create_basic.tmpl b/templates/repo/create_basic.tmpl deleted file mode 100644 index 90545c2769..0000000000 --- a/templates/repo/create_basic.tmpl +++ /dev/null @@ -1,57 +0,0 @@ - - - - diff --git a/templates/repo/create_from_template.tmpl b/templates/repo/create_from_template.tmpl deleted file mode 100644 index 47cda3df02..0000000000 --- a/templates/repo/create_from_template.tmpl +++ /dev/null @@ -1,49 +0,0 @@ - -{{/* If the dropdown is inside the label, the focus works correctly and it is more accessible. - However, the Javascript takes the focus and opens the dropdown again immediately after closing. - When the user interacts (via mouse or keyboard), the dropdown closes again. - Due to the fieldset legend, this solutions is probably acceptable until the dropdown can be fixed properly. */}} - - -
    - {{ctx.Locale.Tr "repo.template.items"}} - - - - - - - - -
    diff --git a/templates/repo/create_init.tmpl b/templates/repo/create_init.tmpl deleted file mode 100644 index 729b44c8e6..0000000000 --- a/templates/repo/create_init.tmpl +++ /dev/null @@ -1,56 +0,0 @@ - - -
    - - - - - {{$supportedReadmesLength := len .Readmes}} - {{/* Only offer README selection if there is an actual choice */}} - {{if ge $supportedReadmesLength 2}} - - {{else}} - - {{end}} -
    diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index f3c0c0989d..230e49752f 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -53,7 +53,7 @@ {{if not .DiffNotAvailable}} {{if and .IsShowingOnlySingleCommit .PageIsPullFiles}}
    -
    {{ctx.Locale.Tr "repo.pulls.showing_only_single_commit" (ShortSha .CommitID)}} - {{ctx.Locale.Tr "repo.pulls.show_all_commits"}}
    +
    {{ctx.Locale.Tr "repo.pulls.showing_only_single_commit" (ShortSha .AfterCommitID)}} - {{ctx.Locale.Tr "repo.pulls.show_all_commits"}}
    {{else if and (not .IsShowingAllCommits) .PageIsPullFiles}}
    @@ -85,6 +85,7 @@ diffFileInfo.files.push(...diffDataFiles); window.config.pageData.diffFileInfo = diffFileInfo; +
    {{end}}
    {{if $showFileTree}} @@ -93,12 +94,6 @@ if (diffTreeVisible) document.getElementById('diff-file-tree').classList.remove('tw-hidden'); {{end}} -
    - {{if .IsShowingOnlySingleCommit}} -
    - {{template "repo/commit_header" .}} -
    - {{end}} {{if .DiffNotAvailable}}

    {{ctx.Locale.Tr "repo.diff.data_not_available"}}

    {{else}} @@ -135,7 +130,7 @@
    {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}} {{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}} - + {{if $file.IsGenerated}} {{ctx.Locale.Tr "repo.diff.generated"}} {{end}} @@ -236,7 +231,6 @@ {{end}}
    {{end}} -
    {{if and (not $.Repository.IsArchived) (not .DiffNotAvailable)}} @@ -254,8 +248,8 @@ {{end}}
    - - + +
    diff --git a/templates/repo/diff/comment_form.tmpl b/templates/repo/diff/comment_form.tmpl index bb29583059..856b3da01a 100644 --- a/templates/repo/diff/comment_form.tmpl +++ b/templates/repo/diff/comment_form.tmpl @@ -31,6 +31,7 @@ {{if $.reply}} + {{else}} {{if $.root.CurrentReview}} diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index 3128149c75..2e0c85d0a1 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -1,6 +1,6 @@ {{range .comments}} -{{$createdStr:= DateUtils.TimeSince .CreatedUnix}} +{{$createdStr:= TimeSinceUnix .CreatedUnix ctx.Locale}}
    {{if .OriginalAuthor}} {{ctx.AvatarUtils.Avatar nil}} @@ -33,15 +33,19 @@
    {{if .Invalidated}} {{$referenceUrl := printf "%s#%s" $.root.Issue.Link .HashTag}} - + {{ctx.Locale.Tr "repo.issues.review.outdated"}} {{end}} {{if and .Review}} {{if eq .Review.Type 0}} -
    +
    {{ctx.Locale.Tr "repo.issues.review.pending"}}
    + {{else}} +
    + {{ctx.Locale.Tr "repo.issues.review.review"}} +
    {{end}} {{end}} {{template "repo/issue/view_content/add_reaction" dict "ctxData" $.root "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}} @@ -49,7 +53,7 @@
    -
    +
    {{if .RenderedContent}} {{.RenderedContent}} {{else}} diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index c1b00c5f9e..110f8ac60b 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -39,13 +39,21 @@ {{svg "octicon-filter" 16}}
    -
    - - {{svg "octicon-git-branch"}}{{ctx.Locale.Tr "repo.branches"}} - - - {{svg "octicon-tag"}}{{ctx.Locale.Tr "repo.tags"}} - + -
    - - {{svg "octicon-git-branch"}}{{ctx.Locale.Tr "repo.branches"}} - - - {{svg "octicon-tag"}}{{ctx.Locale.Tr "repo.tags"}} - + - {{else}} -
    - {{ctx.Locale.Tr "repo.pulls.sign_in_require" .SignInLink}} -
    {{end}} {{if $.IsSigned}}
    diff --git a/templates/repo/diff/conversation.tmpl b/templates/repo/diff/conversation.tmpl index 9753bd80e1..c80d999f47 100644 --- a/templates/repo/diff/conversation.tmpl +++ b/templates/repo/diff/conversation.tmpl @@ -14,7 +14,7 @@ We only handle the case $resolved=true and $invalid=true in this template because if the comment is not resolved it has the outdated label in the comments area (not the header above). The case $resolved=false and $invalid=true is handled in repo/diff/comments.tmpl --> - + {{ctx.Locale.Tr "repo.issues.review.outdated"}} {{end}} diff --git a/templates/repo/diff/image_diff.tmpl b/templates/repo/diff/image_diff.tmpl index a793f54da1..0612854609 100644 --- a/templates/repo/diff/image_diff.tmpl +++ b/templates/repo/diff/image_diff.tmpl @@ -22,7 +22,7 @@ {{if .blobBase}}

    {{ctx.Locale.Tr "repo.diff.file_before"}}

    - +

    {{ctx.Locale.Tr "repo.diff.file_image_width"}}: @@ -37,7 +37,7 @@ {{if .blobHead}}

    {{ctx.Locale.Tr "repo.diff.file_after"}}

    - +

    {{ctx.Locale.Tr "repo.diff.file_image_width"}}: @@ -55,9 +55,9 @@

    - {{ctx.Locale.Tr + - {{ctx.Locale.Tr + @@ -70,8 +70,8 @@
    - {{ctx.Locale.Tr - {{ctx.Locale.Tr + +
    diff --git a/templates/repo/diff/new_review.tmpl b/templates/repo/diff/new_review.tmpl index ded7a6c5fc..1b74a230f4 100644 --- a/templates/repo/diff/new_review.tmpl +++ b/templates/repo/diff/new_review.tmpl @@ -1,14 +1,10 @@
    -
    - -
    + + {{if $.IsShowingAllCommits}}
    @@ -34,22 +30,27 @@ {{end}}
    {{$showSelfTooltip := (and $.IsSigned ($.Issue.IsPoster $.SignedUser.ID))}} - {{if $showSelfTooltip}} - - - - {{else}} - + {{if not $.Issue.IsClosed}} + {{if $showSelfTooltip}} + + + + {{else}} + + {{end}} {{end}} - {{if $showSelfTooltip}} - - - - {{else}} - + {{if not $.Issue.IsClosed}} + {{if $showSelfTooltip}} + + + + {{else}} + + {{end}} {{end}}
    + {{end}}
    diff --git a/templates/repo/diff/options_dropdown.tmpl b/templates/repo/diff/options_dropdown.tmpl index 44b0743e09..09b7b80e41 100644 --- a/templates/repo/diff/options_dropdown.tmpl +++ b/templates/repo/diff/options_dropdown.tmpl @@ -1,6 +1,7 @@
    diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl index 51392e3470..5c768f32bb 100644 --- a/templates/repo/graph/commits.tmpl +++ b/templates/repo/graph/commits.tmpl @@ -6,12 +6,27 @@ {{else}} - {{template "repo/shabox" (dict - "sha1" $commit.Commit.ID.String - "commitLink" (printf "%s/commit/%s" $.RepoLink ($commit.Rev|PathEscape)) - "signature" $commit.Commit.Signature - "verification" $commit.Verification - )}} + {{$class := "ui sha label"}} + {{if $commit.Commit.Signature}} + {{$class = (print $class " isSigned")}} + {{if $commit.Verification.Verified}} + {{if eq $commit.Verification.TrustStatus "trusted"}} + {{$class = (print $class " isVerified")}} + {{else if eq $commit.Verification.TrustStatus "untrusted"}} + {{$class = (print $class " isVerifiedUntrusted")}} + {{else}} + {{$class = (print $class " isVerifiedUnmatched")}} + {{end}} + {{else if $commit.Verification.Warning}} + {{$class = (print $class " isWarning")}} + {{end}} + {{end}} + + {{ShortSha $commit.Commit.ID.String}} + {{- if $commit.Commit.Signature -}} + {{template "repo/shabox_badge" dict "root" $ "verification" $commit.Verification}} + {{- end -}} + {{RenderCommitMessage $.Context $commit.Subject ($.Repository.ComposeMetas ctx)}} @@ -56,7 +71,7 @@ {{$userName}} {{end}} - {{DateUtils.FullTime $commit.Date}} + {{DateTime "full" $commit.Date}} {{end}} {{end}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index b6cbfc7283..e81e65bc7d 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -13,24 +13,24 @@
    {{if .IsArchived}} - {{ctx.Locale.Tr "repo.desc.archived"}} + {{ctx.Locale.Tr "repo.desc.archived"}}
    {{svg "octicon-archive" 18}}
    {{end}} {{if .IsPrivate}} - {{ctx.Locale.Tr "repo.desc.private"}} + {{ctx.Locale.Tr "repo.desc.private"}}
    {{svg "octicon-lock" 18}}
    {{else}} {{if .Owner.Visibility.IsPrivate}} - {{ctx.Locale.Tr "repo.desc.internal"}} + {{ctx.Locale.Tr "repo.desc.internal"}}
    {{svg "octicon-shield-lock" 18}}
    {{end}} {{end}} {{if .IsTemplate}} - {{ctx.Locale.Tr "repo.desc.template"}} + {{ctx.Locale.Tr "repo.desc.template"}}
    {{svg "octicon-repo-template" 18}}
    {{end}} {{if eq .ObjectFormatName "sha256"}} - {{ctx.Locale.Tr "repo.desc.sha256"}} + {{ctx.Locale.Tr "repo.desc.sha256"}} {{end}}
    @@ -67,14 +67,6 @@ {{if not $.DisableForks}} {{template "repo/header_fork" $}} {{end}} - {{if and $.IsModerationEnabled $.IsSigned (not $.IsRepositoryAdmin)}} - - {{end}}
    {{end}}
    @@ -82,7 +74,7 @@
    {{ctx.Locale.Tr "repo.mirror_from"}} {{$.PullMirror.RemoteAddress}} - {{if $.PullMirror.UpdatedUnix}}{{ctx.Locale.Tr "repo.mirror_sync"}} {{DateUtils.TimeSince $.PullMirror.UpdatedUnix}}{{end}} + {{if $.PullMirror.UpdatedUnix}}{{ctx.Locale.Tr "repo.mirror_sync"}} {{TimeSinceUnix $.PullMirror.UpdatedUnix ctx.Locale}}{{end}}
    {{end}} {{if .IsFork}}
    {{ctx.Locale.Tr "repo.forked_from"}} {{.BaseRepo.FullName}}
    {{end}} @@ -143,9 +135,6 @@ {{if .Permission.CanRead $.UnitTypePackages}} {{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}} - {{if .NumPackages}} - {{CountFmt .NumPackages}} - {{end}} {{end}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 39d0c6c751..1f53121995 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -3,6 +3,7 @@ {{template "repo/header" .}}
    {{template "base/alert" .}} + {{template "repo/code/recently_pushed_new_branches" .}} {{if and (not .HideRepoInfo) (not .IsBlame)}}
    @@ -10,6 +11,12 @@ {{if $description}}{{$description | RenderCodeBlock}}{{else}}{{ctx.Locale.Tr "repo.no_desc"}}{{end}} {{if .Repository.Website}}{{.Repository.Website}}{{end}}
    +
    +
    + + {{template "shared/search/button"}} +
    +
    {{/* it should match the code in issue-home.js */}} @@ -46,7 +53,7 @@ {{if .Repository.ArchivedUnix.IsZero}} {{ctx.Locale.Tr "repo.archive.title"}} {{else}} - {{ctx.Locale.Tr "repo.archive.title_date" (DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix)}} {{end}}
    {{end}} @@ -55,8 +62,8 @@ {{$l := Eval $n "-" 1}} {{$isHomepage := (eq $n 0)}}
    -
    - {{template "repo/branch_dropdown" dict "root" .}} +
    + {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} {{$cmpBranch := ""}} {{if ne .Repository.ID .BaseRepo.ID}} @@ -106,7 +113,6 @@ / {{- if eq $i $l -}} {{$v}} - {{- else -}} {{$p := index $.Paths $i}}{{$v}} {{- end -}} @@ -127,7 +133,7 @@ {{svg "octicon-file-zip" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.download_tar"}} {{svg "octicon-package" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.download_bundle"}} {{end}} - {{if .CitationExist}} + {{if .CitiationExist}} {{svg "octicon-cross-reference" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.cite_this_repo"}} {{end}} {{range .OpenWithEditorApps}} @@ -140,48 +146,17 @@ {{template "repo/cite/cite_modal" .}} {{end}} {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}}{{/* IsViewDirectory (not home), TODO: split the templates, avoid using "if" tricks */}} - + + {{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}} + {{end}}
    - - {{template "repo/code/recently_pushed_new_branches" .}} - {{template "repo/code/fork_sync_message" .}} - {{if .IsViewFile}} {{template "repo/view_file" .}} {{else if .IsBlame}} {{template "repo/blame" .}} {{else}}{{/* IsViewDirectory */}} - {{/* display the search bar only if */}} - {{$isCommit := StringUtils.HasPrefix .BranchNameSubURL "commit"}} - {{if and (not $isCommit) (or .CodeIndexerDisabled (and (not .TagName) (eq .Repository.DefaultBranch .BranchName)))}} - - {{end}} {{template "repo/view_list" .}} {{end}}
    diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index 6d2f441793..4c22c28329 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -4,7 +4,7 @@ {{if $attachments}}
    {{range $attachments}} - {{.Name}} + {{.Name}} {{end}}
    {{end}} @@ -14,7 +14,7 @@
    {{template "shared/issueicon" .}}
    - {{RenderRefIssueTitle $.Context .Title}} + {{.Title | RenderEmoji ctx | RenderCodeBlock}} {{if and $.isPinnedIssueCard $.Page.IsRepoAdmin}} {{svg "octicon-x" 16}} @@ -24,7 +24,7 @@
    {{if not $.Page.Repository}}{{.Repo.FullName}}{{end}}#{{.Index}} - {{$timeStr := DateUtils.TimeSince .GetLastEventTimestamp}} + {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} {{if .OriginalAuthor}} {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor}} {{else if gt .Poster.ID 0}} @@ -45,7 +45,7 @@ {{if $.Page.LinkedPRs}} {{range index $.Page.LinkedPRs .ID}}
    - + {{svg "octicon-git-merge" 16 "tw-mr-1 tw-align-middle"}} {{.Title}} #{{.Index}} diff --git a/templates/repo/issue/fields/header.tmpl b/templates/repo/issue/fields/header.tmpl index 06c41af6b9..6034fed5fd 100644 --- a/templates/repo/issue/fields/header.tmpl +++ b/templates/repo/issue/fields/header.tmpl @@ -1,4 +1,4 @@ -{{if and (.item.Attributes.label) (not .item.Attributes.hide_label)}} +{{if .item.Attributes.label}}

    {{.item.Attributes.label}}{{if .item.Validations.required}}{{end}}

    {{end}} {{if .item.Attributes.description}} diff --git a/templates/repo/issue/filter_actions.tmpl b/templates/repo/issue/filter_actions.tmpl index 60237f225d..a341448bcc 100644 --- a/templates/repo/issue/filter_actions.tmpl +++ b/templates/repo/issue/filter_actions.tmpl @@ -1,9 +1,9 @@ {{range .OpenProjects}}
    - {{svg .IconName 16 "tw-mr-2"}}{{.Title}} + {{svg .IconName 18 "tw-mr-2"}}{{.Title}}
    {{end}} {{end}} @@ -96,7 +96,7 @@
    {{range .ClosedProjects}}
    - {{svg .IconName 16 "tw-mr-2"}}{{.Title}} + {{svg .IconName 18 "tw-mr-2"}}{{.Title}}
    {{end}} {{end}} diff --git a/templates/repo/issue/filter_list.tmpl b/templates/repo/issue/filter_list.tmpl index 84ba6e5358..f60389766e 100644 --- a/templates/repo/issue/filter_list.tmpl +++ b/templates/repo/issue/filter_list.tmpl @@ -3,7 +3,7 @@ {{if not .Milestone}} -