diff --git a/.changelog.yml b/.changelog.yml index a7df8779de..bfdee0c0ca 100644 --- a/.changelog.yml +++ b/.changelog.yml @@ -22,25 +22,20 @@ groups: name: FEATURES labels: - type/feature + - + name: API + labels: + - modifies/api - name: ENHANCEMENTS labels: - type/enhancement - - - name: PERFORMANCE - labels: - - performance/memory - - performance/speed - - performance/bigrepo - - performance/cpu + - type/refactoring + - topic/ui - name: BUGFIXES labels: - type/bug - - - name: API - labels: - - modifies/api - name: TESTING labels: diff --git a/.editorconfig b/.editorconfig index e23e4cd649..c0946ac997 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,7 +17,6 @@ insert_final_newline = false [templates/swagger/v1_json.tmpl] indent_style = space -insert_final_newline = false [templates/user/auth/oidc_wellknown.tmpl] indent_style = space diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index f2af1709e4..0000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,1004 +0,0 @@ -const vitestPlugin = require('@vitest/eslint-plugin'); -const restrictedSyntax = ['WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression']; - -module.exports = { - root: true, - reportUnusedDisableDirectives: true, - ignorePatterns: [ - '/web_src/js/vendor', - '/web_src/fomantic', - '/public/assets/js', - ], - parser: '@typescript-eslint/parser', - parserOptions: { - sourceType: 'module', - ecmaVersion: 'latest', - project: true, - extraFileExtensions: ['.vue'], - parser: '@typescript-eslint/parser', // for vue plugin - https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser - }, - settings: { - 'import-x/extensions': ['.js', '.ts'], - 'import-x/parsers': { - '@typescript-eslint/parser': ['.js', '.ts'], - }, - 'import-x/resolver': { - typescript: true, - }, - }, - plugins: [ - '@eslint-community/eslint-plugin-eslint-comments', - '@stylistic/eslint-plugin-js', - '@typescript-eslint/eslint-plugin', - 'eslint-plugin-array-func', - 'eslint-plugin-github', - 'eslint-plugin-import-x', - 'eslint-plugin-no-jquery', - 'eslint-plugin-no-use-extend-native', - 'eslint-plugin-regexp', - 'eslint-plugin-sonarjs', - 'eslint-plugin-unicorn', - 'eslint-plugin-wc', - ], - env: { - es2024: true, - node: true, - }, - overrides: [ - { - files: ['**/*.cjs'], - rules: { - 'import-x/no-commonjs': [0], - '@typescript-eslint/no-require-imports': [0], - }, - }, - { - 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: ['*.config.*'], - rules: { - 'import-x/no-unused-modules': [0], - }, - }, - { - files: ['**/*.d.ts'], - rules: { - 'import-x/no-unused-modules': [0], - '@typescript-eslint/consistent-type-definitions': [0], - '@typescript-eslint/consistent-type-imports': [0], - }, - }, - { - files: ['web_src/js/types.ts'], - rules: { - 'import-x/no-unused-modules': [0], - }, - }, - { - files: ['**/*.test.*', 'web_src/js/test/setup.ts'], - plugins: ['@vitest/eslint-plugin'], - globals: vitestPlugin.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.ts', 'web_src/js/standalone/**/*'], - rules: { - 'no-restricted-syntax': [2, ...restrictedSyntax], - }, - }, - { - files: ['**/*.vue'], - plugins: [ - 'eslint-plugin-vue', - 'eslint-plugin-vue-scoped-css', - ], - extends: [ - 'plugin:vue/vue3-recommended', - 'plugin:vue-scoped-css/vue3-recommended', - ], - rules: { - 'vue/attributes-order': [0], - 'vue/html-closing-bracket-spacing': [2, {startTag: 'never', endTag: 'never', selfClosingTag: 'never'}], - 'vue/max-attributes-per-line': [0], - 'vue/singleline-html-element-content-newline': [0], - }, - }, - { - files: ['tests/e2e/**'], - plugins: [ - 'eslint-plugin-playwright', - ], - extends: [ - 'plugin:playwright/recommended', - ], - }, - ], - 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-argument-newline': [0], - '@stylistic/js/function-call-spacing': [2, 'never'], - '@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/line-comment-position': [0], - '@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-comment-style': [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'], - '@typescript-eslint/adjacent-overload-signatures': [0], - '@typescript-eslint/array-type': [0], - '@typescript-eslint/await-thenable': [2], - '@typescript-eslint/ban-ts-comment': [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}], - '@typescript-eslint/ban-tslint-comment': [0], - '@typescript-eslint/class-literal-property-style': [0], - '@typescript-eslint/class-methods-use-this': [0], - '@typescript-eslint/consistent-generic-constructors': [0], - '@typescript-eslint/consistent-indexed-object-style': [0], - '@typescript-eslint/consistent-return': [0], - '@typescript-eslint/consistent-type-assertions': [2, {assertionStyle: 'as', objectLiteralTypeAssertions: 'allow'}], - '@typescript-eslint/consistent-type-definitions': [2, 'type'], - '@typescript-eslint/consistent-type-exports': [2, {fixMixedExportsWithInlineTypeSpecifier: false}], - '@typescript-eslint/consistent-type-imports': [2, {prefer: 'type-imports', fixStyle: 'separate-type-imports', disallowTypeAnnotations: true}], - '@typescript-eslint/default-param-last': [0], - '@typescript-eslint/dot-notation': [0], - '@typescript-eslint/explicit-function-return-type': [0], - '@typescript-eslint/explicit-member-accessibility': [0], - '@typescript-eslint/explicit-module-boundary-types': [0], - '@typescript-eslint/init-declarations': [0], - '@typescript-eslint/max-params': [0], - '@typescript-eslint/member-ordering': [0], - '@typescript-eslint/method-signature-style': [0], - '@typescript-eslint/naming-convention': [0], - '@typescript-eslint/no-array-constructor': [2], - '@typescript-eslint/no-array-delete': [2], - '@typescript-eslint/no-base-to-string': [0], - '@typescript-eslint/no-confusing-non-null-assertion': [2], - '@typescript-eslint/no-confusing-void-expression': [0], - '@typescript-eslint/no-deprecated': [2], - '@typescript-eslint/no-dupe-class-members': [0], - '@typescript-eslint/no-duplicate-enum-values': [2], - '@typescript-eslint/no-duplicate-type-constituents': [2, {ignoreUnions: true}], - '@typescript-eslint/no-dynamic-delete': [0], - '@typescript-eslint/no-empty-function': [0], - '@typescript-eslint/no-empty-interface': [0], - '@typescript-eslint/no-empty-object-type': [2], - '@typescript-eslint/no-explicit-any': [0], - '@typescript-eslint/no-extra-non-null-assertion': [2], - '@typescript-eslint/no-extraneous-class': [0], - '@typescript-eslint/no-floating-promises': [0], - '@typescript-eslint/no-for-in-array': [2], - '@typescript-eslint/no-implied-eval': [2], - '@typescript-eslint/no-import-type-side-effects': [0], // dupe with consistent-type-imports - '@typescript-eslint/no-inferrable-types': [0], - '@typescript-eslint/no-invalid-this': [0], - '@typescript-eslint/no-invalid-void-type': [0], - '@typescript-eslint/no-loop-func': [0], - '@typescript-eslint/no-loss-of-precision': [0], - '@typescript-eslint/no-magic-numbers': [0], - '@typescript-eslint/no-meaningless-void-operator': [0], - '@typescript-eslint/no-misused-new': [2], - '@typescript-eslint/no-misused-promises': [2, {checksVoidReturn: {attributes: false, arguments: false}}], - '@typescript-eslint/no-mixed-enums': [0], - '@typescript-eslint/no-namespace': [2], - '@typescript-eslint/no-non-null-asserted-nullish-coalescing': [0], - '@typescript-eslint/no-non-null-asserted-optional-chain': [2], - '@typescript-eslint/no-non-null-assertion': [0], - '@typescript-eslint/no-redeclare': [0], - '@typescript-eslint/no-redundant-type-constituents': [2], - '@typescript-eslint/no-require-imports': [2], - '@typescript-eslint/no-restricted-imports': [0], - '@typescript-eslint/no-restricted-types': [0], - '@typescript-eslint/no-shadow': [0], - '@typescript-eslint/no-this-alias': [0], // handled by unicorn/no-this-assignment - '@typescript-eslint/no-unnecessary-boolean-literal-compare': [0], - '@typescript-eslint/no-unnecessary-condition': [0], - '@typescript-eslint/no-unnecessary-qualifier': [0], - '@typescript-eslint/no-unnecessary-template-expression': [0], - '@typescript-eslint/no-unnecessary-type-arguments': [0], - '@typescript-eslint/no-unnecessary-type-assertion': [2], - '@typescript-eslint/no-unnecessary-type-constraint': [2], - '@typescript-eslint/no-unsafe-argument': [0], - '@typescript-eslint/no-unsafe-assignment': [0], - '@typescript-eslint/no-unsafe-call': [0], - '@typescript-eslint/no-unsafe-declaration-merging': [2], - '@typescript-eslint/no-unsafe-enum-comparison': [2], - '@typescript-eslint/no-unsafe-function-type': [2], - '@typescript-eslint/no-unsafe-member-access': [0], - '@typescript-eslint/no-unsafe-return': [0], - '@typescript-eslint/no-unsafe-unary-minus': [2], - '@typescript-eslint/no-unused-expressions': [0], - '@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}], - '@typescript-eslint/no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true, typedefs: false, enums: false, ignoreTypeReferences: true}], - '@typescript-eslint/no-useless-constructor': [0], - '@typescript-eslint/no-useless-empty-export': [0], - '@typescript-eslint/no-wrapper-object-types': [2], - '@typescript-eslint/non-nullable-type-assertion-style': [0], - '@typescript-eslint/only-throw-error': [2], - '@typescript-eslint/parameter-properties': [0], - '@typescript-eslint/prefer-as-const': [2], - '@typescript-eslint/prefer-destructuring': [0], - '@typescript-eslint/prefer-enum-initializers': [0], - '@typescript-eslint/prefer-find': [2], - '@typescript-eslint/prefer-for-of': [2], - '@typescript-eslint/prefer-function-type': [2], - '@typescript-eslint/prefer-includes': [2], - '@typescript-eslint/prefer-literal-enum-member': [0], - '@typescript-eslint/prefer-namespace-keyword': [0], - '@typescript-eslint/prefer-nullish-coalescing': [0], - '@typescript-eslint/prefer-optional-chain': [2, {requireNullish: true}], - '@typescript-eslint/prefer-promise-reject-errors': [0], - '@typescript-eslint/prefer-readonly': [0], - '@typescript-eslint/prefer-readonly-parameter-types': [0], - '@typescript-eslint/prefer-reduce-type-parameter': [0], - '@typescript-eslint/prefer-regexp-exec': [0], - '@typescript-eslint/prefer-return-this-type': [0], - '@typescript-eslint/prefer-string-starts-ends-with': [2, {allowSingleElementEquality: 'always'}], - '@typescript-eslint/promise-function-async': [0], - '@typescript-eslint/require-array-sort-compare': [0], - '@typescript-eslint/require-await': [0], - '@typescript-eslint/restrict-plus-operands': [2], - '@typescript-eslint/restrict-template-expressions': [0], - '@typescript-eslint/return-await': [0], - '@typescript-eslint/strict-boolean-expressions': [0], - '@typescript-eslint/switch-exhaustiveness-check': [0], - '@typescript-eslint/triple-slash-reference': [2], - '@typescript-eslint/typedef': [0], - '@typescript-eslint/unbound-method': [0], // too many false-positives - '@typescript-eslint/unified-signatures': [2], - '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': [0], // https://github.com/github/eslint-plugin-github/issues/599 - '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], - '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': [0], - '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: ['\\?.+$']}], - 'import-x/no-unused-modules': [2, {unusedExports: true}], - '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], - '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': [0], // handled by @typescript-eslint/no-array-constructor - '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': [0], - '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': [0], // handled by @typescript-eslint/no-implied-eval - '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': [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-fx': [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': [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': [2], - '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': [0], // must be disabled for typescript overloads - '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', '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'], - 'no-restricted-imports': [0], - 'no-restricted-syntax': [2, ...restrictedSyntax, {selector: 'CallExpression[callee.name="fetch"]', message: 'use modules/fetch.ts 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], // it is still needed by eslint & IDE to prompt undefined names in real time - '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': [0], // handled by @typescript-eslint/no-unused-vars - 'no-use-before-define': [0], // handled by @typescript-eslint/no-use-before-define - '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], // handled by @typescript-eslint/require-await - '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-empty-array-spread': [2], - 'unicorn/consistent-existence-index-check': [0], - 'unicorn/consistent-function-scoping': [0], - '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-fetch-options': [2], - 'unicorn/no-invalid-remove-event-listener': [2], - 'unicorn/no-keyword-prefix': [0], - 'unicorn/no-length-as-slice-end': [2], - 'unicorn/no-lonely-if': [2], - 'unicorn/no-magic-array-flat-depth': [0], - '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-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-global-this': [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-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': [2], - '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-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-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/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000000..0dd9a6687d --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,967 @@ +root: true +reportUnusedDisableDirectives: true + +ignorePatterns: + - /web_src/js/vendor + - /web_src/fomantic + - /public/assets/js + +parser: "@typescript-eslint/parser" + +parserOptions: + sourceType: module + ecmaVersion: latest + project: true + extraFileExtensions: [".vue"] + parser: "@typescript-eslint/parser" # for vue plugin - https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser + +settings: + import-x/extensions: [".js", ".ts"] + import-x/parsers: + "@typescript-eslint/parser": [".js", ".ts"] + import-x/resolver: + typescript: true + +plugins: + - "@eslint-community/eslint-plugin-eslint-comments" + - "@stylistic/eslint-plugin-js" + - "@typescript-eslint/eslint-plugin" + - eslint-plugin-array-func + - eslint-plugin-github + - eslint-plugin-import-x + - 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: + import-x/no-unused-modules: [0] + - files: ["**/*.d.ts"] + rules: + import-x/no-unused-modules: [0] + "@typescript-eslint/consistent-type-definitions": [0] + "@typescript-eslint/consistent-type-imports": [0] + - files: ["web_src/js/types.ts"] + rules: + import-x/no-unused-modules: [0] + - files: ["**/*.test.*", "web_src/js/test/setup.ts"] + 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.ts", "web_src/js/standalone/**/*"] + rules: + no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression] + - files: ["**/*.vue"] + plugins: + - eslint-plugin-vue + - eslint-plugin-vue-scoped-css + extends: + - plugin:vue/vue3-recommended + - plugin:vue-scoped-css/vue3-recommended + rules: + vue/attributes-order: [0] + vue/html-closing-bracket-spacing: [2, {startTag: never, endTag: never, selfClosingTag: never}] + vue/max-attributes-per-line: [0] + vue/singleline-html-element-content-newline: [0] + - files: ["tests/e2e/**"] + plugins: + - eslint-plugin-playwright + extends: plugin:playwright/recommended + +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-argument-newline": [0] + "@stylistic/js/function-call-spacing": [2, never] + "@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/line-comment-position": [0] + "@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-comment-style": [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] + "@typescript-eslint/adjacent-overload-signatures": [0] + "@typescript-eslint/array-type": [0] + "@typescript-eslint/await-thenable": [2] + "@typescript-eslint/ban-ts-comment": [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}] + "@typescript-eslint/ban-tslint-comment": [0] + "@typescript-eslint/class-literal-property-style": [0] + "@typescript-eslint/class-methods-use-this": [0] + "@typescript-eslint/consistent-generic-constructors": [0] + "@typescript-eslint/consistent-indexed-object-style": [0] + "@typescript-eslint/consistent-return": [0] + "@typescript-eslint/consistent-type-assertions": [2, {assertionStyle: as, objectLiteralTypeAssertions: allow}] + "@typescript-eslint/consistent-type-definitions": [2, type] + "@typescript-eslint/consistent-type-exports": [2, {fixMixedExportsWithInlineTypeSpecifier: false}] + "@typescript-eslint/consistent-type-imports": [2, {prefer: type-imports, fixStyle: separate-type-imports, disallowTypeAnnotations: true}] + "@typescript-eslint/default-param-last": [0] + "@typescript-eslint/dot-notation": [0] + "@typescript-eslint/explicit-function-return-type": [0] + "@typescript-eslint/explicit-member-accessibility": [0] + "@typescript-eslint/explicit-module-boundary-types": [0] + "@typescript-eslint/init-declarations": [0] + "@typescript-eslint/max-params": [0] + "@typescript-eslint/member-ordering": [0] + "@typescript-eslint/method-signature-style": [0] + "@typescript-eslint/naming-convention": [0] + "@typescript-eslint/no-array-constructor": [2] + "@typescript-eslint/no-array-delete": [2] + "@typescript-eslint/no-base-to-string": [0] + "@typescript-eslint/no-confusing-non-null-assertion": [2] + "@typescript-eslint/no-confusing-void-expression": [0] + "@typescript-eslint/no-deprecated": [2] + "@typescript-eslint/no-dupe-class-members": [0] + "@typescript-eslint/no-duplicate-enum-values": [2] + "@typescript-eslint/no-duplicate-type-constituents": [2, {ignoreUnions: true}] + "@typescript-eslint/no-dynamic-delete": [0] + "@typescript-eslint/no-empty-function": [0] + "@typescript-eslint/no-empty-interface": [0] + "@typescript-eslint/no-empty-object-type": [2] + "@typescript-eslint/no-explicit-any": [0] + "@typescript-eslint/no-extra-non-null-assertion": [2] + "@typescript-eslint/no-extraneous-class": [0] + "@typescript-eslint/no-floating-promises": [0] + "@typescript-eslint/no-for-in-array": [2] + "@typescript-eslint/no-implied-eval": [2] + "@typescript-eslint/no-import-type-side-effects": [0] # dupe with consistent-type-imports + "@typescript-eslint/no-inferrable-types": [0] + "@typescript-eslint/no-invalid-this": [0] + "@typescript-eslint/no-invalid-void-type": [0] + "@typescript-eslint/no-loop-func": [0] + "@typescript-eslint/no-loss-of-precision": [0] + "@typescript-eslint/no-magic-numbers": [0] + "@typescript-eslint/no-meaningless-void-operator": [0] + "@typescript-eslint/no-misused-new": [2] + "@typescript-eslint/no-misused-promises": [2, {checksVoidReturn: {attributes: false, arguments: false}}] + "@typescript-eslint/no-mixed-enums": [0] + "@typescript-eslint/no-namespace": [2] + "@typescript-eslint/no-non-null-asserted-nullish-coalescing": [0] + "@typescript-eslint/no-non-null-asserted-optional-chain": [2] + "@typescript-eslint/no-non-null-assertion": [0] + "@typescript-eslint/no-redeclare": [0] + "@typescript-eslint/no-redundant-type-constituents": [2] + "@typescript-eslint/no-require-imports": [2] + "@typescript-eslint/no-restricted-imports": [0] + "@typescript-eslint/no-restricted-types": [0] + "@typescript-eslint/no-shadow": [0] + "@typescript-eslint/no-this-alias": [0] # handled by unicorn/no-this-assignment + "@typescript-eslint/no-unnecessary-boolean-literal-compare": [0] + "@typescript-eslint/no-unnecessary-condition": [0] + "@typescript-eslint/no-unnecessary-qualifier": [0] + "@typescript-eslint/no-unnecessary-template-expression": [0] + "@typescript-eslint/no-unnecessary-type-arguments": [0] + "@typescript-eslint/no-unnecessary-type-assertion": [2] + "@typescript-eslint/no-unnecessary-type-constraint": [2] + "@typescript-eslint/no-unsafe-argument": [0] + "@typescript-eslint/no-unsafe-assignment": [0] + "@typescript-eslint/no-unsafe-call": [0] + "@typescript-eslint/no-unsafe-declaration-merging": [2] + "@typescript-eslint/no-unsafe-enum-comparison": [2] + "@typescript-eslint/no-unsafe-function-type": [2] + "@typescript-eslint/no-unsafe-member-access": [0] + "@typescript-eslint/no-unsafe-return": [0] + "@typescript-eslint/no-unsafe-unary-minus": [2] + "@typescript-eslint/no-unused-expressions": [0] + "@typescript-eslint/no-unused-vars": [2, {vars: all, args: all, caughtErrors: all, ignoreRestSiblings: false, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_}] + "@typescript-eslint/no-use-before-define": [0] + "@typescript-eslint/no-useless-constructor": [0] + "@typescript-eslint/no-useless-empty-export": [0] + "@typescript-eslint/no-wrapper-object-types": [2] + "@typescript-eslint/non-nullable-type-assertion-style": [0] + "@typescript-eslint/only-throw-error": [2] + "@typescript-eslint/parameter-properties": [0] + "@typescript-eslint/prefer-as-const": [2] + "@typescript-eslint/prefer-destructuring": [0] + "@typescript-eslint/prefer-enum-initializers": [0] + "@typescript-eslint/prefer-find": [2] + "@typescript-eslint/prefer-for-of": [2] + "@typescript-eslint/prefer-function-type": [2] + "@typescript-eslint/prefer-includes": [2] + "@typescript-eslint/prefer-literal-enum-member": [0] + "@typescript-eslint/prefer-namespace-keyword": [0] + "@typescript-eslint/prefer-nullish-coalescing": [0] + "@typescript-eslint/prefer-optional-chain": [2, {requireNullish: true}] + "@typescript-eslint/prefer-promise-reject-errors": [0] + "@typescript-eslint/prefer-readonly": [0] + "@typescript-eslint/prefer-readonly-parameter-types": [0] + "@typescript-eslint/prefer-reduce-type-parameter": [0] + "@typescript-eslint/prefer-regexp-exec": [0] + "@typescript-eslint/prefer-return-this-type": [0] + "@typescript-eslint/prefer-string-starts-ends-with": [2, {allowSingleElementEquality: always}] + "@typescript-eslint/promise-function-async": [0] + "@typescript-eslint/require-array-sort-compare": [0] + "@typescript-eslint/require-await": [0] + "@typescript-eslint/restrict-plus-operands": [2] + "@typescript-eslint/restrict-template-expressions": [0] + "@typescript-eslint/return-await": [0] + "@typescript-eslint/strict-boolean-expressions": [0] + "@typescript-eslint/switch-exhaustiveness-check": [0] + "@typescript-eslint/triple-slash-reference": [2] + "@typescript-eslint/typedef": [0] + "@typescript-eslint/unbound-method": [0] # too many false-positives + "@typescript-eslint/unified-signatures": [2] + 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] + 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: [0] + 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: ["\\?.+$"]}] + import-x/no-unused-modules: [2, {unusedExports: true}] + 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] + 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: [0] # handled by @typescript-eslint/no-array-constructor + 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: [0] + 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: [0] # handled by @typescript-eslint/no-implied-eval + 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: [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-fx: [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: [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: [2] + 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: [0] # must be disabled for typescript overloads + 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.ts 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}] # TODO: disable this rule after tsc passes + 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: [0] # handled by @typescript-eslint/no-unused-vars + 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] # handled by @typescript-eslint/require-await + 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-empty-array-spread: [2] + unicorn/consistent-existence-index-check: [0] + unicorn/consistent-function-scoping: [0] + 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-fetch-options: [2] + unicorn/no-invalid-remove-event-listener: [2] + unicorn/no-keyword-prefix: [0] + unicorn/no-length-as-slice-end: [2] + unicorn/no-lonely-if: [2] + unicorn/no-magic-array-flat-depth: [0] + 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-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-global-this: [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-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: [2] + 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-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-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/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d409f18cd9..d37ce219c3 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -13,5 +13,5 @@ contact_links: url: https://docs.gitea.com/help/faq about: Please check if your question isn't mentioned here. - name: Crowdin Translations - url: https://translate.gitea.com + url: https://crowdin.com/project/gitea about: Translations are managed here. diff --git a/.github/labeler.yml b/.github/labeler.yml index 0af43cd029..46efbcb194 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -41,7 +41,7 @@ modifies/internal: - ".dockerignore" - "docker/**" - ".editorconfig" - - ".eslintrc.cjs" + - ".eslintrc.yaml" - ".golangci.yml" - ".gitpod.yml" - ".markdownlint.yaml" @@ -49,7 +49,7 @@ modifies/internal: - "stylelint.config.js" - ".yamllint.yaml" - ".github/**" - - ".gitea/**" + - ".gitea/" - ".devcontainer/**" - "build.go" - "build/**" @@ -73,9 +73,9 @@ modifies/go: modifies/frontend: - changed-files: - any-glob-to-any-file: - - "*.js" - - "*.ts" - - "web_src/**" + - "**/*.js" + - "**/*.ts" + - "**/*.vue" docs-update-needed: - changed-files: diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml index 33cbc507d9..cd8386ecc5 100644 --- a/.github/workflows/cron-licenses.yml +++ b/.github/workflows/cron-licenses.yml @@ -1,8 +1,8 @@ name: cron-licenses on: - # schedule: - # - cron: "7 0 * * 1" # every Monday at 00:07 UTC + schedule: + - cron: "7 0 * * 1" # every Monday at 00:07 UTC workflow_dispatch: jobs: diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml index be27537924..7c1fb02442 100644 --- a/.github/workflows/files-changed.yml +++ b/.github/workflows/files-changed.yml @@ -51,16 +51,14 @@ jobs: - "options/locale/locale_en-US.ini" frontend: - - "*.js" - - "*.ts" + - "**/*.js" - "web_src/**" - - "tools/*.js" - - "tools/*.ts" - "assets/emoji.json" - "package.json" - "package-lock.json" - "Makefile" - - ".eslintrc.cjs" + - ".eslintrc.yaml" + - "stylelint.config.js" - ".npmrc" docs: @@ -87,7 +85,6 @@ jobs: swagger: - "templates/swagger/v1_json.tmpl" - - "templates/swagger/v1_input.json" - "Makefile" - "package.json" - "package-lock.json" diff --git a/.gitignore b/.gitignore index d215468377..86e6e4fefd 100644 --- a/.gitignore +++ b/.gitignore @@ -9,11 +9,6 @@ _test # IntelliJ .idea -.run - -# IntelliJ Gateway -.uuid - # Goland's output filename can not be set manually /go_build_* /gitea_* diff --git a/.golangci.yml b/.golangci.yml index cf7a6f1a1f..c39d7ac5f2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,12 +19,12 @@ linters: - revive - staticcheck - stylecheck + - tenv - testifylint - typecheck - unconvert - unused - unparam - - usetesting - wastedassign run: @@ -102,8 +102,6 @@ linters-settings: desc: do not use the ini package, use gitea's config system instead - pkg: gitea.com/go-chi/cache desc: do not use the go-chi cache package, use gitea's cache system - usetesting: - os-temp-dir: true issues: max-issues-per-linter: 0 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/CHANGELOG.md b/CHANGELOG.md index c32915c1dc..3bb447f091 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -485,36 +485,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Use -s -w ldflags for release artifacts (#33041) #33042 * Remove aws go sdk package dependency (#33029) #33047 -## [1.22.6](https://github.com/go-gitea/gitea/releases/tag/v1.22.6) - 2024-12-12 - -* SECURITY - * Fix misuse of PublicKeyCallback(#32810) -* BUGFIXES - * Fix lfs migration (#32812) (#32818) - * Add missing two sync feed for refs/pull (#32815) -* TESTING - * Avoid MacOS keychain dialog in integration tests (#32813) (#32816) - -## [1.22.5](https://github.com/go-gitea/gitea/releases/tag/v1.22.5) - 2024-12-11 - -* SECURITY - * Upgrade crypto library (#32791) - * Fix delete branch perm checking (#32654) (#32707) -* BUGFIXES - * Add standard-compliant route to serve outdated R packages (#32783) (#32789) - * Fix internal server error when updating labels without write permission (#32776) (#32785) - * Add Swift login endpoint (#32693) (#32701) - * Fix fork page branch selection (#32711) (#32725) - * Fix word overflow in file search page (#32695) (#32699) - * Fix gogit `GetRefCommitID` (#32705) (#32712) - * Fix race condition in mermaid observer (#32599) (#32673) - * Fixe a keystring misuse and refactor duplicates keystrings (#32668) (#32792) - * Bump relative-time-element to v4.4.4 (#32739) -* PERFORMANCE - * Make wiki pages visit fast (#32732) (#32745) -* MISC - * Don't create action when syncing mirror pull refs (#32659) (#32664) - ## [1.22.4](https://github.com/go-gitea/gitea/releases/tag/v1.22.4) - 2024-11-14 * SECURITY diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11c99d1e3a..60146276db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -182,7 +182,7 @@ Here's how to run the test suite: ## Translation -All translation work happens on [Crowdin](https://translate.gitea.com). +All translation work happens on [Crowdin](https://crowdin.com/project/gitea). The only translation that is maintained in this repository is [the English translation](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.ini). It is synced regularly with Crowdin. \ Other locales on main branch **should not** be updated manually as they will be overwritten with each sync. \ diff --git a/Dockerfile b/Dockerfile index 14671d5589..b95ba83289 100644 --- a/Dockerfile +++ b/Dockerfile @@ -83,4 +83,4 @@ CMD ["/usr/bin/s6-svscan", "/etc/s6"] COPY --from=build-env /tmp/local / 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 \ No newline at end of file +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 b74dfa58e0..be6f125104 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,5 @@ # Build stage -FROM docker.io/library/golang:1.24-alpine3.21 AS build-env +FROM docker.io/library/golang:1.23-alpine3.21 AS build-env ARG GOPROXY ENV GOPROXY=${GOPROXY:-direct} diff --git a/MAINTAINERS b/MAINTAINERS index 7d21f449fe..ad02ecc755 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -31,6 +31,7 @@ Gary Kim (@gary-kim) Guillermo Prandi (@guillep2k) Mura Li (@typeless) 6543 <6543@obermui.de> (@6543) +jaqra (@jaqra) David Svantesson (@davidsvantesson) a1012112796 <1012112796@qq.com> (@a1012112796) Karl Heinz Marbaise (@khmarbaise) @@ -62,5 +63,3 @@ Yu Liu <1240335630@qq.com> (@HEREYUA) Kemal Zebari (@kemzeb) Rowan Bohde (@bohde) hiifong (@hiifong) -metiftikci (@metiftikci) -Christopher Homberger (@ChristopherHX) diff --git a/Makefile b/Makefile index d4b416156f..5524cfb08c 100644 --- a/Makefile +++ b/Makefile @@ -23,12 +23,12 @@ SHASUM ?= shasum -a 256 HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) COMMA := , -XGO_VERSION := go-1.24.x +XGO_VERSION := go-1.23.x AIR_PACKAGE ?= github.com/air-verse/air@v1 -EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.1.2 +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.0.3 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.5 +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.12 MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 @@ -36,7 +36,7 @@ XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1 -GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.1 +GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.0 DOCKER_IMAGE ?= gitea/gitea DOCKER_TAG ?= latest @@ -144,9 +144,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 *.ts *.cjs tests/e2e +ESLINT_FILES := web_src/js tools *.js *.ts tests/e2e STYLELINT_FILES := web_src/css web_src/js/components/*.vue -SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*)) +SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml)) EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini GO_SOURCES := $(wildcard *.go) @@ -165,8 +165,10 @@ ifdef DEPS_PLAYWRIGHT endif SWAGGER_SPEC := templates/swagger/v1_json.tmpl -SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json +SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape}}/api/v1"|g +SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape}}/api/v1"|"basePath": "/api/v1"|g SWAGGER_EXCLUDE := code.gitea.io/sdk +SWAGGER_NEWLINE_COMMAND := -e '$$a\' TEST_MYSQL_HOST ?= mysql:3306 TEST_MYSQL_DBNAME ?= testgitea @@ -187,11 +189,67 @@ TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1 all: build .PHONY: help -help: Makefile ## print Makefile help information. - @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m[TARGETS] default target: build\033[0m\n\n\033[35mTargets:\033[0m\n"} /^[0-9A-Za-z._-]+:.*?##/ { printf " \033[36m%-45s\033[0m %s\n", $$1, $$2 }' Makefile #$(MAKEFILE_LIST) - @printf " \033[36m%-46s\033[0m %s\n" "test-e2e[#TestSpecificName]" "test end to end using playwright" - @printf " \033[36m%-46s\033[0m %s\n" "test[#TestSpecificName]" "run unit test" - @printf " \033[36m%-46s\033[0m %s\n" "test-sqlite[#TestSpecificName]" "run integration test for sqlite" +help: + @echo "Make Routines:" + @echo " - \"\" equivalent to \"build\"" + @echo " - build build everything" + @echo " - frontend build frontend files" + @echo " - backend build backend files" + @echo " - watch watch everything and continuously rebuild" + @echo " - watch-frontend watch frontend files and continuously rebuild" + @echo " - watch-backend watch backend files and continuously rebuild" + @echo " - clean delete backend and integration files" + @echo " - clean-all delete backend, frontend and integration files" + @echo " - deps install dependencies" + @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-actions lint action workflow files" + @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-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-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" + @echo " - test test everything" + @echo " - test-frontend test frontend files" + @echo " - test-backend test backend files" + @echo " - test-e2e[\#TestSpecificName] test end to end using playwright" + @echo " - update update js and py dependencies" + @echo " - update-js update js dependencies" + @echo " - update-py update py dependencies" + @echo " - webpack build webpack files" + @echo " - svg build svg files" + @echo " - fomantic build fomantic files" + @echo " - generate run \"go generate\"" + @echo " - fmt format the Go code" + @echo " - generate-license update license files" + @echo " - generate-gitignore update gitignore files" + @echo " - generate-manpage generate manpage" + @echo " - generate-swagger generate the swagger spec from code comments" + @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-sqlite[\#TestSpecificName] run integration test for sqlite" .PHONY: go-check go-check: @@ -222,11 +280,11 @@ node-check: fi .PHONY: clean-all -clean-all: clean ## delete backend, frontend and integration files +clean-all: clean rm -rf $(WEBPACK_DEST_ENTRIES) node_modules .PHONY: clean -clean: ## delete backend and integration files +clean: rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \ integrations*.test \ e2e*.test \ @@ -238,7 +296,7 @@ clean: ## delete backend and integration files tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/ .PHONY: fmt -fmt: ## format the Go code +fmt: @GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}' $(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl')) @# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only @@ -253,7 +311,7 @@ fmt-check: fmt @diff=$$(git diff --color=always $(GO_SOURCES) templates $(WEB_DIRS)); \ if [ -n "$$diff" ]; then \ echo "Please run 'make fmt' and commit the result:"; \ - printf "%s" "$${diff}"; \ + echo "$${diff}"; \ exit 1; \ fi @@ -267,95 +325,95 @@ TAGS_PREREQ := $(TAGS_EVIDENCE) endif .PHONY: generate-swagger -generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments +generate-swagger: $(SWAGGER_SPEC) -$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) $(SWAGGER_SPEC_INPUT) - $(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)' +$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) + $(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)' + $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' + $(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)' .PHONY: swagger-check swagger-check: generate-swagger @diff=$$(git diff --color=always '$(SWAGGER_SPEC)'); \ if [ -n "$$diff" ]; then \ echo "Please run 'make generate-swagger' and commit the result:"; \ - printf "%s" "$${diff}"; \ + echo "$${diff}"; \ exit 1; \ fi .PHONY: swagger-validate -swagger-validate: ## check if the swagger spec is valid - @# swagger "validate" requires that the "basePath" must start with a slash, but we are using Golang template "{{...}}" - @$(SED_INPLACE) -E -e 's|"basePath":( *)"(.*)"|"basePath":\1"/\2"|g' './$(SWAGGER_SPEC)' # add a prefix slash to basePath - @# FIXME: there are some warnings +swagger-validate: + $(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)' $(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)' - @$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath + $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' .PHONY: checks -checks: checks-frontend checks-backend ## run various consistency checks +checks: checks-frontend checks-backend .PHONY: checks-frontend -checks-frontend: lockfile-check svg-check ## check frontend files +checks-frontend: lockfile-check svg-check .PHONY: checks-backend -checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check ## check backend files +checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check .PHONY: lint -lint: lint-frontend lint-backend lint-spell ## lint everything +lint: lint-frontend lint-backend lint-spell .PHONY: lint-fix -lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues +lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix .PHONY: lint-frontend -lint-frontend: lint-js lint-css ## lint frontend files +lint-frontend: lint-js lint-css .PHONY: lint-frontend-fix -lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues +lint-frontend-fix: lint-js-fix lint-css-fix .PHONY: lint-backend -lint-backend: lint-go lint-go-vet lint-go-gopls lint-editorconfig ## lint backend files +lint-backend: lint-go lint-go-vet lint-go-gopls lint-editorconfig .PHONY: lint-backend-fix -lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig ## lint backend files and fix issues +lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig .PHONY: lint-js -lint-js: node_modules ## lint js files +lint-js: node_modules npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) npx vue-tsc .PHONY: lint-js-fix -lint-js-fix: node_modules ## lint js files and fix issues +lint-js-fix: node_modules npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) --fix npx vue-tsc .PHONY: lint-css -lint-css: node_modules ## lint css files +lint-css: node_modules npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) .PHONY: lint-css-fix -lint-css-fix: node_modules ## lint css files and fix issues +lint-css-fix: node_modules npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix .PHONY: lint-swagger -lint-swagger: node_modules ## lint swagger files +lint-swagger: node_modules npx spectral lint -q -F hint $(SWAGGER_SPEC) .PHONY: lint-md -lint-md: node_modules ## lint markdown files +lint-md: node_modules npx markdownlint *.md .PHONY: lint-spell -lint-spell: ## lint spelling +lint-spell: @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES) .PHONY: lint-spell-fix -lint-spell-fix: ## lint spelling and fix issues +lint-spell-fix: @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES) .PHONY: lint-go -lint-go: ## lint go files +lint-go: $(GO) run $(GOLANGCI_LINT_PACKAGE) run .PHONY: lint-go-fix -lint-go-fix: ## lint go files and fix issues +lint-go-fix: $(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix # workaround step for the lint-go-windows CI task because 'go run' can not @@ -366,57 +424,56 @@ lint-go-windows: golangci-lint run .PHONY: lint-go-vet -lint-go-vet: ## lint go files with vet +lint-go-vet: @echo "Running go vet..." @GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet @$(GO) vet -vettool=gitea-vet ./... .PHONY: lint-go-gopls -lint-go-gopls: ## lint go files with 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: - @echo "Running editorconfig check..." @$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES) .PHONY: lint-actions -lint-actions: ## lint action workflow files +lint-actions: $(GO) run $(ACTIONLINT_PACKAGE) .PHONY: lint-templates -lint-templates: .venv node_modules ## lint template files +lint-templates: .venv node_modules @node tools/lint-templates-svg.js @poetry run djlint $(shell find templates -type f -iname '*.tmpl') .PHONY: lint-yaml -lint-yaml: .venv ## lint yaml files - @poetry run yamllint -s . +lint-yaml: .venv + @poetry run yamllint . .PHONY: watch -watch: ## watch everything and continuously rebuild +watch: @bash tools/watch.sh .PHONY: watch-frontend -watch-frontend: node-check node_modules ## watch frontend files and continuously rebuild +watch-frontend: node-check node_modules @rm -rf $(WEBPACK_DEST_ENTRIES) NODE_ENV=development npx webpack --watch --progress .PHONY: watch-backend -watch-backend: go-check ## watch backend files and continuously rebuild +watch-backend: go-check GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml .PHONY: test -test: test-frontend test-backend ## test everything +test: test-frontend test-backend .PHONY: test-backend -test-backend: ## test frontend files +test-backend: @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." @$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES) .PHONY: test-frontend -test-frontend: node_modules ## test backend files +test-frontend: node_modules npx vitest .PHONY: test-check @@ -425,7 +482,7 @@ test-check: @diff=$$(git status -s); \ if [ -n "$$diff" ]; then \ echo "make test-backend has changed files in the source tree:"; \ - printf "%s" "$${diff}"; \ + echo "$${diff}"; \ echo "You should change the tests to create these files in a temporary directory."; \ echo "Do not simply add these files to .gitignore"; \ exit 1; \ @@ -448,7 +505,7 @@ unit-test-coverage: @$(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: ## run go mod tidy +tidy: $(eval MIN_GO_VERSION := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2)) $(GO) mod tidy -compat=$(MIN_GO_VERSION) @$(MAKE) --no-print-directory $(GO_LICENSE_FILE) @@ -462,17 +519,15 @@ tidy-check: tidy @diff=$$(git diff --color=always go.mod go.sum $(GO_LICENSE_FILE)); \ if [ -n "$$diff" ]; then \ echo "Please run 'make tidy' and commit the result:"; \ - printf "%s" "$${diff}"; \ + echo "$${diff}"; \ exit 1; \ fi .PHONY: go-licenses -go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses +go-licenses: $(GO_LICENSE_FILE) $(GO_LICENSE_FILE): go.mod go.sum - @rm -rf $(GO_LICENSE_FILE) - $(GO) install $(GO_LICENSES_PACKAGE) - -GOOS=linux CGO_ENABLED=1 go-licenses save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null + -$(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) @@ -716,17 +771,17 @@ install: $(wildcard *.go) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' .PHONY: build -build: frontend backend ## build everything +build: frontend backend .PHONY: frontend -frontend: $(WEBPACK_DEST) ## build frontend files +frontend: $(WEBPACK_DEST) .PHONY: backend -backend: go-check generate-backend $(EXECUTABLE) ## build backend files +backend: go-check generate-backend $(EXECUTABLE) # We generate the backend before the frontend in case we in future we want to generate things in the frontend from generated files in backend .PHONY: generate -generate: generate-backend ## run "go generate" +generate: generate-backend .PHONY: generate-backend generate-backend: $(TAGS_PREREQ) generate-go @@ -791,20 +846,20 @@ release-sources: | $(DIST_DIRS) rm -f $(STORED_VERSION_FILE) .PHONY: deps -deps: deps-frontend deps-backend deps-tools deps-py ## install dependencies +deps: deps-frontend deps-backend deps-tools deps-py .PHONY: deps-py -deps-py: .venv ## install python dependencies +deps-py: .venv .PHONY: deps-frontend -deps-frontend: node_modules ## install frontend dependencies +deps-frontend: node_modules .PHONY: deps-backend -deps-backend: ## install backend dependencies +deps-backend: $(GO) mod download .PHONY: deps-tools -deps-tools: ## install tool dependencies +deps-tools: $(GO) install $(AIR_PACKAGE) & \ $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \ $(GO) install $(GOFUMPT_PACKAGE) & \ @@ -828,10 +883,10 @@ node_modules: package-lock.json @touch .venv .PHONY: update -update: update-js update-py ## update js and py dependencies +update: update-js update-py .PHONY: update-js -update-js: node-check | node_modules ## update js dependencies +update-js: node-check | node_modules npx updates -u -f package.json rm -rf node_modules package-lock.json npm install --package-lock @@ -840,14 +895,14 @@ update-js: node-check | node_modules ## update js dependencies @touch node_modules .PHONY: update-py -update-py: node-check | node_modules ## update py dependencies +update-py: node-check | node_modules npx updates -u -f pyproject.toml rm -rf .venv poetry.lock poetry install @touch .venv .PHONY: fomantic -fomantic: ## build fomantic files +fomantic: rm -rf $(FOMANTIC_WORK_DIR)/build cd $(FOMANTIC_WORK_DIR) && npm install --no-save cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config @@ -860,7 +915,7 @@ fomantic: ## build fomantic files rm -f $(FOMANTIC_WORK_DIR)/build/*.min.* .PHONY: webpack -webpack: $(WEBPACK_DEST) ## build webpack files +webpack: $(WEBPACK_DEST) $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json @$(MAKE) -s node-check node_modules @@ -870,7 +925,7 @@ $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json @touch $(WEBPACK_DEST) .PHONY: svg -svg: node-check | node_modules ## build svg files +svg: node-check | node_modules rm -rf $(SVG_DEST_DIR) node tools/generate-svg.js @@ -880,7 +935,7 @@ svg-check: svg @diff=$$(git diff --color=always --cached $(SVG_DEST_DIR)); \ if [ -n "$$diff" ]; then \ echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \ - printf "%s" "$${diff}"; \ + echo "$${diff}"; \ exit 1; \ fi @@ -891,7 +946,7 @@ lockfile-check: if [ -n "$$diff" ]; then \ echo "package-lock.json is inconsistent with package.json"; \ echo "Please run 'npm install --package-lock-only' and commit the result:"; \ - printf "%s" "$${diff}"; \ + echo "$${diff}"; \ exit 1; \ fi @@ -906,11 +961,11 @@ update-translations: rmdir ./translations .PHONY: generate-license -generate-license: ## update license files +generate-license: $(GO) run build/generate-licenses.go .PHONY: generate-gitignore -generate-gitignore: ## update gitignore files +generate-gitignore: $(GO) run build/generate-gitignores.go .PHONY: generate-images @@ -919,7 +974,7 @@ generate-images: | node_modules node tools/generate-images.js $(TAGS) .PHONY: generate-manpage -generate-manpage: ## generate manpage +generate-manpage: @[ -f gitea ] || make backend @mkdir -p man/man1/ man/man5 @./gitea docs --man > man/man1/gitea.1 diff --git a/README.md b/README.md index 5ae65cd2ac..c280c832ac 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea") [![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT") [![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea) -[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin") +[![](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea "Crowdin") [View this document in Chinese](./README_ZH.md) @@ -31,14 +31,6 @@ For accessing free Gitea service (with a limited number of repositories), you ca To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com). -## Documentation - -You can find comprehensive documentation on our official [documentation website](https://docs.gitea.com/). - -It includes installation, administration, usage, development, contributing guides, and more to help you get started and explore all features effectively. - -If you have any suggestions or would like to contribute to it, you can visit the [documentation repository](https://gitea.com/gitea/docs) - ## Building From the root of the source tree, run: @@ -60,8 +52,6 @@ More info: https://docs.gitea.com/installation/install-from-source ## Using -After building, a binary file named `gitea` will be generated in the root of the source tree by default. To run it, use: - ./gitea web > [!NOTE] @@ -78,25 +68,22 @@ Expected workflow is: Fork -> Patch -> Push -> Pull Request ## Translating -[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com) - -Translations are done through [Crowdin](https://translate.gitea.com). If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there. +Translations are done through Crowdin. If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there. You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up. -Get more information from [documentation](https://docs.gitea.com/contributing/localization). +https://docs.gitea.com/contributing/localization -## Official and Third-Party Projects +[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) -We provide an official [go-sdk](https://gitea.com/gitea/go-sdk), a CLI tool called [tea](https://gitea.com/gitea/tea) and an [action runner](https://gitea.com/gitea/act_runner) for Gitea Action. +## Further information -We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea), where you can discover more third-party projects, including SDKs, plugins, themes, and more. +For more information and instructions about how to install Gitea, please look at our [documentation](https://docs.gitea.com/). +If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/). -## Communication +We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea). -[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea") - -If you have questions that are not covered by the [documentation](https://docs.gitea.com/), you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/). +The official Gitea CLI is developed at [gitea/tea](https://gitea.com/gitea/tea). ## Authors @@ -135,79 +122,18 @@ Gitea is pronounced [/ɡɪ’ti:/](https://youtu.be/EM71-2uDAoY) as in "gi-tea" We're [working on it](https://github.com/go-gitea/gitea/issues/1029). -**Where can I find the security patches?** - -In the [release log](https://github.com/go-gitea/gitea/releases) or the [change log](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md), search for the keyword `SECURITY` to find the security patches. - ## License This project is licensed under the MIT License. See the [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) file for the full license text. -## Further information +## Screenshots -
-Looking for an overview of the interface? Check it out! +Looking for an overview of the interface? Check it out! -### Login/Register Page - -![Login](https://dl.gitea.com/screenshots/login.png) -![Register](https://dl.gitea.com/screenshots/register.png) - -### User Dashboard - -![Home](https://dl.gitea.com/screenshots/home.png) -![Issues](https://dl.gitea.com/screenshots/issues.png) -![Pull Requests](https://dl.gitea.com/screenshots/pull_requests.png) -![Milestones](https://dl.gitea.com/screenshots/milestones.png) - -### User Profile - -![Profile](https://dl.gitea.com/screenshots/user_profile.png) - -### Explore - -![Repos](https://dl.gitea.com/screenshots/explore_repos.png) -![Users](https://dl.gitea.com/screenshots/explore_users.png) -![Orgs](https://dl.gitea.com/screenshots/explore_orgs.png) - -### Repository - -![Home](https://dl.gitea.com/screenshots/repo_home.png) -![Commits](https://dl.gitea.com/screenshots/repo_commits.png) -![Branches](https://dl.gitea.com/screenshots/repo_branches.png) -![Labels](https://dl.gitea.com/screenshots/repo_labels.png) -![Milestones](https://dl.gitea.com/screenshots/repo_milestones.png) -![Releases](https://dl.gitea.com/screenshots/repo_releases.png) -![Tags](https://dl.gitea.com/screenshots/repo_tags.png) - -#### Repository Issue - -![List](https://dl.gitea.com/screenshots/repo_issues.png) -![Issue](https://dl.gitea.com/screenshots/repo_issue.png) - -#### Repository Pull Requests - -![List](https://dl.gitea.com/screenshots/repo_pull_requests.png) -![Pull Request](https://dl.gitea.com/screenshots/repo_pull_request.png) -![File](https://dl.gitea.com/screenshots/repo_pull_request_file.png) -![Commits](https://dl.gitea.com/screenshots/repo_pull_request_commits.png) - -#### Repository Actions - -![List](https://dl.gitea.com/screenshots/repo_actions.png) -![Details](https://dl.gitea.com/screenshots/repo_actions_run.png) - -#### Repository Activity - -![Activity](https://dl.gitea.com/screenshots/repo_activity.png) -![Contributors](https://dl.gitea.com/screenshots/repo_contributors.png) -![Code Frequency](https://dl.gitea.com/screenshots/repo_code_frequency.png) -![Recent Commits](https://dl.gitea.com/screenshots/repo_recent_commits.png) - -### Organization - -![Home](https://dl.gitea.com/screenshots/org_home.png) - -
+|![Dashboard](https://dl.gitea.com/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.com/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.com/screenshots/global_issues.png)| +|:---:|:---:|:---:| +|![Branches](https://dl.gitea.com/screenshots/branches.png)|![Web Editor](https://dl.gitea.com/screenshots/web_editor.png)|![Activity](https://dl.gitea.com/screenshots/activity.png)| +|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)| +|![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)| diff --git a/README_ZH.md b/README_ZH.md index 89c34f6b63..a2e36dc22f 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -9,13 +9,13 @@ [![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea") [![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT") [![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea) -[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin") +[![](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea "Crowdin") [View this document in English](./README.md) ## 目标 -Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux、macOS 和 Windows 以及各种架构,除了 x86 和 amd64,还包括 ARM 和 PowerPC。 +Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86,amd64,还包括 ARM 和 PowerPC。 如果你想试用在线演示和报告问题,请访问 [demo.gitea.com](https://demo.gitea.com/)。 @@ -23,134 +23,39 @@ Gitea 的首要目标是创建一个极易安装,运行非常快速,安装 如果你想在 Gitea Cloud 上快速部署你自己独享的 Gitea 实例,请访问 [cloud.gitea.com](https://cloud.gitea.com) 开始免费试用。 +## 提示 + +1. **开始贡献代码之前请确保你已经看过了 [贡献者向导(英文)](CONTRIBUTING.md)**. +2. 所有的安全问题,请私下发送邮件给 **security@gitea.io**。谢谢! +3. 如果你要使用API,请参见 [API 文档](https://godoc.org/code.gitea.io/sdk/gitea). + ## 文档 关于如何安装请访问我们的 [文档站](https://docs.gitea.com/zh-cn/category/installation),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。 -## 编译 +## 贡献流程 -在源代码的根目录下执行: - - TAGS="bindata" make build - -或者如果需要SQLite支持: - - TAGS="bindata sqlite sqlite_unlock_notify" make build - -编译过程会分成2个子任务: - -- `make backend`,需要 [Go Stable](https://go.dev/dl/),最低版本需求可查看 [go.mod](/go.mod)。 -- `make frontend`,需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。 - -你需要连接网络来下载 go 和 npm modules。当从 tar 格式的源文件编译时,其中包含了预编译的前端文件,因此 `make frontend` 将不会被执行。这允许编译时不需要 Node.js。 - -更多信息: https://docs.gitea.com/installation/install-from-source - -## 使用 - -编译之后,默认会在根目录下生成一个名为 `gitea` 的文件。你可以这样执行它: - - ./gitea web - -> [!注意] -> 如果你要使用API,请参见 [API 文档](https://godoc.org/code.gitea.io/sdk/gitea)。 - -## 贡献 - -贡献流程:Fork -> Patch -> Push -> Pull Request - -> [!注意] -> -> 1. **开始贡献代码之前请确保你已经看过了 [贡献者向导(英文)](CONTRIBUTING.md)**。 -> 2. 所有的安全问题,请私下发送邮件给 **security@gitea.io**。 谢谢! +Fork -> Patch -> Push -> Pull Request ## 翻译 -[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com) - -多语言翻译是基于Crowdin进行的。 - -从 [文档](https://docs.gitea.com/contributing/localization) 中获取更多信息。 - -## 官方和第三方项目 - -Gitea 提供官方的 [go-sdk](https://gitea.com/gitea/go-sdk),以及名为 [tea](https://gitea.com/gitea/tea) 的 CLI 工具 和 用于 Gitea Action 的 [action runner](https://gitea.com/gitea/act_runner)。 - -[gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea) 是一个 Gitea 相关项目的列表,你可以在这里找到更多的第三方项目,包括 SDK、插件、主题等等。 +多语言翻译是基于Crowdin进行的. +[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) ## 作者 -- [Maintainers](https://github.com/orgs/go-gitea/people) -- [Contributors](https://github.com/go-gitea/gitea/graphs/contributors) -- [Translators](options/locale/TRANSLATORS) +* [Maintainers](https://github.com/orgs/go-gitea/people) +* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors) +* [Translators](options/locale/TRANSLATORS) ## 授权许可 本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) 文件中。 -## 更多信息 +## 截图 -
-截图 - -### 登录界面 - -![登录](https://dl.gitea.com/screenshots/login.png) -![注册](https://dl.gitea.com/screenshots/register.png) - -### 用户首页 - -![首页](https://dl.gitea.com/screenshots/home.png) -![工单列表](https://dl.gitea.com/screenshots/issues.png) -![合并请求列表](https://dl.gitea.com/screenshots/pull_requests.png) -![里程碑列表](https://dl.gitea.com/screenshots/milestones.png) - -### 用户资料 - -![用户资料](https://dl.gitea.com/screenshots/user_profile.png) - -### 探索 - -![仓库列表](https://dl.gitea.com/screenshots/explore_repos.png) -![用户列表](https://dl.gitea.com/screenshots/explore_users.png) -![组织列表](https://dl.gitea.com/screenshots/explore_orgs.png) - -### 仓库 - -![首页](https://dl.gitea.com/screenshots/repo_home.png) -![提交列表](https://dl.gitea.com/screenshots/repo_commits.png) -![分支列表](https://dl.gitea.com/screenshots/repo_branches.png) -![标签列表](https://dl.gitea.com/screenshots/repo_labels.png) -![里程碑列表](https://dl.gitea.com/screenshots/repo_milestones.png) -![版本发布](https://dl.gitea.com/screenshots/repo_releases.png) -![标签列表](https://dl.gitea.com/screenshots/repo_tags.png) - -#### 仓库工单 - -![列表](https://dl.gitea.com/screenshots/repo_issues.png) -![工单](https://dl.gitea.com/screenshots/repo_issue.png) - -#### 仓库合并请求 - -![列表](https://dl.gitea.com/screenshots/repo_pull_requests.png) -![合并请求](https://dl.gitea.com/screenshots/repo_pull_request.png) -![文件](https://dl.gitea.com/screenshots/repo_pull_request_file.png) -![提交列表](https://dl.gitea.com/screenshots/repo_pull_request_commits.png) - -#### 仓库 Actions - -![列表](https://dl.gitea.com/screenshots/repo_actions.png) -![Run](https://dl.gitea.com/screenshots/repo_actions_run.png) - -#### 仓库动态 - -![动态](https://dl.gitea.com/screenshots/repo_activity.png) -![贡献者](https://dl.gitea.com/screenshots/repo_contributors.png) -![代码频率](https://dl.gitea.com/screenshots/repo_code_frequency.png) -![最近的提交](https://dl.gitea.com/screenshots/repo_recent_commits.png) - -### 组织 - -![首页](https://dl.gitea.com/screenshots/org_home.png) - -
+|![Dashboard](https://dl.gitea.com/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.com/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.com/screenshots/global_issues.png)| +|:---:|:---:|:---:| +|![Branches](https://dl.gitea.com/screenshots/branches.png)|![Web Editor](https://dl.gitea.com/screenshots/web_editor.png)|![Activity](https://dl.gitea.com/screenshots/activity.png)| +|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)| +|![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)| diff --git a/assets/favicon.svg b/assets/favicon.svg new file mode 100644 index 0000000000..9df6b83b56 --- /dev/null +++ b/assets/favicon.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/assets/go-licenses.json b/assets/go-licenses.json index b98b5d6471..6d1b2e1689 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -289,11 +289,6 @@ "path": "github.com/blevesearch/zapx/v16/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/bmatcuk/doublestar/v4", - "path": "github.com/bmatcuk/doublestar/v4/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014 Bob Matcuk\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/boombuler/barcode", "path": "github.com/boombuler/barcode/LICENSE", @@ -532,7 +527,7 @@ { "name": "github.com/go-ldap/ldap/v3", "path": "github.com/go-ldap/ldap/v3/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)\nPortions copyright (c) 2015-2024 go-ldap Authors\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": "The MIT License (MIT)\n\nCopyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)\nPortions copyright (c) 2015-2016 go-ldap Authors\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-redsync/redsync/v4", @@ -824,19 +819,14 @@ "path": "github.com/mattn/go-runewidth/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Yasuhiro Matsumoto\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/mattn/go-shellwords", - "path": "github.com/mattn/go-shellwords/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 Yasuhiro Matsumoto\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/meilisearch/meilisearch-go", "path": "github.com/meilisearch/meilisearch-go/LICENSE", "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" }, { @@ -864,11 +854,6 @@ "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", @@ -884,6 +869,11 @@ "path": "github.com/mitchellh/mapstructure/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2013 Mitchell Hashimoto\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/mmcloughlin/avo", + "path": "github.com/mmcloughlin/avo/LICENSE", + "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2018, Michael McLoughlin\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": "github.com/modern-go/concurrent", "path": "github.com/modern-go/concurrent/LICENSE", @@ -1087,7 +1077,7 @@ { "name": "github.com/wneessen/go-mail", "path": "github.com/wneessen/go-mail/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2022-2025 The go-mail Authors\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) 2022-2023 The go-mail Authors\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/wneessen/go-mail/smtp", @@ -1099,6 +1089,11 @@ "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", @@ -1134,11 +1129,6 @@ "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", @@ -1159,11 +1149,6 @@ "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", @@ -1209,6 +1194,11 @@ "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" }, + { + "name": "golang.org/x/tools", + "path": "golang.org/x/tools/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" + }, { "name": "google.golang.org/genproto/googleapis/rpc/status", "path": "google.golang.org/genproto/googleapis/rpc/status/LICENSE", diff --git a/assets/logo.svg b/assets/logo.svg index bcb2678a30..9df6b83b56 100644 --- a/assets/logo.svg +++ b/assets/logo.svg @@ -1,19 +1,31 @@ - - Created by potrace 1.10, written by Peter Selinger 2001-2011 - - - Layer 1 - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index 5e03d6ca3f..bf8cbc7c4c 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -31,11 +31,6 @@ var microcmdUserCreate = &cli.Command{ Name: "username", Usage: "Username", }, - &cli.StringFlag{ - Name: "user-type", - Usage: "Set user's type: individual or bot", - Value: "individual", - }, &cli.StringFlag{ Name: "password", Usage: "User password", @@ -82,22 +77,6 @@ func runCreateUser(c *cli.Context) error { return err } - userTypes := map[string]user_model.UserType{ - "individual": user_model.UserTypeIndividual, - "bot": user_model.UserTypeBot, - } - userType, ok := userTypes[c.String("user-type")] - if !ok { - return fmt.Errorf("invalid user type: %s", c.String("user-type")) - } - if userType != user_model.UserTypeIndividual { - // Some other commands like "change-password" also only support individual users. - // It needs to clarify the "password" behavior for bot users in the future. - // At the moment, we do not allow setting password for bot users. - if c.IsSet("password") || c.IsSet("random-password") { - return errors.New("password can only be set for individual users") - } - } if c.IsSet("name") && c.IsSet("username") { return errors.New("cannot set both --name and --username flags") } @@ -139,19 +118,16 @@ func runCreateUser(c *cli.Context) error { return err } fmt.Printf("generated random password is '%s'\n", password) - } else if userType == user_model.UserTypeIndividual { + } else { return errors.New("must set either password or random-password flag") } isAdmin := c.Bool("admin") mustChangePassword := true // always default to true if c.IsSet("must-change-password") { - if userType != user_model.UserTypeIndividual { - return errors.New("must-change-password flag can only be set for individual users") - } // if the flag is set, use the value provided by the user mustChangePassword = c.Bool("must-change-password") - } else if userType == user_model.UserTypeIndividual { + } else { // check whether there are users in the database hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{}) if err != nil { @@ -175,9 +151,8 @@ func runCreateUser(c *cli.Context) error { u := &user_model.User{ Name: username, Email: c.String("email"), - IsAdmin: isAdmin, - Type: userType, Passwd: password, + IsAdmin: isAdmin, MustChangePassword: mustChangePassword, Visibility: visibility, } diff --git a/cmd/admin_user_create_test.go b/cmd/admin_user_create_test.go index d8044e8de7..83754e97b1 100644 --- a/cmd/admin_user_create_test.go +++ b/cmd/admin_user_create_test.go @@ -13,54 +13,32 @@ import ( user_model "code.gitea.io/gitea/models/user" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestAdminUserCreate(t *testing.T) { app := NewMainApp(AppVersion{}) reset := func() { - require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{})) - require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{})) + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{})) + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{})) } - t.Run("MustChangePassword", func(t *testing.T) { - type check struct { - IsAdmin bool - MustChangePassword bool - } - createCheck := func(name, args string) check { - require.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args)))) - u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name}) - return check{IsAdmin: u.IsAdmin, MustChangePassword: u.MustChangePassword} - } - reset() - assert.Equal(t, check{IsAdmin: false, MustChangePassword: false}, createCheck("u", ""), "first non-admin user doesn't need to change password") + type createCheck struct{ IsAdmin, MustChangePassword bool } + createUser := func(name, args string) createCheck { + assert.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args)))) + u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name}) + return createCheck{u.IsAdmin, u.MustChangePassword} + } + reset() + assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u", ""), "first non-admin user doesn't need to change password") - reset() - assert.Equal(t, check{IsAdmin: true, MustChangePassword: false}, createCheck("u", "--admin"), "first admin user doesn't need to change password") + reset() + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u", "--admin"), "first admin user doesn't need to change password") - reset() - assert.Equal(t, check{IsAdmin: true, MustChangePassword: true}, createCheck("u", "--admin --must-change-password")) - assert.Equal(t, check{IsAdmin: true, MustChangePassword: true}, createCheck("u2", "--admin")) - assert.Equal(t, check{IsAdmin: true, MustChangePassword: false}, createCheck("u3", "--admin --must-change-password=false")) - assert.Equal(t, check{IsAdmin: false, MustChangePassword: true}, createCheck("u4", "")) - assert.Equal(t, check{IsAdmin: false, MustChangePassword: false}, createCheck("u5", "--must-change-password=false")) - }) - - t.Run("UserType", func(t *testing.T) { - createUser := func(name, args string) error { - return app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s", name, name, args))) - } - - reset() - assert.ErrorContains(t, createUser("u", "--user-type invalid"), "invalid user type") - assert.ErrorContains(t, createUser("u", "--user-type bot --password 123"), "can only be set for individual users") - assert.ErrorContains(t, createUser("u", "--user-type bot --must-change-password"), "can only be set for individual users") - - assert.NoError(t, createUser("u", "--user-type bot")) - u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "u"}) - assert.Equal(t, user_model.UserTypeBot, u.Type) - assert.Equal(t, "", u.Passwd) - }) + reset() + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u", "--admin --must-change-password")) + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u2", "--admin")) + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u3", "--admin --must-change-password=false")) + assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: true}, createUser("u4", "")) + assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u5", "--must-change-password=false")) } diff --git a/cmd/hook_test.go b/cmd/hook_test.go index 86cd4834f2..91f24ff2b4 100644 --- a/cmd/hook_test.go +++ b/cmd/hook_test.go @@ -6,6 +6,7 @@ package cmd import ( "bufio" "bytes" + "context" "strings" "testing" @@ -14,7 +15,7 @@ import ( func TestPktLine(t *testing.T) { // test read - ctx := t.Context() + ctx := context.Background() s := strings.NewReader("0000") r := bufio.NewReader(s) result, err := readPktLine(ctx, r, pktLineTypeFlush) diff --git a/cmd/main.go b/cmd/main.go index 7251bd09a3..fd648946ef 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -165,7 +165,6 @@ func NewMainApp(appVer AppVersion) *cli.App { app.Commands = append(app.Commands, subCmdWithConfig...) app.Commands = append(app.Commands, subCmdStandalone...) - setting.InitGiteaEnvVars() return app } diff --git a/cmd/main_test.go b/cmd/main_test.go index 3ec584d323..c182b44019 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -6,6 +6,7 @@ package cmd import ( "fmt" "io" + "os" "path/filepath" "strings" "testing" @@ -112,17 +113,37 @@ func TestCliCmd(t *testing.T) { _, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) return nil }) - for _, c := range cases { - t.Run(c.cmd, func(t *testing.T) { - for k, v := range c.env { - t.Setenv(k, v) + 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...) - assert.NoError(t, err, c.cmd) - assert.NotEmpty(t, c.exp, c.cmd) - assert.Contains(t, r.Stdout, c.exp, c.cmd) - }) + } + } + 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) } } diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 2e3aba021d..6ece4bf661 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -196,7 +196,7 @@ func migrateActionsLog(ctx context.Context, dstStorage storage.ObjectStorage) er func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStorage) error { return db.Iterate(ctx, nil, func(ctx context.Context, artifact *actions_model.ActionArtifact) error { - if artifact.Status == actions_model.ArtifactStatusExpired { + if artifact.Status == int64(actions_model.ArtifactStatusExpired) { return nil } diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go index f8fa95a927..5d8c867993 100644 --- a/cmd/migrate_storage_test.go +++ b/cmd/migrate_storage_test.go @@ -4,6 +4,7 @@ package cmd import ( + "context" "os" "strings" "testing" @@ -52,7 +53,7 @@ func TestMigratePackages(t *testing.T) { assert.NotNil(t, v) assert.NotNil(t, f) - ctx := t.Context() + ctx := context.Background() p := t.TempDir() diff --git a/cmd/serv.go b/cmd/serv.go index 476fd9a2ea..d2271b68d2 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -104,10 +104,7 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error // There appears to be a chance to cause a zombie process and failure to read the Exit status // if nothing is outputted on stdout. _, _ = fmt.Fprintln(os.Stdout, "") - // add extra empty lines to separate our message from other git errors to get more attention - _, _ = fmt.Fprintln(os.Stderr, "error:") - _, _ = fmt.Fprintln(os.Stderr, "error:", userMessage) - _, _ = fmt.Fprintln(os.Stderr, "error:") + _, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage) if logMsgFmt != "" { logMsg := fmt.Sprintf(logMsgFmt, args...) diff --git a/cmd/web.go b/cmd/web.go index dc5c6de48a..f8217758e5 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -18,12 +18,10 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/gtprof" "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/modules/util" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/install" @@ -220,8 +218,6 @@ func serveInstalled(ctx *cli.Context) error { } } - gtprof.EnableBuiltinTracer(util.Iif(setting.IsProd, 2000*time.Millisecond, 100*time.Millisecond)) - // Set up Chi routes webRoutes := routers.NormalRoutes() err := listen(webRoutes, true) diff --git a/compose.yml b/compose.yml deleted file mode 100644 index f81e64e637..0000000000 --- a/compose.yml +++ /dev/null @@ -1,37 +0,0 @@ -services: - server: - build: . - environment: - - USER_UID=1000 - - USER_GID=1000 - - GITEA__database__DB_TYPE=mysql - - GITEA__database__HOST=db:3306 - - GITEA__database__NAME=gitea - - GITEA__database__USER=gitea - - GITEA__database__PASSWD=gitea - - DISABLE_REGISTRATION=true - - CRON_ENABLED=true - - CRON_SCHEDULE=@every 1h - - REQUIRE_SIGNIN_VIEW=true - restart: always - volumes: - - ./data:/var/lib/gitea - - ./config:/etc/gitea - - ./assets:/var/lib/gitea/assets - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - ports: - - "5989:3000" - - "5990:2222" - depends_on: - - db - db: - image: mysql:8 - restart: always - environment: - - MYSQL_ROOT_PASSWORD=gitea - - MYSQL_USER=gitea - - MYSQL_PASSWORD=gitea - - MYSQL_DATABASE=gitea - volumes: - - ./mysql:/var/lib/mysql diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 899209874f..6896b073e1 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -78,9 +78,8 @@ RUN_USER = ; git ;; Set the domain for the server ;DOMAIN = localhost ;; -;; The AppURL used by Gitea to generate absolute links, defaults to "{PROTOCOL}://{DOMAIN}:{HTTP_PORT}/". -;; Most users should set it to the real website URL of their Gitea instance. -;ROOT_URL = +;; Overwrite the automatically generated public URL. Necessary for proxies and docker. +;ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ ;; ;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy. ;; DO NOT USE IT IN PRODUCTION!!! @@ -104,8 +103,8 @@ RUN_USER = ; git ;REDIRECT_OTHER_PORT = false ;PORT_TO_REDIRECT = 80 ;; -;; expect PROXY protocol header on connections to https redirector, defaults to USE_PROXY_PROTOCOL -;REDIRECTOR_USE_PROXY_PROTOCOL = +;; expect PROXY protocol header on connections to https redirector. +;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;; Minimum and maximum supported TLS versions ;SSL_MIN_VERSION=TLSv1.2 ;SSL_MAX_VERSION= @@ -129,14 +128,13 @@ RUN_USER = ; git ;; most cases you do not need to change the default value. Alter it only if ;; your SSH server node is not the same as HTTP node. For different protocol, the default ;; values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`. -;; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`. -;; If listen on `0.0.0.0`, the default value is `{PROTOCOL}://localhost:{HTTP_PORT}/`. -;; Otherwise the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`. -;; Most users don't need (and shouldn't) set this value. -;LOCAL_ROOT_URL = +;; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`. +;; If listen on `0.0.0.0`, the default value is `%(PROTOCOL)s://localhost:%(HTTP_PORT)s/`, Otherwise the default +;; value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`. +;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ ;; -;; When making local connections pass the PROXY protocol header, defaults to USE_PROXY_PROTOCOL -;LOCAL_USE_PROXY_PROTOCOL = +;; When making local connections pass the PROXY protocol header. +;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;; ;; Disable SSH feature when not available ;DISABLE_SSH = false @@ -148,17 +146,13 @@ RUN_USER = ; git ;SSH_SERVER_USE_PROXY_PROTOCOL = false ;; ;; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER. -;BUILTIN_SSH_SERVER_USER = +;BUILTIN_SSH_SERVER_USER = %(RUN_USER)s ;; -;; Domain name to be exposed in clone URL, defaults to DOMAIN or the domain part of ROOT_URL -;SSH_DOMAIN = +;; Domain name to be exposed in clone URL +;SSH_DOMAIN = %(DOMAIN)s ;; -;; SSH username displayed in clone URLs. It defaults to BUILTIN_SSH_SERVER_USER or RUN_USER. -;; If it is set to "(DOER_USERNAME)", it will use current signed-in user's username. -;; This option is only for some advanced users who have configured their SSH reverse-proxy -;; and need to use different usernames for git SSH clone. -;; Most users should just leave it blank. -;SSH_USER = +;; SSH username displayed in clone URLs. +;SSH_USER = %(BUILTIN_SSH_SERVER_USER)s ;; ;; The network interface the builtin SSH server should listen on ;SSH_LISTEN_HOST = @@ -166,8 +160,8 @@ RUN_USER = ; git ;; Port number to be exposed in clone URL ;SSH_PORT = 22 ;; -;; The port number the builtin SSH server should listen on, defaults to SSH_PORT -;SSH_LISTEN_PORT = +;; The port number the builtin SSH server should listen on +;SSH_LISTEN_PORT = %(SSH_PORT)s ;; ;; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. ;SSH_ROOT_PATH = @@ -194,7 +188,7 @@ RUN_USER = ; git ;; ;; For the built-in SSH server, choose the keypair to offer as the host key ;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub -;; relative paths are made absolute relative to the APP_DATA_PATH +;; relative paths are made absolute relative to the %(APP_DATA_PATH)s ;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa ;; ;; Directory to create temporary files in when testing public keys using ssh-keygen, @@ -588,7 +582,7 @@ ENABLED = true [log] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Root path for the log files - defaults to "{AppWorkPath}/log" +;; Root path for the log files - defaults to %(GITEA_WORK_DIR)/log ;ROOT_PATH = ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -688,8 +682,8 @@ LEVEL = Info ;; The path of git executable. If empty, Gitea searches through the PATH environment. ;PATH = ;; -;; The HOME directory for Git, defaults to "{APP_DATA_PATH}/home" -;HOME_PATH = +;; The HOME directory for Git +;HOME_PATH = %(APP_DATA_PATH)s/home ;; ;; Disables highlight of added and removed changes ;DISABLE_DIFF_HIGHLIGHT = false @@ -790,13 +784,10 @@ LEVEL = Info ;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token ;ENABLE_BASIC_AUTHENTICATION = true ;; -;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 or passkey login methods if they are enabled. +;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 login methods. ;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION to false to completely disable password-based authentication. ;ENABLE_PASSWORD_SIGNIN_FORM = true ;; -;; Allow users to sign-in with a passkey -;ENABLE_PASSKEY_AUTHENTICATION = true -;; ;; More detail: https://github.com/gogits/gogs/issues/165 ;ENABLE_REVERSE_PROXY_AUTHENTICATION = false ; Enable this to allow reverse proxy authentication for API requests, the reverse proxy is responsible for ensuring that no CSRF is possible. @@ -955,8 +946,8 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[repository] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Root path for storing all repository data. By default, it is set to "{APP_DATA_PATH}/gitea-repositories". -;; A relative path is interpreted as "{AppWorkPath}/{ROOT}" (use AppWorkPath as base path). +;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)s/gitea-repositories. +;; A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s ;ROOT = ;; ;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. @@ -1129,9 +1120,6 @@ LEVEL = Info ;; In default merge messages only include approvers who are official ;DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY = true ;; -;; In default squash-merge messages include the commit message of all commits comprising the pull request. -;POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES = false -;; ;; Add co-authored-by and co-committed-by trailers if committer does not match author ;ADD_CO_COMMITTER_TRAILERS = true ;; @@ -1351,9 +1339,6 @@ LEVEL = Info ;; Number of repos that are displayed on one page ;REPO_PAGING_NUM = 15 -;; Number of orgs that are displayed on profile page -;ORG_PAGING_NUM = 15 - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[ui.meta] @@ -1518,8 +1503,7 @@ LEVEL = Info ;TYPE = persistable-channel ;; ;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared. -;; Relative paths will be made absolute against "APP_DATA_PATH" -;DATADIR = queues/ +;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`. ;; ;; Default queue length before a channel queue will block ;LENGTH = 100000 diff --git a/flake.lock b/flake.lock index 2f7b86359b..1890b82dcf 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1739214665, - "narHash": "sha256-26L8VAu3/1YRxS8MHgBOyOM8xALdo6N0I04PgorE7UM=", + "lastModified": 1731139594, + "narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "64e75cd44acf21c7933d61d7721e812eac1b5a0a", + "rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 1b930649d0..e3655b627e 100644 --- a/flake.nix +++ b/flake.nix @@ -29,14 +29,9 @@ poetry # backend - go_1_24 gofumpt sqlite ]; - shellHook = '' - export GO="${pkgs.go_1_24}/bin/go" - export GOROOT="${pkgs.go_1_24}/share/go" - ''; }; } ); diff --git a/go.mod b/go.mod index 827979307e..f7b16ce9ae 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module code.gitea.io/gitea -go 1.24 +go 1.23.0 + +toolchain go1.23.6 // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // But some CAs use negative serial number, just relax the check. related: @@ -10,9 +12,9 @@ godebug x509negativeserial=1 require ( code.gitea.io/actions-proto-go v0.4.0 code.gitea.io/gitea-vet v0.2.3 - code.gitea.io/sdk/gitea v0.20.0 + code.gitea.io/sdk/gitea v0.19.0 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 - connectrpc.com/connect v1.18.1 + connectrpc.com/connect v1.17.0 gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed gitea.com/go-chi/cache v0.2.1 gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 @@ -21,19 +23,19 @@ require ( gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 github.com/42wim/httpsig v1.2.2 github.com/42wim/sshsig v0.0.0-20240818000253-e3a6333df815 - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 - github.com/ProtonMail/go-crypto v1.1.6 - github.com/PuerkitoBio/goquery v1.10.2 + github.com/ProtonMail/go-crypto v1.1.4 + github.com/PuerkitoBio/goquery v1.10.0 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3 github.com/alecthomas/chroma/v2 v2.15.0 - github.com/aws/aws-sdk-go-v2/credentials v1.17.60 - github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.16 + github.com/aws/aws-sdk-go-v2/credentials v1.17.42 + github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.3 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.4.2 - github.com/buildkite/terminal-to-html/v3 v3.16.6 - github.com/caddyserver/certmagic v0.21.7 + github.com/buildkite/terminal-to-html/v3 v3.16.3 + github.com/caddyserver/certmagic v0.21.4 github.com/charmbracelet/git-lfs-transfer v0.2.0 github.com/chi-middleware/proxy v1.1.1 github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 @@ -46,19 +48,19 @@ require ( github.com/emirpasic/gods v1.18.1 github.com/ethantkoenig/rupture v1.0.1 github.com/felixge/fgprof v0.9.5 - github.com/fsnotify/fsnotify v1.8.0 + github.com/fsnotify/fsnotify v1.7.0 github.com/gliderlabs/ssh v0.3.8 - github.com/go-ap/activitypub v0.0.0-20250212090640-aeb6499ba581 + github.com/go-ap/activitypub v0.0.0-20240910141749-b4b8c8aa484c github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 - github.com/go-chi/chi/v5 v5.2.1 + github.com/go-chi/chi/v5 v5.1.0 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-billy/v5 v5.6.2 - github.com/go-git/go-git/v5 v5.13.2 - github.com/go-ldap/ldap/v3 v3.4.10 + github.com/go-enry/go-enry/v2 v2.9.1 + github.com/go-git/go-billy/v5 v5.6.1 + github.com/go-git/go-git/v5 v5.13.1 + github.com/go-ldap/ldap/v3 v3.4.8 github.com/go-redsync/redsync/v4 v4.13.0 - github.com/go-sql-driver/mysql v1.9.0 + github.com/go-sql-driver/mysql v1.8.1 github.com/go-swagger/go-swagger v0.31.0 github.com/go-webauthn/webauthn v0.11.2 github.com/gobwas/glob v0.2.3 @@ -67,10 +69,11 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/go-github/v61 v61.0.0 github.com/google/licenseclassifier/v2 v2.0.0 - github.com/google/pprof v0.0.0-20250208200701-d0013a598941 + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.2.0 github.com/gorilla/sessions v1.4.0 + github.com/h2non/gock v1.2.0 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/huandu/xstrings v1.5.0 @@ -78,8 +81,8 @@ require ( github.com/jhillyerd/enmime v1.3.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.9 + github.com/klauspost/compress v1.17.11 + github.com/klauspost/cpuid/v2 v2.2.8 github.com/lib/pq v1.10.9 github.com/markbates/goth v1.80.0 github.com/mattn/go-isatty v0.0.20 @@ -87,8 +90,8 @@ require ( github.com/meilisearch/meilisearch-go v0.29.1-0.20241106140435-0bf60fad690a github.com/mholt/archiver/v3 v3.5.1 github.com/microcosm-cc/bluemonday v1.0.27 - github.com/microsoft/go-mssqldb v1.8.0 - github.com/minio/minio-go/v7 v7.0.87 + github.com/microsoft/go-mssqldb v1.7.2 + github.com/minio/minio-go/v7 v7.0.80 github.com/msteinert/pam v1.2.0 github.com/nektos/act v0.2.63 github.com/niklasfasching/go-org v1.7.0 @@ -97,7 +100,7 @@ require ( github.com/opencontainers/image-spec v1.1.0 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 - github.com/prometheus/client_golang v1.21.0 + github.com/prometheus/client_golang v1.20.5 github.com/quasoft/websspi v1.1.2 github.com/redis/go-redis/v9 v9.7.0 github.com/robfig/cron/v3 v3.0.1 @@ -110,61 +113,61 @@ require ( github.com/tstranex/u2f v1.0.0 github.com/ulikunitz/xz v0.5.12 github.com/urfave/cli/v2 v2.27.5 - github.com/wneessen/go-mail v0.6.2 + github.com/wneessen/go-mail v0.5.2 + github.com/xanzy/go-gitlab v0.112.0 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yohcop/openid-go v1.0.1 github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-meta v1.1.0 - gitlab.com/gitlab-org/api/client-go v0.123.0 golang.org/x/crypto v0.35.0 - golang.org/x/image v0.24.0 - golang.org/x/net v0.35.0 + golang.org/x/image v0.21.0 + golang.org/x/net v0.34.0 golang.org/x/oauth2 v0.27.0 golang.org/x/sync v0.11.0 golang.org/x/sys v0.30.0 golang.org/x/text v0.22.0 - golang.org/x/tools v0.30.0 - google.golang.org/grpc v1.70.0 - google.golang.org/protobuf v1.36.5 + golang.org/x/tools v0.29.0 + google.golang.org/grpc v1.67.1 + google.golang.org/protobuf v1.35.1 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 - mvdan.cc/xurls/v2 v2.6.0 + 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 ) require ( - cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/compute/metadata v0.5.2 // indirect dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/DataDog/zstd v1.5.6 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.3.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/RoaringBitmap/roaring v1.9.4 // indirect github.com/andybalholm/brotli v1.1.1 // indirect - github.com/andybalholm/cascadia v1.3.3 // 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/aws/aws-sdk-go-v2 v1.36.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 // indirect - github.com/aws/smithy-go v1.22.3 // indirect + github.com/aws/aws-sdk-go-v2 v1.32.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect + github.com/aws/smithy-go v1.22.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/bits-and-blooms/bitset v1.14.3 // indirect github.com/blevesearch/bleve_index_api v1.1.12 // indirect github.com/blevesearch/geo v0.1.20 // indirect - github.com/blevesearch/go-faiss v1.0.20 // indirect + github.com/blevesearch/go-faiss v1.0.23 // 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.2.15 // indirect + github.com/blevesearch/scorch_segment_api/v2 v2.2.16 // 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 @@ -173,30 +176,29 @@ require ( 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.1.5 // indirect - github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect + github.com/blevesearch/zapx/v15 v15.3.16 // indirect + github.com/blevesearch/zapx/v16 v16.1.7 // indirect github.com/boombuler/barcode v1.0.2 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/caddyserver/zerossl v0.1.3 // 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.0 // indirect + github.com/cloudflare/circl v1.5.0 // indirect github.com/couchbase/go-couchbase v0.1.1 // indirect github.com/couchbase/gomemcached v0.3.2 // indirect github.com/couchbase/goutils v0.1.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect - github.com/cyphar/filepath-securejoin v0.4.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect + github.com/cyphar/filepath-securejoin v0.3.6 // 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.4 // indirect github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect - github.com/go-ap/errors v0.0.0-20250124135319-3da8adefd4a9 // indirect + github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568 // indirect github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect @@ -213,8 +215,8 @@ require ( github.com/go-openapi/strfmt v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect - github.com/go-webauthn/x v0.1.16 // indirect - github.com/goccy/go-json v0.10.5 // indirect + github.com/go-webauthn/x v0.1.15 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect @@ -224,11 +226,12 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/go-tpm v0.9.3 // indirect + github.com/google/go-tpm v0.9.1 // 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/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -241,20 +244,19 @@ require ( github.com/klauspost/pgzip v1.2.6 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/libdns/libdns v0.2.3 // indirect - github.com/magiconair/properties v1.8.9 // indirect - github.com/mailru/easyjson v0.9.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.14 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mattn/go-shellwords v1.0.12 // indirect - github.com/mholt/acmez/v3 v3.0.1 // indirect - github.com/miekg/dns v1.1.63 // indirect - github.com/minio/crc64nvme v1.0.1 // indirect + github.com/mholt/acmez/v2 v2.0.3 // indirect + github.com/miekg/dns v1.1.62 // 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/mmcloughlin/avo v0.6.0 // 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 @@ -265,27 +267,27 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/pjbgf/sha1cd v0.3.2 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/pjbgf/sha1cd v0.3.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/common v0.60.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rhysd/actionlint v1.7.7 // indirect + github.com/rhysd/actionlint v1.7.3 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rs/xid v1.6.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.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.1 // indirect + github.com/skeema/knownhosts v1.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.12.0 // indirect - github.com/spf13/cast v1.7.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/subosito/gotenv v1.6.0 // indirect @@ -300,16 +302,15 @@ require ( github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // 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 - go.mongodb.org/mongo-driver v1.17.2 // indirect + go.etcd.io/bbolt v1.3.11 // indirect + go.mongodb.org/mongo-driver v1.17.1 // 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/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/time v0.10.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 // indirect + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/time v0.7.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 2b285a3671..7ff8d437db 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,15 @@ -cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= 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/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.20.0 h1:Zm/QDwwZK1awoM4AxdjeAQbxolzx2rIP8dDfmKu+KoU= -code.gitea.io/sdk/gitea v0.20.0/go.mod h1:faouBHC/zyx5wLgjmRKR62ydyvMzwWf3QnU0bH7Cw6U= +code.gitea.io/sdk/gitea v0.19.0 h1:8I6s1s4RHgzxiPHhOQdgim1RWIRcr0LVMbHBjBFXq4Y= +code.gitea.io/sdk/gitea v0.19.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI= 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.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk= +connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -40,10 +40,10 @@ github.com/42wim/sshsig v0.0.0-20240818000253-e3a6333df815 h1:5EoemV++kUK2Sw98yW github.com/42wim/sshsig v0.0.0-20240818000253-e3a6333df815/go.mod h1:zjsWZdDLrcDojDIfpQg7A6J4YZLT0cbwuAD26AppDBo= 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/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c= @@ -52,29 +52,29 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 h1:UXT0o77lXQrikd1kgwIPQOUect7EoR/+sbP4wQKdzxM= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0/go.mod h1:cTvi54pg19DoT07ekoeMgE/taAwNtCShVeZqA+Iv2xI= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 h1:cf+OIKbkmMHBaC3u78AXomweqM0oxQSgBXRZf3WH4yM= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1/go.mod h1:ap1dmS6vQKJxSMNiGJcq4QuUQkOynyD93gLw6MDF7ek= 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/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY= github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= 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.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= -github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= 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.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= -github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8= -github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU= +github.com/ProtonMail/go-crypto v1.1.4 h1:G5U5asvD5N/6/36oIw3k2bOfBn5XVcZrb7PBjzzKKoE= +github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4= +github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4= github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv2QzDdQ= @@ -96,8 +96,8 @@ github.com/anchore/archiver/v3 v3.5.2/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnons 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/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/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -105,18 +105,18 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd 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/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU= -github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.60 h1:1dq+ELaT5ogfmqtV1eocq8SpOK1NRsuUfmhQtD/XAh4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.60/go.mod h1:HDes+fn/xo9VeszXqjBVkxOo/aUy8Mc6QqKvZk32GlE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.16 h1:DodiGgET+sAVT1Wsx9lHDpEPxzoY7Y6wCpYh6LsGTWQ= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.16/go.mod h1:FyuFDtt95CXzQCClFbkb9rqKDX8+IRvSzmjFSkQOX4g= -github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k= -github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk= +github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.3 h1:NbAYtQnTXzv4u5uesdDhXGWDTsEtTyFXlzfXELtI6cc= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.3/go.mod h1:ZhgiuB7I3d3UU6PnCWwb0IYFgGzJz0VT+DK3Xv1xtF8= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= 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= @@ -124,8 +124,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= -github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA= +github.com/bits-and-blooms/bitset v1.14.3/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.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM= @@ -136,8 +136,8 @@ github.com/blevesearch/bleve_index_api v1.1.12 h1:P4bw9/G/5rulOF7SJ9l4FsDoo7UFJ+ github.com/blevesearch/bleve_index_api v1.1.12/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.20 h1:AIkdTQFWuZ5LQmKQSebgMR4RynGNw8ZseJXaan5kvtI= -github.com/blevesearch/go-faiss v1.0.20/go.mod h1:jrxHrbl42X/RnDPI+wBoZU8joxxuRwedrxqswQ3xfU8= +github.com/blevesearch/go-faiss v1.0.23 h1:Wmc5AFwDLKGl2L6mjLX1Da3vCL0EKa2uHHSorcIS1Uc= +github.com/blevesearch/go-faiss v1.0.23/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk= 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= @@ -146,8 +146,8 @@ github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+ 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.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU= -github.com/blevesearch/scorch_segment_api/v2 v2.2.15 h1:prV17iU/o+A8FiZi9MXmqbagd8I0bCqM7OKUYPbnb5Y= -github.com/blevesearch/scorch_segment_api/v2 v2.2.15/go.mod h1:db0cmP03bPNadXrCDuVkKLV6ywFSiRgPFT1YVrestBc= +github.com/blevesearch/scorch_segment_api/v2 v2.2.16 h1:uGvKVvG7zvSxCwcm4/ehBa9cCEuZVE+/zvrSl57QUVY= +github.com/blevesearch/scorch_segment_api/v2 v2.2.16/go.mod h1:VF5oHVbIFTu+znY1v30GjSpT5+9YFs9dV2hjvuh34F0= github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ= 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= @@ -173,12 +173,10 @@ github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCq 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.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A= -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.1.5 h1:b0sMcarqNFxuXvjoXsF8WtwVahnxyhEvBSRJi/AUHjU= -github.com/blevesearch/zapx/v16 v16.1.5/go.mod h1:J4mSF39w1QELc11EWRSBFkPeZuO7r/NPKkHzDCoiaI8= -github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= -github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/blevesearch/zapx/v15 v15.3.16 h1:Ct3rv7FUJPfPk99TI/OofdC+Kpb4IdyfdMH48sb+FmE= +github.com/blevesearch/zapx/v15 v15.3.16/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg= +github.com/blevesearch/zapx/v16 v16.1.7 h1:I07qV6l1rPda19zyof9Q2J9E8cjZ57pQhNY0+ePI5vM= +github.com/blevesearch/zapx/v16 v16.1.7/go.mod h1:JqQlOqlRVaYDkpLIl3JnKql8u4zKTNlVEa3nLsi0Gn8= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4= github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -188,10 +186,10 @@ 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.6 h1:QKHWPjAnKQnV1hVG/Nb2TwYDr4pliSbvCQDENk8EaJo= -github.com/buildkite/terminal-to-html/v3 v3.16.6/go.mod h1:PgzeBymbRFC8I2m46Sci3S18AbwonEgpaz3TGhD7EPs= -github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg= -github.com/caddyserver/certmagic v0.21.7/go.mod h1:LCPG3WLxcnjVKl/xpjzM0gqh0knrKKKiO5WVttX2eEI= +github.com/buildkite/terminal-to-html/v3 v3.16.3 h1:IGuJjboHjuMLWOGsKZKNxbbn41emOLiHzXPmQZk31fk= +github.com/buildkite/terminal-to-html/v3 v3.16.3/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0= +github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0= +github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE= 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/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI= @@ -206,8 +204,8 @@ 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.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= -github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= +github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -220,11 +218,11 @@ github.com/couchbase/goutils v0.1.2 h1:gWr8B6XNWPIhfalHNog3qQKfGiYyh4K4VhO3P2o9B github.com/couchbase/goutils v0.1.2/go.mod h1:h89Ek/tiOxxqjz30nPPlwZdQbdB8BwgnuBxeoUe/ViE= github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= -github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +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/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= @@ -243,8 +241,8 @@ 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.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/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/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= @@ -254,8 +252,8 @@ github.com/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72/go.mod h1:11Gm+ccJ 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/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -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/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= +github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= 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= @@ -279,8 +277,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk 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.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +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.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 h1:mtDjlmloH7ytdblogrMz1/8Hqua1y8B4ID+bh3rvod0= @@ -289,39 +287,40 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-ap/activitypub v0.0.0-20250212090640-aeb6499ba581 h1:73sFEdBsWBTBut0aDMPgt8HRuMO+ML0fd8AA/zjO8BQ= -github.com/go-ap/activitypub v0.0.0-20250212090640-aeb6499ba581/go.mod h1:IO2PtAsxfGXN5IHrPuOslENFbq7MprYLNOyiiOELoRQ= -github.com/go-ap/errors v0.0.0-20250124135319-3da8adefd4a9 h1:AJBGzuJVgfkKF3LoXCNQfH9yWmsVDV/oPDJE/zeXOjE= -github.com/go-ap/errors v0.0.0-20250124135319-3da8adefd4a9/go.mod h1:Vkh+Z3f24K8nMsJKXo1FHn5ebPsXvB/WDH5JRtYqdNo= +github.com/go-ap/activitypub v0.0.0-20240910141749-b4b8c8aa484c h1:82lzmsy5Nr6JA6HcLRVxGfbdSoWfW45C6jnY3zFS7Ks= +github.com/go-ap/activitypub v0.0.0-20240910141749-b4b8c8aa484c/go.mod h1:rpIPGre4qtTgSpVT0zz3hycAMuLtUt7BNngVNpyXhL8= +github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568 h1:eQEXAzWEijFbwtm/Hr2EtFbM0LvATRd1ltpDb+mfjQk= +github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568/go.mod h1:Vkh+Z3f24K8nMsJKXo1FHn5ebPsXvB/WDH5JRtYqdNo= github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw= github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk= github.com/go-asn1-ber/asn1-ber v1.5.7/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.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= -github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/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.9.1 h1:G9iDteJ/Mc0F4Di5NeQknf83R2OkRbwY9cAYmcqVG6U= +github.com/go-enry/go-enry/v2 v2.9.1/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.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.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= +github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= 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-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= +github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= 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-ldap/ldap/v3 v3.4.10 h1:ot/iwPOhfpNVgB1o+AVXljizWZ9JTp7YF5oeyONmcJU= -github.com/go-ldap/ldap/v3 v3.4.10/go.mod h1:JXh4Uxgi40P6E9rdsYqpUtbW46D9UTjJ9QSwGRznplY= +github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ= +github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= @@ -352,8 +351,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkvQ1EkZKA= github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ= -github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= -github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= +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.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc= github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -361,15 +360,15 @@ 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-webauthn/webauthn v0.11.2 h1:Fgx0/wlmkClTKlnOsdOQ+K5HcHDsDcYIvtYmfhEOSUc= github.com/go-webauthn/webauthn v0.11.2/go.mod h1:aOtudaF94pM71g3jRwTYYwQTG1KyTILTcZqN1srkmD0= -github.com/go-webauthn/x v0.1.16 h1:EaVXZntpyHviN9ykjdRBQIw9B0Ed3LO5FW7mDiMQEa8= -github.com/go-webauthn/x v0.1.16/go.mod h1:jhYjfwe/AVYaUs2mUXArj7vvZj+SpooQPyyQGNab+Us= +github.com/go-webauthn/x v0.1.15 h1:eG1OhggBJTkDE8gUeOlGRbRe8E/PSVG26YG4AyFbwkU= +github.com/go-webauthn/x v0.1.15/go.mod h1:pf7VI23raFLHPO9VVIs9/u1etqwAOP0S2KoHGL6WbZ8= 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.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 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= @@ -416,16 +415,16 @@ github.com/google/go-github/v61 v61.0.0 h1:VwQCBwhyE9JclCI+22/7mLB1PuU9eowCXKY5p github.com/google/go-github/v61 v61.0.0/go.mod h1:0WR+KmsWX75G2EbpyGsGmradjo3IiciuI4BmdVCobQY= 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.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc= -github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/go-tpm v0.9.1 h1:0pGc4X//bAlmZzMKf8iz6IsDo1nYTbYJ6FZN/rg4zdM= +github.com/google/go-tpm v0.9.1/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= 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/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA= github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= -github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= 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= @@ -451,6 +450,10 @@ github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 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/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/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -509,12 +512,12 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4 github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= 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.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/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= @@ -533,47 +536,43 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= 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 v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8= -github.com/libdns/libdns v0.2.3/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/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.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +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= github.com/markbates/goth v1.80.0/go.mod h1:4/GYHo+W6NWisrMPZnq0Yr2Q70UntNLn7KXEFhrIdAY= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 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-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= -github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/meilisearch/meilisearch-go v0.29.1-0.20241106140435-0bf60fad690a h1:F0y+3QtCG00mr4KueQWuHv1tlIQeNXhH+XAKYLhb3X4= github.com/meilisearch/meilisearch-go v0.29.1-0.20241106140435-0bf60fad690a/go.mod h1:NYOgjEGt/+oExD+NixreBMqxtIB0kCndXOOgpGhoqEs= -github.com/mholt/acmez/v3 v3.0.1 h1:4PcjKjaySlgXK857aTfDuRbmnM5gb3Ruz3tvoSJAUp8= -github.com/mholt/acmez/v3 v3.0.1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= +github.com/mholt/acmez/v2 v2.0.3 h1:CgDBlEwg3QBp6s45tPQmFIBrkRIkBT4rW4orMM6p4sw= +github.com/mholt/acmez/v2 v2.0.3/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw= 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/microsoft/go-mssqldb v1.8.0 h1:7cyZ/AT7ycDsEoWPIXibd+aVKFtteUNhDGf3aobP+tw= -github.com/microsoft/go-mssqldb v1.8.0/go.mod h1:6znkekS3T2vp0waiMhen4GPU1BiAsrP+iXHcE7a7rFo= -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/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= +github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= 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.87 h1:nkr9x0u53PespfxfUqxP3UYWiE2a41gaofgNnC4Y8WQ= -github.com/minio/minio-go/v7 v7.0.87/go.mod h1:33+O8h0tO7pCeCWwBVa07RhVVfB/3vS4kEX7rwYKmIg= +github.com/minio/minio-go/v7 v7.0.80 h1:2mdUHXEykRdY/BigLt3Iuu1otL0JTogT0Nmltg0wujk= +github.com/minio/minio-go/v7 v7.0.80/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0= 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/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -582,6 +581,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= +github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= 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= @@ -596,6 +597,8 @@ 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/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/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= @@ -630,10 +633,10 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= -github.com/pierrec/lz4/v4 v4.1.22/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/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.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI= +github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -644,12 +647,12 @@ 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.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= -github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= 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/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= 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/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw= @@ -661,8 +664,8 @@ github.com/redis/rueidis v1.0.19 h1:s65oWtotzlIFN8eMPhyYwxlwLR1lUdhza2KtWprKYSo= github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo= 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.7.7 h1:0KgkoNTrYY7vmOCs9BW2AHxLvvpoY9nEUzgBHiPUr0k= -github.com/rhysd/actionlint v1.7.7/go.mod h1:AE6I6vJEkNaIfWqC2GNE5spIJNhxf8NCtLEKU4NnUXg= +github.com/rhysd/actionlint v1.7.3 h1:WD919WuLYrSCwY8VGBqJBEuzyVEIL5viXmXqRRcKOVs= +github.com/rhysd/actionlint v1.7.3/go.mod h1:rl+8ZoX1rqnbcMWKaTyOHmw08mmb/zlmG/Zu1fY47F4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -672,15 +675,15 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG 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.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a h1:w3tdWGKbLGBPtR/8/oO74W6hmz0qE5q0z9aqSAewaaM= -github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:S8kfXMp+yh77OxPD4fdM6YUknrZpQxLhvxzS4gDHENY= +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/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 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.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= 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= @@ -698,8 +701,8 @@ github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1 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.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= -github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +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/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= @@ -709,16 +712,16 @@ github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:s 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.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +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.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +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.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= @@ -763,10 +766,12 @@ github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5 github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/wneessen/go-mail v0.6.2 h1:c6V7c8D2mz868z9WJ+8zDKtUyLfZ1++uAZmo2GRFji8= -github.com/wneessen/go-mail v0.6.2/go.mod h1:L/PYjPK3/2ZlNb2/FjEBIn9n1rUWjW+Toy531oVmeb4= +github.com/wneessen/go-mail v0.5.2 h1:MZKwgHJoRboLJ+EHMLuHpZc95wo+u1xViL/4XSswDT8= +github.com/wneessen/go-mail v0.5.2/go.mod h1:kRroJvEq2hOSEPFRiKjN7Csrz0G1w+RpiGR3b6yo+Ck= 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.112.0 h1:6Z0cqEooCvBMfBIHw+CgO4AKGRV8na/9781xOb0+DKw= +github.com/xanzy/go-gitlab v0.112.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= 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/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -801,13 +806,11 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= 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.123.0 h1:W3LZ5QNyiSCJA0Zchkwz8nQIUzOuDoSWMZtRDT5DjPI= -gitlab.com/gitlab-org/api/client-go v0.123.0/go.mod h1:Jh0qjLILEdbO6z/OY94RD+3NDQRUKiuFSFYozN6cpKM= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -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.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM= -go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= +go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= +go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM= +go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4= 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= @@ -817,8 +820,6 @@ 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-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -829,15 +830,15 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 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.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= 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.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= -golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= -golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= +golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -847,8 +848,8 @@ 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/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -862,13 +863,14 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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.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.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -881,7 +883,7 @@ 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/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -907,24 +909,29 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc 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.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.18.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.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +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.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= 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.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -936,11 +943,11 @@ 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.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= -golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -951,24 +958,24 @@ 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/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= 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/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 h1:DMTIbak9GhdaSxEjvVzAeNZvyc03I61duqNbnm3SU0M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= 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.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1012,8 +1019,8 @@ modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= 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.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI= -mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk= +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= diff --git a/models/actions/artifact.go b/models/actions/artifact.go index 524224f070..706eb2e43a 100644 --- a/models/actions/artifact.go +++ b/models/actions/artifact.go @@ -48,7 +48,7 @@ type ActionArtifact struct { ContentEncoding string // The content encoding of the artifact ArtifactPath string `xorm:"index unique(runid_name_path)"` // The path to the artifact when runner uploads it ArtifactName string `xorm:"index unique(runid_name_path)"` // The name of the artifact when runner uploads it - Status ArtifactStatus `xorm:"index"` // The status of the artifact, uploading, expired or need-delete + Status int64 `xorm:"index"` // The status of the artifact, uploading, expired or need-delete CreatedUnix timeutil.TimeStamp `xorm:"created"` UpdatedUnix timeutil.TimeStamp `xorm:"updated index"` ExpiredUnix timeutil.TimeStamp `xorm:"index"` // The time when the artifact will be expired @@ -68,7 +68,7 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa RepoID: t.RepoID, OwnerID: t.OwnerID, CommitSHA: t.CommitSHA, - Status: ArtifactStatusUploadPending, + Status: int64(ArtifactStatusUploadPending), ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays), } if _, err := db.GetEngine(ctx).Insert(artifact); err != nil { @@ -108,11 +108,10 @@ func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) erro type FindArtifactsOptions struct { db.ListOptions - RepoID int64 - RunID int64 - ArtifactName string - Status int - FinalizedArtifactsV4 bool + RepoID int64 + RunID int64 + ArtifactName string + Status int } func (opts FindArtifactsOptions) ToOrders() string { @@ -135,10 +134,6 @@ func (opts FindArtifactsOptions) ToConds() builder.Cond { if opts.Status > 0 { cond = cond.And(builder.Eq{"status": opts.Status}) } - if opts.FinalizedArtifactsV4 { - cond = cond.And(builder.Eq{"status": ArtifactStatusUploadConfirmed}.Or(builder.Eq{"status": ArtifactStatusExpired})) - cond = cond.And(builder.Eq{"content_encoding": "application/zip"}) - } return cond } @@ -177,18 +172,18 @@ func ListPendingDeleteArtifacts(ctx context.Context, limit int) ([]*ActionArtifa // SetArtifactExpired sets an artifact to expired func SetArtifactExpired(ctx context.Context, artifactID int64) error { - _, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusExpired}) + _, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusExpired)}) return err } // SetArtifactNeedDelete sets an artifact to need-delete, cron job will delete it func SetArtifactNeedDelete(ctx context.Context, runID int64, name string) error { - _, err := db.GetEngine(ctx).Where("run_id=? AND artifact_name=? AND status = ?", runID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion}) + _, err := db.GetEngine(ctx).Where("run_id=? AND artifact_name=? AND status = ?", runID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusPendingDeletion)}) return err } // SetArtifactDeleted sets an artifact to deleted func SetArtifactDeleted(ctx context.Context, artifactID int64) error { - _, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusDeleted}) + _, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusDeleted)}) return err } diff --git a/models/actions/run.go b/models/actions/run.go index 60fbbcd323..f40bc1eb3d 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -88,7 +88,7 @@ func (run *ActionRun) RefLink() string { if refName.IsPull() { return run.Repo.Link() + "/pulls/" + refName.ShortName() } - return run.Repo.Link() + "/src/" + refName.RefWebLinkPath() + return git.RefURL(run.Repo.Link(), run.Ref) } // PrettyRef return #id for pull ref or ShortName for others @@ -154,7 +154,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) { } func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) { - if run.Event.IsPullRequest() { + 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 @@ -275,7 +275,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork return err } run.Index = index - run.Title = util.EllipsisDisplayString(run.Title, 255) + run.Title, _ = util.SplitStringAtByteN(run.Title, 255) if err := db.Insert(ctx, run); err != nil { return err @@ -308,7 +308,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork } else { hasWaiting = true } - job.Name = util.EllipsisDisplayString(job.Name, 255) + job.Name, _ = util.SplitStringAtByteN(job.Name, 255) runJobs = append(runJobs, &ActionRunJob{ RunID: run.ID, RepoID: run.RepoID, @@ -402,7 +402,7 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error { if len(cols) > 0 { sess.Cols(cols...) } - run.Title = util.EllipsisDisplayString(run.Title, 255) + run.Title, _ = util.SplitStringAtByteN(run.Title, 255) affected, err := sess.Update(run) if err != nil { return err diff --git a/models/actions/run_list.go b/models/actions/run_list.go index b9b9324e07..4046c7d369 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -10,7 +10,6 @@ import ( 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/translation" 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/runner.go b/models/actions/runner.go index 798a647180..c4e5f9d121 100644 --- a/models/actions/runner.go +++ b/models/actions/runner.go @@ -261,7 +261,7 @@ 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.EllipsisDisplayString(r.Name, 255) + r.Name, _ = util.SplitStringAtByteN(r.Name, 255) var err error if len(cols) == 0 { _, err = e.ID(r.ID).AllCols().Update(r) @@ -288,7 +288,7 @@ func CreateRunner(ctx context.Context, t *ActionRunner) error { // Remove OwnerID to avoid confusion; it's not worth returning an error here. t.OwnerID = 0 } - t.Name = util.EllipsisDisplayString(t.Name, 255) + t.Name, _ = util.SplitStringAtByteN(t.Name, 255) return db.Insert(ctx, t) } diff --git a/models/actions/runner_token.go b/models/actions/runner_token.go index bbd2af73b6..1eab5efcce 100644 --- a/models/actions/runner_token.go +++ b/models/actions/runner_token.go @@ -10,6 +10,7 @@ import ( "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/base" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" ) @@ -51,7 +52,7 @@ func GetRunnerToken(ctx context.Context, token string) (*ActionRunnerToken, erro if err != nil { return nil, err } else if !has { - return nil, fmt.Errorf(`runner token "%s...": %w`, util.TruncateRunes(token, 3), util.ErrNotExist) + return nil, fmt.Errorf(`runner token "%s...": %w`, base.TruncateString(token, 3), util.ErrNotExist) } return &runnerToken, nil } diff --git a/models/actions/schedule.go b/models/actions/schedule.go index e2cc32eedc..961ffd0851 100644 --- a/models/actions/schedule.go +++ b/models/actions/schedule.go @@ -68,7 +68,7 @@ func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error { // Loop through each schedule row for _, row := range rows { - row.Title = util.EllipsisDisplayString(row.Title, 255) + row.Title, _ = util.SplitStringAtByteN(row.Title, 255) // Create new schedule row if err = db.Insert(ctx, row); err != nil { return err diff --git a/models/actions/task.go b/models/actions/task.go index 9f13ff94c9..af74faf937 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -298,7 +298,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask if len(workflowJob.Steps) > 0 { steps := make([]*ActionTaskStep, len(workflowJob.Steps)) for i, v := range workflowJob.Steps { - name := util.EllipsisDisplayString(v.String(), 255) + name, _ := util.SplitStringAtByteN(v.String(), 255) steps[i] = &ActionTaskStep{ Name: name, TaskID: task.ID, diff --git a/models/activities/action.go b/models/activities/action.go index 52dffe07fd..7432e073b9 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -20,12 +20,12 @@ import ( 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/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" - "code.gitea.io/gitea/modules/util" "xorm.io/builder" "xorm.io/xorm/schemas" @@ -226,7 +226,7 @@ func (a *Action) GetActUserName(ctx context.Context) string { // ShortActUserName gets the action's user name trimmed to max 20 // chars. func (a *Action) ShortActUserName(ctx context.Context) string { - return util.EllipsisDisplayString(a.GetActUserName(ctx), 20) + return base.EllipsisString(a.GetActUserName(ctx), 20) } // GetActDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank. @@ -260,7 +260,7 @@ func (a *Action) GetRepoUserName(ctx context.Context) string { // ShortRepoUserName returns the name of the action repository owner // trimmed to max 20 chars. func (a *Action) ShortRepoUserName(ctx context.Context) string { - return util.EllipsisDisplayString(a.GetRepoUserName(ctx), 20) + return base.EllipsisString(a.GetRepoUserName(ctx), 20) } // GetRepoName returns the name of the action repository. @@ -275,7 +275,7 @@ func (a *Action) GetRepoName(ctx context.Context) string { // ShortRepoName returns the name of the action repository // trimmed to max 33 chars. func (a *Action) ShortRepoName(ctx context.Context) string { - return util.EllipsisDisplayString(a.GetRepoName(ctx), 33) + return base.EllipsisString(a.GetRepoName(ctx), 33) } // GetRepoPath returns the virtual path to the action repository. @@ -355,7 +355,7 @@ func (a *Action) GetBranch() string { // GetRefLink returns the action's ref link. func (a *Action) GetRefLink(ctx context.Context) string { - return a.GetRepoLink(ctx) + "/src/" + git.RefName(a.RefName).RefWebLinkPath() + return git.RefURL(a.GetRepoLink(ctx), a.RefName) } // GetTag returns the action's repository tag. @@ -529,7 +529,7 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder. } if opts.RequestedTeam != nil { - env := repo_model.AccessibleTeamReposEnv(ctx, organization.OrgFromUser(opts.RequestedUser), opts.RequestedTeam) + env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam) teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos) if err != nil { return nil, fmt.Errorf("GetTeamRepositories: %w", err) diff --git a/models/activities/user_heatmap_test.go b/models/activities/user_heatmap_test.go index 380045d3c5..a039fd3613 100644 --- a/models/activities/user_heatmap_test.go +++ b/models/activities/user_heatmap_test.go @@ -64,9 +64,11 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { for _, tc := range testCases { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID}) - var doer *user_model.User - if tc.doerID != 0 { - doer = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.doerID}) + doer := &user_model.User{ID: tc.doerID} + _, err := unittest.LoadBeanIfExists(doer) + assert.NoError(t, err) + if tc.doerID == 0 { + doer = nil } // get the action for comparison diff --git a/models/asymkey/error.go b/models/asymkey/error.go index 2e65d76612..03bc82302f 100644 --- a/models/asymkey/error.go +++ b/models/asymkey/error.go @@ -217,7 +217,6 @@ func (err ErrGPGKeyAccessDenied) Unwrap() error { // ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. type ErrKeyAccessDenied struct { UserID int64 - RepoID int64 KeyID int64 Note string } @@ -229,8 +228,8 @@ func IsErrKeyAccessDenied(err error) bool { } func (err ErrKeyAccessDenied) Error() string { - return fmt.Sprintf("user does not have access to the key [user_id: %d, repo_id: %d, key_id: %d, note: %s]", - err.UserID, err.RepoID, err.KeyID, err.Note) + return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d, note: %s]", + err.UserID, err.KeyID, err.Note) } func (err ErrKeyAccessDenied) Unwrap() error { diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go index 7f35a96a59..e921340730 100644 --- a/models/asymkey/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -106,7 +106,7 @@ func GPGKeyToEntity(ctx context.Context, k *GPGKey) (*openpgp.Entity, error) { if err != nil { return nil, err } - keys, err := CheckArmoredGPGKeyString(impKey.Content) + keys, err := checkArmoredGPGKeyString(impKey.Content) if err != nil { return nil, err } @@ -115,7 +115,7 @@ func GPGKeyToEntity(ctx context.Context, k *GPGKey) (*openpgp.Entity, error) { // parseSubGPGKey parse a sub Key func parseSubGPGKey(ownerID int64, primaryID string, pubkey *packet.PublicKey, expiry time.Time) (*GPGKey, error) { - content, err := Base64EncPubKey(pubkey) + content, err := base64EncPubKey(pubkey) if err != nil { return nil, err } @@ -183,7 +183,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified } } - content, err := Base64EncPubKey(pubkey) + content, err := base64EncPubKey(pubkey) if err != nil { return nil, err } @@ -239,3 +239,33 @@ func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err err return committer.Commit() } + +func checkKeyEmails(ctx context.Context, email string, keys ...*GPGKey) (bool, string) { + uid := int64(0) + var userEmails []*user_model.EmailAddress + var user *user_model.User + for _, key := range keys { + for _, e := range key.Emails { + if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) { + return true, e.Email + } + } + if key.Verified && key.OwnerID != 0 { + if uid != key.OwnerID { + userEmails, _ = user_model.GetEmailAddresses(ctx, key.OwnerID) + uid = key.OwnerID + user = &user_model.User{ID: uid} + _, _ = user_model.GetUser(ctx, user) + } + for _, e := range userEmails { + if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) { + return true, e.Email + } + } + if user.KeepEmailPrivate && strings.EqualFold(email, user.GetEmail()) { + return true, user.GetEmail() + } + } + } + return false, email +} diff --git a/models/asymkey/gpg_key_add.go b/models/asymkey/gpg_key_add.go index ec2031088a..6c0f6e01a7 100644 --- a/models/asymkey/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -67,7 +67,7 @@ func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) { // AddGPGKey adds new public key to database. func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature string) ([]*GPGKey, error) { - ekeys, err := CheckArmoredGPGKeyString(content) + ekeys, err := checkArmoredGPGKeyString(content) if err != nil { return nil, err } diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 1591cd5068..9219a509df 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -4,12 +4,17 @@ package asymkey import ( + "context" "fmt" "hash" + "strings" + "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" ) @@ -65,6 +70,263 @@ const ( NoKeyFound = "gpg.error.no_gpg_keys_found" ) +// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys. +func ParseCommitsWithSignature(ctx context.Context, oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error)) []*SignCommit { + newCommits := make([]*SignCommit, 0, len(oldCommits)) + keyMap := map[string]bool{} + + for _, c := range oldCommits { + signCommit := &SignCommit{ + UserCommit: c, + Verification: ParseCommitWithSignature(ctx, c.Commit), + } + + _ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isOwnerMemberCollaborator, &keyMap) + + newCommits = append(newCommits, signCommit) + } + return newCommits +} + +// ParseCommitWithSignature check if signature is good against keystore. +func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerification { + var committer *user_model.User + if c.Committer != nil { + var err error + // Find Committer account + committer, err = user_model.GetUserByEmail(ctx, c.Committer.Email) // This finds the user by primary email or activated email so commit will not be valid if email is not + if err != nil { // Skipping not user for committer + committer = &user_model.User{ + Name: c.Committer.Name, + Email: c.Committer.Email, + } + // We can expect this to often be an ErrUserNotExist. in the case + // it is not, however, it is important to log it. + if !user_model.IsErrUserNotExist(err) { + log.Error("GetUserByEmail: %v", err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.no_committer_account", + } + } + } + } + + // If no signature just report the committer + if c.Signature == nil { + return &CommitVerification{ + CommittingUser: committer, + Verified: false, // Default value + Reason: "gpg.error.not_signed_commit", // Default value + } + } + + // If this a SSH signature handle it differently + if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") { + return ParseCommitWithSSHSignature(ctx, c, committer) + } + + // Parsing signature + sig, err := extractSignature(c.Signature.Signature) + if err != nil { // Skipping failed to extract sign + log.Error("SignatureRead err: %v", err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.extract_sign", + } + } + + keyID := tryGetKeyIDFromSignature(sig) + defaultReason := NoKeyFound + + // First check if the sig has a keyID and if so just look at that + if commitVerification := hashAndVerifyForKeyID( + ctx, + sig, + c.Signature.Payload, + committer, + keyID, + setting.AppName, + ""); commitVerification != nil { + if commitVerification.Reason == BadSignature { + defaultReason = BadSignature + } else { + return commitVerification + } + } + + // Now try to associate the signature with the committer, if present + if committer.ID != 0 { + keys, err := db.Find[GPGKey](ctx, FindGPGKeyOptions{ + OwnerID: committer.ID, + }) + if err != nil { // Skipping failed to get gpg keys of user + log.Error("ListGPGKeys: %v", err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.failed_retrieval_gpg_keys", + } + } + + if err := GPGKeyList(keys).LoadSubKeys(ctx); err != nil { + log.Error("LoadSubKeys: %v", err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.failed_retrieval_gpg_keys", + } + } + + committerEmailAddresses, _ := user_model.GetEmailAddresses(ctx, committer.ID) + activated := false + for _, e := range committerEmailAddresses { + if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) { + activated = true + break + } + } + + for _, k := range keys { + // Pre-check (& optimization) that emails attached to key can be attached to the committer email and can validate + canValidate := false + email := "" + if k.Verified && activated { + canValidate = true + email = c.Committer.Email + } + if !canValidate { + for _, e := range k.Emails { + if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) { + canValidate = true + email = e.Email + break + } + } + } + if !canValidate { + continue // Skip this key + } + + commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, c.Signature.Payload, k, committer, committer, email) + if commitVerification != nil { + return commitVerification + } + } + } + + 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, + KeyID: setting.Repository.Signing.SigningKey, + Name: setting.Repository.Signing.SigningName, + Email: setting.Repository.Signing.SigningEmail, + } + if err := gpgSettings.LoadPublicKeyContent(); err != nil { + log.Error("Error getting default signing key: %s %v", gpgSettings.KeyID, err) + } else if commitVerification := verifyWithGPGSettings(ctx, &gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { + if commitVerification.Reason == BadSignature { + defaultReason = BadSignature + } else { + return commitVerification + } + } + } + + defaultGPGSettings, err := c.GetRepositoryDefaultPublicGPGKey(false) + if err != nil { + log.Error("Error getting default public gpg key: %v", err) + } else if defaultGPGSettings == nil { + log.Warn("Unable to get defaultGPGSettings for unattached commit: %s", c.ID.String()) + } else if defaultGPGSettings.Sign { + if commitVerification := verifyWithGPGSettings(ctx, defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { + if commitVerification.Reason == BadSignature { + defaultReason = BadSignature + } else { + return commitVerification + } + } + } + + return &CommitVerification{ // Default at this stage + CommittingUser: committer, + Verified: false, + Warning: defaultReason != NoKeyFound, + Reason: defaultReason, + SigningKey: &GPGKey{ + KeyID: keyID, + }, + } +} + +func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *CommitVerification { + // First try to find the key in the db + if commitVerification := hashAndVerifyForKeyID(ctx, sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil { + return commitVerification + } + + // Otherwise we have to parse the key + ekeys, err := checkArmoredGPGKeyString(gpgSettings.PublicKeyContent) + if err != nil { + log.Error("Unable to get default signing key: %v", err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.generate_hash", + } + } + for _, ekey := range ekeys { + pubkey := ekey.PrimaryKey + content, err := base64EncPubKey(pubkey) + if err != nil { + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.generate_hash", + } + } + k := &GPGKey{ + Content: content, + CanSign: pubkey.CanSign(), + KeyID: pubkey.KeyIdString(), + } + for _, subKey := range ekey.Subkeys { + content, err := base64EncPubKey(subKey.PublicKey) + if err != nil { + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.generate_hash", + } + } + k.SubsKey = append(k.SubsKey, &GPGKey{ + Content: content, + CanSign: subKey.PublicKey.CanSign(), + KeyID: subKey.PublicKey.KeyIdString(), + }) + } + if commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, payload, k, committer, &user_model.User{ + Name: gpgSettings.Name, + Email: gpgSettings.Email, + }, gpgSettings.Email); commitVerification != nil { + return commitVerification + } + if keyID == k.KeyID { + // This is a bad situation ... We have a key id that matches our default key but the signature doesn't match. + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Warning: true, + Reason: BadSignature, + } + } + } + return nil +} + func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error { // Check if key can sign if !k.CanSign { @@ -107,7 +369,7 @@ func hashAndVerifyWithSubKeys(sig *packet.Signature, payload string, k *GPGKey) return nil, nil } -func HashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload string, k *GPGKey, committer, signer *user_model.User, email string) *CommitVerification { +func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload string, k *GPGKey, committer, signer *user_model.User, email string) *CommitVerification { key, err := hashAndVerifyWithSubKeys(sig, payload, k) if err != nil { // Skipping failed to generate hash return &CommitVerification{ @@ -130,6 +392,78 @@ func HashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload s return nil } +func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload string, committer *user_model.User, keyID, name, email string) *CommitVerification { + if keyID == "" { + return nil + } + keys, err := db.Find[GPGKey](ctx, FindGPGKeyOptions{ + KeyID: keyID, + IncludeSubKeys: true, + }) + if err != nil { + log.Error("GetGPGKeysByKeyID: %v", err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.failed_retrieval_gpg_keys", + } + } + if len(keys) == 0 { + return nil + } + for _, key := range keys { + var primaryKeys []*GPGKey + if key.PrimaryKeyID != "" { + primaryKeys, err = db.Find[GPGKey](ctx, FindGPGKeyOptions{ + KeyID: key.PrimaryKeyID, + IncludeSubKeys: true, + }) + if err != nil { + log.Error("GetGPGKeysByKeyID: %v", err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.failed_retrieval_gpg_keys", + } + } + } + + activated, email := checkKeyEmails(ctx, email, append([]*GPGKey{key}, primaryKeys...)...) + if !activated { + continue + } + + signer := &user_model.User{ + Name: name, + Email: email, + } + if key.OwnerID != 0 { + owner, err := user_model.GetUserByID(ctx, key.OwnerID) + if err == nil { + signer = owner + } else if !user_model.IsErrUserNotExist(err) { + log.Error("Failed to user_model.GetUserByID: %d for key ID: %d (%s) %v", key.OwnerID, key.ID, key.KeyID, err) + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Reason: "gpg.error.no_committer_account", + } + } + } + commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, payload, key, committer, signer, email) + if commitVerification != nil { + return commitVerification + } + } + // This is a bad situation ... We have a key id that is in our database but the signature doesn't match. + return &CommitVerification{ + CommittingUser: committer, + Verified: false, + Warning: true, + Reason: BadSignature, + } +} + // CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository // There are several trust models in Gitea func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error), keyMap *map[string]bool) error { diff --git a/models/asymkey/gpg_key_common.go b/models/asymkey/gpg_key_common.go index 1291cbc542..92c34a2569 100644 --- a/models/asymkey/gpg_key_common.go +++ b/models/asymkey/gpg_key_common.go @@ -33,9 +33,9 @@ import ( // This file provides common functions relating to GPG Keys -// CheckArmoredGPGKeyString checks if the given key string is a valid GPG armored key. +// checkArmoredGPGKeyString checks if the given key string is a valid GPG armored key. // The function returns the actual public key on success -func CheckArmoredGPGKeyString(content string) (openpgp.EntityList, error) { +func checkArmoredGPGKeyString(content string) (openpgp.EntityList, error) { list, err := openpgp.ReadArmoredKeyRing(strings.NewReader(content)) if err != nil { return nil, ErrGPGKeyParsing{err} @@ -43,8 +43,8 @@ func CheckArmoredGPGKeyString(content string) (openpgp.EntityList, error) { return list, nil } -// Base64EncPubKey encode public key content to base 64 -func Base64EncPubKey(pubkey *packet.PublicKey) (string, error) { +// base64EncPubKey encode public key content to base 64 +func base64EncPubKey(pubkey *packet.PublicKey) (string, error) { var w bytes.Buffer err := pubkey.Serialize(&w) if err != nil { @@ -119,7 +119,7 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) { return block.Body, nil } -func ExtractSignature(s string) (*packet.Signature, error) { +func extractSignature(s string) (*packet.Signature, error) { r, err := readArmoredSign(strings.NewReader(s)) if err != nil { return nil, fmt.Errorf("Failed to read signature armor") @@ -135,7 +135,7 @@ func ExtractSignature(s string) (*packet.Signature, error) { return sig, nil } -func TryGetKeyIDFromSignature(sig *packet.Signature) string { +func tryGetKeyIDFromSignature(sig *packet.Signature) string { if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { return fmt.Sprintf("%016X", *sig.IssuerKeyId) } diff --git a/models/asymkey/gpg_key_test.go b/models/asymkey/gpg_key_test.go index 408cf15763..de463dfbe2 100644 --- a/models/asymkey/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -16,7 +16,6 @@ import ( "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/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== =i9b7 -----END PGP PUBLIC KEY BLOCK-----` - key, err := CheckArmoredGPGKeyString(testGPGArmor) + key, err := checkArmoredGPGKeyString(testGPGArmor) 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 =ZiSe -----END PGP PUBLIC KEY BLOCK-----` - key, err := CheckArmoredGPGKeyString(testGPGArmor) + key, err := checkArmoredGPGKeyString(testGPGArmor) assert.NoError(t, err, "Could not parse a valid GPG public armored brainpoolP256r1 key", key) // TODO verify value of key } @@ -108,14 +107,15 @@ Av844q/BfRuVsJsK1NDNG09LC30B0l3LKBqlrRmRTUMHtgchdX2dY+p7GPOoSzlR MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg== =i9b7 -----END PGP PUBLIC KEY BLOCK-----` - keys, err := CheckArmoredGPGKeyString(testGPGArmor) - require.NotEmpty(t, keys) - + keys, err := checkArmoredGPGKeyString(testGPGArmor) + if !assert.NotEmpty(t, keys) { + return + } ekey := keys[0] assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey) pubkey := ekey.PrimaryKey - content, err := Base64EncPubKey(pubkey) + content, err := base64EncPubKey(pubkey) assert.NoError(t, err, "Could not base64 encode a valid PublicKey content", ekey) key := &GPGKey{ @@ -176,9 +176,9 @@ committer Antoine GIRARD 1489013107 +0100 Unknown GPG key with good email ` // Reading Sign - goodSig, err := ExtractSignature(testGoodSigArmor) + goodSig, err := extractSignature(testGoodSigArmor) assert.NoError(t, err, "Could not parse a valid GPG armored signature", testGoodSigArmor) - badSig, err := ExtractSignature(testBadSigArmor) + badSig, err := extractSignature(testBadSigArmor) assert.NoError(t, err, "Could not parse a valid GPG armored signature", testBadSigArmor) // Generating hash of commit @@ -386,7 +386,7 @@ epiDVQ== =VSKJ -----END PGP PUBLIC KEY BLOCK----- ` - keys, err := CheckArmoredGPGKeyString(testIssue6599) + keys, err := checkArmoredGPGKeyString(testIssue6599) assert.NoError(t, err) if assert.NotEmpty(t, keys) { ekey := keys[0] @@ -396,11 +396,11 @@ epiDVQ== } func TestTryGetKeyIDFromSignature(t *testing.T) { - assert.Empty(t, TryGetKeyIDFromSignature(&packet.Signature{})) - assert.Equal(t, "038D1A3EADDBEA9C", TryGetKeyIDFromSignature(&packet.Signature{ + assert.Empty(t, tryGetKeyIDFromSignature(&packet.Signature{})) + assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ IssuerKeyId: util.ToPointer(uint64(0x38D1A3EADDBEA9C)), })) - assert.Equal(t, "038D1A3EADDBEA9C", TryGetKeyIDFromSignature(&packet.Signature{ + assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ IssuerFingerprint: []uint8{0xb, 0x23, 0x24, 0xc7, 0xe6, 0xfe, 0x4f, 0x3a, 0x6, 0x26, 0xc1, 0x21, 0x3, 0x8d, 0x1a, 0x3e, 0xad, 0xdb, 0xea, 0x9c}, })) } @@ -411,9 +411,9 @@ func TestParseGPGKey(t *testing.T) { // create a key for test email e, err := openpgp.NewEntity("name", "comment", "email1@example.com", nil) - require.NoError(t, err) + assert.NoError(t, err) k, err := parseGPGKey(db.DefaultContext, 1, e, true) - require.NoError(t, err) + assert.NoError(t, err) assert.NotEmpty(t, k.KeyID) assert.NotEmpty(t, k.Emails) // the key is valid, matches the email @@ -422,7 +422,7 @@ func TestParseGPGKey(t *testing.T) { id.Revocations = append(id.Revocations, &packet.Signature{RevocationReason: util.ToPointer(packet.KeyCompromised)}) } k, err = parseGPGKey(db.DefaultContext, 1, e, true) - require.NoError(t, err) + assert.NoError(t, err) assert.NotEmpty(t, k.KeyID) assert.Empty(t, k.Emails) // the key is revoked, matches no email } diff --git a/models/asymkey/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go index 6eedb5b7ba..01812a2d54 100644 --- a/models/asymkey/gpg_key_verify.go +++ b/models/asymkey/gpg_key_verify.go @@ -50,7 +50,7 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st return "", err } - sig, err := ExtractSignature(signature) + sig, err := extractSignature(signature) if err != nil { return "", ErrGPGInvalidTokenSignature{ ID: key.KeyID, diff --git a/models/auth/access_token_scope.go b/models/auth/access_token_scope.go index 0e5b2e96e6..897ff3fc9e 100644 --- a/models/auth/access_token_scope.go +++ b/models/auth/access_token_scope.go @@ -5,7 +5,6 @@ package auth import ( "fmt" - "slices" "strings" "code.gitea.io/gitea/models/perm" @@ -15,7 +14,7 @@ import ( type AccessTokenScopeCategory int const ( - AccessTokenScopeCategoryActivityPub AccessTokenScopeCategory = iota + AccessTokenScopeCategoryActivityPub = iota AccessTokenScopeCategoryAdmin AccessTokenScopeCategoryMisc // WARN: this is now just a placeholder, don't remove it which will change the following values AccessTokenScopeCategoryNotification @@ -194,14 +193,6 @@ var accessTokenScopes = map[AccessTokenScopeLevel]map[AccessTokenScopeCategory]A }, } -func GetAccessTokenCategories() (res []string) { - for _, cat := range accessTokenScopes[Read] { - res = append(res, strings.TrimPrefix(string(cat), "read:")) - } - slices.Sort(res) - return res -} - // GetRequiredScopes gets the specific scopes for a given level and categories func GetRequiredScopes(level AccessTokenScopeLevel, scopeCategories ...AccessTokenScopeCategory) []AccessTokenScope { scopes := make([]AccessTokenScope, 0, len(scopeCategories)) @@ -279,9 +270,6 @@ func (s AccessTokenScope) parse() (accessTokenScopeBitmap, error) { // StringSlice returns the AccessTokenScope as a []string func (s AccessTokenScope) StringSlice() []string { - if s == "" { - return nil - } return strings.Split(string(s), ",") } diff --git a/models/auth/access_token_scope_test.go b/models/auth/access_token_scope_test.go index 9e4aa83633..a6097e45d7 100644 --- a/models/auth/access_token_scope_test.go +++ b/models/auth/access_token_scope_test.go @@ -17,7 +17,6 @@ type scopeTestNormalize struct { } func TestAccessTokenScope_Normalize(t *testing.T) { - assert.Equal(t, []string{"activitypub", "admin", "issue", "misc", "notification", "organization", "package", "repository", "user"}, GetAccessTokenCategories()) tests := []scopeTestNormalize{ {"", "", nil}, {"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil}, @@ -26,7 +25,7 @@ func TestAccessTokenScope_Normalize(t *testing.T) { {"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,public-only", "public-only,all", nil}, } - for _, scope := range GetAccessTokenCategories() { + for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} { tests = append(tests, scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%s", scope)), AccessTokenScope(fmt.Sprintf("read:%s", scope)), nil}, scopeTestNormalize{AccessTokenScope(fmt.Sprintf("write:%s", scope)), AccessTokenScope(fmt.Sprintf("write:%s", scope)), nil}, @@ -60,7 +59,7 @@ func TestAccessTokenScope_HasScope(t *testing.T) { {"public-only", "read:issue", false, nil}, } - for _, scope := range GetAccessTokenCategories() { + for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} { tests = append(tests, scopeTestHasScope{ AccessTokenScope(fmt.Sprintf("read:%s", scope)), diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go index fa89a58b14..43daa0b5ec 100644 --- a/models/auth/oauth2_test.go +++ b/models/auth/oauth2_test.go @@ -25,7 +25,7 @@ func TestOAuth2Application_GenerateClientSecret(t *testing.T) { func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) { assert.NoError(b, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1}) - for b.Loop() { + for i := 0; i < b.N; i++ { _, _ = app.GenerateClientSecret(db.DefaultContext) } } diff --git a/models/auth/source_test.go b/models/auth/source_test.go index 84aede0a6b..36e76d5e28 100644 --- a/models/auth/source_test.go +++ b/models/auth/source_test.go @@ -13,8 +13,6 @@ import ( "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "xorm.io/xorm" "xorm.io/xorm/schemas" ) @@ -56,8 +54,7 @@ func TestDumpAuthSource(t *testing.T) { sb := new(strings.Builder) - // TODO: this test is quite hacky, it should use a low-level "select" (without model processors) but not a database dump - engine := db.GetEngine(db.DefaultContext).(*xorm.Engine) - require.NoError(t, engine.DumpTables([]*schemas.Table{authSourceSchema}, sb)) + db.DumpTables([]*schemas.Table{authSourceSchema}, sb) + assert.Contains(t, sb.String(), `"Provider":"ConvertibleSourceName"`) } diff --git a/models/auth/webauthn_test.go b/models/auth/webauthn_test.go index 654427e974..f1cf398adf 100644 --- a/models/auth/webauthn_test.go +++ b/models/auth/webauthn_test.go @@ -44,7 +44,7 @@ func TestWebAuthnCredential_UpdateSignCount(t *testing.T) { cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred.SignCount = 1 assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) - unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1}) + unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1}) } func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) { @@ -52,7 +52,7 @@ func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) { cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred.SignCount = 0xffffffff assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) - unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff}) + unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff}) } func TestCreateCredential(t *testing.T) { @@ -63,5 +63,5 @@ func TestCreateCredential(t *testing.T) { assert.Equal(t, "WebAuthn Created Credential", res.Name) assert.Equal(t, []byte("Test"), res.CredentialID) - unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1}) + unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1}) } diff --git a/models/db/collation.go b/models/db/collation.go index 79ade87380..a7db9f5442 100644 --- a/models/db/collation.go +++ b/models/db/collation.go @@ -140,7 +140,7 @@ func CheckCollations(x *xorm.Engine) (*CheckCollationsResult, error) { } func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) { - return CheckCollations(xormEngine) + return CheckCollations(x) } func alterDatabaseCollation(x *xorm.Engine, collation string) error { diff --git a/models/db/context.go b/models/db/context.go index 51627712b1..171e26b933 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -94,7 +94,7 @@ func GetEngine(ctx context.Context) Engine { if e := getExistingEngine(ctx); e != nil { return e } - return xormEngine.Context(ctx) + return x.Context(ctx) } // getExistingEngine gets an existing db Engine/Statement from this context or returns nil @@ -155,7 +155,7 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) { return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil } - sess := xormEngine.NewSession() + sess := x.NewSession() if err := sess.Begin(); err != nil { _ = sess.Close() return nil, nil, err @@ -179,7 +179,7 @@ func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error } func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error { - sess := xormEngine.NewSession() + sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err @@ -322,7 +322,7 @@ func CountByBean(ctx context.Context, bean any) (int64, error) { // TableName returns the table name according a bean object func TableName(bean any) string { - return xormEngine.TableName(bean) + return x.TableName(bean) } // InTransaction returns true if the engine is in a transaction otherwise return false diff --git a/models/db/convert.go b/models/db/convert.go index 80b0f7b04b..8c124471ab 100644 --- a/models/db/convert.go +++ b/models/db/convert.go @@ -16,30 +16,30 @@ import ( // ConvertDatabaseTable converts database and tables from utf8 to utf8mb4 if it's mysql and set ROW_FORMAT=dynamic func ConvertDatabaseTable() error { - if xormEngine.Dialect().URI().DBType != schemas.MYSQL { + if x.Dialect().URI().DBType != schemas.MYSQL { return nil } - r, err := CheckCollations(xormEngine) + r, err := CheckCollations(x) if err != nil { return err } - _, err = xormEngine.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", setting.Database.Name, 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 } - tables, err := xormEngine.DBMetas() + tables, err := x.DBMetas() if err != nil { return err } for _, table := range tables { - if _, err := xormEngine.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic", table.Name)); err != nil { + if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic", table.Name)); err != nil { return err } - if _, err := xormEngine.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE %s", table.Name, r.ExpectedCollation)); err != nil { + if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE %s", table.Name, r.ExpectedCollation)); err != nil { return err } } @@ -49,11 +49,11 @@ func ConvertDatabaseTable() error { // ConvertVarcharToNVarchar converts database and tables from varchar to nvarchar if it's mssql func ConvertVarcharToNVarchar() error { - if xormEngine.Dialect().URI().DBType != schemas.MSSQL { + if x.Dialect().URI().DBType != schemas.MSSQL { return nil } - sess := xormEngine.NewSession() + sess := x.NewSession() defer sess.Close() res, err := sess.QuerySliceString(`SELECT 'ALTER TABLE ' + OBJECT_NAME(SC.object_id) + ' MODIFY SC.name NVARCHAR(' + CONVERT(VARCHAR(5),SC.max_length) + ')' FROM SYS.columns SC diff --git a/models/db/engine.go b/models/db/engine.go index 91015f7038..b17188945a 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -8,10 +8,17 @@ import ( "context" "database/sql" "fmt" + "io" "reflect" "strings" + "time" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" + "xorm.io/xorm/contexts" + "xorm.io/xorm/names" "xorm.io/xorm/schemas" _ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver @@ -20,9 +27,9 @@ import ( ) var ( - xormEngine *xorm.Engine - registeredModels []any - registeredInitFuncs []func() error + x *xorm.Engine + tables []any + initFuncs []func() error ) // Engine represents a xorm engine or session. @@ -63,38 +70,167 @@ type Engine interface { // TableInfo returns table's information via an object func TableInfo(v any) (*schemas.Table, error) { - return xormEngine.TableInfo(v) + return x.TableInfo(v) } -// RegisterModel registers model, if initFuncs provided, it will be invoked after data model sync +// DumpTables dump tables information +func DumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error { + return x.DumpTables(tables, w, tp...) +} + +// RegisterModel registers model, if initfunc provided, it will be invoked after data model sync func RegisterModel(bean any, initFunc ...func() error) { - registeredModels = append(registeredModels, bean) - if len(registeredInitFuncs) > 0 && initFunc[0] != nil { - registeredInitFuncs = append(registeredInitFuncs, initFunc[0]) + tables = append(tables, bean) + if len(initFuncs) > 0 && initFunc[0] != nil { + initFuncs = append(initFuncs, initFunc[0]) } } +func init() { + gonicNames := []string{"SSL", "UID"} + for _, name := range gonicNames { + names.LintGonicMapper[name] = true + } +} + +// newXORMEngine returns a new XORM engine from the configuration +func newXORMEngine() (*xorm.Engine, error) { + connStr, err := setting.DBConnStr() + if err != nil { + return nil, err + } + + 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() + engine, err = xorm.NewEngine("postgresschema", connStr) + } else { + engine, err = xorm.NewEngine(setting.Database.Type.String(), connStr) + } + + if err != nil { + return nil, err + } + if setting.Database.Type == "mysql" { + engine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"}) + } else if setting.Database.Type == "mssql" { + engine.Dialect().SetParams(map[string]string{"DEFAULT_VARCHAR": "nvarchar"}) + } + engine.SetSchema(setting.Database.Schema) + return engine, nil +} + // SyncAllTables sync the schemas of all tables, is required by unit test code func SyncAllTables() error { - _, err := xormEngine.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ + _, err := x.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ WarnIfDatabaseColumnMissed: true, - }, registeredModels...) + }, tables...) return err } +// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext +func InitEngine(ctx context.Context) error { + xormEngine, err := newXORMEngine() + if err != nil { + if strings.Contains(err.Error(), "SQLite3 support") { + return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err) + } + return fmt.Errorf("failed to connect to database: %w", err) + } + + 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.SetDefaultContext(ctx) + + if setting.Database.SlowQueryThreshold > 0 { + xormEngine.AddHook(&SlowQueryHook{ + Threshold: setting.Database.SlowQueryThreshold, + Logger: log.GetLogger("xorm"), + }) + } + + SetDefaultEngine(ctx, xormEngine) + return nil +} + +// SetDefaultEngine sets the default engine for db +func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) { + x = eng + DefaultContext = &Context{Context: ctx, engine: x} +} + +// UnsetDefaultEngine closes and unsets the default engine +// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now, +// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `x` and DefaultContext without close +// Global database engine related functions are all racy and there is no graceful close right now. +func UnsetDefaultEngine() { + if x != nil { + _ = x.Close() + x = nil + } + DefaultContext = nil +} + +// 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(*xorm.Engine) error) (err error) { + if err = InitEngine(ctx); err != nil { + return err + } + + if err = x.Ping(); err != nil { + return err + } + + preprocessDatabaseCollation(x) + + // We have to run migrateFunc here in case the user is re-running installation on a previously created DB. + // If we do not then table schemas will be changed and there will be conflicts when the migrations run properly. + // + // Installation should only be being re-run if users want to recover an old database. + // However, we should think carefully about should we support re-install on an installed instance, + // as there may be other problems due to secret reinitialization. + if err = migrateFunc(x); err != nil { + return fmt.Errorf("migrate: %w", err) + } + + if err = SyncAllTables(); err != nil { + return fmt.Errorf("sync database struct error: %w", err) + } + + for _, initFunc := range initFuncs { + if err := initFunc(); err != nil { + return fmt.Errorf("initFunc failed: %w", err) + } + } + + return nil +} + // NamesToBean return a list of beans or an error func NamesToBean(names ...string) ([]any, error) { beans := []any{} if len(names) == 0 { - beans = append(beans, registeredModels...) + beans = append(beans, tables...) return beans, nil } // Need to map provided names to beans... beanMap := make(map[string]any) - for _, bean := range registeredModels { + for _, bean := range tables { beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean - beanMap[strings.ToLower(xormEngine.TableName(bean))] = bean - beanMap[strings.ToLower(xormEngine.TableName(bean, true))] = bean + beanMap[strings.ToLower(x.TableName(bean))] = bean + beanMap[strings.ToLower(x.TableName(bean, true))] = bean } gotBean := make(map[any]bool) @@ -111,9 +247,36 @@ func NamesToBean(names ...string) ([]any, error) { return beans, nil } +// 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 { + t, err := x.TableInfo(t) + if err != nil { + return err + } + tbs = append(tbs, t) + } + + type Version struct { + ID int64 `xorm:"pk autoincr"` + Version int64 + } + t, err := x.TableInfo(&Version{}) + if err != nil { + return err + } + tbs = append(tbs, t) + + if len(dbType) > 0 { + return x.DumpTablesToFile(tbs, filePath, schemas.DBType(dbType)) + } + return x.DumpTablesToFile(tbs, filePath) +} + // MaxBatchInsertSize returns the table's max batch insert size func MaxBatchInsertSize(bean any) int { - t, err := xormEngine.TableInfo(bean) + t, err := x.TableInfo(bean) if err != nil { return 50 } @@ -122,18 +285,18 @@ func MaxBatchInsertSize(bean any) int { // IsTableNotEmpty returns true if table has at least one record func IsTableNotEmpty(beanOrTableName any) (bool, error) { - return xormEngine.Table(beanOrTableName).Exist() + return x.Table(beanOrTableName).Exist() } // DeleteAllRecords will delete all the records of this table func DeleteAllRecords(tableName string) error { - _, err := xormEngine.Exec(fmt.Sprintf("DELETE FROM %s", tableName)) + _, err := x.Exec(fmt.Sprintf("DELETE FROM %s", tableName)) return err } // GetMaxID will return max id of the table func GetMaxID(beanOrTableName any) (maxID int64, err error) { - _, err = xormEngine.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) + _, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) return maxID, err } @@ -145,3 +308,24 @@ func SetLogSQL(ctx context.Context, on bool) { sess.Engine().ShowSQL(on) } } + +type SlowQueryHook struct { + Threshold time.Duration + Logger log.Logger +} + +var _ contexts.Hook = &SlowQueryHook{} + +func (SlowQueryHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) { + return c.Ctx, nil +} + +func (h *SlowQueryHook) AfterProcess(c *contexts.ContextHook) error { + if c.ExecuteTime >= h.Threshold { + // 8 is the amount of skips passed to runtime.Caller, so that in the log the correct function + // is being displayed (the function that ultimately wants to execute the query in the code) + // instead of the function of the slow query hook being called. + h.Logger.Log(8, log.WARN, "[Slow SQL Query] %s %v - %v", c.SQL, c.Args, c.ExecuteTime) + } + return nil +} diff --git a/models/db/engine_dump.go b/models/db/engine_dump.go deleted file mode 100644 index 63f2d4e093..0000000000 --- a/models/db/engine_dump.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package db - -import "xorm.io/xorm/schemas" - -// 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 registeredModels { - t, err := xormEngine.TableInfo(t) - if err != nil { - return err - } - tbs = append(tbs, t) - } - - type Version struct { - ID int64 `xorm:"pk autoincr"` - Version int64 - } - t, err := xormEngine.TableInfo(&Version{}) - if err != nil { - return err - } - tbs = append(tbs, t) - - if dbType != "" { - return xormEngine.DumpTablesToFile(tbs, filePath, schemas.DBType(dbType)) - } - return xormEngine.DumpTablesToFile(tbs, filePath) -} diff --git a/models/db/engine_hook.go b/models/db/engine_hook.go deleted file mode 100644 index 2c9fc09c99..0000000000 --- a/models/db/engine_hook.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package db - -import ( - "context" - "time" - - "code.gitea.io/gitea/modules/gtprof" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - - "xorm.io/xorm/contexts" -) - -type EngineHook struct { - Threshold time.Duration - Logger log.Logger -} - -var _ contexts.Hook = (*EngineHook)(nil) - -func (*EngineHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) { - ctx, _ := gtprof.GetTracer().Start(c.Ctx, gtprof.TraceSpanDatabase) - return ctx, nil -} - -func (h *EngineHook) AfterProcess(c *contexts.ContextHook) error { - span := gtprof.GetContextSpan(c.Ctx) - if span != nil { - // Do not record SQL parameters here: - // * It shouldn't expose the parameters because they contain sensitive information, end users need to report the trace details safely. - // * Some parameters contain quite long texts, waste memory and are difficult to display. - span.SetAttributeString(gtprof.TraceAttrDbSQL, c.SQL) - span.End() - } else { - setting.PanicInDevOrTesting("span in database engine hook is nil") - } - if c.ExecuteTime >= h.Threshold { - // 8 is the amount of skips passed to runtime.Caller, so that in the log the correct function - // is being displayed (the function that ultimately wants to execute the query in the code) - // instead of the function of the slow query hook being called. - h.Logger.Log(8, log.WARN, "[Slow SQL Query] %s %v - %v", c.SQL, c.Args, c.ExecuteTime) - } - return nil -} diff --git a/models/db/engine_init.go b/models/db/engine_init.go deleted file mode 100644 index edca697934..0000000000 --- a/models/db/engine_init.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package db - -import ( - "context" - "fmt" - "strings" - - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - - "xorm.io/xorm" - "xorm.io/xorm/names" -) - -func init() { - gonicNames := []string{"SSL", "UID"} - for _, name := range gonicNames { - names.LintGonicMapper[name] = true - } -} - -// newXORMEngine returns a new XORM engine from the configuration -func newXORMEngine() (*xorm.Engine, error) { - connStr, err := setting.DBConnStr() - if err != nil { - return nil, err - } - - 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() - engine, err = xorm.NewEngine("postgresschema", connStr) - } else { - engine, err = xorm.NewEngine(setting.Database.Type.String(), connStr) - } - - if err != nil { - return nil, err - } - if setting.Database.Type == "mysql" { - engine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"}) - } else if setting.Database.Type == "mssql" { - engine.Dialect().SetParams(map[string]string{"DEFAULT_VARCHAR": "nvarchar"}) - } - engine.SetSchema(setting.Database.Schema) - return engine, nil -} - -// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext -func InitEngine(ctx context.Context) error { - xe, err := newXORMEngine() - if err != nil { - if strings.Contains(err.Error(), "SQLite3 support") { - return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err) - } - return fmt.Errorf("failed to connect to database: %w", err) - } - - xe.SetMapper(names.GonicMapper{}) - // WARNING: for serv command, MUST remove the output to os.stdout, - // so use log file to instead print to stdout. - xe.SetLogger(NewXORMLogger(setting.Database.LogSQL)) - xe.ShowSQL(setting.Database.LogSQL) - xe.SetMaxOpenConns(setting.Database.MaxOpenConns) - xe.SetMaxIdleConns(setting.Database.MaxIdleConns) - xe.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) - xe.SetDefaultContext(ctx) - - if setting.Database.SlowQueryThreshold > 0 { - xe.AddHook(&EngineHook{ - Threshold: setting.Database.SlowQueryThreshold, - Logger: log.GetLogger("xorm"), - }) - } - - SetDefaultEngine(ctx, xe) - return nil -} - -// SetDefaultEngine sets the default engine for db -func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) { - xormEngine = eng - DefaultContext = &Context{Context: ctx, engine: xormEngine} -} - -// UnsetDefaultEngine closes and unsets the default engine -// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now, -// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `xormEngine` and DefaultContext without close -// Global database engine related functions are all racy and there is no graceful close right now. -func UnsetDefaultEngine() { - if xormEngine != nil { - _ = xormEngine.Close() - xormEngine = nil - } - DefaultContext = nil -} - -// 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(*xorm.Engine) error) (err error) { - if err = InitEngine(ctx); err != nil { - return err - } - - if err = xormEngine.Ping(); err != nil { - return err - } - - preprocessDatabaseCollation(xormEngine) - - // We have to run migrateFunc here in case the user is re-running installation on a previously created DB. - // If we do not then table schemas will be changed and there will be conflicts when the migrations run properly. - // - // Installation should only be being re-run if users want to recover an old database. - // However, we should think carefully about should we support re-install on an installed instance, - // as there may be other problems due to secret reinitialization. - if err = migrateFunc(xormEngine); err != nil { - return fmt.Errorf("migrate: %w", err) - } - - if err = SyncAllTables(); err != nil { - return fmt.Errorf("sync database struct error: %w", err) - } - - for _, initFunc := range registeredInitFuncs { - if err := initFunc(); err != nil { - return fmt.Errorf("initFunc failed: %w", err) - } - } - - return nil -} diff --git a/models/db/engine_test.go b/models/db/engine_test.go index 10a1a33ff0..e3dbfbdc24 100644 --- a/models/db/engine_test.go +++ b/models/db/engine_test.go @@ -15,7 +15,6 @@ import ( _ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestDumpDatabase(t *testing.T) { @@ -63,7 +62,9 @@ func TestPrimaryKeys(t *testing.T) { // Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called. beans, err := db.NamesToBean() - require.NoError(t, err) + if err != nil { + t.Fatal(err) + } whitelist := map[string]string{ "the_table_name_to_skip_checking": "Write a note here to explain why", @@ -78,6 +79,8 @@ func TestPrimaryKeys(t *testing.T) { t.Logf("ignore %q because %q", table.Name, why) continue } - assert.NotEmpty(t, table.PrimaryKeys, "table %q has no primary key", table.Name) + if len(table.PrimaryKeys) == 0 { + t.Errorf("table %q has no primary key", table.Name) + } } } diff --git a/models/db/name.go b/models/db/name.go index e2165fd76b..51be33a8bc 100644 --- a/models/db/name.go +++ b/models/db/name.go @@ -5,12 +5,21 @@ package db import ( "fmt" + "regexp" "strings" "unicode/utf8" "code.gitea.io/gitea/modules/util" ) +var ( + // ErrNameEmpty name is empty error + ErrNameEmpty = util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument} + + // AlphaDashDotPattern characters prohibited in a user name (anything except A-Za-z0-9_.-) + AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) +) + // ErrNameReserved represents a "reserved name" error. type ErrNameReserved struct { Name string @@ -73,20 +82,20 @@ func (err ErrNameCharsNotAllowed) Unwrap() error { // IsUsableName checks if name is reserved or pattern of name is not allowed // based on given reserved names and patterns. -// Names are exact match, patterns can be a prefix or suffix match with placeholder '*'. -func IsUsableName(reservedNames, reservedPatterns []string, name string) error { +// Names are exact match, patterns can be prefix or suffix match with placeholder '*'. +func IsUsableName(names, patterns []string, name string) error { name = strings.TrimSpace(strings.ToLower(name)) if utf8.RuneCountInString(name) == 0 { - return util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument} + return ErrNameEmpty } - for i := range reservedNames { - if name == reservedNames[i] { + for i := range names { + if name == names[i] { return ErrNameReserved{name} } } - for _, pat := range reservedPatterns { + for _, pat := range patterns { if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) || (pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) { return ErrNamePatternNotAllowed{pat} diff --git a/models/db/sequence.go b/models/db/sequence.go index 9adc5113ac..f49ad935de 100644 --- a/models/db/sequence.go +++ b/models/db/sequence.go @@ -17,11 +17,11 @@ func CountBadSequences(_ context.Context) (int64, error) { return 0, nil } - sess := xormEngine.NewSession() + sess := x.NewSession() defer sess.Close() var sequences []string - schema := xormEngine.Dialect().URI().Schema + schema := x.Dialect().URI().Schema sess.Engine().SetSchema("") if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__%_id_seq%' AND sequence_catalog = ?", setting.Database.Name).Find(&sequences); err != nil { @@ -38,7 +38,7 @@ func FixBadSequences(_ context.Context) error { return nil } - sess := xormEngine.NewSession() + sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err diff --git a/models/error.go b/models/error.go new file mode 100644 index 0000000000..75c53245de --- /dev/null +++ b/models/error.go @@ -0,0 +1,552 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package models + +import ( + "fmt" + + 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. +type ErrUserOwnRepos struct { + UID int64 +} + +// IsErrUserOwnRepos checks if an error is a ErrUserOwnRepos. +func IsErrUserOwnRepos(err error) bool { + _, ok := err.(ErrUserOwnRepos) + return ok +} + +func (err ErrUserOwnRepos) Error() string { + return fmt.Sprintf("user still has ownership of repositories [uid: %d]", err.UID) +} + +// ErrUserHasOrgs represents a "UserHasOrgs" kind of error. +type ErrUserHasOrgs struct { + UID int64 +} + +// IsErrUserHasOrgs checks if an error is a ErrUserHasOrgs. +func IsErrUserHasOrgs(err error) bool { + _, ok := err.(ErrUserHasOrgs) + return ok +} + +func (err ErrUserHasOrgs) Error() string { + return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID) +} + +// ErrUserOwnPackages notifies that the user (still) owns the packages. +type ErrUserOwnPackages struct { + UID int64 +} + +// IsErrUserOwnPackages checks if an error is an ErrUserOwnPackages. +func IsErrUserOwnPackages(err error) bool { + _, ok := err.(ErrUserOwnPackages) + return ok +} + +func (err ErrUserOwnPackages) Error() string { + return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID) +} + +// ErrDeleteLastAdminUser represents a "DeleteLastAdminUser" kind of error. +type ErrDeleteLastAdminUser struct { + UID int64 +} + +// IsErrDeleteLastAdminUser checks if an error is a ErrDeleteLastAdminUser. +func IsErrDeleteLastAdminUser(err error) bool { + _, ok := err.(ErrDeleteLastAdminUser) + return ok +} + +func (err ErrDeleteLastAdminUser) Error() string { + return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID) +} + +// ErrNoPendingRepoTransfer is an error type for repositories without a pending +// transfer request +type ErrNoPendingRepoTransfer struct { + RepoID int64 +} + +func (err ErrNoPendingRepoTransfer) Error() string { + return fmt.Sprintf("repository doesn't have a pending transfer [repo_id: %d]", err.RepoID) +} + +// IsErrNoPendingTransfer is an error type when a repository has no pending +// transfers +func IsErrNoPendingTransfer(err error) bool { + _, ok := err.(ErrNoPendingRepoTransfer) + return ok +} + +func (err ErrNoPendingRepoTransfer) Unwrap() error { + return util.ErrNotExist +} + +// ErrRepoTransferInProgress represents the state of a repository that has an +// ongoing transfer +type ErrRepoTransferInProgress struct { + Uname string + Name string +} + +// IsErrRepoTransferInProgress checks if an error is a ErrRepoTransferInProgress. +func IsErrRepoTransferInProgress(err error) bool { + _, ok := err.(ErrRepoTransferInProgress) + return ok +} + +func (err ErrRepoTransferInProgress) Error() string { + return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name) +} + +func (err ErrRepoTransferInProgress) Unwrap() error { + return util.ErrAlreadyExist +} + +// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error. +type ErrInvalidCloneAddr struct { + Host string + IsURLError bool + IsInvalidPath bool + IsProtocolInvalid bool + IsPermissionDenied bool + LocalPath bool +} + +// IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr. +func IsErrInvalidCloneAddr(err error) bool { + _, ok := err.(*ErrInvalidCloneAddr) + return ok +} + +func (err *ErrInvalidCloneAddr) Error() string { + if err.IsInvalidPath { + return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided path is invalid", err.Host) + } + if err.IsProtocolInvalid { + return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url protocol is not allowed", err.Host) + } + if err.IsPermissionDenied { + return fmt.Sprintf("migration/cloning from '%s' is not allowed.", err.Host) + } + if err.IsURLError { + return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url is invalid", err.Host) + } + + return fmt.Sprintf("migration/cloning from '%s' is not allowed", err.Host) +} + +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 +} + +// IsErrInvalidTagName checks if an error is a ErrInvalidTagName. +func IsErrInvalidTagName(err error) bool { + _, ok := err.(ErrInvalidTagName) + return ok +} + +func (err ErrInvalidTagName) Error() string { + return fmt.Sprintf("release tag name is not valid [tag_name: %s]", err.TagName) +} + +func (err ErrInvalidTagName) Unwrap() error { + return util.ErrInvalidArgument +} + +// ErrProtectedTagName represents a "ProtectedTagName" kind of error. +type ErrProtectedTagName struct { + TagName string +} + +// IsErrProtectedTagName checks if an error is a ErrProtectedTagName. +func IsErrProtectedTagName(err error) bool { + _, ok := err.(ErrProtectedTagName) + return ok +} + +func (err ErrProtectedTagName) Error() string { + return fmt.Sprintf("release tag name is protected [tag_name: %s]", err.TagName) +} + +func (err ErrProtectedTagName) Unwrap() error { + return util.ErrPermissionDenied +} + +// ErrRepoFileAlreadyExists represents a "RepoFileAlreadyExist" kind of error. +type ErrRepoFileAlreadyExists struct { + Path string +} + +// IsErrRepoFileAlreadyExists checks if an error is a ErrRepoFileAlreadyExists. +func IsErrRepoFileAlreadyExists(err error) bool { + _, ok := err.(ErrRepoFileAlreadyExists) + return ok +} + +func (err ErrRepoFileAlreadyExists) Error() string { + return fmt.Sprintf("repository file already exists [path: %s]", err.Path) +} + +func (err ErrRepoFileAlreadyExists) Unwrap() error { + return util.ErrAlreadyExist +} + +// ErrRepoFileDoesNotExist represents a "RepoFileDoesNotExist" kind of error. +type ErrRepoFileDoesNotExist struct { + Path string + Name string +} + +// IsErrRepoFileDoesNotExist checks if an error is a ErrRepoDoesNotExist. +func IsErrRepoFileDoesNotExist(err error) bool { + _, ok := err.(ErrRepoFileDoesNotExist) + return ok +} + +func (err ErrRepoFileDoesNotExist) Error() string { + return fmt.Sprintf("repository file does not exist [path: %s]", err.Path) +} + +func (err ErrRepoFileDoesNotExist) Unwrap() error { + return util.ErrNotExist +} + +// ErrFilenameInvalid represents a "FilenameInvalid" kind of error. +type ErrFilenameInvalid struct { + Path string +} + +// IsErrFilenameInvalid checks if an error is an ErrFilenameInvalid. +func IsErrFilenameInvalid(err error) bool { + _, ok := err.(ErrFilenameInvalid) + return ok +} + +func (err ErrFilenameInvalid) Error() string { + return fmt.Sprintf("path contains a malformed path component [path: %s]", err.Path) +} + +func (err ErrFilenameInvalid) Unwrap() error { + return util.ErrInvalidArgument +} + +// ErrUserCannotCommit represents "UserCannotCommit" kind of error. +type ErrUserCannotCommit struct { + UserName string +} + +// IsErrUserCannotCommit checks if an error is an ErrUserCannotCommit. +func IsErrUserCannotCommit(err error) bool { + _, ok := err.(ErrUserCannotCommit) + return ok +} + +func (err ErrUserCannotCommit) Error() string { + return fmt.Sprintf("user cannot commit to repo [user: %s]", err.UserName) +} + +func (err ErrUserCannotCommit) Unwrap() error { + return util.ErrPermissionDenied +} + +// ErrFilePathInvalid represents a "FilePathInvalid" kind of error. +type ErrFilePathInvalid struct { + Message string + Path string + Name string + Type git.EntryMode +} + +// IsErrFilePathInvalid checks if an error is an ErrFilePathInvalid. +func IsErrFilePathInvalid(err error) bool { + _, ok := err.(ErrFilePathInvalid) + return ok +} + +func (err ErrFilePathInvalid) Error() string { + if err.Message != "" { + return err.Message + } + return fmt.Sprintf("path is invalid [path: %s]", err.Path) +} + +func (err ErrFilePathInvalid) Unwrap() error { + return util.ErrInvalidArgument +} + +// ErrFilePathProtected represents a "FilePathProtected" kind of error. +type ErrFilePathProtected struct { + Message string + Path string +} + +// IsErrFilePathProtected checks if an error is an ErrFilePathProtected. +func IsErrFilePathProtected(err error) bool { + _, ok := err.(ErrFilePathProtected) + return ok +} + +func (err ErrFilePathProtected) Error() string { + if err.Message != "" { + return err.Message + } + return fmt.Sprintf("path is protected and can not be changed [path: %s]", err.Path) +} + +func (err ErrFilePathProtected) Unwrap() error { + return util.ErrPermissionDenied +} + +// ErrDisallowedToMerge represents an error that a branch is protected and the current user is not allowed to modify it. +type ErrDisallowedToMerge struct { + Reason string +} + +// IsErrDisallowedToMerge checks if an error is an ErrDisallowedToMerge. +func IsErrDisallowedToMerge(err error) bool { + _, ok := err.(ErrDisallowedToMerge) + return ok +} + +func (err ErrDisallowedToMerge) Error() string { + return fmt.Sprintf("not allowed to merge [reason: %s]", err.Reason) +} + +func (err ErrDisallowedToMerge) Unwrap() error { + return util.ErrPermissionDenied +} + +// ErrTagAlreadyExists represents an error that tag with such name already exists. +type ErrTagAlreadyExists struct { + TagName string +} + +// IsErrTagAlreadyExists checks if an error is an ErrTagAlreadyExists. +func IsErrTagAlreadyExists(err error) bool { + _, ok := err.(ErrTagAlreadyExists) + return ok +} + +func (err ErrTagAlreadyExists) Error() string { + return fmt.Sprintf("tag already exists [name: %s]", err.TagName) +} + +func (err ErrTagAlreadyExists) Unwrap() error { + return util.ErrAlreadyExist +} + +// ErrSHADoesNotMatch represents a "SHADoesNotMatch" kind of error. +type ErrSHADoesNotMatch struct { + Path string + GivenSHA string + CurrentSHA string +} + +// IsErrSHADoesNotMatch checks if an error is a ErrSHADoesNotMatch. +func IsErrSHADoesNotMatch(err error) bool { + _, ok := err.(ErrSHADoesNotMatch) + return ok +} + +func (err ErrSHADoesNotMatch) Error() string { + return fmt.Sprintf("sha does not match [given: %s, expected: %s]", err.GivenSHA, err.CurrentSHA) +} + +// ErrSHANotFound represents a "SHADoesNotMatch" kind of error. +type ErrSHANotFound struct { + SHA string +} + +// IsErrSHANotFound checks if an error is a ErrSHANotFound. +func IsErrSHANotFound(err error) bool { + _, ok := err.(ErrSHANotFound) + return ok +} + +func (err ErrSHANotFound) Error() string { + return fmt.Sprintf("sha not found [%s]", err.SHA) +} + +func (err ErrSHANotFound) Unwrap() error { + return util.ErrNotExist +} + +// ErrCommitIDDoesNotMatch represents a "CommitIDDoesNotMatch" kind of error. +type ErrCommitIDDoesNotMatch struct { + GivenCommitID string + CurrentCommitID string +} + +// IsErrCommitIDDoesNotMatch checks if an error is a ErrCommitIDDoesNotMatch. +func IsErrCommitIDDoesNotMatch(err error) bool { + _, ok := err.(ErrCommitIDDoesNotMatch) + return ok +} + +func (err ErrCommitIDDoesNotMatch) Error() string { + return fmt.Sprintf("file CommitID does not match [given: %s, expected: %s]", err.GivenCommitID, err.CurrentCommitID) +} + +// ErrSHAOrCommitIDNotProvided represents a "SHAOrCommitIDNotProvided" kind of error. +type ErrSHAOrCommitIDNotProvided struct{} + +// IsErrSHAOrCommitIDNotProvided checks if an error is a ErrSHAOrCommitIDNotProvided. +func IsErrSHAOrCommitIDNotProvided(err error) bool { + _, ok := err.(ErrSHAOrCommitIDNotProvided) + return ok +} + +func (err ErrSHAOrCommitIDNotProvided) Error() string { + return "a SHA or commit ID must be proved when updating a file" +} + +// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy +type ErrInvalidMergeStyle struct { + ID int64 + Style repo_model.MergeStyle +} + +// IsErrInvalidMergeStyle checks if an error is a ErrInvalidMergeStyle. +func IsErrInvalidMergeStyle(err error) bool { + _, ok := err.(ErrInvalidMergeStyle) + return ok +} + +func (err ErrInvalidMergeStyle) Error() string { + return fmt.Sprintf("merge strategy is not allowed or is invalid [repo_id: %d, strategy: %s]", + err.ID, err.Style) +} + +func (err ErrInvalidMergeStyle) Unwrap() error { + return util.ErrInvalidArgument +} + +// ErrMergeConflicts represents an error if merging fails with a conflict +type ErrMergeConflicts struct { + Style repo_model.MergeStyle + StdOut string + StdErr string + Err error +} + +// IsErrMergeConflicts checks if an error is a ErrMergeConflicts. +func IsErrMergeConflicts(err error) bool { + _, ok := err.(ErrMergeConflicts) + return ok +} + +func (err ErrMergeConflicts) Error() string { + return fmt.Sprintf("Merge Conflict Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) +} + +// ErrMergeUnrelatedHistories represents an error if merging fails due to unrelated histories +type ErrMergeUnrelatedHistories struct { + Style repo_model.MergeStyle + StdOut string + StdErr string + Err error +} + +// IsErrMergeUnrelatedHistories checks if an error is a ErrMergeUnrelatedHistories. +func IsErrMergeUnrelatedHistories(err error) bool { + _, ok := err.(ErrMergeUnrelatedHistories) + return ok +} + +func (err ErrMergeUnrelatedHistories) Error() string { + return fmt.Sprintf("Merge UnrelatedHistories Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) +} + +// ErrMergeDivergingFastForwardOnly represents an error if a fast-forward-only merge fails because the branches diverge +type ErrMergeDivergingFastForwardOnly struct { + StdOut string + StdErr string + Err error +} + +// IsErrMergeDivergingFastForwardOnly checks if an error is a ErrMergeDivergingFastForwardOnly. +func IsErrMergeDivergingFastForwardOnly(err error) bool { + _, ok := err.(ErrMergeDivergingFastForwardOnly) + return ok +} + +func (err ErrMergeDivergingFastForwardOnly) Error() string { + return fmt.Sprintf("Merge DivergingFastForwardOnly Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) +} + +// ErrRebaseConflicts represents an error if rebase fails with a conflict +type ErrRebaseConflicts struct { + Style repo_model.MergeStyle + CommitSHA string + StdOut string + StdErr string + Err error +} + +// IsErrRebaseConflicts checks if an error is a ErrRebaseConflicts. +func IsErrRebaseConflicts(err error) bool { + _, ok := err.(ErrRebaseConflicts) + return ok +} + +func (err ErrRebaseConflicts) Error() string { + return fmt.Sprintf("Rebase Error: %v: Whilst Rebasing: %s\n%s\n%s", err.Err, err.CommitSHA, err.StdErr, err.StdOut) +} + +// ErrPullRequestHasMerged represents a "PullRequestHasMerged"-error +type ErrPullRequestHasMerged struct { + ID int64 + IssueID int64 + HeadRepoID int64 + BaseRepoID int64 + HeadBranch string + BaseBranch string +} + +// IsErrPullRequestHasMerged checks if an error is a ErrPullRequestHasMerged. +func IsErrPullRequestHasMerged(err error) bool { + _, ok := err.(ErrPullRequestHasMerged) + return ok +} + +// Error does pretty-printing :D +func (err ErrPullRequestHasMerged) Error() string { + return fmt.Sprintf("pull request has merged [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]", + err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch) +} diff --git a/models/fixtures/access.yml b/models/fixtures/access.yml index 596046e950..4171e31fef 100644 --- a/models/fixtures/access.yml +++ b/models/fixtures/access.yml @@ -171,9 +171,3 @@ user_id: 40 repo_id: 61 mode: 4 - -- - id: 30 - user_id: 40 - repo_id: 1 - mode: 2 diff --git a/models/fixtures/action_artifact.yml b/models/fixtures/action_artifact.yml index 485474108f..2c51c11ebd 100644 --- a/models/fixtures/action_artifact.yml +++ b/models/fixtures/action_artifact.yml @@ -69,21 +69,3 @@ created_unix: 1730330775 updated_unix: 1730330775 expired_unix: 1738106775 - -- - id: 23 - run_id: 793 - runner_id: 1 - repo_id: 2 - owner_id: 2 - 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/issue_pin.yml b/models/fixtures/issue_pin.yml deleted file mode 100644 index 14b7a72d84..0000000000 --- a/models/fixtures/issue_pin.yml +++ /dev/null @@ -1,6 +0,0 @@ -- - id: 1 - repo_id: 2 - issue_id: 4 - is_pull: false - pin_order: 1 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 552a78cbd2..bbb028eb7b 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -1694,6 +1694,19 @@ is_fsck_enabled: true close_issues_via_commit_in_any_branch: false +- + id: 59 + owner_id: 2 + owner_name: user2 + lower_name: test_commit_revert + name: test_commit_revert + default_branch: main + is_empty: false + is_archived: false + is_private: true + status: 0 + num_issues: 0 + - id: 60 owner_id: 40 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index 976a236011..b3bece5589 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -67,7 +67,7 @@ num_followers: 2 num_following: 1 num_stars: 2 - num_repos: 14 + num_repos: 15 num_teams: 0 num_members: 0 visibility: 0 diff --git a/models/fixtures/webhook.yml b/models/fixtures/webhook.yml index ebc4062b60..f62bae1f31 100644 --- a/models/fixtures/webhook.yml +++ b/models/fixtures/webhook.yml @@ -22,7 +22,6 @@ content_type: 1 # json events: '{"push_only":false,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":true}}' is_active: true - - id: 4 repo_id: 2 @@ -30,23 +29,3 @@ content_type: 1 # json events: '{"push_only":true,"branch_filter":"{master,feature*}"}' is_active: true - -- - id: 5 - repo_id: 0 - owner_id: 0 - url: www.example.com/url5 - content_type: 1 # json - events: '{"push_only":true,"branch_filter":"{master,feature*}"}' - is_active: true - is_system_webhook: true - -- - id: 6 - repo_id: 0 - owner_id: 0 - url: www.example.com/url6 - content_type: 1 # json - events: '{"push_only":true,"branch_filter":"{master,feature*}"}' - is_active: true - is_system_webhook: false diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 5432eea55e..0579a41209 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -496,11 +496,47 @@ type SignCommitWithStatuses struct { *asymkey_model.SignCommit } +// ParseCommitsWithStatus checks commits latest statuses and calculates its worst status state +func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.SignCommit, repo *repo_model.Repository) []*SignCommitWithStatuses { + newCommits := make([]*SignCommitWithStatuses, 0, len(oldCommits)) + + for _, c := range oldCommits { + commit := &SignCommitWithStatuses{ + SignCommit: c, + } + statuses, _, err := GetLatestCommitStatus(ctx, repo.ID, commit.ID.String(), db.ListOptions{}) + if err != nil { + log.Error("GetLatestCommitStatus: %v", err) + } else { + commit.Statuses = statuses + commit.Status = CalcCommitStatus(statuses) + } + + newCommits = append(newCommits, commit) + } + return newCommits +} + // hashCommitStatusContext hash context func hashCommitStatusContext(context string) string { return fmt.Sprintf("%x", sha1.Sum([]byte(context))) } +// ConvertFromGitCommit converts git commits into SignCommitWithStatuses +func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses { + return ParseCommitsWithStatus(ctx, + asymkey_model.ParseCommitsWithSignature( + ctx, + user_model.ValidateCommitsWithEmails(ctx, commits), + repo.GetTrustModel(), + func(user *user_model.User) (bool, error) { + return repo_model.IsOwnerMemberCollaborator(ctx, repo, user.ID) + }, + ), + repo, + ) +} + // CommitStatusesHideActionsURL hide Gitea Actions urls func CommitStatusesHideActionsURL(ctx context.Context, statuses []*CommitStatus) { idToRepos := make(map[int64]*repo_model.Repository) diff --git a/models/issues/comment.go b/models/issues/comment.go index ab9b2042f3..729fc1b9e5 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -19,6 +19,8 @@ import ( 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/gitrepo" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/references" @@ -110,8 +112,8 @@ const ( CommentTypePRScheduledToAutoMerge // 34 pr was scheduled to auto merge when checks succeed CommentTypePRUnScheduledToAutoMerge // 35 pr was un scheduled to auto merge when checks succeed - CommentTypePin // 36 pin Issue/PullRequest - CommentTypeUnpin // 37 unpin Issue/PullRequest + CommentTypePin // 36 pin Issue + CommentTypeUnpin // 37 unpin Issue CommentTypeChangeTimeEstimate // 38 Change time estimate ) @@ -604,26 +606,26 @@ func (c *Comment) LoadAttachments(ctx context.Context) error { return nil } -// UpdateCommentAttachments update attachments by UUIDs for the comment -func UpdateCommentAttachments(ctx context.Context, c *Comment, uuids []string) error { - if len(uuids) == 0 { - return nil +// UpdateAttachments update attachments by UUIDs for the comment +func (c *Comment) UpdateAttachments(ctx context.Context, uuids []string) error { + ctx, committer, err := db.TxContext(ctx) + if err != nil { + return err } - return db.WithTx(ctx, func(ctx context.Context) error { - attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids) - if err != nil { - return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", uuids, err) + defer committer.Close() + + attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids) + if err != nil { + return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", uuids, err) + } + for i := 0; i < len(attachments); i++ { + attachments[i].IssueID = c.IssueID + attachments[i].CommentID = c.ID + if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil { + return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err) } - for i := 0; i < len(attachments); i++ { - attachments[i].IssueID = c.IssueID - attachments[i].CommentID = c.ID - if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil { - return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err) - } - } - c.Attachments = attachments - return nil - }) + } + return committer.Commit() } // LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees @@ -772,6 +774,41 @@ func (c *Comment) CodeCommentLink(ctx context.Context) string { return fmt.Sprintf("%s/files#%s", c.Issue.Link(), c.HashTag()) } +// LoadPushCommits Load push commits +func (c *Comment) LoadPushCommits(ctx context.Context) (err error) { + if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullRequestPush { + return nil + } + + var data PushActionContent + + err = json.Unmarshal([]byte(c.Content), &data) + if err != nil { + return err + } + + c.IsForcePush = data.IsForcePush + + if c.IsForcePush { + if len(data.CommitIDs) != 2 { + return nil + } + c.OldCommit = data.CommitIDs[0] + c.NewCommit = data.CommitIDs[1] + } else { + gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, c.Issue.Repo) + if err != nil { + return err + } + defer closer.Close() + + c.Commits = git_model.ConvertFromGitCommit(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo) + c.CommitsNum = int64(len(c.Commits)) + } + + return err +} + // CreateComment creates comment with context func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) { ctx, committer, err := db.TxContext(ctx) @@ -855,7 +892,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment // Check comment type. switch opts.Type { case CommentTypeCode: - if err = UpdateCommentAttachments(ctx, comment, opts.Attachments); err != nil { + if err = updateAttachments(ctx, opts, comment); err != nil { return err } if comment.ReviewID != 0 { @@ -875,7 +912,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment } fallthrough case CommentTypeReview: - if err = UpdateCommentAttachments(ctx, comment, opts.Attachments); err != nil { + if err = updateAttachments(ctx, opts, comment); err != nil { return err } case CommentTypeReopen, CommentTypeClose: @@ -887,6 +924,23 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment return UpdateIssueCols(ctx, opts.Issue, "updated_unix") } +func updateAttachments(ctx context.Context, opts *CreateCommentOptions, comment *Comment) error { + attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, opts.Attachments) + if err != nil { + return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", opts.Attachments, err) + } + for i := range attachments { + attachments[i].IssueID = opts.Issue.ID + attachments[i].CommentID = comment.ID + // No assign value could be 0, so ignore AllCols(). + if _, err = db.GetEngine(ctx).ID(attachments[i].ID).Update(attachments[i]); err != nil { + return fmt.Errorf("update attachment [%d]: %w", attachments[i].ID, err) + } + } + comment.Attachments = attachments + return nil +} + func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Issue, newDeadlineUnix timeutil.TimeStamp) (*Comment, error) { var content string var commentType CommentType diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go index c483ada75a..61ac1c8f56 100644 --- a/models/issues/comment_list.go +++ b/models/issues/comment_list.go @@ -26,14 +26,14 @@ func (comments CommentList) LoadPosters(ctx context.Context) error { return c.PosterID, c.Poster == nil && c.PosterID > 0 }) - posterMaps, err := user_model.GetUsersMapByIDs(ctx, posterIDs) + posterMaps, err := getPostersByIDs(ctx, posterIDs) if err != nil { return err } for _, comment := range comments { if comment.Poster == nil { - comment.Poster = user_model.GetPossibleUserFromMap(comment.PosterID, posterMaps) + comment.Poster = getPoster(comment.PosterID, posterMaps) } } return nil @@ -41,7 +41,7 @@ func (comments CommentList) LoadPosters(ctx context.Context) error { func (comments CommentList) getLabelIDs() []int64 { return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { - return comment.LabelID, comment.LabelID > 0 && comment.Label == nil + return comment.LabelID, comment.LabelID > 0 }) } @@ -51,9 +51,6 @@ func (comments CommentList) loadLabels(ctx context.Context) error { } labelIDs := comments.getLabelIDs() - if len(labelIDs) == 0 { - return nil - } commentLabels := make(map[int64]*Label, len(labelIDs)) left := len(labelIDs) for left > 0 { @@ -121,8 +118,8 @@ func (comments CommentList) loadMilestones(ctx context.Context) error { milestoneIDs = milestoneIDs[limit:] } - for _, comment := range comments { - comment.Milestone = milestoneMaps[comment.MilestoneID] + for _, issue := range comments { + issue.Milestone = milestoneMaps[issue.MilestoneID] } return nil } @@ -178,9 +175,6 @@ func (comments CommentList) loadAssignees(ctx context.Context) error { } assigneeIDs := comments.getAssigneeIDs() - if len(assigneeIDs) == 0 { - return nil - } assignees := make(map[int64]*user_model.User, len(assigneeIDs)) left := len(assigneeIDs) for left > 0 { @@ -307,9 +301,6 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error { e := db.GetEngine(ctx) issueIDs := comments.getDependentIssueIDs() - if len(issueIDs) == 0 { - return nil - } issues := make(map[int64]*Issue, len(issueIDs)) left := len(issueIDs) for left > 0 { @@ -436,9 +427,6 @@ func (comments CommentList) loadReviews(ctx context.Context) error { } reviewIDs := comments.getReviewIDs() - if len(reviewIDs) == 0 { - return nil - } reviews := make(map[int64]*Review, len(reviewIDs)) if err := db.GetEngine(ctx).In("id", reviewIDs).Find(&reviews); err != nil { return err diff --git a/models/issues/comment_test.go b/models/issues/comment_test.go index ae0bc3ce17..cb31a21f92 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -45,24 +45,6 @@ func TestCreateComment(t *testing.T) { unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix)) } -func Test_UpdateCommentAttachment(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 1}) - attachment := repo_model.Attachment{ - Name: "test.txt", - } - assert.NoError(t, db.Insert(db.DefaultContext, &attachment)) - - err := issues_model.UpdateCommentAttachments(db.DefaultContext, comment, []string{attachment.UUID}) - assert.NoError(t, err) - - attachment2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: attachment.ID}) - assert.EqualValues(t, attachment.Name, attachment2.Name) - assert.EqualValues(t, comment.ID, attachment2.CommentID) - assert.EqualValues(t, comment.IssueID, attachment2.IssueID) -} - func TestFetchCodeComments(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/models/issues/dependency_test.go b/models/issues/dependency_test.go index 67418039de..6eed483cc9 100644 --- a/models/issues/dependency_test.go +++ b/models/issues/dependency_test.go @@ -49,13 +49,9 @@ func TestCreateIssueDependency(t *testing.T) { assert.False(t, left) // Close #2 and check again - _, err = issues_model.CloseIssue(db.DefaultContext, issue2, user1) + _, err = issues_model.ChangeIssueStatus(db.DefaultContext, issue2, user1, true) assert.NoError(t, err) - issue2Closed, err := issues_model.GetIssueByID(db.DefaultContext, 2) - assert.NoError(t, err) - assert.True(t, issue2Closed.IsClosed) - left, err = issues_model.IssueNoDependenciesLeft(db.DefaultContext, issue1) assert.NoError(t, err) assert.True(t, left) @@ -63,11 +59,4 @@ func TestCreateIssueDependency(t *testing.T) { // Test removing the dependency err = issues_model.RemoveIssueDependency(db.DefaultContext, user1, issue1, issue2, issues_model.DependencyTypeBlockedBy) assert.NoError(t, err) - - _, err = issues_model.ReopenIssue(db.DefaultContext, issue2, user1) - assert.NoError(t, err) - - issue2Reopened, err := issues_model.GetIssueByID(db.DefaultContext, 2) - assert.NoError(t, err) - assert.False(t, issue2Reopened.IsClosed) } diff --git a/models/issues/issue.go b/models/issues/issue.go index 7e72bb776c..f4b575d804 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -47,6 +47,23 @@ func (err ErrIssueNotExist) Unwrap() error { return util.ErrNotExist } +// ErrIssueIsClosed represents a "IssueIsClosed" kind of error. +type ErrIssueIsClosed struct { + ID int64 + RepoID int64 + Index int64 +} + +// IsErrIssueIsClosed checks if an error is a ErrIssueNotExist. +func IsErrIssueIsClosed(err error) bool { + _, ok := err.(ErrIssueIsClosed) + return ok +} + +func (err ErrIssueIsClosed) Error() string { + return fmt.Sprintf("issue is closed [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index) +} + // ErrNewIssueInsert is used when the INSERT statement in newIssue fails type ErrNewIssueInsert struct { OriginalError error @@ -62,6 +79,22 @@ func (err ErrNewIssueInsert) Error() string { return err.OriginalError.Error() } +// ErrIssueWasClosed is used when close a closed issue +type ErrIssueWasClosed struct { + ID int64 + Index int64 +} + +// IsErrIssueWasClosed checks if an error is a ErrIssueWasClosed. +func IsErrIssueWasClosed(err error) bool { + _, ok := err.(ErrIssueWasClosed) + return ok +} + +func (err ErrIssueWasClosed) Error() string { + return fmt.Sprintf("Issue [%d] %d was already closed", err.ID, err.Index) +} + var ErrIssueAlreadyChanged = util.NewInvalidArgumentErrorf("the issue is already changed") // Issue represents an issue or pull request of repository. @@ -97,7 +130,7 @@ type Issue struct { // TODO: RemoveIssueRef: see "repo/issue/branch_selector_field.tmpl" Ref string - PinOrder int `xorm:"-"` // 0 means not loaded, -1 means loaded but not pinned + PinOrder int `xorm:"DEFAULT 0"` DeadlineUnix timeutil.TimeStamp `xorm:"INDEX"` @@ -239,9 +272,6 @@ func (issue *Issue) loadCommentsByType(ctx context.Context, tp CommentType) (err IssueID: issue.ID, Type: tp, }) - for _, comment := range issue.Comments { - comment.Issue = issue - } return err } @@ -291,23 +321,6 @@ func (issue *Issue) LoadMilestone(ctx context.Context) (err error) { return nil } -func (issue *Issue) LoadPinOrder(ctx context.Context) error { - if issue.PinOrder != 0 { - return nil - } - issuePin, err := GetIssuePin(ctx, issue) - if err != nil && !db.IsErrNotExist(err) { - return err - } - - if issuePin != nil { - issue.PinOrder = issuePin.PinOrder - } else { - issue.PinOrder = -1 - } - return nil -} - // LoadAttributes loads the attribute of this issue. func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { if err = issue.LoadRepo(ctx); err != nil { @@ -347,10 +360,6 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { return err } - if err = issue.LoadPinOrder(ctx); err != nil { - return err - } - if err = issue.Comments.LoadAttributes(ctx); err != nil { return err } @@ -363,14 +372,6 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { return issue.loadReactions(ctx) } -// IsPinned returns if a Issue is pinned -func (issue *Issue) IsPinned() bool { - if issue.PinOrder == 0 { - setting.PanicInDevOrTesting("issue's pinorder has not been loaded") - } - return issue.PinOrder > 0 -} - func (issue *Issue) ResetAttributesLoaded() { issue.isLabelsLoaded = false issue.isMilestoneLoaded = false @@ -749,6 +750,190 @@ func (issue *Issue) HasOriginalAuthor() bool { return issue.OriginalAuthor != "" && issue.OriginalAuthorID != 0 } +var ErrIssueMaxPinReached = util.NewInvalidArgumentErrorf("the max number of pinned issues has been readched") + +// IsPinned returns if a Issue is pinned +func (issue *Issue) IsPinned() bool { + return issue.PinOrder != 0 +} + +// Pin pins a Issue +func (issue *Issue) Pin(ctx context.Context, user *user_model.User) error { + // If the Issue is already pinned, we don't need to pin it twice + if issue.IsPinned() { + return nil + } + + var maxPin int + _, err := db.GetEngine(ctx).SQL("SELECT MAX(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ?", issue.RepoID, issue.IsPull).Get(&maxPin) + if err != nil { + return err + } + + // Check if the maximum allowed Pins reached + if maxPin >= setting.Repository.Issue.MaxPinned { + return ErrIssueMaxPinReached + } + + _, err = db.GetEngine(ctx).Table("issue"). + Where("id = ?", issue.ID). + Update(map[string]any{ + "pin_order": maxPin + 1, + }) + if err != nil { + return err + } + + // Add the pin event to the history + opts := &CreateCommentOptions{ + Type: CommentTypePin, + Doer: user, + Repo: issue.Repo, + Issue: issue, + } + if _, err = CreateComment(ctx, opts); err != nil { + return err + } + + return nil +} + +// UnpinIssue unpins a Issue +func (issue *Issue) Unpin(ctx context.Context, user *user_model.User) error { + // If the Issue is not pinned, we don't need to unpin it + if !issue.IsPinned() { + return nil + } + + // This sets the Pin for all Issues that come after the unpined Issue to the correct value + _, err := db.GetEngine(ctx).Exec("UPDATE issue SET pin_order = pin_order - 1 WHERE repo_id = ? AND is_pull = ? AND pin_order > ?", issue.RepoID, issue.IsPull, issue.PinOrder) + if err != nil { + return err + } + + _, err = db.GetEngine(ctx).Table("issue"). + Where("id = ?", issue.ID). + Update(map[string]any{ + "pin_order": 0, + }) + if err != nil { + return err + } + + // Add the unpin event to the history + opts := &CreateCommentOptions{ + Type: CommentTypeUnpin, + Doer: user, + Repo: issue.Repo, + Issue: issue, + } + if _, err = CreateComment(ctx, opts); err != nil { + return err + } + + return nil +} + +// PinOrUnpin pins or unpins a Issue +func (issue *Issue) PinOrUnpin(ctx context.Context, user *user_model.User) error { + if !issue.IsPinned() { + return issue.Pin(ctx, user) + } + + return issue.Unpin(ctx, user) +} + +// MovePin moves a Pinned Issue to a new Position +func (issue *Issue) MovePin(ctx context.Context, newPosition int) error { + // If the Issue is not pinned, we can't move them + if !issue.IsPinned() { + return nil + } + + if newPosition < 1 { + return fmt.Errorf("The Position can't be lower than 1") + } + + dbctx, committer, err := db.TxContext(ctx) + if err != nil { + return err + } + defer committer.Close() + + var maxPin int + _, err = db.GetEngine(dbctx).SQL("SELECT MAX(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ?", issue.RepoID, issue.IsPull).Get(&maxPin) + if err != nil { + return err + } + + // If the new Position bigger than the current Maximum, set it to the Maximum + if newPosition > maxPin+1 { + newPosition = maxPin + 1 + } + + // Lower the Position of all Pinned Issue that came after the current Position + _, err = db.GetEngine(dbctx).Exec("UPDATE issue SET pin_order = pin_order - 1 WHERE repo_id = ? AND is_pull = ? AND pin_order > ?", issue.RepoID, issue.IsPull, issue.PinOrder) + if err != nil { + return err + } + + // Higher the Position of all Pinned Issues that comes after the new Position + _, err = db.GetEngine(dbctx).Exec("UPDATE issue SET pin_order = pin_order + 1 WHERE repo_id = ? AND is_pull = ? AND pin_order >= ?", issue.RepoID, issue.IsPull, newPosition) + if err != nil { + return err + } + + _, err = db.GetEngine(dbctx).Table("issue"). + Where("id = ?", issue.ID). + Update(map[string]any{ + "pin_order": newPosition, + }) + if err != nil { + return err + } + + return committer.Commit() +} + +// GetPinnedIssues returns the pinned Issues for the given Repo and type +func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) (IssueList, error) { + issues := make(IssueList, 0) + + err := db.GetEngine(ctx). + Table("issue"). + Where("repo_id = ?", repoID). + And("is_pull = ?", isPull). + And("pin_order > 0"). + OrderBy("pin_order"). + Find(&issues) + if err != nil { + return nil, err + } + + err = issues.LoadAttributes(ctx) + if err != nil { + return nil, err + } + + return issues, nil +} + +// IsNewPinAllowed returns if a new Issue or Pull request can be pinned +func IsNewPinAllowed(ctx context.Context, repoID int64, isPull bool) (bool, error) { + var maxPin int + _, err := db.GetEngine(ctx).SQL("SELECT COUNT(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ? AND pin_order > 0", repoID, isPull).Get(&maxPin) + if err != nil { + return false, err + } + + return maxPin < setting.Repository.Issue.MaxPinned, nil +} + +// IsErrIssueMaxPinReached returns if the error is, that the User can't pin more Issues +func IsErrIssueMaxPinReached(err error) bool { + return err == ErrIssueMaxPinReached +} + // InsertIssues insert issues to database func InsertIssues(ctx context.Context, issues ...*Issue) error { ctx, committer, err := db.TxContext(ctx) diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 6c74b533b3..22a4548adc 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -81,19 +81,53 @@ func (issues IssueList) LoadPosters(ctx context.Context) error { return issue.PosterID, issue.Poster == nil && issue.PosterID > 0 }) - posterMaps, err := user_model.GetUsersMapByIDs(ctx, posterIDs) + posterMaps, err := getPostersByIDs(ctx, posterIDs) if err != nil { return err } for _, issue := range issues { if issue.Poster == nil { - issue.Poster = user_model.GetPossibleUserFromMap(issue.PosterID, posterMaps) + issue.Poster = getPoster(issue.PosterID, posterMaps) } } return nil } +func getPostersByIDs(ctx context.Context, posterIDs []int64) (map[int64]*user_model.User, error) { + posterMaps := make(map[int64]*user_model.User, len(posterIDs)) + left := len(posterIDs) + for left > 0 { + limit := db.DefaultMaxInSize + if left < limit { + limit = left + } + err := db.GetEngine(ctx). + In("id", posterIDs[:limit]). + Find(&posterMaps) + if err != nil { + return nil, err + } + left -= limit + posterIDs = posterIDs[limit:] + } + return posterMaps, nil +} + +func getPoster(posterID int64, posterMaps map[int64]*user_model.User) *user_model.User { + if posterID == user_model.ActionsUserID { + return user_model.NewActionsUser() + } + if posterID <= 0 { + return nil + } + poster, ok := posterMaps[posterID] + if !ok { + return user_model.NewGhostUser() + } + return poster +} + func (issues IssueList) getIssueIDs() []int64 { ids := make([]int64, 0, len(issues)) for _, issue := range issues { @@ -506,39 +540,6 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) { return nil } -func (issues IssueList) LoadPinOrder(ctx context.Context) error { - if len(issues) == 0 { - return nil - } - - issueIDs := container.FilterSlice(issues, func(issue *Issue) (int64, bool) { - return issue.ID, issue.PinOrder == 0 - }) - if len(issueIDs) == 0 { - return nil - } - issuePins, err := GetIssuePinsByIssueIDs(ctx, issueIDs) - if err != nil { - return err - } - - for _, issue := range issues { - if issue.PinOrder != 0 { - continue - } - for _, pin := range issuePins { - if pin.IssueID == issue.ID { - issue.PinOrder = pin.PinOrder - break - } - } - if issue.PinOrder == 0 { - issue.PinOrder = -1 - } - } - return nil -} - // loadAttributes loads all attributes, expect for attachments and comments func (issues IssueList) LoadAttributes(ctx context.Context) error { if _, err := issues.LoadRepositories(ctx); err != nil { diff --git a/models/issues/issue_pin.go b/models/issues/issue_pin.go deleted file mode 100644 index ae6195b05d..0000000000 --- a/models/issues/issue_pin.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2025 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package issues - -import ( - "context" - "errors" - "sort" - - "code.gitea.io/gitea/models/db" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" -) - -type IssuePin struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"UNIQUE(s) NOT NULL"` - IssueID int64 `xorm:"UNIQUE(s) NOT NULL"` - IsPull bool `xorm:"NOT NULL"` - PinOrder int `xorm:"DEFAULT 0"` -} - -var ErrIssueMaxPinReached = util.NewInvalidArgumentErrorf("the max number of pinned issues has been readched") - -// IsErrIssueMaxPinReached returns if the error is, that the User can't pin more Issues -func IsErrIssueMaxPinReached(err error) bool { - return err == ErrIssueMaxPinReached -} - -func init() { - db.RegisterModel(new(IssuePin)) -} - -func GetIssuePin(ctx context.Context, issue *Issue) (*IssuePin, error) { - pin := new(IssuePin) - has, err := db.GetEngine(ctx). - Where("repo_id = ?", issue.RepoID). - And("issue_id = ?", issue.ID).Get(pin) - if err != nil { - return nil, err - } else if !has { - return nil, db.ErrNotExist{ - Resource: "IssuePin", - ID: issue.ID, - } - } - return pin, nil -} - -func GetIssuePinsByIssueIDs(ctx context.Context, issueIDs []int64) ([]IssuePin, error) { - var pins []IssuePin - if err := db.GetEngine(ctx).In("issue_id", issueIDs).Find(&pins); err != nil { - return nil, err - } - return pins, nil -} - -// Pin pins a Issue -func PinIssue(ctx context.Context, issue *Issue, user *user_model.User) error { - return db.WithTx(ctx, func(ctx context.Context) error { - pinnedIssuesNum, err := getPinnedIssuesNum(ctx, issue.RepoID, issue.IsPull) - if err != nil { - return err - } - - // Check if the maximum allowed Pins reached - if pinnedIssuesNum >= setting.Repository.Issue.MaxPinned { - return ErrIssueMaxPinReached - } - - pinnedIssuesMaxPinOrder, err := getPinnedIssuesMaxPinOrder(ctx, issue.RepoID, issue.IsPull) - if err != nil { - return err - } - - if _, err = db.GetEngine(ctx).Insert(&IssuePin{ - RepoID: issue.RepoID, - IssueID: issue.ID, - IsPull: issue.IsPull, - PinOrder: pinnedIssuesMaxPinOrder + 1, - }); err != nil { - return err - } - - // Add the pin event to the history - _, err = CreateComment(ctx, &CreateCommentOptions{ - Type: CommentTypePin, - Doer: user, - Repo: issue.Repo, - Issue: issue, - }) - return err - }) -} - -// UnpinIssue unpins a Issue -func UnpinIssue(ctx context.Context, issue *Issue, user *user_model.User) error { - return db.WithTx(ctx, func(ctx context.Context) error { - // This sets the Pin for all Issues that come after the unpined Issue to the correct value - cnt, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Delete(new(IssuePin)) - if err != nil { - return err - } - if cnt == 0 { - return nil - } - - // Add the unpin event to the history - _, err = CreateComment(ctx, &CreateCommentOptions{ - Type: CommentTypeUnpin, - Doer: user, - Repo: issue.Repo, - Issue: issue, - }) - return err - }) -} - -func getPinnedIssuesNum(ctx context.Context, repoID int64, isPull bool) (int, error) { - var pinnedIssuesNum int - _, err := db.GetEngine(ctx).SQL("SELECT count(pin_order) FROM issue_pin WHERE repo_id = ? AND is_pull = ?", repoID, isPull).Get(&pinnedIssuesNum) - return pinnedIssuesNum, err -} - -func getPinnedIssuesMaxPinOrder(ctx context.Context, repoID int64, isPull bool) (int, error) { - var maxPinnedIssuesMaxPinOrder int - _, err := db.GetEngine(ctx).SQL("SELECT max(pin_order) FROM issue_pin WHERE repo_id = ? AND is_pull = ?", repoID, isPull).Get(&maxPinnedIssuesMaxPinOrder) - return maxPinnedIssuesMaxPinOrder, err -} - -// MovePin moves a Pinned Issue to a new Position -func MovePin(ctx context.Context, issue *Issue, newPosition int) error { - if newPosition < 1 { - return errors.New("The Position can't be lower than 1") - } - - issuePin, err := GetIssuePin(ctx, issue) - if err != nil { - return err - } - if issuePin.PinOrder == newPosition { - return nil - } - - return db.WithTx(ctx, func(ctx context.Context) error { - if issuePin.PinOrder > newPosition { // move the issue to a lower position - _, err = db.GetEngine(ctx).Exec("UPDATE issue_pin SET pin_order = pin_order + 1 WHERE repo_id = ? AND is_pull = ? AND pin_order >= ? AND pin_order < ?", issue.RepoID, issue.IsPull, newPosition, issuePin.PinOrder) - } else { // move the issue to a higher position - // Lower the Position of all Pinned Issue that came after the current Position - _, err = db.GetEngine(ctx).Exec("UPDATE issue_pin SET pin_order = pin_order - 1 WHERE repo_id = ? AND is_pull = ? AND pin_order > ? AND pin_order <= ?", issue.RepoID, issue.IsPull, issuePin.PinOrder, newPosition) - } - if err != nil { - return err - } - - _, err = db.GetEngine(ctx). - Table("issue_pin"). - Where("id = ?", issuePin.ID). - Update(map[string]any{ - "pin_order": newPosition, - }) - return err - }) -} - -func GetPinnedIssueIDs(ctx context.Context, repoID int64, isPull bool) ([]int64, error) { - var issuePins []IssuePin - if err := db.GetEngine(ctx). - Table("issue_pin"). - Where("repo_id = ?", repoID). - And("is_pull = ?", isPull). - Find(&issuePins); err != nil { - return nil, err - } - - sort.Slice(issuePins, func(i, j int) bool { - return issuePins[i].PinOrder < issuePins[j].PinOrder - }) - - var ids []int64 - for _, pin := range issuePins { - ids = append(ids, pin.IssueID) - } - return ids, nil -} - -func GetIssuePinsByRepoID(ctx context.Context, repoID int64, isPull bool) ([]*IssuePin, error) { - var pins []*IssuePin - if err := db.GetEngine(ctx).Where("repo_id = ? AND is_pull = ?", repoID, isPull).Find(&pins); err != nil { - return nil, err - } - return pins, nil -} - -// GetPinnedIssues returns the pinned Issues for the given Repo and type -func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) (IssueList, error) { - issuePins, err := GetIssuePinsByRepoID(ctx, repoID, isPull) - if err != nil { - return nil, err - } - if len(issuePins) == 0 { - return IssueList{}, nil - } - ids := make([]int64, 0, len(issuePins)) - for _, pin := range issuePins { - ids = append(ids, pin.IssueID) - } - - issues := make(IssueList, 0, len(ids)) - if err := db.GetEngine(ctx).In("id", ids).Find(&issues); err != nil { - return nil, err - } - for _, issue := range issues { - for _, pin := range issuePins { - if pin.IssueID == issue.ID { - issue.PinOrder = pin.PinOrder - break - } - } - if (!setting.IsProd || setting.IsInTesting) && issue.PinOrder == 0 { - panic("It should not happen that a pinned Issue has no PinOrder") - } - } - sort.Slice(issues, func(i, j int) bool { - return issues[i].PinOrder < issues[j].PinOrder - }) - - if err = issues.LoadAttributes(ctx); err != nil { - return nil, err - } - - return issues, nil -} - -// IsNewPinAllowed returns if a new Issue or Pull request can be pinned -func IsNewPinAllowed(ctx context.Context, repoID int64, isPull bool) (bool, error) { - var maxPin int - _, err := db.GetEngine(ctx).SQL("SELECT COUNT(pin_order) FROM issue_pin WHERE repo_id = ? AND is_pull = ?", repoID, isPull).Get(&maxPin) - if err != nil { - return false, err - } - - return maxPin < setting.Repository.Issue.MaxPinned, nil -} diff --git a/models/issues/issue_stats.go b/models/issues/issue_stats.go index 50409fbbd8..9ef9347a16 100644 --- a/models/issues/issue_stats.go +++ b/models/issues/issue_stats.go @@ -107,7 +107,7 @@ func GetIssueStats(ctx context.Context, opts *IssuesOptions) (*IssueStats, error accum.YourRepositoriesCount += stats.YourRepositoriesCount accum.AssignCount += stats.AssignCount accum.CreateCount += stats.CreateCount - accum.MentionCount += stats.MentionCount + accum.OpenCount += stats.MentionCount accum.ReviewRequestedCount += stats.ReviewRequestedCount accum.ReviewedCount += stats.ReviewedCount i = chunk diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index 3f76a81bb6..dbbb1e4179 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -4,6 +4,7 @@ package issues_test import ( + "context" "fmt" "sort" "sync" @@ -325,7 +326,7 @@ func TestCorrectIssueStats(t *testing.T) { wg.Wait() // Now we will get all issueID's that match the "Bugs are nasty" query. - issues, err := issues_model.Issues(t.Context(), &issues_model.IssuesOptions{ + issues, err := issues_model.Issues(context.TODO(), &issues_model.IssuesOptions{ Paginator: &db.ListOptions{ PageSize: issueAmount, }, diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 7b3fe04aa5..5b929c9115 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -28,40 +28,38 @@ import ( // UpdateIssueCols updates cols of issue func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error { - _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue) - return err + if _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue); err != nil { + return err + } + return nil } -// ErrIssueIsClosed is used when close a closed issue -type ErrIssueIsClosed struct { - ID int64 - RepoID int64 - Index int64 - IsPull bool -} +func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed, isMergePull bool) (*Comment, error) { + // Reload the issue + currentIssue, err := GetIssueByID(ctx, issue.ID) + if err != nil { + return nil, err + } -// IsErrIssueIsClosed checks if an error is a ErrIssueIsClosed. -func IsErrIssueIsClosed(err error) bool { - _, ok := err.(ErrIssueIsClosed) - return ok -} - -func (err ErrIssueIsClosed) Error() string { - return fmt.Sprintf("%s [id: %d, repo_id: %d, index: %d] is already closed", util.Iif(err.IsPull, "Pull Request", "Issue"), err.ID, err.RepoID, err.Index) -} - -func SetIssueAsClosed(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) { - if issue.IsClosed { - return nil, ErrIssueIsClosed{ - ID: issue.ID, - RepoID: issue.RepoID, - Index: issue.Index, - IsPull: issue.IsPull, + // Nothing should be performed if current status is same as target status + if currentIssue.IsClosed == isClosed { + if !issue.IsPull { + return nil, ErrIssueWasClosed{ + ID: issue.ID, + } + } + return nil, ErrPullWasClosed{ + ID: issue.ID, } } + issue.IsClosed = isClosed + return doChangeIssueStatus(ctx, issue, doer, isMergePull) +} + +func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) { // Check for open dependencies - if issue.Repo.IsDependenciesEnabled(ctx) { + if issue.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) { // only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies noDeps, err := IssueNoDependenciesLeft(ctx, issue) if err != nil { @@ -73,63 +71,16 @@ func SetIssueAsClosed(ctx context.Context, issue *Issue, doer *user_model.User, } } - issue.IsClosed = true - issue.ClosedUnix = timeutil.TimeStampNow() + if issue.IsClosed { + issue.ClosedUnix = timeutil.TimeStampNow() + } else { + issue.ClosedUnix = 0 + } - if cnt, err := db.GetEngine(ctx).ID(issue.ID).Cols("is_closed", "closed_unix"). - Where("is_closed = ?", false). - Update(issue); err != nil { + if err := UpdateIssueCols(ctx, issue, "is_closed", "closed_unix"); err != nil { return nil, err - } else if cnt != 1 { - return nil, ErrIssueAlreadyChanged } - return updateIssueNumbers(ctx, issue, doer, util.Iif(isMergePull, CommentTypeMergePull, CommentTypeClose)) -} - -// ErrIssueIsOpen is used when reopen an opened issue -type ErrIssueIsOpen struct { - ID int64 - RepoID int64 - IsPull bool - Index int64 -} - -// IsErrIssueIsOpen checks if an error is a ErrIssueIsOpen. -func IsErrIssueIsOpen(err error) bool { - _, ok := err.(ErrIssueIsOpen) - return ok -} - -func (err ErrIssueIsOpen) Error() string { - return fmt.Sprintf("%s [id: %d, repo_id: %d, index: %d] is already open", util.Iif(err.IsPull, "Pull Request", "Issue"), err.ID, err.RepoID, err.Index) -} - -func setIssueAsReopen(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) { - if !issue.IsClosed { - return nil, ErrIssueIsOpen{ - ID: issue.ID, - RepoID: issue.RepoID, - Index: issue.Index, - IsPull: issue.IsPull, - } - } - - issue.IsClosed = false - issue.ClosedUnix = 0 - - if cnt, err := db.GetEngine(ctx).ID(issue.ID).Cols("is_closed", "closed_unix"). - Where("is_closed = ?", true). - Update(issue); err != nil { - return nil, err - } else if cnt != 1 { - return nil, ErrIssueAlreadyChanged - } - - return updateIssueNumbers(ctx, issue, doer, CommentTypeReopen) -} - -func updateIssueNumbers(ctx context.Context, issue *Issue, doer *user_model.User, cmtType CommentType) (*Comment, error) { // Update issue count of labels if err := issue.LoadLabels(ctx); err != nil { return nil, err @@ -152,6 +103,14 @@ func updateIssueNumbers(ctx context.Context, issue *Issue, doer *user_model.User return nil, err } + // New action comment + cmtType := CommentTypeClose + if !issue.IsClosed { + cmtType = CommentTypeReopen + } else if isMergePull { + cmtType = CommentTypeMergePull + } + return CreateComment(ctx, &CreateCommentOptions{ Type: cmtType, Doer: doer, @@ -160,8 +119,8 @@ func updateIssueNumbers(ctx context.Context, issue *Issue, doer *user_model.User }) } -// CloseIssue changes issue status to closed. -func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) { +// ChangeIssueStatus changes issue status to open or closed. +func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed bool) (*Comment, error) { if err := issue.LoadRepo(ctx); err != nil { return nil, err } @@ -169,45 +128,7 @@ func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comm return nil, err } - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return nil, err - } - defer committer.Close() - - comment, err := SetIssueAsClosed(ctx, issue, doer, false) - if err != nil { - return nil, err - } - if err := committer.Commit(); err != nil { - return nil, err - } - return comment, nil -} - -// ReopenIssue changes issue status to open. -func ReopenIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) { - if err := issue.LoadRepo(ctx); err != nil { - return nil, err - } - if err := issue.LoadPoster(ctx); err != nil { - return nil, err - } - - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return nil, err - } - defer committer.Close() - - comment, err := setIssueAsReopen(ctx, issue, doer) - if err != nil { - return nil, err - } - if err := committer.Commit(); err != nil { - return nil, err - } - return comment, nil + return changeIssueStatus(ctx, issue, doer, isClosed, false) } // ChangeIssueTitle changes the title of this issue, as the given user. @@ -218,7 +139,7 @@ func ChangeIssueTitle(ctx context.Context, issue *Issue, doer *user_model.User, } defer committer.Close() - issue.Title = util.EllipsisDisplayString(issue.Title, 255) + issue.Title, _ = util.SplitStringAtByteN(issue.Title, 255) if err = UpdateIssueCols(ctx, issue, "name"); err != nil { return fmt.Errorf("updateIssueCols: %w", err) } @@ -446,10 +367,19 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue return err } - if err := UpdateIssueAttachments(ctx, opts.Issue.ID, opts.Attachments); err != nil { - return err - } + if len(opts.Attachments) > 0 { + attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, opts.Attachments) + if err != nil { + return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", opts.Attachments, err) + } + for i := 0; i < len(attachments); i++ { + attachments[i].IssueID = opts.Issue.ID + if _, err = e.ID(attachments[i].ID).Update(attachments[i]); err != nil { + return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err) + } + } + } if err = opts.Issue.LoadAttributes(ctx); err != nil { return err } @@ -472,7 +402,7 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, la } issue.Index = idx - issue.Title = util.EllipsisDisplayString(issue.Title, 255) + issue.Title, _ = util.SplitStringAtByteN(issue.Title, 255) if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{ Repo: repo, diff --git a/models/issues/issue_user_test.go b/models/issues/issue_user_test.go index 7c21aa15ee..ce47adb53a 100644 --- a/models/issues/issue_user_test.go +++ b/models/issues/issue_user_test.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_NewIssueUsers(t *testing.T) { @@ -28,8 +27,9 @@ func Test_NewIssueUsers(t *testing.T) { } // artificially insert new issue - require.NoError(t, db.Insert(db.DefaultContext, newIssue)) - require.NoError(t, issues_model.NewIssueUsers(db.DefaultContext, repo, newIssue)) + unittest.AssertSuccessfulInsert(t, newIssue) + + assert.NoError(t, issues_model.NewIssueUsers(db.DefaultContext, repo, newIssue)) // issue_user table should now have entries for new issue unittest.AssertExistsAndLoadBean(t, &issues_model.IssueUser{IssueID: newIssue.ID, UID: newIssue.PosterID}) diff --git a/models/issues/issue_xref_test.go b/models/issues/issue_xref_test.go index 7f257330b7..f1b1bb2a6b 100644 --- a/models/issues/issue_xref_test.go +++ b/models/issues/issue_xref_test.go @@ -98,7 +98,7 @@ func TestXRef_ResolveCrossReferences(t *testing.T) { i1 := testCreateIssue(t, 1, 2, "title1", "content1", false) i2 := testCreateIssue(t, 1, 2, "title2", "content2", false) i3 := testCreateIssue(t, 1, 2, "title3", "content3", false) - _, err := issues_model.CloseIssue(db.DefaultContext, i3, d) + _, err := issues_model.ChangeIssueStatus(db.DefaultContext, i3, d, true) assert.NoError(t, err) pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index)) diff --git a/models/issues/label_test.go b/models/issues/label_test.go index 185fa11bbc..1d4b6f4684 100644 --- a/models/issues/label_test.go +++ b/models/issues/label_test.go @@ -387,7 +387,7 @@ func TestDeleteIssueLabel(t *testing.T) { expectedNumIssues := label.NumIssues expectedNumClosedIssues := label.NumClosedIssues - if unittest.GetBean(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID}) != nil { + if unittest.BeanExists(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID}) { expectedNumIssues-- if issue.IsClosed { expectedNumClosedIssues-- diff --git a/models/issues/pull.go b/models/issues/pull.go index e3af00224d..319ead5dbd 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -80,6 +80,22 @@ func (err ErrPullRequestAlreadyExists) Unwrap() error { return util.ErrAlreadyExist } +// ErrPullWasClosed is used close a closed pull request +type ErrPullWasClosed struct { + ID int64 + Index int64 +} + +// IsErrPullWasClosed checks if an error is a ErrErrPullWasClosed. +func IsErrPullWasClosed(err error) bool { + _, ok := err.(ErrPullWasClosed) + return ok +} + +func (err ErrPullWasClosed) Error() string { + return fmt.Sprintf("Pull request [%d] %d was already closed", err.ID, err.Index) +} + // PullRequestType defines pull request type type PullRequestType int @@ -483,6 +499,65 @@ func (pr *PullRequest) IsFromFork() bool { return pr.HeadRepoID != pr.BaseRepoID } +// SetMerged sets a pull request to merged and closes the corresponding issue +func (pr *PullRequest) SetMerged(ctx context.Context) (bool, error) { + if pr.HasMerged { + return false, fmt.Errorf("PullRequest[%d] already merged", pr.Index) + } + if pr.MergedCommitID == "" || pr.MergedUnix == 0 || pr.Merger == nil { + return false, fmt.Errorf("Unable to merge PullRequest[%d], some required fields are empty", pr.Index) + } + + pr.HasMerged = true + sess := db.GetEngine(ctx) + + if _, err := sess.Exec("UPDATE `issue` SET `repo_id` = `repo_id` WHERE `id` = ?", pr.IssueID); err != nil { + return false, err + } + + if _, err := sess.Exec("UPDATE `pull_request` SET `issue_id` = `issue_id` WHERE `id` = ?", pr.ID); err != nil { + return false, err + } + + pr.Issue = nil + if err := pr.LoadIssue(ctx); err != nil { + return false, err + } + + if tmpPr, err := GetPullRequestByID(ctx, pr.ID); err != nil { + return false, err + } else if tmpPr.HasMerged { + if pr.Issue.IsClosed { + return false, nil + } + return false, fmt.Errorf("PullRequest[%d] already merged but it's associated issue [%d] is not closed", pr.Index, pr.IssueID) + } else if pr.Issue.IsClosed { + return false, fmt.Errorf("PullRequest[%d] already closed", pr.Index) + } + + if err := pr.Issue.LoadRepo(ctx); err != nil { + return false, err + } + + if err := pr.Issue.Repo.LoadOwner(ctx); err != nil { + return false, err + } + + if _, err := changeIssueStatus(ctx, pr.Issue, pr.Merger, true, true); err != nil { + return false, fmt.Errorf("Issue.changeStatus: %w", err) + } + + // reset the conflicted files as there cannot be any if we're merged + pr.ConflictedFiles = []string{} + + // We need to save all of the data used to compute this merge as it may have already been changed by TestPatch. FIXME: need to set some state to prevent TestPatch from running whilst we are merging. + if _, err := sess.Where("id = ?", pr.ID).Cols("has_merged, status, merge_base, merged_commit_id, merger_id, merged_unix, conflicted_files").Update(pr); err != nil { + return false, fmt.Errorf("Failed to update pr[%d]: %w", pr.ID, err) + } + + return true, nil +} + // NewPullRequest creates new pull request with labels for repository. func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) { ctx, committer, err := db.TxContext(ctx) @@ -497,7 +572,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Iss } issue.Index = idx - issue.Title = util.EllipsisDisplayString(issue.Title, 255) + issue.Title, _ = util.SplitStringAtByteN(issue.Title, 255) if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{ Repo: repo, diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go index b105fab97c..59010aa9d0 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -28,16 +28,11 @@ type PullRequestsOptions struct { Labels []int64 MilestoneID int64 PosterID int64 - BaseBranch string } func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullRequestsOptions) *xorm.Session { sess := db.GetEngine(ctx).Where("pull_request.base_repo_id=?", baseRepoID) - if opts.BaseBranch != "" { - sess.And("pull_request.base_branch=?", opts.BaseBranch) - } - sess.Join("INNER", "issue", "pull_request.issue_id = issue.id") switch opts.State { case "closed", "open": @@ -171,23 +166,6 @@ func (prs PullRequestList) getRepositoryIDs() []int64 { return repoIDs.Values() } -func (prs PullRequestList) SetBaseRepo(baseRepo *repo_model.Repository) { - for _, pr := range prs { - if pr.BaseRepo == nil { - pr.BaseRepo = baseRepo - } - } -} - -func (prs PullRequestList) SetHeadRepo(headRepo *repo_model.Repository) { - for _, pr := range prs { - if pr.HeadRepo == nil { - pr.HeadRepo = headRepo - pr.isHeadRepoLoaded = true - } - } -} - func (prs PullRequestList) LoadRepositories(ctx context.Context) error { repoIDs := prs.getRepositoryIDs() reposMap := make(map[int64]*repo_model.Repository, len(repoIDs)) diff --git a/models/issues/reaction.go b/models/issues/reaction.go index f24001fd23..11b3c6be20 100644 --- a/models/issues/reaction.go +++ b/models/issues/reaction.go @@ -7,7 +7,6 @@ import ( "bytes" "context" "fmt" - "strings" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" @@ -322,11 +321,6 @@ func valuesUser(m map[int64]*user_model.User) []*user_model.User { return values } -// newMigrationOriginalUser creates and returns a fake user for external user -func newMigrationOriginalUser(name string) *user_model.User { - return &user_model.User{ID: 0, Name: name, LowerName: strings.ToLower(name)} -} - // LoadUsers loads reactions' all users func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Repository) ([]*user_model.User, error) { if len(list) == 0 { @@ -344,7 +338,7 @@ func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Reposit for _, reaction := range list { if reaction.OriginalAuthor != "" { - reaction.User = newMigrationOriginalUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name())) + reaction.User = user_model.NewReplaceUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name())) } else if user, ok := userMaps[reaction.UserID]; ok { reaction.User = user } else { diff --git a/models/issues/review.go b/models/issues/review.go index 1c5c2ee30a..3e787273be 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -930,19 +930,17 @@ func MarkConversation(ctx context.Context, comment *Comment, doer *user_model.Us } // CanMarkConversation Add or remove Conversation mark for a code comment permission check -// the PR writer , official reviewer and poster can do it +// the PR writer , offfcial reviewer and poster can do it func CanMarkConversation(ctx context.Context, issue *Issue, doer *user_model.User) (permResult bool, err error) { if doer == nil || issue == nil { return false, fmt.Errorf("issue or doer is nil") } - if err = issue.LoadRepo(ctx); err != nil { - return false, err - } - if issue.Repo.IsArchived { - return false, nil - } if doer.ID != issue.PosterID { + if err = issue.LoadRepo(ctx); err != nil { + return false, err + } + p, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return false, err diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index 7c05a3a883..baffe04ace 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -46,6 +46,11 @@ func (s Stopwatch) Seconds() int64 { return int64(timeutil.TimeStampNow() - s.CreatedUnix) } +// Duration returns a human-readable duration string based on local server time +func (s Stopwatch) Duration() string { + return util.SecToHours(s.Seconds()) +} + func getStopwatch(ctx context.Context, userID, issueID int64) (sw *Stopwatch, exists bool, err error) { sw = new(Stopwatch) exists, err = db.GetEngine(ctx). diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index fe6de9c517..c2134f702a 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -13,9 +13,9 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/testlogger" "github.com/stretchr/testify/require" @@ -76,7 +76,7 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu t.Errorf("error whilst initializing fixtures from %s: %v", fixturesDir, err) return x, deferFn } - if err := unittest.LoadFixtures(); err != nil { + if err := unittest.LoadFixtures(x); err != nil { t.Errorf("error whilst loading fixtures from %s: %v", fixturesDir, err) return x, deferFn } @@ -92,7 +92,10 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu func MainTest(m *testing.M) { testlogger.Init() - giteaRoot := test.SetupGiteaRoot() + giteaRoot := base.SetupGiteaRoot() + if giteaRoot == "" { + testlogger.Fatalf("Environment variable $GITEA_ROOT not set\n") + } giteaBinary := "gitea" if runtime.GOOS == "windows" { giteaBinary += ".exe" diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 87d674a440..52d10c4fe8 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -22,7 +22,6 @@ import ( "code.gitea.io/gitea/models/migrations/v1_21" "code.gitea.io/gitea/models/migrations/v1_22" "code.gitea.io/gitea/models/migrations/v1_23" - "code.gitea.io/gitea/models/migrations/v1_24" "code.gitea.io/gitea/models/migrations/v1_6" "code.gitea.io/gitea/models/migrations/v1_7" "code.gitea.io/gitea/models/migrations/v1_8" @@ -370,10 +369,6 @@ func prepareMigrationTasks() []*migration { newMigration(309, "Improve Notification table indices", v1_23.ImproveNotificationTableIndices), newMigration(310, "Add Priority to ProtectedBranch", v1_23.AddPriorityToProtectedBranch), newMigration(311, "Add TimeEstimate to Issue table", v1_23.AddTimeEstimateColumnToIssueTable), - - // Gitea 1.23.0-rc0 ends at migration ID number 311 (database version 312) - newMigration(312, "Add DeleteBranchAfterMerge to AutoMerge", v1_24.AddDeleteBranchAfterMergeForAutoMerge), - newMigration(313, "Move PinOrder from issue table to a new table issue_pin", v1_24.MovePinOrderToTableIssuePin), } return preparedMigrations } diff --git a/models/migrations/v1_21/v276.go b/models/migrations/v1_21/v276.go index 9d22c9052e..15177bf040 100644 --- a/models/migrations/v1_21/v276.go +++ b/models/migrations/v1_21/v276.go @@ -172,7 +172,7 @@ func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) { return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err) } - u, err := giturl.ParseGitURL(remoteURL) + u, err := giturl.Parse(remoteURL) if err != nil { return "", err } diff --git a/models/migrations/v1_24/v312.go b/models/migrations/v1_24/v312.go deleted file mode 100644 index 9766dc1ccf..0000000000 --- a/models/migrations/v1_24/v312.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package v1_24 //nolint - -import ( - "xorm.io/xorm" -) - -type pullAutoMerge struct { - DeleteBranchAfterMerge bool -} - -// TableName return database table name for xorm -func (pullAutoMerge) TableName() string { - return "pull_auto_merge" -} - -func AddDeleteBranchAfterMergeForAutoMerge(x *xorm.Engine) error { - return x.Sync(new(pullAutoMerge)) -} diff --git a/models/migrations/v1_24/v313.go b/models/migrations/v1_24/v313.go deleted file mode 100644 index ee9d479340..0000000000 --- a/models/migrations/v1_24/v313.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2025 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package v1_24 //nolint - -import ( - "code.gitea.io/gitea/models/migrations/base" - - "xorm.io/xorm" -) - -func MovePinOrderToTableIssuePin(x *xorm.Engine) error { - type IssuePin struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"UNIQUE(s) NOT NULL"` - IssueID int64 `xorm:"UNIQUE(s) NOT NULL"` - IsPull bool `xorm:"NOT NULL"` - PinOrder int `xorm:"DEFAULT 0"` - } - - if err := x.Sync(new(IssuePin)); err != nil { - return err - } - - if _, err := x.Exec("INSERT INTO issue_pin (repo_id, issue_id, is_pull, pin_order) SELECT repo_id, id, is_pull, pin_order FROM issue WHERE pin_order > 0"); err != nil { - return err - } - sess := x.NewSession() - defer sess.Close() - return base.DropTableColumns(sess, "issue", "pin_order") -} diff --git a/models/organization/org.go b/models/organization/org.go index 3e55a36758..725a99356e 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -9,8 +9,11 @@ import ( "fmt" "strings" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" + secret_model "code.gitea.io/gitea/models/secret" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -404,6 +407,33 @@ func GetOrgByName(ctx context.Context, name string) (*Organization, error) { return u, nil } +// DeleteOrganization deletes models associated to an organization. +func DeleteOrganization(ctx context.Context, org *Organization) error { + if org.Type != user_model.UserTypeOrganization { + return fmt.Errorf("%s is a user not an organization", org.Name) + } + + if err := db.DeleteBeans(ctx, + &Team{OrgID: org.ID}, + &OrgUser{OrgID: org.ID}, + &TeamUser{OrgID: org.ID}, + &TeamUnit{OrgID: org.ID}, + &TeamInvite{OrgID: org.ID}, + &secret_model.Secret{OwnerID: org.ID}, + &user_model.Blocking{BlockerID: org.ID}, + &actions_model.ActionRunner{OwnerID: org.ID}, + &actions_model.ActionRunnerToken{OwnerID: org.ID}, + ); err != nil { + return fmt.Errorf("DeleteBeans: %w", err) + } + + if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil { + return fmt.Errorf("Delete: %w", err) + } + + return nil +} + // GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) { var authorize perm.AccessMode @@ -574,9 +604,7 @@ func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error { return err } -// GetUserTeams returns all teams that belong to user, -// and that the user has joined. -func (org *Organization) GetUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) { +func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) { teams := make([]*Team, 0, org.NumTeams) return teams, db.GetEngine(ctx). Where("`team_user`.org_id = ?", org.ID). @@ -588,8 +616,7 @@ func (org *Organization) GetUserTeams(ctx context.Context, userID int64, cols .. Find(&teams) } -// GetUserTeamIDs returns of all team IDs of the organization that user is member of. -func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) { +func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) { teamIDs := make([]int64, 0, org.NumTeams) return teamIDs, db.GetEngine(ctx). Table("team"). @@ -613,3 +640,175 @@ func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder { func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) { return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode) } + +// GetUserTeamIDs returns of all team IDs of the organization that user is member of. +func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) { + return org.getUserTeamIDs(ctx, userID) +} + +// GetUserTeams returns all teams that belong to user, +// and that the user has joined. +func (org *Organization) GetUserTeams(ctx context.Context, userID int64) ([]*Team, error) { + return org.getUserTeams(ctx, userID) +} + +// AccessibleReposEnvironment operations involving the repositories that are +// accessible to a particular user +type AccessibleReposEnvironment interface { + CountRepos() (int64, error) + RepoIDs(page, pageSize int) ([]int64, error) + Repos(page, pageSize int) (repo_model.RepositoryList, error) + MirrorRepos() (repo_model.RepositoryList, error) + AddKeyword(keyword string) + SetSort(db.SearchOrderBy) +} + +type accessibleReposEnv struct { + org *Organization + user *user_model.User + team *Team + teamIDs []int64 + ctx context.Context + keyword string + orderBy db.SearchOrderBy +} + +// AccessibleReposEnv builds an AccessibleReposEnvironment for the repositories in `org` +// that are accessible to the specified user. +func AccessibleReposEnv(ctx context.Context, org *Organization, userID int64) (AccessibleReposEnvironment, error) { + var user *user_model.User + + if userID > 0 { + u, err := user_model.GetUserByID(ctx, userID) + if err != nil { + return nil, err + } + user = u + } + + teamIDs, err := org.getUserTeamIDs(ctx, userID) + if err != nil { + return nil, err + } + return &accessibleReposEnv{ + org: org, + user: user, + teamIDs: teamIDs, + ctx: ctx, + orderBy: db.SearchOrderByRecentUpdated, + }, nil +} + +// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org` +// that are accessible to the specified team. +func (org *Organization) AccessibleTeamReposEnv(ctx context.Context, team *Team) AccessibleReposEnvironment { + return &accessibleReposEnv{ + org: org, + team: team, + ctx: ctx, + orderBy: db.SearchOrderByRecentUpdated, + } +} + +func (env *accessibleReposEnv) cond() builder.Cond { + cond := builder.NewCond() + if env.team != nil { + cond = cond.And(builder.Eq{"team_repo.team_id": env.team.ID}) + } else { + if env.user == nil || !env.user.IsRestricted { + cond = cond.Or(builder.Eq{ + "`repository`.owner_id": env.org.ID, + "`repository`.is_private": false, + }) + } + if len(env.teamIDs) > 0 { + cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs)) + } + } + if env.keyword != "" { + cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)}) + } + return cond +} + +func (env *accessibleReposEnv) CountRepos() (int64, error) { + repoCount, err := db.GetEngine(env.ctx). + Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id"). + Where(env.cond()). + Distinct("`repository`.id"). + Count(&repo_model.Repository{}) + if err != nil { + return 0, fmt.Errorf("count user repositories in organization: %w", err) + } + return repoCount, nil +} + +func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) { + if page <= 0 { + page = 1 + } + + repoIDs := make([]int64, 0, pageSize) + return repoIDs, db.GetEngine(env.ctx). + Table("repository"). + Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id"). + Where(env.cond()). + GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]). + OrderBy(string(env.orderBy)). + Limit(pageSize, (page-1)*pageSize). + Cols("`repository`.id"). + Find(&repoIDs) +} + +func (env *accessibleReposEnv) Repos(page, pageSize int) (repo_model.RepositoryList, error) { + repoIDs, err := env.RepoIDs(page, pageSize) + if err != nil { + return nil, fmt.Errorf("GetUserRepositoryIDs: %w", err) + } + + repos := make([]*repo_model.Repository, 0, len(repoIDs)) + if len(repoIDs) == 0 { + return repos, nil + } + + return repos, db.GetEngine(env.ctx). + In("`repository`.id", repoIDs). + OrderBy(string(env.orderBy)). + Find(&repos) +} + +func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) { + repoIDs := make([]int64, 0, 10) + return repoIDs, db.GetEngine(env.ctx). + Table("repository"). + Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true). + Where(env.cond()). + GroupBy("`repository`.id, `repository`.updated_unix"). + OrderBy(string(env.orderBy)). + Cols("`repository`.id"). + Find(&repoIDs) +} + +func (env *accessibleReposEnv) MirrorRepos() (repo_model.RepositoryList, error) { + repoIDs, err := env.MirrorRepoIDs() + if err != nil { + return nil, fmt.Errorf("MirrorRepoIDs: %w", err) + } + + repos := make([]*repo_model.Repository, 0, len(repoIDs)) + if len(repoIDs) == 0 { + return repos, nil + } + + return repos, db.GetEngine(env.ctx). + In("`repository`.id", repoIDs). + Find(&repos) +} + +func (env *accessibleReposEnv) AddKeyword(keyword string) { + env.keyword = keyword +} + +func (env *accessibleReposEnv) SetSort(orderBy db.SearchOrderBy) { + env.orderBy = orderBy +} diff --git a/models/organization/org_list.go b/models/organization/org_list.go index 78ac0e704a..4c4168af1f 100644 --- a/models/organization/org_list.go +++ b/models/organization/org_list.go @@ -124,7 +124,6 @@ func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, if err := db.GetEngine(ctx).Select(columnsStr). Table("user"). Where(builder.In("`user`.`id`", queryUserOrgIDs(user.ID, true))). - OrderBy("`user`.lower_name ASC"). Find(&orgs); err != nil { return nil, err } diff --git a/models/organization/org_repo.go b/models/organization/org_repo.go new file mode 100644 index 0000000000..f7e59928f4 --- /dev/null +++ b/models/organization/org_repo.go @@ -0,0 +1,17 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package organization + +import ( + "context" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" +) + +// GetOrgRepositories get repos belonging to the given organization +func GetOrgRepositories(ctx context.Context, orgID int64) (repo_model.RepositoryList, error) { + var orgRepos []*repo_model.Repository + return orgRepos, db.GetEngine(ctx).Where("owner_id = ?", orgID).Find(&orgRepos) +} diff --git a/models/organization/org_test.go b/models/organization/org_test.go index b882a25be3..5e99e88689 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -16,7 +16,6 @@ import ( "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestUser_IsOwnedBy(t *testing.T) { @@ -181,8 +180,9 @@ func TestRestrictedUserOrgMembers(t *testing.T) { ID: 29, IsRestricted: true, }) - // ensure fixtures return restricted user - require.True(t, restrictedUser.IsRestricted) + if !assert.True(t, restrictedUser.IsRestricted) { + return // ensure fixtures return restricted user + } testCases := []struct { name string @@ -318,7 +318,7 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID, expectedCount int64) { - env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) count, err := env.CountRepos() assert.NoError(t, err) @@ -332,7 +332,7 @@ func TestAccessibleReposEnv_RepoIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID int64, expectedRepoIDs []int64) { - env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) repoIDs, err := env.RepoIDs(1, 100) assert.NoError(t, err) @@ -346,7 +346,7 @@ func TestAccessibleReposEnv_Repos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID int64, expectedRepoIDs []int64) { - env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) repos, err := env.Repos(1, 100) assert.NoError(t, err) @@ -365,7 +365,7 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID int64, expectedRepoIDs []int64) { - env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) repos, err := env.MirrorRepos() assert.NoError(t, err) diff --git a/models/organization/org_user.go b/models/organization/org_user.go index 08d936d922..1d3b2fab44 100644 --- a/models/organization/org_user.go +++ b/models/organization/org_user.go @@ -36,21 +36,6 @@ func init() { db.RegisterModel(new(OrgUser)) } -// ErrUserHasOrgs represents a "UserHasOrgs" kind of error. -type ErrUserHasOrgs struct { - UID int64 -} - -// IsErrUserHasOrgs checks if an error is a ErrUserHasOrgs. -func IsErrUserHasOrgs(err error) bool { - _, ok := err.(ErrUserHasOrgs) - return ok -} - -func (err ErrUserHasOrgs) Error() string { - return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID) -} - // GetOrganizationCount returns count of membership of organization of the user. func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) { return db.GetEngine(ctx). diff --git a/models/organization/org_user_test.go b/models/organization/org_user_test.go index c5110b2a34..55abb63203 100644 --- a/models/organization/org_user_test.go +++ b/models/organization/org_user_test.go @@ -131,7 +131,7 @@ func TestAddOrgUser(t *testing.T) { testSuccess := func(orgID, userID int64, isPublic bool) { org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}) expectedNumMembers := org.NumMembers - if unittest.GetBean(t, &organization.OrgUser{OrgID: orgID, UID: userID}) == nil { + if !unittest.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) { expectedNumMembers++ } assert.NoError(t, organization.AddOrgUser(db.DefaultContext, orgID, userID)) diff --git a/models/organization/org_worktime.go b/models/organization/org_worktime.go deleted file mode 100644 index 7b57182a8a..0000000000 --- a/models/organization/org_worktime.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2025 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package organization - -import ( - "sort" - - "code.gitea.io/gitea/models/db" - - "xorm.io/builder" -) - -type WorktimeSumByRepos struct { - RepoName string - SumTime int64 -} - -func GetWorktimeByRepos(org *Organization, unitFrom, unixTo int64) (results []WorktimeSumByRepos, err error) { - err = db.GetEngine(db.DefaultContext). - Select("repository.name AS repo_name, SUM(tracked_time.time) AS sum_time"). - Table("tracked_time"). - Join("INNER", "issue", "tracked_time.issue_id = issue.id"). - Join("INNER", "repository", "issue.repo_id = repository.id"). - Where(builder.Eq{"repository.owner_id": org.ID}). - And(builder.Eq{"tracked_time.deleted": false}). - And(builder.Gte{"tracked_time.created_unix": unitFrom}). - And(builder.Lte{"tracked_time.created_unix": unixTo}). - GroupBy("repository.name"). - OrderBy("repository.name"). - Find(&results) - return results, err -} - -type WorktimeSumByMilestones struct { - RepoName string - MilestoneName string - MilestoneID int64 - MilestoneDeadline int64 - SumTime int64 - HideRepoName bool -} - -func GetWorktimeByMilestones(org *Organization, unitFrom, unixTo int64) (results []WorktimeSumByMilestones, err error) { - err = db.GetEngine(db.DefaultContext). - Select("repository.name AS repo_name, milestone.name AS milestone_name, milestone.id AS milestone_id, milestone.deadline_unix as milestone_deadline, SUM(tracked_time.time) AS sum_time"). - Table("tracked_time"). - Join("INNER", "issue", "tracked_time.issue_id = issue.id"). - Join("INNER", "repository", "issue.repo_id = repository.id"). - Join("LEFT", "milestone", "issue.milestone_id = milestone.id"). - Where(builder.Eq{"repository.owner_id": org.ID}). - And(builder.Eq{"tracked_time.deleted": false}). - And(builder.Gte{"tracked_time.created_unix": unitFrom}). - And(builder.Lte{"tracked_time.created_unix": unixTo}). - GroupBy("repository.name, milestone.name, milestone.deadline_unix, milestone.id"). - OrderBy("repository.name, milestone.deadline_unix, milestone.id"). - Find(&results) - - // TODO: pgsql: NULL values are sorted last in default ascending order, so we need to sort them manually again. - sort.Slice(results, func(i, j int) bool { - if results[i].RepoName != results[j].RepoName { - return results[i].RepoName < results[j].RepoName - } - if results[i].MilestoneDeadline != results[j].MilestoneDeadline { - return results[i].MilestoneDeadline < results[j].MilestoneDeadline - } - return results[i].MilestoneID < results[j].MilestoneID - }) - - // Show only the first RepoName, for nicer output. - prevRepoName := "" - for i := 0; i < len(results); i++ { - res := &results[i] - res.MilestoneDeadline = 0 // clear the deadline because we do not really need it - if prevRepoName == res.RepoName { - res.HideRepoName = true - } - prevRepoName = res.RepoName - } - return results, err -} - -type WorktimeSumByMembers struct { - UserName string - SumTime int64 -} - -func GetWorktimeByMembers(org *Organization, unitFrom, unixTo int64) (results []WorktimeSumByMembers, err error) { - err = db.GetEngine(db.DefaultContext). - Select("`user`.name AS user_name, SUM(tracked_time.time) AS sum_time"). - Table("tracked_time"). - Join("INNER", "issue", "tracked_time.issue_id = issue.id"). - Join("INNER", "repository", "issue.repo_id = repository.id"). - Join("INNER", "`user`", "tracked_time.user_id = `user`.id"). - Where(builder.Eq{"repository.owner_id": org.ID}). - And(builder.Eq{"tracked_time.deleted": false}). - And(builder.Gte{"tracked_time.created_unix": unitFrom}). - And(builder.Lte{"tracked_time.created_unix": unixTo}). - GroupBy("`user`.name"). - OrderBy("sum_time DESC"). - Find(&results) - return results, err -} diff --git a/models/organization/team.go b/models/organization/team.go index 96666da39a..fb7f0c0493 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + 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/log" @@ -77,8 +78,9 @@ type Team struct { LowerName string Name string Description string - AccessMode perm.AccessMode `xorm:"'authorize'"` - Members []*user_model.User `xorm:"-"` + AccessMode perm.AccessMode `xorm:"'authorize'"` + Repos []*repo_model.Repository `xorm:"-"` + Members []*user_model.User `xorm:"-"` NumRepos int NumMembers int Units []*TeamUnit `xorm:"-"` @@ -153,6 +155,17 @@ func (t *Team) IsMember(ctx context.Context, userID int64) bool { return isMember } +// LoadRepositories returns paginated repositories in team of organization. +func (t *Team) LoadRepositories(ctx context.Context) (err error) { + if t.Repos != nil { + return nil + } + t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{ + TeamID: t.ID, + }) + return err +} + // LoadMembers returns paginated members in team of organization. func (t *Team) LoadMembers(ctx context.Context) (err error) { t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{ diff --git a/models/organization/team_list.go b/models/organization/team_list.go index 6f2a922e95..4ceb405e31 100644 --- a/models/organization/team_list.go +++ b/models/organization/team_list.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "xorm.io/builder" @@ -97,11 +98,11 @@ func SearchTeam(ctx context.Context, opts *SearchTeamOptions) (TeamList, int64, } // GetRepoTeams gets the list of teams that has access to the repository -func GetRepoTeams(ctx context.Context, orgID, repoID int64) (teams TeamList, err error) { +func GetRepoTeams(ctx context.Context, repo *repo_model.Repository) (teams TeamList, err error) { return teams, db.GetEngine(ctx). Join("INNER", "team_repo", "team_repo.team_id = team.id"). - Where("team.org_id = ?", orgID). - And("team_repo.repo_id=?", repoID). + Where("team.org_id = ?", repo.OwnerID). + And("team_repo.repo_id=?", repo.ID). OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END"). Find(&teams) } diff --git a/models/organization/team_repo.go b/models/organization/team_repo.go index 53edd203a8..c90dfdeda0 100644 --- a/models/organization/team_repo.go +++ b/models/organization/team_repo.go @@ -8,7 +8,10 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" + + "xorm.io/builder" ) // TeamRepo represents an team-repository relation. @@ -29,6 +32,29 @@ func HasTeamRepo(ctx context.Context, orgID, teamID, repoID int64) bool { return has } +type SearchTeamRepoOptions struct { + db.ListOptions + TeamID int64 +} + +// GetRepositories returns paginated repositories in team of organization. +func GetTeamRepositories(ctx context.Context, opts *SearchTeamRepoOptions) (repo_model.RepositoryList, error) { + sess := db.GetEngine(ctx) + if opts.TeamID > 0 { + sess = sess.In("id", + builder.Select("repo_id"). + From("team_repo"). + Where(builder.Eq{"team_id": opts.TeamID}), + ) + } + if opts.PageSize > 0 { + sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) + } + var repos []*repo_model.Repository + return repos, sess.OrderBy("repository.name"). + Find(&repos) +} + // AddTeamRepo adds a repo for an organization's team func AddTeamRepo(ctx context.Context, orgID, teamID, repoID int64) error { _, err := db.GetEngine(ctx).Insert(&TeamRepo{ diff --git a/models/organization/team_test.go b/models/organization/team_test.go index deaabbfa2c..8c34e7a612 100644 --- a/models/organization/team_test.go +++ b/models/organization/team_test.go @@ -8,7 +8,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" - repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -43,12 +42,9 @@ func TestTeam_GetRepositories(t *testing.T) { test := func(teamID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - repos, err := repo_model.GetTeamRepositories(db.DefaultContext, &repo_model.SearchTeamRepoOptions{ - TeamID: team.ID, - }) - assert.NoError(t, err) - assert.Len(t, repos, team.NumRepos) - for _, repo := range repos { + assert.NoError(t, team.LoadRepositories(db.DefaultContext)) + assert.Len(t, team.Repos, team.NumRepos) + for _, repo := range team.Repos { unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID}) } } diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go index d251fcc4a9..803b73c968 100644 --- a/models/packages/descriptor.go +++ b/models/packages/descriptor.go @@ -110,12 +110,9 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc if err != nil { return nil, err } - var repository *repo_model.Repository - if p.RepoID > 0 { - repository, err = repo_model.GetRepositoryByID(ctx, p.RepoID) - if err != nil && !repo_model.IsErrRepoNotExist(err) { - return nil, err - } + repository, err := repo_model.GetRepositoryByID(ctx, p.RepoID) + if err != nil && !repo_model.IsErrRepoNotExist(err) { + return nil, err } creator, err := user_model.GetUserByID(ctx, pv.CreatorID) if err != nil { diff --git a/models/packages/package.go b/models/packages/package.go index 8935dbaa1c..b7464f9140 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -228,11 +228,6 @@ func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error { return err } -func UnlinkRepository(ctx context.Context, packageID int64) error { - _, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: 0}) - return err -} - // UnlinkRepositoryFromAllPackages unlinks every package from the repository func UnlinkRepositoryFromAllPackages(ctx context.Context, repoID int64) error { _, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Cols("repo_id").Update(&Package{}) @@ -318,21 +313,6 @@ func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) { Find(&ps) } -// ErrUserOwnPackages notifies that the user (still) owns the packages. -type ErrUserOwnPackages struct { - UID int64 -} - -// IsErrUserOwnPackages checks if an error is an ErrUserOwnPackages. -func IsErrUserOwnPackages(err error) bool { - _, ok := err.(ErrUserOwnPackages) - return ok -} - -func (err ErrUserOwnPackages) Error() string { - return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID) -} - // HasOwnerPackages tests if a user/org has accessible packages func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) { return db.GetEngine(ctx). diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 5e7ecb31ea..0ed116a132 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -152,7 +152,7 @@ func (p *Permission) ReadableUnitTypes() []unit.Type { } func (p *Permission) LogString() string { - format := "= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] { if perm.everyoneAccessMode == nil { @@ -193,40 +187,17 @@ func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) { perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode } } - - if perm.unitsMode == nil { - // if unitsMode is not set, then it means that the default p.AccessMode applies to all units - return - } - - // remove no permission units - origPermUnits := perm.units - perm.units = make([]*repo_model.RepoUnit, 0, len(perm.units)) - for _, u := range origPermUnits { - shouldKeep := false - for t := range perm.unitsMode { - if shouldKeep = u.Type == t; shouldKeep { - break - } - } - for t := range perm.everyoneAccessMode { - if shouldKeep = shouldKeep || u.Type == t; shouldKeep { - break - } - } - if shouldKeep { - perm.units = append(perm.units, u) - } - } } // GetUserRepoPermission returns the user permissions to the repository func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (perm Permission, err error) { defer func() { if err == nil { - finalProcessRepoUnitPermission(user, &perm) + applyEveryoneRepoPermission(user, &perm) + } + if log.IsTrace() { + log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm) } - log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm) }() if err = repo.LoadUnits(ctx); err != nil { @@ -323,6 +294,16 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use } } + // remove no permission units + perm.units = make([]*repo_model.RepoUnit, 0, len(repo.Units)) + for t := range perm.unitsMode { + for _, u := range repo.Units { + if u.Type == t { + perm.units = append(perm.units, u) + } + } + } + return perm, err } diff --git a/models/perm/access/repo_permission_test.go b/models/perm/access/repo_permission_test.go index 9862da0673..50070c4368 100644 --- a/models/perm/access/repo_permission_test.go +++ b/models/perm/access/repo_permission_test.go @@ -50,7 +50,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) { {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, }, } - finalProcessRepoUnitPermission(nil, &perm) + applyEveryoneRepoPermission(nil, &perm) assert.False(t, perm.CanRead(unit.TypeWiki)) perm = Permission{ @@ -59,7 +59,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) { {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, }, } - finalProcessRepoUnitPermission(&user_model.User{ID: 0}, &perm) + applyEveryoneRepoPermission(&user_model.User{ID: 0}, &perm) assert.False(t, perm.CanRead(unit.TypeWiki)) perm = Permission{ @@ -68,7 +68,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) { {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, }, } - finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm) + applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) assert.True(t, perm.CanRead(unit.TypeWiki)) perm = Permission{ @@ -77,22 +77,20 @@ func TestApplyEveryoneRepoPermission(t *testing.T) { {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, }, } - finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm) + applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) // it should work the same as "EveryoneAccessMode: none" because the default AccessMode should be applied to units assert.True(t, perm.CanWrite(unit.TypeWiki)) perm = Permission{ units: []*repo_model.RepoUnit{ - {Type: unit.TypeCode}, // will be removed {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, }, unitsMode: map[unit.Type]perm_model.AccessMode{ unit.TypeWiki: perm_model.AccessModeWrite, }, } - finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm) + applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) assert.True(t, perm.CanWrite(unit.TypeWiki)) - assert.Len(t, perm.units, 1) } func TestUnitAccessMode(t *testing.T) { diff --git a/models/project/project.go b/models/project/project.go index d27e053094..78cba8b574 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -247,10 +247,6 @@ func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy { return db.SearchOrderByRecentUpdated case "leastupdate": return db.SearchOrderByLeastUpdated - case "alphabetically": - return "title ASC" - case "reversealphabetically": - return "title DESC" default: return db.SearchOrderByNewest } @@ -271,7 +267,7 @@ func NewProject(ctx context.Context, p *Project) error { return util.NewInvalidArgumentErrorf("project type is not valid") } - p.Title = util.EllipsisDisplayString(p.Title, 255) + p.Title, _ = util.SplitStringAtByteN(p.Title, 255) return db.WithTx(ctx, func(ctx context.Context) error { if err := db.Insert(ctx, p); err != nil { @@ -326,7 +322,7 @@ func UpdateProject(ctx context.Context, p *Project) error { p.CardType = CardTypeTextOnly } - p.Title = util.EllipsisDisplayString(p.Title, 255) + p.Title, _ = util.SplitStringAtByteN(p.Title, 255) _, err := db.GetEngine(ctx).ID(p.ID).Cols( "title", "description", diff --git a/models/pull/automerge.go b/models/pull/automerge.go index 3cafacc3a4..f69fcb60d1 100644 --- a/models/pull/automerge.go +++ b/models/pull/automerge.go @@ -15,14 +15,13 @@ import ( // AutoMerge represents a pull request scheduled for merging when checks succeed type AutoMerge struct { - ID int64 `xorm:"pk autoincr"` - PullID int64 `xorm:"UNIQUE"` - DoerID int64 `xorm:"INDEX NOT NULL"` - Doer *user_model.User `xorm:"-"` - MergeStyle repo_model.MergeStyle `xorm:"varchar(30)"` - Message string `xorm:"LONGTEXT"` - DeleteBranchAfterMerge bool - CreatedUnix timeutil.TimeStamp `xorm:"created"` + ID int64 `xorm:"pk autoincr"` + PullID int64 `xorm:"UNIQUE"` + DoerID int64 `xorm:"INDEX NOT NULL"` + Doer *user_model.User `xorm:"-"` + MergeStyle repo_model.MergeStyle `xorm:"varchar(30)"` + Message string `xorm:"LONGTEXT"` + CreatedUnix timeutil.TimeStamp `xorm:"created"` } // TableName return database table name for xorm @@ -50,7 +49,7 @@ func IsErrAlreadyScheduledToAutoMerge(err error) bool { } // ScheduleAutoMerge schedules a pull request to be merged when all checks succeed -func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64, style repo_model.MergeStyle, message string, deleteBranchAfterMerge bool) error { +func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64, style repo_model.MergeStyle, message string) error { // Check if we already have a merge scheduled for that pull request if exists, _, err := GetScheduledMergeByPullID(ctx, pullID); err != nil { return err @@ -59,11 +58,10 @@ func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64, } _, err := db.GetEngine(ctx).Insert(&AutoMerge{ - DoerID: doer.ID, - PullID: pullID, - MergeStyle: style, - Message: message, - DeleteBranchAfterMerge: deleteBranchAfterMerge, + DoerID: doer.ID, + PullID: pullID, + MergeStyle: style, + Message: message, }) return err } diff --git a/models/renderhelper/repo_comment_test.go b/models/renderhelper/repo_comment_test.go index 776152db96..01e20b9e02 100644 --- a/models/renderhelper/repo_comment_test.go +++ b/models/renderhelper/repo_comment_test.go @@ -4,6 +4,7 @@ package renderhelper import ( + "context" "testing" repo_model "code.gitea.io/gitea/models/repo" @@ -20,7 +21,7 @@ func TestRepoComment(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) t.Run("AutoLink", func(t *testing.T) { - rctx := NewRenderContextRepoComment(t.Context(), repo1).WithMarkupType(markdown.MarkupName) + rctx := NewRenderContextRepoComment(context.Background(), repo1).WithMarkupType(markdown.MarkupName) rendered, err := markup.RenderString(rctx, ` 65f1bf27bc3bf70f64657658635e66094edbcb4d #1 @@ -35,7 +36,7 @@ func TestRepoComment(t *testing.T) { }) t.Run("AbsoluteAndRelative", func(t *testing.T) { - rctx := NewRenderContextRepoComment(t.Context(), repo1).WithMarkupType(markdown.MarkupName) + rctx := NewRenderContextRepoComment(context.Background(), repo1).WithMarkupType(markdown.MarkupName) // It is Gitea's old behavior, the relative path is resolved to the repo path // It is different from GitHub, GitHub resolves relative links to current page's path @@ -55,7 +56,7 @@ func TestRepoComment(t *testing.T) { }) t.Run("WithCurrentRefPath", func(t *testing.T) { - rctx := NewRenderContextRepoComment(t.Context(), repo1, RepoCommentOptions{CurrentRefPath: "/commit/1234"}). + rctx := NewRenderContextRepoComment(context.Background(), repo1, RepoCommentOptions{CurrentRefPath: "/commit/1234"}). WithMarkupType(markdown.MarkupName) // the ref path is only used to render commit message: a commit message is rendered at the commit page with its commit ID path diff --git a/models/renderhelper/repo_file_test.go b/models/renderhelper/repo_file_test.go index 29cb45f6f7..959648b660 100644 --- a/models/renderhelper/repo_file_test.go +++ b/models/renderhelper/repo_file_test.go @@ -4,6 +4,7 @@ package renderhelper import ( + "context" "testing" repo_model "code.gitea.io/gitea/models/repo" @@ -21,7 +22,7 @@ func TestRepoFile(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) t.Run("AutoLink", func(t *testing.T) { - rctx := NewRenderContextRepoFile(t.Context(), repo1).WithMarkupType(markdown.MarkupName) + rctx := NewRenderContextRepoFile(context.Background(), repo1).WithMarkupType(markdown.MarkupName) rendered, err := markup.RenderString(rctx, ` 65f1bf27bc3bf70f64657658635e66094edbcb4d #1 @@ -36,7 +37,7 @@ func TestRepoFile(t *testing.T) { }) t.Run("AbsoluteAndRelative", func(t *testing.T) { - rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefPath: "branch/main"}). + rctx := NewRenderContextRepoFile(context.Background(), repo1, RepoFileOptions{CurrentRefPath: "branch/main"}). WithMarkupType(markdown.MarkupName) rendered, err := markup.RenderString(rctx, ` [/test](/test) @@ -54,7 +55,7 @@ func TestRepoFile(t *testing.T) { }) t.Run("WithCurrentRefPath", func(t *testing.T) { - rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefPath: "/commit/1234"}). + rctx := NewRenderContextRepoFile(context.Background(), repo1, RepoFileOptions{CurrentRefPath: "/commit/1234"}). WithMarkupType(markdown.MarkupName) rendered, err := markup.RenderString(rctx, ` [/test](/test) @@ -67,7 +68,7 @@ func TestRepoFile(t *testing.T) { }) t.Run("WithCurrentRefPathByTag", func(t *testing.T) { - rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{ + rctx := NewRenderContextRepoFile(context.Background(), repo1, RepoFileOptions{ CurrentRefPath: "/commit/1234", CurrentTreePath: "my-dir", }). @@ -88,7 +89,7 @@ func TestRepoFileOrgMode(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) t.Run("Links", func(t *testing.T) { - rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{ + rctx := NewRenderContextRepoFile(context.Background(), repo1, RepoFileOptions{ CurrentRefPath: "/commit/1234", CurrentTreePath: "my-dir", }).WithRelativePath("my-dir/a.org") @@ -105,7 +106,7 @@ func TestRepoFileOrgMode(t *testing.T) { }) t.Run("CodeHighlight", func(t *testing.T) { - rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{}).WithRelativePath("my-dir/a.org") + rctx := NewRenderContextRepoFile(context.Background(), repo1, RepoFileOptions{}).WithRelativePath("my-dir/a.org") rendered, err := markup.RenderString(rctx, ` #+begin_src c diff --git a/models/renderhelper/repo_wiki_test.go b/models/renderhelper/repo_wiki_test.go index b24508f1f2..beab2570e7 100644 --- a/models/renderhelper/repo_wiki_test.go +++ b/models/renderhelper/repo_wiki_test.go @@ -4,6 +4,7 @@ package renderhelper import ( + "context" "testing" repo_model "code.gitea.io/gitea/models/repo" @@ -19,7 +20,7 @@ func TestRepoWiki(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) t.Run("AutoLink", func(t *testing.T) { - rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName) + rctx := NewRenderContextRepoWiki(context.Background(), repo1).WithMarkupType(markdown.MarkupName) rendered, err := markup.RenderString(rctx, ` 65f1bf27bc3bf70f64657658635e66094edbcb4d #1 @@ -34,7 +35,7 @@ func TestRepoWiki(t *testing.T) { }) t.Run("AbsoluteAndRelative", func(t *testing.T) { - rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName) + rctx := NewRenderContextRepoWiki(context.Background(), repo1).WithMarkupType(markdown.MarkupName) rendered, err := markup.RenderString(rctx, ` [/test](/test) [./test](./test) @@ -51,7 +52,7 @@ func TestRepoWiki(t *testing.T) { }) t.Run("PathInTag", func(t *testing.T) { - rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName) + rctx := NewRenderContextRepoWiki(context.Background(), repo1).WithMarkupType(markdown.MarkupName) rendered, err := markup.RenderString(rctx, `