diff --git a/.changelog.yml b/.changelog.yml index bfdee0c0ca..a7df8779de 100644 --- a/.changelog.yml +++ b/.changelog.yml @@ -22,20 +22,25 @@ groups: name: FEATURES labels: - type/feature - - - name: API - labels: - - modifies/api - name: ENHANCEMENTS labels: - type/enhancement - - type/refactoring - - topic/ui + - + name: PERFORMANCE + labels: + - performance/memory + - performance/speed + - performance/bigrepo + - performance/cpu - name: BUGFIXES labels: - type/bug + - + name: API + labels: + - modifies/api - name: TESTING labels: diff --git a/.dockerignore b/.dockerignore index b696e1603c..94aca6b8d3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -79,18 +79,6 @@ cpu.out /public/assets/fonts /public/assets/img/avatar /vendor -/web_src/fomantic/node_modules -/web_src/fomantic/build/* -!/web_src/fomantic/build/semantic.js -!/web_src/fomantic/build/semantic.css -!/web_src/fomantic/build/themes -/web_src/fomantic/build/themes/* -!/web_src/fomantic/build/themes/default -/web_src/fomantic/build/themes/default/assets/* -!/web_src/fomantic/build/themes/default/assets/fonts -/web_src/fomantic/build/themes/default/assets/fonts/* -!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2 -!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2 /VERSION /.air /.go-licenses diff --git a/.editorconfig b/.editorconfig index c0946ac997..e23e4cd649 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,6 +17,7 @@ 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 new file mode 100644 index 0000000000..f2af1709e4 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,1004 @@ +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 deleted file mode 100644 index 809817396e..0000000000 --- a/.eslintrc.yaml +++ /dev/null @@ -1,963 +0,0 @@ -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/extensions: [".js", ".ts"] - import/parsers: - "@typescript-eslint/parser": [".js", ".ts"] - import/resolver: - typescript: true - -plugins: - - "@eslint-community/eslint-plugin-eslint-comments" - - "@stylistic/eslint-plugin-js" - - "@typescript-eslint/eslint-plugin" - - eslint-plugin-array-func - - eslint-plugin-deprecation - - eslint-plugin-github - - eslint-plugin-i - - eslint-plugin-no-jquery - - eslint-plugin-no-use-extend-native - - eslint-plugin-regexp - - eslint-plugin-sonarjs - - eslint-plugin-unicorn - - eslint-plugin-vitest - - eslint-plugin-vitest-globals - - eslint-plugin-wc - -env: - es2024: true - node: true - -overrides: - - files: ["web_src/**/*"] - globals: - __webpack_public_path__: true - process: false # https://github.com/webpack/webpack/issues/15833 - - files: ["web_src/**/*", "docs/**/*"] - env: - browser: true - node: false - - files: ["web_src/**/*worker.*"] - env: - worker: true - rules: - no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top] - - files: ["*.config.*"] - rules: - i/no-unused-modules: [0] - - files: ["**/*.d.ts"] - rules: - i/no-unused-modules: [0] - "@typescript-eslint/consistent-type-definitions": [0] - "@typescript-eslint/consistent-type-imports": [0] - - files: ["web_src/js/types.ts"] - rules: - i/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-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] - deprecation/deprecation: [2] - dot-notation: [0] - eqeqeq: [2] - for-direction: [2] - func-name-matching: [2] - func-names: [0] - func-style: [0] - getter-return: [2] - github/a11y-aria-label-is-well-formatted: [0] - github/a11y-no-title-attribute: [0] - github/a11y-no-visually-hidden-interactive-element: [0] - github/a11y-role-supports-aria-props: [0] - github/a11y-svg-has-accessible-name: [0] - github/array-foreach: [0] - github/async-currenttarget: [2] - github/async-preventdefault: [2] - github/authenticity-token: [0] - github/get-attribute: [0] - github/js-class-name: [0] - github/no-blur: [0] - github/no-d-none: [0] - github/no-dataset: [2] - github/no-dynamic-script-tag: [2] - github/no-implicit-buggy-globals: [2] - github/no-inner-html: [0] - github/no-innerText: [2] - github/no-then: [2] - github/no-useless-passive: [2] - github/prefer-observers: [2] - github/require-passive-events: [2] - github/unescaped-html-literal: [0] - grouped-accessor-pairs: [2] - guard-for-in: [0] - id-blacklist: [0] - id-length: [0] - id-match: [0] - i/consistent-type-specifier-style: [0] - i/default: [0] - i/dynamic-import-chunkname: [0] - i/export: [2] - i/exports-last: [0] - i/extensions: [2, always, {ignorePackages: true}] - i/first: [2] - i/group-exports: [0] - i/max-dependencies: [0] - i/named: [2] - i/namespace: [0] - i/newline-after-import: [0] - i/no-absolute-path: [0] - i/no-amd: [2] - i/no-anonymous-default-export: [0] - i/no-commonjs: [2] - i/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}] - i/no-default-export: [0] - i/no-deprecated: [0] - i/no-dynamic-require: [0] - i/no-empty-named-blocks: [2] - i/no-extraneous-dependencies: [2] - i/no-import-module-exports: [0] - i/no-internal-modules: [0] - i/no-mutable-exports: [0] - i/no-named-as-default-member: [0] - i/no-named-as-default: [0] - i/no-named-default: [0] - i/no-named-export: [0] - i/no-namespace: [0] - i/no-nodejs-modules: [0] - i/no-relative-packages: [0] - i/no-relative-parent-imports: [0] - i/no-restricted-paths: [0] - i/no-self-import: [2] - i/no-unassigned-import: [0] - i/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$"]}] - i/no-unused-modules: [2, {unusedExports: true}] - i/no-useless-path-segments: [2, {commonjs: true}] - i/no-webpack-loader-syntax: [2] - i/order: [0] - i/prefer-default-export: [0] - i/unambiguous: [0] - init-declarations: [0] - 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-each-collection: [0] - no-jquery/no-each-util: [0] - no-jquery/no-each: [0] - no-jquery/no-error-shorthand: [2] - no-jquery/no-error: [2] - no-jquery/no-escape-selector: [2] - no-jquery/no-event-shorthand: [2] - no-jquery/no-extend: [2] - no-jquery/no-fade: [2] - no-jquery/no-filter: [0] - no-jquery/no-find-collection: [0] - no-jquery/no-find-util: [2] - no-jquery/no-find: [0] - no-jquery/no-fx-interval: [2] - no-jquery/no-global-eval: [2] - no-jquery/no-global-selector: [0] - no-jquery/no-grep: [2] - no-jquery/no-has: [2] - no-jquery/no-hold-ready: [2] - no-jquery/no-html: [0] - no-jquery/no-in-array: [2] - no-jquery/no-is-array: [2] - no-jquery/no-is-empty-object: [2] - no-jquery/no-is-function: [2] - no-jquery/no-is-numeric: [2] - no-jquery/no-is-plain-object: [2] - no-jquery/no-is-window: [2] - no-jquery/no-is: [2] - no-jquery/no-jquery-constructor: [0] - no-jquery/no-live: [2] - no-jquery/no-load-shorthand: [2] - no-jquery/no-load: [2] - no-jquery/no-map-collection: [0] - no-jquery/no-map-util: [2] - no-jquery/no-map: [2] - no-jquery/no-merge: [2] - no-jquery/no-node-name: [2] - no-jquery/no-noop: [2] - no-jquery/no-now: [2] - no-jquery/no-on-ready: [2] - no-jquery/no-other-methods: [0] - no-jquery/no-other-utils: [2] - no-jquery/no-param: [2] - no-jquery/no-parent: [0] - no-jquery/no-parents: [2] - no-jquery/no-parse-html-literal: [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}] - 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-function-scoping: [2] - unicorn/custom-error-definition: [0] - unicorn/empty-brace-spaces: [2] - unicorn/error-message: [0] - unicorn/escape-case: [0] - unicorn/expiring-todo-comments: [0] - unicorn/explicit-length-check: [0] - unicorn/filename-case: [0] - unicorn/import-index: [0] - unicorn/import-style: [0] - unicorn/new-for-builtins: [2] - unicorn/no-abusive-eslint-disable: [0] - unicorn/no-anonymous-default-export: [0] - unicorn/no-array-callback-reference: [0] - unicorn/no-array-for-each: [2] - unicorn/no-array-method-this-argument: [2] - unicorn/no-array-push-push: [2] - unicorn/no-array-reduce: [2] - unicorn/no-await-expression-member: [0] - unicorn/no-await-in-promise-methods: [2] - unicorn/no-console-spaces: [0] - unicorn/no-document-cookie: [2] - unicorn/no-empty-file: [2] - unicorn/no-for-loop: [0] - unicorn/no-hex-escape: [0] - unicorn/no-instanceof-array: [0] - unicorn/no-invalid-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-includes: [2] - unicorn/prefer-json-parse-buffer: [0] - unicorn/prefer-keyboard-event-key: [2] - unicorn/prefer-logical-operator-over-ternary: [2] - unicorn/prefer-math-trunc: [2] - unicorn/prefer-modern-dom-apis: [0] - unicorn/prefer-modern-math-apis: [2] - unicorn/prefer-module: [2] - unicorn/prefer-native-coercion-functions: [2] - unicorn/prefer-negative-index: [2] - unicorn/prefer-node-protocol: [2] - unicorn/prefer-number-properties: [0] - unicorn/prefer-object-from-entries: [2] - unicorn/prefer-object-has-own: [0] - unicorn/prefer-optional-catch-binding: [2] - unicorn/prefer-prototype-methods: [0] - unicorn/prefer-query-selector: [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/.gitattributes b/.gitattributes index 9fb4a4e83d..52695f70c2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,7 +5,5 @@ /public/assets/img/svg/*.svg linguist-generated /templates/swagger/v1_json.tmpl linguist-generated /vendor/** -text -eol linguist-vendored -/web_src/fomantic/build/** linguist-generated -/web_src/fomantic/_site/globals/site.variables linguist-language=Less /web_src/js/vendor/** -text -eol linguist-vendored Dockerfile.* linguist-language=Dockerfile diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d37ce219c3..d409f18cd9 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://crowdin.com/project/gitea + url: https://translate.gitea.com about: Translations are managed here. diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index 023fb05a29..2adea23aa4 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -3,3 +3,5 @@ self-hosted-runner: - actuated-4cpu-8gb - actuated-4cpu-16gb - nscloud + - namespace-profile-gitea-release-docker + - namespace-profile-gitea-release-binary diff --git a/.github/labeler.yml b/.github/labeler.yml index 46efbcb194..0af43cd029 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -41,7 +41,7 @@ modifies/internal: - ".dockerignore" - "docker/**" - ".editorconfig" - - ".eslintrc.yaml" + - ".eslintrc.cjs" - ".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" - - "**/*.vue" + - "*.js" + - "*.ts" + - "web_src/**" docs-update-needed: - changed-files: diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml index cd8386ecc5..c34066d318 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: @@ -15,7 +15,7 @@ jobs: with: go-version-file: go.mod check-latest: true - - run: make generate-license generate-gitignore + - run: make generate-gitignore timeout-minutes: 40 - name: push translations to repo uses: appleboy/git-push-action@v0.0.3 diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml index 7c1fb02442..be27537924 100644 --- a/.github/workflows/files-changed.yml +++ b/.github/workflows/files-changed.yml @@ -51,14 +51,16 @@ jobs: - "options/locale/locale_en-US.ini" frontend: - - "**/*.js" + - "*.js" + - "*.ts" - "web_src/**" + - "tools/*.js" + - "tools/*.ts" - "assets/emoji.json" - "package.json" - "package-lock.json" - "Makefile" - - ".eslintrc.yaml" - - "stylelint.config.js" + - ".eslintrc.cjs" - ".npmrc" docs: @@ -85,6 +87,7 @@ jobs: swagger: - "templates/swagger/v1_json.tmpl" + - "templates/swagger/v1_input.json" - "Makefile" - "package.json" - "package-lock.json" diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index 429829dfe0..64090d6490 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -37,7 +37,7 @@ jobs: python-version: "3.12" - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: pip install poetry @@ -66,7 +66,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: make deps-frontend @@ -95,7 +95,7 @@ jobs: go-version-file: go.mod check-latest: true - run: make deps-backend deps-tools - - run: make lint-go-windows lint-go-vet + - run: make lint-go-windows lint-go-gitea-vet env: TAGS: bindata sqlite sqlite_unlock_notify GOOS: windows @@ -137,7 +137,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: make deps-frontend @@ -186,7 +186,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: make deps-frontend diff --git a/.github/workflows/pull-db-tests.yml b/.github/workflows/pull-db-tests.yml index 22cb784245..6e879053d3 100644 --- a/.github/workflows/pull-db-tests.yml +++ b/.github/workflows/pull-db-tests.yml @@ -154,12 +154,15 @@ jobs: runs-on: ubuntu-latest services: mysql: - image: mysql:8.0 + # the bitnami mysql image has more options than the official one, it's easier to customize + image: bitnami/mysql:8.0 env: - MYSQL_ALLOW_EMPTY_PASSWORD: true + ALLOW_EMPTY_PASSWORD: true MYSQL_DATABASE: testgitea ports: - "3306:3306" + options: >- + --mount type=tmpfs,destination=/bitnami/mysql/data elasticsearch: image: elasticsearch:7.5.0 env: @@ -188,7 +191,8 @@ jobs: - name: run migration tests run: make test-mysql-migration - name: run tests - run: make integration-test-coverage + # run: make integration-test-coverage (at the moment, no coverage is really handled) + run: make test-mysql env: TAGS: bindata RACE_ENABLED: true @@ -198,12 +202,10 @@ jobs: test-mssql: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed - # specifying the version of ubuntu in use as mssql fails on newer kernels - # pending resolution from vendor - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest services: mssql: - image: mcr.microsoft.com/mssql/server:2017-latest + image: mcr.microsoft.com/mssql/server:2019-latest env: ACCEPT_EULA: Y MSSQL_PID: Standard diff --git a/.github/workflows/pull-e2e-tests.yml b/.github/workflows/pull-e2e-tests.yml index 35ac7598f6..b84c69e4a0 100644 --- a/.github/workflows/pull-e2e-tests.yml +++ b/.github/workflows/pull-e2e-tests.yml @@ -23,7 +23,7 @@ jobs: check-latest: true - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: make deps-frontend frontend deps-backend diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index 10fe94b296..2264c9e822 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -10,7 +10,7 @@ concurrency: jobs: nightly-binary: - runs-on: nscloud + runs-on: namespace-profile-gitea-release-binary steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions @@ -22,7 +22,7 @@ jobs: check-latest: true - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: make deps-frontend deps-backend @@ -58,7 +58,7 @@ jobs: run: | aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress nightly-docker-rootful: - runs-on: ubuntu-latest + runs-on: namespace-profile-gitea-release-docker steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions @@ -95,7 +95,7 @@ jobs: push: true tags: gitea/gitea:${{ steps.clean_name.outputs.branch }} nightly-docker-rootless: - runs-on: ubuntu-latest + runs-on: namespace-profile-gitea-release-docker steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions diff --git a/.github/workflows/release-tag-rc.yml b/.github/workflows/release-tag-rc.yml index 55908d3657..a406602dc0 100644 --- a/.github/workflows/release-tag-rc.yml +++ b/.github/workflows/release-tag-rc.yml @@ -11,7 +11,7 @@ concurrency: jobs: binary: - runs-on: nscloud + runs-on: namespace-profile-gitea-release-binary steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions @@ -23,7 +23,7 @@ jobs: check-latest: true - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: make deps-frontend deps-backend @@ -68,7 +68,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} docker-rootful: - runs-on: ubuntu-latest + runs-on: namespace-profile-gitea-release-docker steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions @@ -99,7 +99,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} docker-rootless: - runs-on: ubuntu-latest + runs-on: namespace-profile-gitea-release-docker steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions diff --git a/.github/workflows/release-tag-version.yml b/.github/workflows/release-tag-version.yml index edf7ea1270..08bb9baecf 100644 --- a/.github/workflows/release-tag-version.yml +++ b/.github/workflows/release-tag-version.yml @@ -13,7 +13,7 @@ concurrency: jobs: binary: - runs-on: nscloud + runs-on: namespace-profile-gitea-release-binary steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions @@ -25,7 +25,7 @@ jobs: check-latest: true - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm cache-dependency-path: package-lock.json - run: make deps-frontend deps-backend @@ -70,7 +70,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} docker-rootful: - runs-on: ubuntu-latest + runs-on: namespace-profile-gitea-release-docker steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions @@ -88,9 +88,9 @@ jobs: # 1.2 # 1.2.3 tags: | + type=semver,pattern={{version}} type=semver,pattern={{major}} type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{version}} - name: Login to Docker Hub uses: docker/login-action@v3 with: @@ -105,7 +105,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} docker-rootless: - runs-on: ubuntu-latest + runs-on: namespace-profile-gitea-release-docker steps: - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions @@ -126,9 +126,9 @@ jobs: # 1.2 # 1.2.3 tags: | + type=semver,pattern={{version}} type=semver,pattern={{major}} type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{version}} - name: Login to Docker Hub uses: docker/login-action@v3 with: diff --git a/.gitignore b/.gitignore index 7889df77b1..703be8f681 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,11 @@ _test # IntelliJ .idea +.run + +# IntelliJ Gateway +.uuid + # Goland's output filename can not be set manually /go_build_* /gitea_* @@ -28,6 +33,7 @@ _testmain.go *.exe *.test *.prof +*.tsbuildinfo *coverage.out coverage.all @@ -78,18 +84,6 @@ cpu.out /public/assets/fonts /public/assets/licenses.txt /vendor -/web_src/fomantic/node_modules -/web_src/fomantic/build/* -!/web_src/fomantic/build/semantic.js -!/web_src/fomantic/build/semantic.css -!/web_src/fomantic/build/themes -/web_src/fomantic/build/themes/* -!/web_src/fomantic/build/themes/default -/web_src/fomantic/build/themes/default/assets/* -!/web_src/fomantic/build/themes/default/assets/fonts -/web_src/fomantic/build/themes/default/assets/fonts/* -!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2 -!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2 /VERSION /.air /.go-licenses diff --git a/.golangci.yml b/.golangci.yml index 37617ad365..cf7a6f1a1f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,10 +19,12 @@ linters: - revive - staticcheck - stylecheck + - testifylint - typecheck - unconvert - unused - unparam + - usetesting - wastedassign run: @@ -34,6 +36,10 @@ output: show-stats: true linters-settings: + testifylint: + disable: + - go-require + - require-error stylecheck: checks: ["all", "-ST1005", "-ST1003"] nakedret: @@ -96,6 +102,8 @@ 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 new file mode 100644 index 0000000000..88ff1591a4 --- /dev/null +++ b/.mailmap @@ -0,0 +1,2 @@ +Unknwon +Unknwon 无闻 diff --git a/CHANGELOG.md b/CHANGELOG.md index 04fffd4a4e..7541bccb2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,932 @@ This changelog goes through the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.com). +## [1.23.5](https://github.com/go-gitea/gitea/releases/tag/v1.23.5) - 2025-03-04 + +* SECURITY + * Bump x/oauth2 & x/crypto (#33704) (#33727) +* PERFORMANCE + * Optimize user dashboard loading (#33686) (#33708) +* BUGFIXES + * Fix navbar dropdown item align (#33782) + * Fix inconsistent closed issue list icon (#33722) (#33728) + * Fix for Maven Package Naming Convention Handling (#33678) (#33679) + * Improve Open-with URL encoding (#33666) (#33680) + * Deleting repository should unlink all related packages (#33653) (#33673) + * Fix omitempty bug (#33663) (#33670) + * Upgrade go-crypto from 1.1.4 to 1.1.6 (#33745) (#33754) + * Fix OCI image.version annotation for releases to use full semver (#33698) (#33701) + * Try to fix ACME path when renew (#33668) (#33693) + * Fix mCaptcha bug (#33659) (#33661) + * Git graph: don't show detached commits (#33645) (#33650) + * Use MatchPhraseQuery for bleve code search (#33628) + * Adjust appearence of commit status webhook (#33778) #33789 + * Upgrade golang net from 0.35.0 -> 0.36.0 (#33795) #33796 + +## [1.23.4](https://github.com/go-gitea/gitea/releases/tag/v1.23.4) - 2025-02-16 + +* SECURITY + * Enhance routers for the Actions variable operations (#33547) (#33553) + * Enhance routers for the Actions runner operations (#33549) (#33555) + * Fix project issues list and counting (#33594) #33619 +* PERFORMANCES + * Performance optimization for pull request files loading comments attachments (#33585) (#33592) +* BUGFIXES + * Add a transaction to `pickTask` (#33543) (#33563) + * Fix mirror bug (#33597) (#33607) + * Use default Git timeout when checking repo health (#33593) (#33598) + * Fix PR's target branch dropdown (#33589) (#33591) + * Fix various problems (artifact order, api empty slice, assignee check, fuzzy prompt, mirror proxy, adopt git) (#33569) (#33577) + * Rework suggestion backend (#33538) (#33546) + * Fix context usage (#33554) (#33557) + * Only show the latest version in the Arch index (#33262) (#33580) + * Skip deletion error for action artifacts (#33476) (#33568) + * Make actions URL in commit status webhooks absolute (#33620) #33632 + * Add missing locale (#33641) #33642 + +## [1.23.3](https://github.com/go-gitea/gitea/releases/tag/v1.23.3) - 2025-02-06 + +* Security + * Build Gitea with Golang v1.23.6 to fix security bugs +* BUGFIXES + * Fix a bug caused by status webhook template #33512 + +## [1.23.2](https://github.com/go-gitea/gitea/releases/tag/1.23.2) - 2025-02-04 + +* BREAKING + * Add tests for webhook and fix some webhook bugs (#33396) (#33442) + * Package webhook’s Organization was incorrectly used as the User struct. This PR fixes the issue. + * This changelog is just a hint. The change is not really breaking because most fields are the same, most users are not affected. +* ENHANCEMENTS + * Clone button enhancements (#33362) (#33404) + * Repo homepage styling tweaks (#33289) (#33381) + * Add a confirm dialog for "sync fork" (#33270) (#33273) + * Make tracked time representation display as hours (#33315) (#33334) + * Improve sync fork behavior (#33319) (#33332) +* BUGFIXES + * Fix code button alignment (#33345) (#33351) + * Correct bot label `vertical-align` (#33477) (#33480) + * Fix SSH LFS memory usage (#33455) (#33460) + * Fix issue sidebar dropdown keyboard support (#33447) (#33450) + * Fix user avatar (#33439) + * Fix `GetCommitBranchStart` bug (#33298) (#33421) + * Add pubdate for repository rss and add some tests (#33411) (#33416) + * Add missed auto merge feed message on dashboard (#33309) (#33405) + * Fix issue suggestion bug (#33389) (#33391) + * Make issue suggestion work for all editors (#33340) (#33342) + * Fix issue count (#33338) (#33341) + * Fix Account linking page (#33325) (#33327) + * Fix closed dependency title (#33285) (#33287) + * Fix sidebar milestone link (#33269) (#33272) + * Fix missing license when sync mirror (#33255) (#33258) + * Fix upload file form (#33230) (#33233) + * Fix mirror bug (#33224) (#33225) + * Fix system admin cannot fork or get private fork with API (#33401) (#33417) + * Fix push message behavior (#33215) (#33317) + * Trivial fixes (#33304) (#33312) + * Fix "stop time tracking button" on navbar (#33084) (#33300) + * Fix tag route and empty repo (#33253) + * Fix cache test triggered by non memory cache (#33220) (#33221) + * Revert empty lfs ref name (#33454) (#33457) + * Fix flex width (#33414) (#33418) + * Fix commit status events (#33320) #33493 + * Fix unnecessary comment when moving issue on the same project column (#33496) #33499 + * Add timetzdata build tag to binary releases (#33463) #33503 +* MISC + * Use ProtonMail/go-crypto to replace keybase/go-crypto (#33402) (#33410) + * Update katex to latest version (#33361) + * Update go tool dependencies (#32916) (#33355) + +## [1.23.1](https://github.com/go-gitea/gitea/releases/tag/v1.23.1) - 2025-01-09 + +* ENHANCEMENTS + * Move repo size to sidebar (#33155) (#33182) +* BUGFIXES + * Use updated path to s6-svscan after alpine upgrade (#33185) (#33188) + * Fix fuzz test (#33156) (#33158) + * Fix raw file API ref handling (#33172) (#33189) + * Fix ACME panic (#33178) (#33186) + * Fix branch dropdown not display ref name (#33159) (#33183) + * Fix assignee list overlapping in Issue sidebar (#33176) (#33181) + * Fix sync fork for consistency (#33147) #33192 + * Fix editor markdown not incrementing in a numbered list (#33187) #33193 + +## [1.23.0](https://github.com/go-gitea/gitea/releases/tag/v1.23.0) - 2025-01-08 + +* BREAKING + * Rename config option `[camo].Allways` to `[camo].Always` (#32097) + * Remove SHA1 for support for ssh rsa signing (#31857) + * Use UTC as default timezone when schedule Actions cron tasks (#31742) + * Delete Actions logs older than 1 year by default (#31735) + * Make OIDC introspection authentication strictly require Client ID and secret (#31632) + +* SECURITY + * Include file extension checks in attachment API (#32151) + * Include all security fixes which have been backported to v1.22 + +* FEATURES + * Allow to fork repository into the same owner (#32819) + * Support "merge upstream branch" (Sync fork) (#32741) + * Add Arch package registry (#32692) + * Allow to disable the password-based login (sign-in) form (#32687) + * Allow cropping an avatar before setting it (#32565) + * Support quote selected comments to reply (#32431) + * Add reviewers selection to new pull request (#32403) + * Suggestions for issues (#32327) + * Add priority to protected branch (#32286) + * Included tag search capabilities (#32045) + * Add option to filter board cards by labels and assignees (#31999) + * Add automatic light/dark option for the colorblind theme (#31997) + * Support migration from AWS CodeCommit (#31981) + * Introduce globallock as distributed locks (#31908 & #31813) + * Support compression for Actions logs & enable by default (#31761 & #32013) + * Add pure SSH LFS support (#31516) + * Add Passkey login support (#31504) + * Actions support workflow dispatch event (#28163) + * Support repo license (#24872) + * Issue time estimate, meaningful time tracking (#23113) + * GitHub like repo home page (#32213 & #32847) + * Rearrange Clone Panel (#31142) + * Enhancing Gitea OAuth2 Provider with Granular Scopes for Resource Access (#32573) + * Use env GITEA_RUNNER_REGISTRATION_TOKEN as global runner token (#32946) #32964 + * Update i18n.go - Language Picker (#32933) #32935 + +* PERFORMANCE + * Perf: add extra index to notification table (#32395) + * Introduce OrgList and add LoadTeams, optimaze Load teams for orgs (#32543) + * Improve performance of diffs (#32393) + * Make LFS http_client parallel within a batch. (#32369) + * Add new index for action to resolve the performance problem (#32333) + * Improve get feed with pagination (#31821) + * Performance improvements for pull request list API (#30490) + * Use batch database operations instead of one by one to optimze api pulls (#32680) + * Use gitrepo.GetTreePathLatestCommit to get file lastest commit instead from latest commit cache (#32987) #33046 + +* ENHANCEMENTS + * Code + * Remove unnecessary border in repo home page sidebar (#32767) + * Add 'Copy path' button to file view (#32584) + * Improve diff file tree (#32658) + * Add new [lfs_client].BATCH_SIZE and [server].LFS_MAX_BATCH_SIZE config settings. (#32307) + * Updated tokenizer to better matching when search for code snippets (#32261) + * Change the code search to sort results by relevance (#32134) + * Support migrating GitHub/GitLab PR draft status (#32242) + * Move lock icon position and add additional tooltips to branch list page (#31839) + * Add tag name in the commits list (#31082) + * Add `MAX_ROWS` option for CSV rendering (#30268) + * Allow code search by filename (#32210) + * Make git push options accept short name (#32245) + * Repo file list enhancements (#32835) + + * Markdown & Editor + * Refactor markdown math render, add dollor-backquote syntax support (#32831) + * Make Monaco theme follow browser, fully type codeeditor.ts (#32756) + * Refactor markdown editor and use it for milestone description editor (#32688) + * Add some handy markdown editor features (#32400) + * Improve markdown textarea for indentation and lists (#31406) + + * Issue + * Add label/author/assignee filters to the user/org home issue list (#32779) + * Refactor issue filter (labels, poster, assignee) (#32771) + * Style unification for the issue_management area (#32605) + * Add "View all branches/tags" entry to Branch Selector (#32653) + * Improve textarea paste (#31948) + * Add avif image file support (#32508) + * Prevent from submitting issue/comment on uploading (#32263) + * Issue Templates: add option to have dropdown printed list (#31577) + * Allow searching issues by ID (#31479) + * Add `is_archived` option for issue indexer (#32735) + * Improve attachment upload methods (#30513) + * Support issue template assignees (#31083) + * Prevent simultaneous editing of comments and issues (#31053) + * Add issue comment when moving issues from one column to another of the project (#29311) + + * Pull Request + * Display head branch more comfortable on pull request view (#32000) + * Simplify review UI (#31062) + * Allow force push to protected branches (#28086) + * Add line-through for deleted branch on pull request view page (#32500) + * Support requested_reviewers data in comment webhook events (#26178) + * Allow maintainers to view and edit files of private repos when "Allow maintainers to edit" is enabled (#32215) + * Allow including `Reviewed-on`/`Reviewed-by` lines for custom merge messages (#31211) + + * Actions + * Render job title as commit message (#32748) + * Refactor RepoActionView.vue, add `::group::` support (#32713) + * Make RepoActionView.vue support `##[group]` (#32770) + * Support `pull_request_target` event for commit status (#31703) + * Detect whether action view branch was deleted (#32764) + * Allow users with write permission to run actions (#32644) + * Show latest run when visit /run/latest (#31808) + + * Packages + * Improve rubygems package registry (#31357) + * Add support for npm bundleDependencies (#30751) + * Add signature support for the RPM module (#27069) + * Extract and display readme and comments for Composer packages (#30927) + + * Project + * Add title to project view page (#32747) + * Set the columns height to hug all its contents (#31726) + * Rename project `board` -> `column` to make the UI less confusing (#30170) + + * User & Organazition + * Use better name for userinfo structure (#32544) + * Use user.FullName in Oauth2 id_token response (#32542) + * Limit org member view of restricted users (#32211) + * Allow disabling authentication related user features (#31535) + * Add option to change mail from user display name (#31528) + * Use FullName in Emails to address the recipient if possible (#31527) + + * Administration + * Add support for a credentials chain for minio access (#31051) + * Move admin routers from /admin to /-/admin (#32189) + * Add cache test for admins (#31265) + * Add option for mailer to override mail headers (#27860) + * Azure blob storage support (#30995) + * Supports forced use of S3 virtual-hosted style (#30969) + * Move repository visibility to danger zone in the settings area (#31126) + + * Others + * Remove urls from translations (#31950) + * Simplify 404/500 page (#31409) + * Optimize installation-page experience (#32558) + * Refactor login page (#31530) + * Add new event commit status creation and webhook implementation (#27151) + * Repo Activity: count new issues that were closed (#31776) + * Set manual `tabindex`es on login page (#31689) + * Add `YEAR`, `MONTH`, `MONTH_ENGLISH`, `DAY` variables for template repos (#31584) + * Add typescript guideline and typescript-specific eslint plugins and fix issues (#31521) + * Make toast support preventDuplicates (#31501) + * Fix tautological conditions (#30735) + * Issue change title notifications (#33050) #33065 + +* API + * Implement update branch API (#32433) + * Fix missing outputs for jobs with matrix (#32823) + * Make API "compare" accept commit IDs (#32801) + * Add github compatible tarball download API endpoints (#32572) + * Harden runner updateTask and updateLog api (#32462) + * Add `DISABLE_ORGANIZATIONS_PAGE` and `DISABLE_CODE_PAGE` settings for explore pages and fix an issue related to user search (#32288) + * Make admins adhere to branch protection rules (#32248) + * Calculate `PublicOnly` for org membership only once (#32234) + * Allow filtering PRs by poster in the ListPullRequests API (#32209) + * Return 404 instead of error when commit not exist (#31977) + * Save initial signup information for users to aid in spam prevention (#31852) + * Fix upload maven pacakge parallelly (#31851) + * Fix null requested_reviewer from API (#31773) + * Add permission description for API to add repo collaborator (#31744) + * Add return type to GetRawFileOrLFS and GetRawFile (#31680) + * Add skip secondary authorization option for public oauth2 clients (#31454) + * Add tag protection via rest api #17862 (#31295) + * Document possible action types for the user activity feed API (#31196) + * Add topics for repository API (#31127) + * Add support for searching users by email (#30908) + * Add API endpoints for getting action jobs status (#26673) + +* REFACTOR + * Update JS and PY dependencies (#31940) + * Enable `no-jquery/no-parse-html-literal` and fix violation (#31684) + * Refactor image diff (#31444) + * Refactor CSRF token (#32216) + * Fix some typescript issues (#32586) + * Refactor names (#31405) + * Use per package global lock for container uploads instead of memory lock (#31860) + * Move team related functions to service layer (#32537) + * Move GetFeeds to service layer (#32526) + * Resolve lint for unused parameter and unnecessary type arguments (#30750) + * Reimplement GetUserOrgsList to make it simple and clear (#32486) + * Move some functions from issue.go to standalone files (#32468) + * Refactor sidebar assignee&milestone&project selectors (#32465) + * Refactor sidebar label selector (#32460) + * Fix a number of typescript issues (#32459) + * Refactor language menu and dom utils (#32450) + * Refactor issue page info (#32445) + * Split issue sidebar into small templates (#32444) + * Refactor template ctx and render utils (#32422) + * Refactor repo legacy (#32404) + * Refactor markup package (#32399) + * Refactor markup render system (#32533 & #32589 & #32612) + * Refactor the DB migration system slightly (#32344) + * Remove jQuery import from some files (#32512) + * Strict pagination check (#32548) + * Split mail sender sub package from mailer service package (#32618) + * Remove outdated code about fixture generation (#32708) + * Refactor RepoBranchTagSelector (#32681) + * Refactor issue list (#32755) + * Refactor LabelEdit (#32752) + * Split issue/pull view router function as multiple smaller functions (#32749) + * Refactor some LDAP code (#32849) + * Unify repo search order by logic (#30876) + * Remove duplicate empty repo check in delete branch API (#32569) + * Replace deprecated `math/rand` functions (#30733) + * Remove fomantic dimmer module (#30723) + * Add types to fetch,toast,bootstrap,svg (#31627) + * Refactor webhook (#31587) + * Move AddCollabrator and CreateRepositoryByExample to service layer (#32419) + * Refactor RepoRefByType (#32413) + * Refactor: remove redundant err declarations (#32381) + * Refactor markup code (#31399) + * Refactor render system (orgmode) (#32671) + * Refactor render system (#32492) + * Refactor markdown render (#32736 & #32728) + * Refactor repo unit "disabled" check (#31389) + * Refactor route path normalization (#31381) + * Refactor to use UnsafeStringToBytes (#31358) + * Migrate vue components to setup (#32329) + * Refactor globallock (#31933) + * Use correct function name (#31887) + * Use a common message template instead of a special one (#31878) + * Fix a number of Typescript issues (#31877) + * Refactor dropzone (#31482) + * Move custom `tw-` helpers to tailwind plugin (#31184) + * Replace `gt-word-break` with `tw-break-anywhere` (#31183) + * Drop `IDOrderDesc` for listing Actions task and always order by `id DESC` (#31150) + * Split common-global.js into separate files (#31438) + * Improve detecting empty files (#31332) + * Use `querySelector` over alternative DOM methods (#31280) + * Remove jQuery `.text()` (#30506) + * Use repo as of renderctx's member rather than a repoPath on metas (#29222) + * Refactor some frontend problems (#32646) + * Refactor DateUtils and merge TimeSince (#32409) + * Replace DateTime with proper functions (#32402) + * Replace DateTime with DateUtils (#32383) + * Convert frontend code to typescript (#31559) + * Refactor maven package registry (#33049) #33057 + * Refactor testfixtures #33028 + +* BUGFIXES + * Fix issues with inconsistent spacing in areas (#32607) + * Fix incomplete Actions status aggregations (#32859) + * In some lfs server implementations, they require the ref attribute. (#32838) + * Update the list of watchers and stargazers when clicking watch/unwatch or star/unstar (#32570) + * Fix `recentupdate` sorting bugs (#32505) + * Fix incorrect "Target branch does not exist" in PR title (#32222) + * Handle "close" actionable references for manual merges (#31879) + * render plain text file if the LFS object doesn't exist (#31812) + * Fix Null Pointer error for CommitStatusesHideActionsURL (#31731) + * Fix loadRepository error when access user dashboard (#31719) + * Hide the "Details" link of commit status when the user cannot access actions (#30156) + * Fix duplicate dropdown dividers (#32760) + * Fix SSPI button visibility when SSPI is the only enabled method (#32841) + * Fix overflow on org header (#32837) + * Exclude protected branches from recently pushed (#31748) + * Fix large image overflow in comment page (#31740) + * Fix milestone deadline and date related problems (#32339) + * Fix markdown preview $$ support (#31514) + * Fix a compilation error in the Gitpod environment (#32559) + * Fix PR diff review form submit (#32596) + * Fix a number of typescript issues (#32308) + * Fix some function names in comment (#32300) + * Fix absolute-date (#32375) + * Clarify Actions resources ownership (#31724) + * Try to fix ACME directory problem (#33072) #33077 + * Inherit submodules from template repository content (#16237) #33068 + * Use project's redirect url instead of composing url (#33058) #33064 + * Fix toggle commit body button ui when latest commit message is long (#32997) #33034 + * Fix package error handling and npm meta and empty repo guide #33112 + * Fix empty git repo handling logic and fix mobile view (#33101) #33102 + * Fix line-number and scroll bugs (#33094) #33095 + * Fix bleve fuzziness search (#33078) #33087 + * Fix broken forms #33082 + * Fix empty repo updated time (#33120) #33124 + * Add missing transaction when set merge #33113 + * Fix issue comment number (#30556) #33055 + * Fix duplicate co-author in squashed merge commit messages (#33020) #33054 + * Fix Agit pull request permission check (#32999) #33005 + * Fix scoped label ui when contains emoji (#33007) #33014 + * Fix bug on activities (#33008) #33016 + * Fix review code comment avatar alignment (#33031) #33032 + * Fix templating in pull request comparison (#33025) #33038 + * Fix bug automerge cannot be chosed when there is only 1 merge style (#33040) #33043 + * Fix settings not being loaded at CLI (#26402) #33048 + * Support for email addresses containing uppercase characters when activating user account (#32998) #33001 + * Support org labels when adding labels by label names (#32988) #32996 + * Do not render truncated links in markdown (#32980) #32983 + * Demilestone should not include milestone (#32923) #32979 + * Fix Azure blob object Seek (#32974) #32975 + * Fix maven pom inheritance (#32943) #32976 + * Fix textarea newline handle (#32966) #32977 + * Fix outdated tmpl code (#32953) #32961 + * Fix commit range paging (#32944) #32962 + * Fix repo avatar conflict (#32958) #32960 + * Fix trailing comma not matched in the case of alphanumeric issue (#32945) + * Relax the version checking for Arch packages (#32908) #32913 + * Add more load functions to make sure the reference object loaded (#32901) #32912 + * Filter reviews of one pull request in memory instead of database to reduce slow response because of lacking database index (#33106) #33128 + * Fix git remote error check, fix dependencies, fix js error (#33129) #33133 + +* MISC + * Optimize branch protection rule loading (#32280) + * Bump to go 1.23 (#31855) + * Remove unused call to $.HeadRepo in view_title template (#32317) + * Do not display `attestation-manifest` and use short sha256 instead of full sha256 (#32851) + * Upgrade htmx to 2.0.4 (#32834) + * Improve JSX/TSX support in code editor (#32833) + * Add User-Agent for gitea's self-implemented lfs client. (#32832) + * Use errors.New to replace fmt.Errorf with no parameters (#32800) + * Add "n commits" link to contributors in contributors graph page (#32799) + * Update dependencies, tweak eslint (#32719) + * Remove all "floated" CSS styles (#32691) + * Show tag name on branch/tag selector if repo shown from tag ref (#32689) + * Use new mail package instead of an unmintained one (#32682) + * Optimize the styling of icon buttons within file-header-right (#32675) + * Validate OAuth Redirect URIs (#32643) + * Support optional/configurable IAMEndpoint for Minio Client (#32581) (#32581) + * Make search box in issue sidebar dropdown list always show when scrolling (#32576) + * Bump CI,Flake and Snap to Node 22 (#32487) + * Update `github.com/meilisearch/meilisearch-go` (#32484) + * Add `DEFAULT_MIRROR_REPO_UNITS` and `DEFAULT_TEMPLATE_REPO_UNITS` options (#32416) + * Update go dependencies (#32389) + * Update JS and PY dependencies (#32388) + * Upgrade rollup to 4.24.0 (#32312) + * Upgrade vue to 3.5.12 (#32311) + * Improve the maintainblity of the reserved username list (#32229) + * Upgrade htmx to 2.0.3 (#32192) + * Count typescript files as frontend for labeling (#32088) + * Only use Host header from reverse proxy (#32060) + * Failed authentications are logged to level Warning (#32016) + * Enhance USER_DISABLED_FEATURES to allow disabling change username or full name (#31959) + * Distinguish official vs non-official reviews, add tool tips, and upgr… (#31924) + * Update mermaid to v11 (#31913) + * Bump relative-time-element to v4.4.3 (#31910) + * Upgrade `htmx` to `2.0.2` (#31847) + * Add warning message in merge instructions when `AutodetectManualMerge` was not enabled (#31805) + * Add types to various low-level functions (#31781) + * Update JS dependencies (#31766) + * Remove unused code from models/repos/release.go (#31756) + * Support delete user email in admin panel (#31690) + * Add `username` to OIDC introspection response (#31688) + * Use GetDisplayName() instead of DisplayName() to generate rss feeds (#31687) + * Code editor theme enhancements (#31629) + * Update JS dependencies (#31616) + * Add types for js globals (#31586) + * Add back esbuild-loader for .js files (#31585) + * Don't show hidden labels when filling out an issue template (#31576) + * Allow synchronizing user status from OAuth2 login providers (#31572) + * Display app name in the registration email title (#31562) + * Use stable version of fabric (#31526) + * Support legacy _links LFS batch responses (#31513) + * Fix JS error with disabled attachment and easymde (#31511) + * Always use HTML attributes for avatar size (#31509) + * Use nolyfill to remove some polyfills (#31468) + * Disable issue/PR comment button given empty input (#31463) + * Add simple JS init performance trace (#31459) + * Bump htmx to 2.0.0 (#31413) + * Update JS dependencies, remove `eslint-plugin-jquery` (#31402) + * Split org Propfile README to a new tab `overview` (#31373) + * Update nix flake and add gofumpt (#31320) + * Code optimization (#31315) + * Enable poetry non-package mode (#31282) + * Optimize profile layout to enhance visual experience (#31278) + * Update `golang.org/x/net` (#31260) + * Bump `@github/relative-time-element` to v4.4.1 (#31232) + * Remove unnecessary inline style for tab-size (#31224) + * Update golangci-lint to v1.59.0 (#31221) + * Update chroma to v2.14.0 (#31177) + * Update JS dependencies (#31120) + * Improve the handling of `jobs..if` (#31070) + * Clean up revive linter config, tweak golangci output (#30980) + * Use CSS `inset` shorthand (#30939) + * Forbid deprecated `break-word` in CSS (#30934) + * Remove obsolete monaco workaround (#30893) + * Update JS dependencies, add new eslint rules (#30840) + * Fix body margin shifting with modals, fix error on project column edit (#30831) + * Remove disk-clean workflow (#30741) + * Bump `github.com/google/go-github` to v61 (#30738) + * Add built js files to eslint ignore (#30737) + * Use `ProtonMail/go-crypto` for `opengpg` in tests (#30736) + * Upgrade xorm to v1.3.9 and improve some migrations Sync (#29899) + * Added default sorting milestones by name (#27084) + * Enable `unparam` linter (#31277) + * Use Alpine 3.21 for the docker images (#32924) #32951 + * Bump x/net (#32896) #32899 + * 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 + * Fix basic auth with webauthn (#32531) (#32536) + * Refactor internal routers (partial backport, auth token const time comparing) (#32473) (#32479) +* PERFORMANCE + * Remove transaction for archive download (#32186) (#32520) +* BUGFIXES + * Fix `missing signature key` error when pulling Docker images with `SERVE_DIRECT` enabled (#32365) (#32397) + * Fix get reviewers fails when selecting user without pull request permissions unit (#32415) (#32616) + * Fix adding index files to tmp directory (#32360) (#32593) + * Fix PR creation on forked repositories via API (#31863) (#32591) + * Fix missing menu tabs in organization project view page (#32313) (#32592) + * Support HTTP POST requests to `/userinfo`, aligning to OpenID Core specification (#32578) (#32594) + * Fix debian package clean up cron job (#32351) (#32590) + * Fix GetInactiveUsers (#32540) (#32588) + * Allow the actions user to login via the jwt token (#32527) (#32580) + * Fix submodule parsing (#32571) (#32577) + * Refactor find forks and fix possible bugs that weaken permissions check (#32528) (#32547) + * Fix some places that don't respect org full name setting (#32243) (#32550) + * Refactor push mirror find and add check for updating push mirror (#32539) (#32549) + * Fix basic auth with webauthn (#32531) (#32536) + * Fix artifact v4 upload above 8MB (#31664) (#32523) + * Fix oauth2 error handle not return immediately (#32514) (#32516) + * Fix action not triggered when commit message is too long (#32498) (#32507) + * Fix `GetRepoLink` nil pointer dereference on dashboard feed page when repo is deleted with actions enabled (#32501) (#32502) + * Fix `missing signature key` error when pulling Docker images with `SERVE_DIRECT` enabled (#32397) (#32397) + * Fix the permission check for user search API and limit the number of returned users for `/user/search` (#32310) + * Fix SearchIssues swagger docs (#32208) (#32298) + * Fix dropdown content overflow (#31610) (#32250) + * Disable Oauth check if oauth disabled (#32368) (#32480) + * Respect renamed dependencies of Cargo registry (#32430) (#32478) + * Fix mermaid diagram height when initially hidden (#32457) (#32464) + * Fix broken releases when re-pushing tags (#32435) (#32449) + * Only provide the commit summary for Discord webhook push events (#32432) (#32447) + * Only query team tables if repository is under org when getting assignees (#32414) (#32426) + * Fix created_unix for mirroring (#32342) (#32406) + * Respect UI.ExploreDefaultSort setting again (#32357) (#32385) + * Fix broken image when editing comment with non-image attachments (#32319) (#32345) + * Fix disable 2fa bug (#32320) (#32330) + * Always update expiration time when creating an artifact (#32281) (#32285) + * Fix null errors on conversation holder (#32258) (#32266) (#32282) + * Only rename a user when they should receive a different name (#32247) (#32249) + * Fix checkbox bug on private/archive filter (#32236) (#32240) + * Add a doctor check to disable the "Actions" unit for mirrors (#32424) (#32497) + * Quick fix milestone deadline 9999 (#32423) + * Make `show stats` work when only one file changed (#32244) (#32268) + * Make `owner/repo/pulls` handlers use "PR reader" permission (#32254) (#32265) + * Update scheduled tasks even if changes are pushed by "ActionsUser" (#32246) (#32252) +* MISC + * Remove unnecessary code: `GetPushMirrorsByRepoID` called on all repo pages (#32560) (#32567) + * Improve some sanitizer rules (#32534) + * Update nix development environment vor v1.22.x (#32495) + * Add warn log when deleting inactive users (#32318) (#32321) + * Update github.com/go-enry/go-enry to v2.9.1 (#32295) (#32296) + * Warn users when they try to use a non-root-url to sign in/up (#32272) (#32273) + +## [1.22.3](https://github.com/go-gitea/gitea/releases/tag/v1.22.3) - 2024-10-08 + +* SECURITY + * Fix bug when a token is given public only (#32204) (#32218) +* PERFORMANCE + * Increase `cacheContextLifetime` to reduce false reports (#32011) (#32023) + * Don't join repository when loading action table data (#32127) (#32143) +* BUGFIXES + * Fix javascript error when an anonymous user visits migration page (#32144) (#32179) + * Don't init signing keys if oauth2 provider is disabled (#32177) + * Fix wrong status of `Set up Job` when first step is skipped (#32120) (#32125) + * Fix bug when deleting a migrated branch (#32075) (#32123) + * Truncate commit message during Discord webhook push events (#31970) (#32121) + * Allow to set branch protection in an empty repository (#32095) (#32119) + * Fix panic when cloning with wrong ssh format. (#32076) (#32118) + * Fix rename branch permission bug (#32066) (#32108) + * Fix: database not update release when using `git push --tags --force` (#32040) (#32074) + * Add missing comment reply handling (#32050) (#32065) + * Do not escape relative path in RPM primary index (#32038) (#32054) + * Fix `/repos/{owner}/{repo}/pulls/{index}/files` endpoint not populating `previous_filename` (#32017) (#32028) + * Support allowed hosts for migrations to work with proxy (#32025) (#32026) + * Fix the logic of finding the latest pull review commit ID (#32139) (#32165) + * Fix bug in getting merged pull request by commit (#32079) (#32117) + * Fix wrong last modify time (#32102) (#32104) + * Fix incorrect `/tokens` api (#32085) (#32092) + * Handle invalid target when creating releases using API (#31841) (#32043) + * Check if the `due_date` is nil when editing issues (#32035) (#32042) + * Fix container parallel upload bugs (#32022) + * Fixed race condition when deleting documents by repoId in ElasticSearch (#32185) (#32188) + * Refactor CSRF protector (#32057) (#32069) + * Fix Bug in Issue/pulls list (#32081) (#32115) + * Include collaboration repositories on dashboard source/forks/mirrors list (#31946) (#32122) + * Add null check for responseData.invalidTopics (#32212) (#32217) +* TESTING + * Fix mssql ci with a new mssql version on ci (#32094) +* MISC + * Upgrade some dependencies include minio-go (#32166) + * Add bin to Composer Metadata (#32099) (#32106) + * Lazy load avatar images (#32051) (#32063) + * Upgrade cache to v0.2.1 (#32003) (#32009) + +## [1.22.2](https://github.com/go-gitea/gitea/releases/tag/v1.22.2) - 2024-08-28 + +* Security + * Replace v-html with v-text in search inputbox (#31966) (#31973) + * Fix nuget/conan/container packages upload bugs (#31967) (#31982) +* PERFORMANCE + * Refactor the usage of batch catfile (#31754) (#31889) +* BUGFIXES + * Fix overflowing content in action run log (#31842) (#31853) + * Scroll images in project issues separately from the remaining issue (#31683) (#31823) + * Add `:focus-visible` style to buttons (#31799) (#31819) + * Fix the display of project type for deleted projects (#31732) (#31734) + * Fix API owner ID should be zero when created repo secret (#31715) (#31811) + * Set owner id to zero when GetRegistrationToken for repo (#31725) (#31729) + * Fix API endpoint for registration-token (#31722) (#31728) + * Add permission check when creating PR (#31033) (#31720) + * Don't return 500 if mirror url contains special chars (#31859) (#31895) + * Fix agit automerge (#31207) (#31881) + * Add CfTurnstileSitekey context data to all captcha templates (#31874) (#31876) + * Avoid returning without written ctx when posting PR (#31843) (#31848) + * Fix raw wiki links (#31825) (#31845) + * Fix panic of ssh public key page after deletion of auth source (#31829) (#31836) + * Fixes for unreachable project issues when transfer repository from organization (#31770) (#31828) + * Show lock owner instead of repo owner on LFS setting page (#31788) (#31817) + * Fix `IsObjectExist` with gogit (#31790) (#31806) + * Fix protected branch files detection on pre_receive hook (#31778) (#31796) + * Add `TAGS` to `TEST_TAGS` and fix bugs found with gogit (#31791) (#31795) + * Rename head branch of pull requests when renaming a branch (#31759) (#31774) + * Fix wiki revision pagination (#31760) (#31772) + * Bump vue-bar-graph (#31705) (#31753) + * Distinguish LFS object errors to ignore missing objects during migration (#31702) (#31745) + * Make GetRepositoryByName more safer (#31712) (#31718) + * Fix a branch divergence cache bug (#31659) (#31661) + * Allow org team names of length 255 in create team form (#31564) (#31603) + * Use old behavior for telegram webhook (#31588) + * Bug fix for translation in ru (#31892) + * Fix actions notify bug (#31866) (#31875) + * Fix the component of access token list not mounted (#31824) (#31868) + * Add missing repository type filter parameters to pager (#31832) (#31837) + * Fix dates displaying in a wrong manner when we're close to the end of… (#31750) + * Fix "Filter by commit" Dropdown (#31695) (#31696) + * Properly filter issue list given no assignees filter (#31522) (#31685) + * Prevent update pull refs manually and will not affect other refs update (#31931)(#31955) + * Fix sort order for organization home and user profile page (#31921) (#31922) + * Fix search team (#31923) (#31942) + * Fix 500 error when state params is set when editing issue/PR by API (#31880) (#31952) + * Fix index too many file names bug (#31903) (#31953) + * Add lock for parallel maven upload (#31851) (#31954) +* MISC + * Remove "dsa-1024" testcases from Test_SSHParsePublicKey and Test_calcFingerprint (#31905) (#31914) + * Upgrade bleve to 2.4.2 (#31894) + * Remove unneccessary uses of `word-break: break-all` (#31637) (#31652) + * Return an empty string when a repo has no avatar in the repo API (#31187) (#31567) + * Upgrade micromatch to 4.0.8 (#31944) + * Update webpack to 5.94.0 (#31941) + +## [1.22.1](https://github.com/go-gitea/gitea/releases/tag/v1.22.1) - 2024-07-04 + +* SECURITY + * Add replacement module for `mholt/archiver` (#31267) (#31270) +* API + * Fix missing images in editor preview due to wrong links (#31299) (#31393) + * Fix duplicate sub-path for avatars (#31365) (#31368) + * Reduce memory usage for chunked artifact uploads to MinIO (#31325) (#31338) + * Remove sub-path from container registry realm (#31293) (#31300) + * Fix NuGet Package API for $filter with Id equality (#31188) (#31242) + * Add an immutable tarball link to archive download headers for Nix (#31139) (#31145) + * Add missed return after `ctx.ServerError` (#31130) (#31133) +* BUGFIXES + * Fix avatar radius problem on the new issue page (#31506) (#31508) + * Fix overflow menu flickering on mobile (#31484) (#31488) + * Fix poor table column width due to breaking words (#31473) (#31477) + * Support relative paths to videos from Wiki pages (#31061) (#31453) + * Fix new issue/pr avatar (#31419) (#31424) + * Increase max length of org team names from 30 to 255 characters (#31410) (#31421) + * Fix line number width in code preview (#31307) (#31316) + * Optimize runner-tags layout to enhance visual experience (#31258) (#31263) + * Fix overflow on push notification (#31179) (#31238) + * Fix overflow on notifications (#31178) (#31237) + * Fix overflow in issue card (#31203) (#31225) + * Split sanitizer functions and fine-tune some tests (#31192) (#31200) + * use correct l10n string (#31487) (#31490) + * Fix dropzone JS error when attachment is disabled (#31486) + * Fix web notification icon not updated once you read all notifications (#31447) (#31466) + * Switch to "Write" tab when edit comment again (#31445) (#31461) + * Fix the link for .git-blame-ignore-revs bypass (#31432) (#31442) + * Fix the wrong line number in the diff view page when expanded twice. (#31431) (#31440) + * Fix labels and projects menu overflow on issue page (#31435) (#31439) + * Fix Account Linking UpdateMigrationsByType (#31428) (#31434) + * Fix markdown math brackets render problem (#31420) (#31430) + * Fix rendered wiki page link (#31398) (#31407) + * Fix natural sort (#31384) (#31394) + * Allow downloading attachments of draft releases (#31369) (#31380) + * Fix repo graph JS (#31377) + * Fix incorrect localization `explorer.go` (#31348) (#31350) + * Fix hash render end with colon (#31319) (#31346) + * Fix line number widths (#31341) (#31343) + * Fix navbar `+` menu flashing on page load (#31281) (#31342) + * Fix adopt repository has empty object name in database (#31333) (#31335) + * Delete legacy cookie before setting new cookie (#31306) (#31317) + * Fix some URLs whose sub-path is missing (#31289) (#31292) + * Fix admin oauth2 custom URL settings (#31246) (#31247) + * Make pasted "img" tag has the same behavior as markdown image (#31235) (#31243) + * Fix agit checkout command line hint & fix ShowMergeInstructions checking (#31219) (#31222) + * Fix the possible migration failure on 286 with postgres 16 (#31209) (#31218) + * Fix branch order (#31174) (#31193) + * Fix markup preview (#31158) (#31166) + * Fix push multiple branches error with tests (#31151) (#31153) + * Fix API repository object format missed (#31118) (#31132) + * Fix missing memcache import (#31105) (#31109) + * Upgrade `github.com/hashicorp/go-retryablehttp` (#31499) + * Fix double border in system status table (#31363) (#31401) + * Fix bug filtering issues which have no project (#31337) (#31367) + * Fix #31185 try fix lfs download from bitbucket failed (#31201) (#31329) + * Add nix flake for dev shell (#30967) (#31310) + * Fix and clean up `ConfirmModal` (#31283) (#31291) + * Optimize repo-list layout to enhance visual experience (#31272) (#31276) + * fixed the dropdown menu for the top New button to expand to the left (#31273) (#31275) + * Fix Activity Page Contributors dropdown (#31264) (#31269) + * fix: allow actions artifacts storage migration to complete succesfully (#31251) (#31257) + * Make blockquote attention recognize more syntaxes (#31240) (#31250) + * Remove .segment from .project-column (#31204) (#31239) + * Ignore FindRecentlyPushedNewBranches err (#31164) (#31171) + * Use vertical layout for multiple code expander buttons (#31122) (#31152) + * Remove duplicate `ProxyPreserveHost` in Apache httpd doc (#31143) (#31147) + * Improve mobile review ui (#31091) (#31136) + * Fix DashboardRepoList margin (#31121) (#31128) + * Update pip related commands for docker (#31106) (#31111) + +## [1.22.0](https://github.com/go-gitea/gitea/releases/tag/v1.22.0) - 2024-05-27 + +This release stands as a monumental milestone in our development journey with a record-breaking incorporation of [1528](https://github.com/go-gitea/gitea/pulls?q=is%3Apr+milestone%3A1.22.0+is%3Amerged) pull requests. It marks the most extensive update in Gitea's history, showcasing a plethora of new features and infrastructure improvements. + +Noteworthy advancements in this release include the introduction of `HTMX` and `Tailwind`, signaling a strategic shift as we gradually phase out `jquery` and `Fomantic UI`. These changes reflect our commitment to embracing modern technologies and enhancing the user experience. + +Key highlights of this release encompass significant changes categorized under `BREAKING`, `FEATURES`, `ENHANCEMENTS`, and `PERFORMANCE`, each contributing to a more robust and efficient Gitea platform. + +* BREAKING + * Improve reverse proxy documents and clarify the AppURL guessing behavior (#31003) (#31020) + * Remember log in for a month by default (#30150) + * Breaking summary for template refactoring (#29395) + * All custom templates need to follow these changes + * Recommend/convert to use case-sensitive collation for MySQL/MSSQL (#28662) + * Make offline mode as default to not connect external avatar service by default (#28548) + * Include public repos in the doer's dashboard for issue search (#28304) + * Use restricted sanitizer for repository description (#28141) + * Support storage base path as prefix (#27827) + * Enhanced auth token / remember me (#27606) + * Rename the default themes to `gitea-light`, `gitea-dark`, `gitea-auto` (#27419) + * If you didn't see the new themes, please remove the `[ui].THEMES` config option from `app.ini` + * Require MySQL 8.0, PostgreSQL 12, MSSQL 2012 (#27337) +* FEATURES + * Allow everyone to read or write a wiki by a repo unit setting (#30495) + * Use raw Wiki links for non-renderable Wiki files (#30273) + * Render embedded code preview by permalink in markdown (#30234) (#30249) + * Support repo code search without setting up an indexer (#29998) + * Support pasting URLs over markdown text (#29566) + * Allow to change primary email before account activation (#29412) + * Customizable "Open with" applications for repository clone (#29320) + * Allow options to disable user deletion from the interface on app.ini (#29275) + * Extend issue template YAML engine (#29274) + * Add support for `linguist-detectable` and `linguist-documentation` (#29267) + * Implement code frequency graph (#29191) + * Show commit status for releases (#29149) + * Add user blocking (#29028) + * Actions Artifacts v4 backend (#28965) + * Add merge style `fast-forward-only` (#28954) + * Retarget depending pulls when the parent branch is deleted (#28686) + * Add global setting on how timestamps should be rendered (#28657) + * Implement actions badge SVGs (#28102) + * Add skip ci functionality (#28075) + * Show latest commit for file (#28067) + * Allow to sync tags from the admin dashboard (#28045) + * Add Profile Readme for Organisations (#27955) + * Implement contributors graph (#27882) + * Artifact deletion in actions ui (#27172) + * Add API routes to get runner registration token (#27144) + * Add support for forking single branch (#25821) + * Add support for sha256 repositories (#23894) + * Add admin API route for managing user's badges (#23106) +* ENHANCEMENTS + * Make gitea webhooks openproject compatible (#28435) (#31081) + * Support using label names when changing issue labels (#30943) (#30958) + * Fix various problems around project board view (#30696) (#30902) + * Improve context popup rendering (#30824) (#30829) + * Allow to save empty comment (#30706) + * Prevent allow/reject reviews on merged/closed PRs (#30686) + * Initial support for colorblindness-friendly themes (#30625) + * Some NuGet package enhancements (#30280) (#30324) + * Markup color and font size fixes (#30282) (#30310) + * Show 12 lines in markup code preview (#30255) (#30257) + * Add `[other].SHOW_FOOTER_POWERED_BY` setting to hide `Powered by` (#30253) + * Pulse page improvements (#30149) + * Render code tags in commit messages (#30146) + * Prevent re-review and dismiss review actions on closed and merged PRs (#30065) + * Cancel previous runs of the same PR automatically (#29961) + * Drag-and-drop improvements for projects and issue pins (#29875) + * Add default board to new projects, remove uncategorized pseudo-board (#29874) + * Prevent layout shift in `` items (#29831) + * Add skip ci support for pull request title (#29774) + * Add more stats tables (#29730) + * Update API to return 'source_id' for users (#29718) + * Determine fuzziness of bleve indexer by keyword length (#29706) + * Expose fuzzy search for issues/pulls (#29701) + * Put an edit file button on pull request files to allow a quick operation (#29697) + * Fix action runner offline label padding (#29691) + * Update allowed attachment types (#29688) + * Completely style the webkit autofill (#29683) + * Highlight archived labels (#29680) + * Add a warning for disallowed email domains (#29658) + * Set user's 24h preference from their current OS locale (#29651) + * Add setting to disable user features when user login type is not plain (#29615) + * Improve natural sort (#29611) + * Make wiki default branch name changeable (#29603) + * Unify search boxes (#29530) + * Add support for API blob upload of release attachments (#29507) + * Detect broken git hooks (#29494) + * Sync branches to DB immediately when handling git hook calling (#29493) + * Allow options to disable user GPG key configuration from the interface on app.ini (#29486) + * Allow options to disable user SSH key configuration from the interface on app.ini (#29447) + * Use relative links for commits, mentions, and issues in markdown (#29427) + * Add ``, rename webcomponents (#29400) + * Include resource state events in Gitlab downloads (#29382) + * Properly migrate target branch change GitLab comment (#29340) + * Recolor dark theme to blue shade (#29283) + * Partially enable MSSQL case-sensitive collation support (#29238) + * Auto-update the system status in the admin dashboard (#29163) + * Integrate alpine `noarch` packages into other architectures index (#29137) + * Document how the TOC election process works (#29135) + * Tweak repo header (#29134) + * Make blockquote border size less aggressive (#29124) + * Downscale pasted PNG images based on metadata (#29123) + * Show `View at this point in history` for every commit (#29122) + * Add support for action artifact serve direct (#29120) + * Change webhook-type in create-view (#29114) + * Drop "@" from the email sender to avoid spam filters (#29109) + * Allow non-admin users to delete review requests (#29057) + * Improve user search display name (#29002) + * Include username in email headers (#28981) + * Show whether a PR is WIP inside popups (#28975) + * Also match weakly validated ETags (#28957) + * Support nuspec manifest download for Nuget packages (#28921) + * Fix hardcoded GitHub icon used as migrated release avatar (#28910) + * Propagate install_if and provider_priority to APKINDEX (#28899) + * Add artifacts v4 JWT to job message and accept it (#28885) + * Enable/disable owner and repo projects independently (#28805) + * Add non-JS fallback for reaction tooltips (#28785) + * Add the ability to see open and closed issues at the same time (#28757) + * Move sign-in labels to be above inputs (#28753) + * Display the latest sync time for pull mirrors on the repo page (#28712) + * Show in Web UI if the file is vendored and generated (#28620) + * Add orphaned topic consistency check (#28507) + * Add branch protection setting for ignoring stale approvals (#28498) + * Add option to set language in admin user view (#28449) + * Fix incorrect run order of action jobs (#28367) + * Add missing exclusive in advanced label options (#28322) + * Added instance-level variables (#28115) + * Add edit option for README.md (#28071) + * Fix link to `Code` tab on wiki commits (#28041) + * Allow to set explore page default sort (#27951) + * Improve PR diff view on mobile (#27883) + * Properly migrate automatic merge GitLab comments (#27873) + * Display issue task list on project cards (#27865) + * Add Index to pull_auto_merge.doer_id (#27811) + * Fix display member unit in the menu bar if there are no hidden members in public org (#27795) + * List all Debian package versions in `Packages` (#27786) + * Allow pull requests Manually Merged option to be used by non-admins (#27780) + * Only show diff file tree when more than one file changed (#27775) + * Show placeholder email in privacy popup (#27770) + * Revamp repo header (#27760) + * Add `must-change-password` command line parameter (#27626) + * Unify password changing and invalidate auth tokens (#27625) + * Add border to file tree 'sub-items' and add padding to 'item-file' (#27593) + * Add slow SQL query warning (#27545) + * Pre-register OAuth application for tea (#27509) + * Differentiate between `push` and `pull` `mirror sync in progress` (#27390) + * Link to file from its history (#27354) + * Add a shortcut to user's profile page to admin user details (#27299) + * Doctor: delete action entries without existing user (#27292) + * Show total TrackedTime on issue/pull/milestone lists (#26672) + * Don't show the new pull request button when the page is not compare pull (#26431) + * Add `Hide/Show all checks` button to commit status check (#26284) + * Improvements of releases list and tags list (#25859) +* PERFORMANCE + * Fix package list performance (#30520) (#30616) + * Add commit status summary table to reduce query from commit status table (#30223) + * Refactor markup/csv: don't read all to memory (#29760) + * Lazy load object format with command line and don't do it in OpenRepository (#29712) + * Add cache for branch divergence on branch list page (#29577) + * Do some performance optimization for issues list and view issue/pull (#29515) + * Cache repository default branch commit status to reduce query on commit status table (#29444) + * Use `crypto/sha256` (#29386) + * Some performance optimization on the dashboard and issues page (#29010) + * Add combined index for issue_user.uid and issue_id (#28080) + ## [1.21.11](https://github.com/go-gitea/gitea/releases/tag/v1.21.11) - 2024-04-07 * SECURITY diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60146276db..11c99d1e3a 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://crowdin.com/project/gitea). +All translation work happens on [Crowdin](https://translate.gitea.com). 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 2a6b1dd6b7..fa2ae9913c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage -FROM docker.io/library/golang:1.23-alpine3.20 AS build-env +FROM docker.io/library/golang:1.24-alpine3.21 AS build-env ARG GOPROXY ENV GOPROXY=${GOPROXY:-direct} @@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM docker.io/library/alpine:3.20 +FROM docker.io/library/alpine:3.21 LABEL maintainer="maintainers@gitea.io" EXPOSE 22 3000 @@ -78,7 +78,7 @@ ENV GITEA_CUSTOM=/data/gitea VOLUME ["/data"] ENTRYPOINT ["/usr/bin/entrypoint"] -CMD ["/bin/s6-svscan", "/etc/s6"] +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 diff --git a/Dockerfile.rootless b/Dockerfile.rootless index 26f02205a7..b74dfa58e0 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,5 @@ # Build stage -FROM docker.io/library/golang:1.23-alpine3.20 AS build-env +FROM docker.io/library/golang:1.24-alpine3.21 AS build-env ARG GOPROXY ENV GOPROXY=${GOPROXY:-direct} @@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM docker.io/library/alpine:3.20 +FROM docker.io/library/alpine:3.21 LABEL maintainer="maintainers@gitea.io" EXPOSE 2222 3000 diff --git a/MAINTAINERS b/MAINTAINERS index 160bffcdb7..7d21f449fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -31,7 +31,6 @@ 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) @@ -46,7 +45,6 @@ Wim (@42wim) Jason Song (@wolfogre) Yarden Shoham (@yardenshoham) Yu Tian (@Zettat123) -Eddie Yang <576951401@qq.com> (@yp05327) Dong Ge (@sillyguodong) Xinyi Gong (@HesterG) wxiaoguang (@wxiaoguang) @@ -63,3 +61,6 @@ Tim-Niclas Oelschläger (@zokkis) 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 b9e940b248..6c8798318c 100644 --- a/Makefile +++ b/Makefile @@ -23,20 +23,20 @@ SHASUM ?= shasum -a 256 HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) COMMA := , -XGO_VERSION := go-1.23.x +XGO_VERSION := go-1.24.x AIR_PACKAGE ?= github.com/air-verse/air@v1 -EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0 +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.1.2 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.60.3 -GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 -MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1 +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.5 +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 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.15.3 +GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.1 DOCKER_IMAGE ?= gitea/gitea DOCKER_TAG ?= latest @@ -73,6 +73,7 @@ EXTRA_GOFLAGS ?= MAKE_VERSION := $(shell "$(MAKE)" -v | cat | head -n 1) MAKE_EVIDENCE_DIR := .make_evidence +GOTESTFLAGS ?= ifeq ($(RACE_ENABLED),true) GOFLAGS += -race GOTESTFLAGS += -race @@ -114,8 +115,6 @@ LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64 GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/)) MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) -FOMANTIC_WORK_DIR := web_src/fomantic - WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f) WEBPACK_CONFIGS := webpack.config.js tailwind.config.js WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css @@ -139,14 +138,14 @@ TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags TEST_TAGS ?= $(TAGS_SPLIT) sqlite sqlite_unlock_notify -TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMANTIC_WORK_DIR)/node_modules $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR) +TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR) 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 tests/e2e +ESLINT_FILES := web_src/js tools *.js *.ts *.cjs 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)) +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/*)) EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini GO_SOURCES := $(wildcard *.go) @@ -165,10 +164,8 @@ ifdef DEPS_PLAYWRIGHT endif SWAGGER_SPEC := templates/swagger/v1_json.tmpl -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_SPEC_INPUT := templates/swagger/v1_input.json SWAGGER_EXCLUDE := code.gitea.io/sdk -SWAGGER_NEWLINE_COMMAND := -e '$$a\' TEST_MYSQL_HOST ?= mysql:3306 TEST_MYSQL_DBNAME ?= testgitea @@ -189,67 +186,11 @@ TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1 all: build .PHONY: help -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" +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" .PHONY: go-check go-check: @@ -280,11 +221,11 @@ node-check: fi .PHONY: clean-all -clean-all: clean +clean-all: clean ## delete backend, frontend and integration files rm -rf $(WEBPACK_DEST_ENTRIES) node_modules .PHONY: clean -clean: +clean: ## delete backend and integration files rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \ integrations*.test \ e2e*.test \ @@ -296,7 +237,7 @@ clean: tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/ .PHONY: fmt -fmt: +fmt: ## format the Go code @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 @@ -311,7 +252,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:"; \ - echo "$${diff}"; \ + printf "%s" "$${diff}"; \ exit 1; \ fi @@ -325,95 +266,95 @@ TAGS_PREREQ := $(TAGS_EVIDENCE) endif .PHONY: generate-swagger -generate-swagger: $(SWAGGER_SPEC) +generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments -$(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)' +$(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)' .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:"; \ - echo "$${diff}"; \ + printf "%s" "$${diff}"; \ exit 1; \ fi .PHONY: swagger-validate -swagger-validate: - $(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)' +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 $(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)' - $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' + @$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath .PHONY: checks -checks: checks-frontend checks-backend +checks: checks-frontend checks-backend ## run various consistency checks .PHONY: checks-frontend -checks-frontend: lockfile-check svg-check +checks-frontend: lockfile-check svg-check ## check frontend files .PHONY: checks-backend -checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check +checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check ## check backend files .PHONY: lint -lint: lint-frontend lint-backend lint-spell +lint: lint-frontend lint-backend lint-spell ## lint everything .PHONY: lint-fix -lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix +lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues .PHONY: lint-frontend -lint-frontend: lint-js lint-css +lint-frontend: lint-js lint-css ## lint frontend files .PHONY: lint-frontend-fix -lint-frontend-fix: lint-js-fix lint-css-fix +lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues .PHONY: lint-backend -lint-backend: lint-go lint-go-vet lint-go-gopls lint-editorconfig +lint-backend: lint-go lint-go-gitea-vet lint-go-gopls lint-editorconfig ## lint backend files .PHONY: lint-backend-fix -lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig +lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backend files and fix issues .PHONY: lint-js -lint-js: node_modules +lint-js: node_modules ## lint js files npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) -# npx tsc + npx vue-tsc .PHONY: lint-js-fix -lint-js-fix: node_modules +lint-js-fix: node_modules ## lint js files and fix issues npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) --fix -# npx tsc + npx vue-tsc .PHONY: lint-css -lint-css: node_modules +lint-css: node_modules ## lint css files npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) .PHONY: lint-css-fix -lint-css-fix: node_modules +lint-css-fix: node_modules ## lint css files and fix issues npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix .PHONY: lint-swagger -lint-swagger: node_modules +lint-swagger: node_modules ## lint swagger files npx spectral lint -q -F hint $(SWAGGER_SPEC) .PHONY: lint-md -lint-md: node_modules +lint-md: node_modules ## lint markdown files npx markdownlint *.md .PHONY: lint-spell -lint-spell: +lint-spell: ## lint spelling @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES) .PHONY: lint-spell-fix -lint-spell-fix: +lint-spell-fix: ## lint spelling and fix issues @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES) .PHONY: lint-go -lint-go: +lint-go: ## lint go files $(GO) run $(GOLANGCI_LINT_PACKAGE) run .PHONY: lint-go-fix -lint-go-fix: +lint-go-fix: ## lint go files and fix issues $(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix # workaround step for the lint-go-windows CI task because 'go run' can not @@ -423,57 +364,58 @@ lint-go-windows: @GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE) golangci-lint run -.PHONY: lint-go-vet -lint-go-vet: - @echo "Running go vet..." +.PHONY: lint-go-gitea-vet +lint-go-gitea-vet: ## lint go files with gitea-vet + @echo "Running gitea-vet..." @GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet @$(GO) vet -vettool=gitea-vet ./... .PHONY: lint-go-gopls -lint-go-gopls: +lint-go-gopls: ## lint go files with 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-actions: ## lint action workflow files $(GO) run $(ACTIONLINT_PACKAGE) .PHONY: lint-templates -lint-templates: .venv node_modules +lint-templates: .venv node_modules ## lint template files @node tools/lint-templates-svg.js @poetry run djlint $(shell find templates -type f -iname '*.tmpl') .PHONY: lint-yaml -lint-yaml: .venv - @poetry run yamllint . +lint-yaml: .venv ## lint yaml files + @poetry run yamllint -s . .PHONY: watch -watch: +watch: ## watch everything and continuously rebuild @bash tools/watch.sh .PHONY: watch-frontend -watch-frontend: node-check node_modules +watch-frontend: node-check node_modules ## watch frontend files and continuously rebuild @rm -rf $(WEBPACK_DEST_ENTRIES) NODE_ENV=development npx webpack --watch --progress .PHONY: watch-backend -watch-backend: go-check +watch-backend: go-check ## watch backend files and continuously rebuild GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml .PHONY: test -test: test-frontend test-backend +test: test-frontend test-backend ## test everything .PHONY: test-backend -test-backend: +test-backend: ## test frontend files @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-frontend: node_modules ## test backend files npx vitest .PHONY: test-check @@ -482,7 +424,7 @@ test-check: @diff=$$(git status -s); \ if [ -n "$$diff" ]; then \ echo "make test-backend has changed files in the source tree:"; \ - echo "$${diff}"; \ + printf "%s" "$${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; \ @@ -505,7 +447,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: +tidy: ## run go mod 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) @@ -519,15 +461,17 @@ 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:"; \ - echo "$${diff}"; \ + printf "%s" "$${diff}"; \ exit 1; \ fi .PHONY: go-licenses -go-licenses: $(GO_LICENSE_FILE) +go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses $(GO_LICENSE_FILE): go.mod go.sum - -$(GO) run $(GO_LICENSES_PACKAGE) save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null + @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 build/generate-go-licenses.go $(GO_LICENSE_TMP_DIR) $(GO_LICENSE_FILE) @rm -rf $(GO_LICENSE_TMP_DIR) @@ -771,17 +715,17 @@ install: $(wildcard *.go) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' .PHONY: build -build: frontend backend +build: frontend backend ## build everything .PHONY: frontend -frontend: $(WEBPACK_DEST) +frontend: $(WEBPACK_DEST) ## build frontend files .PHONY: backend -backend: go-check generate-backend $(EXECUTABLE) +backend: go-check generate-backend $(EXECUTABLE) ## build backend files # 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 +generate: generate-backend ## run "go generate" .PHONY: generate-backend generate-backend: $(TAGS_PREREQ) generate-go @@ -806,22 +750,22 @@ $(DIST_DIRS): .PHONY: release-windows release-windows: | $(DIST_DIRS) - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . ifeq (,$(findstring gogit,$(TAGS))) - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . endif .PHONY: release-linux release-linux: | $(DIST_DIRS) - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) . .PHONY: release-darwin release-darwin: | $(DIST_DIRS) - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) . .PHONY: release-freebsd release-freebsd: | $(DIST_DIRS) - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) . .PHONY: release-copy release-copy: | $(DIST_DIRS) @@ -846,20 +790,20 @@ release-sources: | $(DIST_DIRS) rm -f $(STORED_VERSION_FILE) .PHONY: deps -deps: deps-frontend deps-backend deps-tools deps-py +deps: deps-frontend deps-backend deps-tools deps-py ## install dependencies .PHONY: deps-py -deps-py: .venv +deps-py: .venv ## install python dependencies .PHONY: deps-frontend -deps-frontend: node_modules +deps-frontend: node_modules ## install frontend dependencies .PHONY: deps-backend -deps-backend: +deps-backend: ## install backend dependencies $(GO) mod download .PHONY: deps-tools -deps-tools: +deps-tools: ## install tool dependencies $(GO) install $(AIR_PACKAGE) & \ $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \ $(GO) install $(GOFUMPT_PACKAGE) & \ @@ -883,10 +827,10 @@ node_modules: package-lock.json @touch .venv .PHONY: update -update: update-js update-py +update: update-js update-py ## update js and py dependencies .PHONY: update-js -update-js: node-check | node_modules +update-js: node-check | node_modules ## update js dependencies npx updates -u -f package.json rm -rf node_modules package-lock.json npm install --package-lock @@ -895,27 +839,14 @@ update-js: node-check | node_modules @touch node_modules .PHONY: update-py -update-py: node-check | node_modules +update-py: node-check | node_modules ## update py dependencies npx updates -u -f pyproject.toml rm -rf .venv poetry.lock poetry install @touch .venv -.PHONY: fomantic -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 - cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/ - $(SED_INPLACE) -e 's/ overrideBrowserslist\r/ overrideBrowserslist: ["defaults"]\r/g' $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/tasks/config/tasks.js - cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build - # fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event - $(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js - $(SED_INPLACE) -e 's/\r//g' $(FOMANTIC_WORK_DIR)/build/semantic.css $(FOMANTIC_WORK_DIR)/build/semantic.js - rm -f $(FOMANTIC_WORK_DIR)/build/*.min.* - .PHONY: webpack -webpack: $(WEBPACK_DEST) +webpack: $(WEBPACK_DEST) ## build webpack files $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json @$(MAKE) -s node-check node_modules @@ -925,7 +856,7 @@ $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json @touch $(WEBPACK_DEST) .PHONY: svg -svg: node-check | node_modules +svg: node-check | node_modules ## build svg files rm -rf $(SVG_DEST_DIR) node tools/generate-svg.js @@ -935,7 +866,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:"; \ - echo "$${diff}"; \ + printf "%s" "$${diff}"; \ exit 1; \ fi @@ -946,7 +877,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:"; \ - echo "$${diff}"; \ + printf "%s" "$${diff}"; \ exit 1; \ fi @@ -960,12 +891,8 @@ update-translations: mv ./translations/*.ini ./options/locale/ rmdir ./translations -.PHONY: generate-license -generate-license: - $(GO) run build/generate-licenses.go - .PHONY: generate-gitignore -generate-gitignore: +generate-gitignore: ## update gitignore files $(GO) run build/generate-gitignores.go .PHONY: generate-images @@ -974,7 +901,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 c280c832ac..5ae65cd2ac 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://crowdin.com/project/gitea "Crowdin") +[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin") [View this document in Chinese](./README_ZH.md) @@ -31,6 +31,14 @@ 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: @@ -52,6 +60,8 @@ 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] @@ -68,22 +78,25 @@ Expected workflow is: Fork -> Patch -> Push -> Pull Request ## Translating -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. +[![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. 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. -https://docs.gitea.com/contributing/localization +Get more information from [documentation](https://docs.gitea.com/contributing/localization). -[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) +## Official and Third-Party Projects -## Further information +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. -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/). +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. -We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea). +## Communication -The official Gitea CLI is developed at [gitea/tea](https://gitea.com/gitea/tea). +[![](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/). ## Authors @@ -122,18 +135,79 @@ 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. -## Screenshots +## Further information -Looking for an overview of the interface? Check it out! +
+Looking for an overview of the interface? Check it out! -|![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)| +### 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) + +
diff --git a/README_ZH.md b/README_ZH.md index a2e36dc22f..89c34f6b63 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://crowdin.com/project/gitea "Crowdin") +[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "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,39 +23,134 @@ 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 来和我们交流。 -## 贡献流程 +## 编译 -Fork -> Patch -> Push -> Pull Request +在源代码的根目录下执行: + + 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**。 谢谢! ## 翻译 -多语言翻译是基于Crowdin进行的. -[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) +[![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、插件、主题等等。 ## 作者 -* [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) 文件中。 -## 截图 +## 更多信息 -|![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)| +
+截图 + +### 登录界面 + +![登录](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) + +
diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 4b78a12030..b98b5d6471 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -104,16 +104,6 @@ "path": "github.com/Azure/go-ntlmssp/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "github.com/ClickHouse/ch-go", - "path": "github.com/ClickHouse/ch-go/LICENSE", - "licenseText": "Copyright 2016-2023 ClickHouse, Inc.\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016-2023 ClickHouse, Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, - { - "name": "github.com/ClickHouse/clickhouse-go/v2", - "path": "github.com/ClickHouse/clickhouse-go/v2/LICENSE", - "licenseText": "Copyright 2016-2023 ClickHouse, Inc.\n\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016-2023 ClickHouse, Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, { "name": "github.com/DataDog/zstd", "path": "github.com/DataDog/zstd/LICENSE", @@ -179,16 +169,6 @@ "path": "github.com/aws/aws-sdk-go-v2/service/codecommit/LICENSE.txt", "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/aws/aws-sdk-go", - "path": "github.com/aws/aws-sdk-go/LICENSE.txt", - "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/aws/aws-sdk-go/internal/sync/singleflight", - "path": "github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE", - "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - }, { "name": "github.com/aws/smithy-go", "path": "github.com/aws/smithy-go/LICENSE", @@ -309,6 +289,11 @@ "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", @@ -382,7 +367,7 @@ { "name": "github.com/cyphar/filepath-securejoin", "path": "github.com/cyphar/filepath-securejoin/LICENSE", - "licenseText": "Copyright (C) 2014-2015 Docker Inc \u0026 Go Authors. All rights reserved.\nCopyright (C) 2017 SUSE LLC. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (C) 2014-2015 Docker Inc \u0026 Go Authors. All rights reserved.\nCopyright (C) 2017-2024 SUSE LLC. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "github.com/davecgh/go-spew/spew", @@ -519,16 +504,6 @@ "path": "github.com/go-enry/go-enry/v2/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." }, - { - "name": "github.com/go-faster/city", - "path": "github.com/go-faster/city/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2018 tenfy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, - { - "name": "github.com/go-faster/errors", - "path": "github.com/go-faster/errors/LICENSE", - "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - }, { "name": "github.com/go-fed/httpsig", "path": "github.com/go-fed/httpsig/LICENSE", @@ -557,7 +532,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-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" + "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" }, { "name": "github.com/go-redsync/redsync/v4", @@ -569,11 +544,6 @@ "path": "github.com/go-sql-driver/mysql/LICENSE", "licenseText": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n means each individual or legal entity that creates, contributes to\n the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n means the combination of the Contributions of others (if any) used\n by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n means Source Code Form to which the initial Contributor has attached\n the notice in Exhibit A, the Executable Form of such Source Code\n Form, and Modifications of such Source Code Form, in each case\n including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n means\n\n (a) that the initial Contributor has attached the notice described\n in Exhibit B to the Covered Software; or\n\n (b) that the Covered Software was made available under the terms of\n version 1.1 or earlier of the License, but not also under the\n terms of a Secondary License.\n\n1.6. \"Executable Form\"\n means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n means a work that combines Covered Software with other material, in \n a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n means this document.\n\n1.9. \"Licensable\"\n means having the right to grant, to the maximum extent possible,\n whether at the time of the initial grant or subsequently, any and\n all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n means any of the following:\n\n (a) any file in Source Code Form that results from an addition to,\n deletion from, or modification of the contents of Covered\n Software; or\n\n (b) any new file in Source Code Form that contains any Covered\n Software.\n\n1.11. \"Patent Claims\" of a Contributor\n means any patent claim(s), including without limitation, method,\n process, and apparatus claims, in any patent Licensable by such\n Contributor that would be infringed, but for the grant of the\n License, by the making, using, selling, offering for sale, having\n made, import, or transfer of either its Contributions or its\n Contributor Version.\n\n1.12. \"Secondary License\"\n means either the GNU General Public License, Version 2.0, the GNU\n Lesser General Public License, Version 2.1, the GNU Affero General\n Public License, Version 3.0, or any later versions of those\n licenses.\n\n1.13. \"Source Code Form\"\n means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n means an individual or a legal entity exercising rights under this\n License. For legal entities, \"You\" includes any entity that\n controls, is controlled by, or is under common control with You. For\n purposes of this definition, \"control\" means (a) the power, direct\n or indirect, to cause the direction or management of such entity,\n whether by contract or otherwise, or (b) ownership of more than\n fifty percent (50%) of the outstanding shares or beneficial\n ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n Licensable by such Contributor to use, reproduce, make available,\n modify, display, perform, distribute, and otherwise exploit its\n Contributions, either on an unmodified basis, with Modifications, or\n as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n for sale, have made, import, and otherwise transfer either its\n Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n or\n\n(b) for infringements caused by: (i) Your and any other third party's\n modifications of Covered Software, or (ii) the combination of its\n Contributions with other software (except as part of its Contributor\n Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n Form, as described in Section 3.1, and You must inform recipients of\n the Executable Form how they can obtain a copy of such Source Code\n Form by reasonable means in a timely manner, at a charge no more\n than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n License, or sublicense it under different terms, provided that the\n license for the Executable Form does not attempt to limit or alter\n the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n* *\n* 6. Disclaimer of Warranty *\n* ------------------------- *\n* *\n* Covered Software is provided under this License on an \"as is\" *\n* basis, without warranty of any kind, either expressed, implied, or *\n* statutory, including, without limitation, warranties that the *\n* Covered Software is free of defects, merchantable, fit for a *\n* particular purpose or non-infringing. The entire risk as to the *\n* quality and performance of the Covered Software is with You. *\n* Should any Covered Software prove defective in any respect, You *\n* (not any Contributor) assume the cost of any necessary servicing, *\n* repair, or correction. This disclaimer of warranty constitutes an *\n* essential part of this License. No use of any Covered Software is *\n* authorized under this License except under this disclaimer. *\n* *\n************************************************************************\n\n************************************************************************\n* *\n* 7. Limitation of Liability *\n* -------------------------- *\n* *\n* Under no circumstances and under no legal theory, whether tort *\n* (including negligence), contract, or otherwise, shall any *\n* Contributor, or anyone who distributes Covered Software as *\n* permitted above, be liable to You for any direct, indirect, *\n* special, incidental, or consequential damages of any character *\n* including, without limitation, damages for lost profits, loss of *\n* goodwill, work stoppage, computer failure or malfunction, or any *\n* and all other commercial damages or losses, even if such party *\n* shall have been informed of the possibility of such damages. This *\n* limitation of liability shall not apply to liability for death or *\n* personal injury resulting from such party's negligence to the *\n* extent applicable law prohibits such limitation. Some *\n* jurisdictions do not allow the exclusion or limitation of *\n* incidental or consequential damages, so this exclusion and *\n* limitation may not apply to You. *\n* *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n This Source Code Form is subject to the terms of the Mozilla Public\n License, v. 2.0. If a copy of the MPL was not distributed with this\n file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n This Source Code Form is \"Incompatible With Secondary Licenses\", as\n defined by the Mozilla Public License, v. 2.0.\n" }, - { - "name": "github.com/go-testfixtures/testfixtures/v3", - "path": "github.com/go-testfixtures/testfixtures/v3/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Andrey Nering\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "github.com/go-webauthn/webauthn", "path": "github.com/go-webauthn/webauthn/LICENSE", @@ -702,7 +672,7 @@ { "name": "github.com/gorilla/sessions", "path": "github.com/gorilla/sessions/LICENSE", - "licenseText": "Copyright (c) 2023 The Gorilla Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n\t * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\t * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2024 The Gorilla Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n\t * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\t * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "github.com/hashicorp/errwrap", @@ -779,11 +749,6 @@ "path": "github.com/kevinburke/ssh_config/LICENSE", "licenseText": "Copyright (c) 2017 Kevin Burke.\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\n===================\n\nThe lexer and parser borrow heavily from github.com/pelletier/go-toml. The\nlicense for that project is copied below.\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "github.com/keybase/go-crypto", - "path": "github.com/keybase/go-crypto/LICENSE", - "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - }, { "name": "github.com/klauspost/compress", "path": "github.com/klauspost/compress/LICENSE", @@ -859,14 +824,19 @@ "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/v2", - "path": "github.com/mholt/acmez/v2/LICENSE", + "name": "github.com/mholt/acmez/v3", + "path": "github.com/mholt/acmez/v3/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" }, { @@ -877,7 +847,7 @@ { "name": "github.com/microcosm-cc/bluemonday", "path": "github.com/microcosm-cc/bluemonday/LICENSE.md", - "licenseText": "SPDX short identifier: BSD-3-Clause\nhttps://opensource.org/licenses/BSD-3-Clause\n\nCopyright (c) 2014, David Kitchen \u003cdavid@buro9.com\u003e\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the organisation (Microcosm) nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (c) 2014, David Kitchen \u003cdavid@buro9.com\u003e\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the organisation (Microcosm) nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "github.com/microsoft/go-mssqldb", @@ -894,6 +864,11 @@ "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", @@ -964,11 +939,6 @@ "path": "github.com/opencontainers/image-spec/specs-go/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 Copyright 2016 The Linux Foundation.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, - { - "name": "github.com/paulmach/orb", - "path": "github.com/paulmach/orb/LICENSE.md", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 Paul Mach\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, { "name": "github.com/pierrec/lz4/v4", "path": "github.com/pierrec/lz4/v4/LICENSE", @@ -977,7 +947,7 @@ { "name": "github.com/pjbgf/sha1cd", "path": "github.com/pjbgf/sha1cd/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [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" + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2023 pjbgf\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { "name": "github.com/pkg/errors", @@ -994,6 +964,11 @@ "path": "github.com/pquerna/otp/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, + { + "name": "github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil", + "path": "github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/LICENSE", + "licenseText": "Copyright (c) 2013 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, { "name": "github.com/prometheus/client_golang/prometheus", "path": "github.com/prometheus/client_golang/prometheus/LICENSE", @@ -1054,21 +1029,11 @@ "path": "github.com/sassoftware/go-rpmutils/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, - { - "name": "github.com/segmentio/asm", - "path": "github.com/segmentio/asm/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2021 Segment\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "github.com/sergi/go-diff/diffmatchpatch", "path": "github.com/sergi/go-diff/diffmatchpatch/LICENSE", "licenseText": "Copyright (c) 2012-2016 The go-diff Authors. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\n" }, - { - "name": "github.com/shopspring/decimal", - "path": "github.com/shopspring/decimal/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015 Spring, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n- Based on https://github.com/oguzbilgic/fpd, which has the following license:\n\"\"\"\nThe MIT License (MIT)\n\nCopyright (c) 2013 Oguz Bilgic\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\n" - }, { "name": "github.com/sirupsen/logrus", "path": "github.com/sirupsen/logrus/LICENSE", @@ -1085,8 +1050,8 @@ "licenseText": "MIT License\n\nCopyright (c) 2017 Asher\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/stretchr/testify/assert", - "path": "github.com/stretchr/testify/assert/LICENSE", + "name": "github.com/stretchr/testify", + "path": "github.com/stretchr/testify/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { @@ -1114,31 +1079,26 @@ "path": "github.com/urfave/cli/v2/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2022 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "github.com/valyala/bytebufferpool", - "path": "github.com/valyala/bytebufferpool/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Aliaksandr Valialkin, VertaMedia\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" - }, - { - "name": "github.com/valyala/fasthttp", - "path": "github.com/valyala/fasthttp/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, { "name": "github.com/valyala/fastjson", "path": "github.com/valyala/fastjson/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2018 Aliaksandr Valialkin\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/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" + }, + { + "name": "github.com/wneessen/go-mail/smtp", + "path": "github.com/wneessen/go-mail/smtp/LICENSE", + "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + }, { "name": "github.com/x448/float16", "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", @@ -1174,21 +1134,16 @@ "path": "github.com/zeebo/blake3/LICENSE", "licenseText": "This work is released into the public domain with CC0 1.0.\n\n-------------------------------------------------------------------------------\n\nCreative Commons Legal Code\n\nCC0 1.0 Universal\n\n CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE\n LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN\n ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS\n INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES\n REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS\n PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM\n THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED\n HEREUNDER.\n\nStatement of Purpose\n\nThe laws of most jurisdictions throughout the world automatically confer\nexclusive Copyright and Related Rights (defined below) upon the creator\nand subsequent owner(s) (each and all, an \"owner\") of an original work of\nauthorship and/or a database (each, a \"Work\").\n\nCertain owners wish to permanently relinquish those rights to a Work for\nthe purpose of contributing to a commons of creative, cultural and\nscientific works (\"Commons\") that the public can reliably and without fear\nof later claims of infringement build upon, modify, incorporate in other\nworks, reuse and redistribute as freely as possible in any form whatsoever\nand for any purposes, including without limitation commercial purposes.\nThese owners may contribute to the Commons to promote the ideal of a free\nculture and the further production of creative, cultural and scientific\nworks, or to gain reputation or greater distribution for their Work in\npart through the use and efforts of others.\n\nFor these and/or other purposes and motivations, and without any\nexpectation of additional consideration or compensation, the person\nassociating CC0 with a Work (the \"Affirmer\"), to the extent that he or she\nis an owner of Copyright and Related Rights in the Work, voluntarily\nelects to apply CC0 to the Work and publicly distribute the Work under its\nterms, with knowledge of his or her Copyright and Related Rights in the\nWork and the meaning and intended legal effect of CC0 on those rights.\n\n1. Copyright and Related Rights. A Work made available under CC0 may be\nprotected by copyright and related or neighboring rights (\"Copyright and\nRelated Rights\"). Copyright and Related Rights include, but are not\nlimited to, the following:\n\n i. the right to reproduce, adapt, distribute, perform, display,\n communicate, and translate a Work;\n ii. moral rights retained by the original author(s) and/or performer(s);\niii. publicity and privacy rights pertaining to a person's image or\n likeness depicted in a Work;\n iv. rights protecting against unfair competition in regards to a Work,\n subject to the limitations in paragraph 4(a), below;\n v. rights protecting the extraction, dissemination, use and reuse of data\n in a Work;\n vi. database rights (such as those arising under Directive 96/9/EC of the\n European Parliament and of the Council of 11 March 1996 on the legal\n protection of databases, and under any national implementation\n thereof, including any amended or successor version of such\n directive); and\nvii. other similar, equivalent or corresponding rights throughout the\n world based on applicable law or treaty, and any national\n implementations thereof.\n\n2. Waiver. To the greatest extent permitted by, but not in contravention\nof, applicable law, Affirmer hereby overtly, fully, permanently,\nirrevocably and unconditionally waives, abandons, and surrenders all of\nAffirmer's Copyright and Related Rights and associated claims and causes\nof action, whether now known or unknown (including existing as well as\nfuture claims and causes of action), in the Work (i) in all territories\nworldwide, (ii) for the maximum duration provided by applicable law or\ntreaty (including future time extensions), (iii) in any current or future\nmedium and for any number of copies, and (iv) for any purpose whatsoever,\nincluding without limitation commercial, advertising or promotional\npurposes (the \"Waiver\"). Affirmer makes the Waiver for the benefit of each\nmember of the public at large and to the detriment of Affirmer's heirs and\nsuccessors, fully intending that such Waiver shall not be subject to\nrevocation, rescission, cancellation, termination, or any other legal or\nequitable action to disrupt the quiet enjoyment of the Work by the public\nas contemplated by Affirmer's express Statement of Purpose.\n\n3. Public License Fallback. Should any part of the Waiver for any reason\nbe judged legally invalid or ineffective under applicable law, then the\nWaiver shall be preserved to the maximum extent permitted taking into\naccount Affirmer's express Statement of Purpose. In addition, to the\nextent the Waiver is so judged Affirmer hereby grants to each affected\nperson a royalty-free, non transferable, non sublicensable, non exclusive,\nirrevocable and unconditional license to exercise Affirmer's Copyright and\nRelated Rights in the Work (i) in all territories worldwide, (ii) for the\nmaximum duration provided by applicable law or treaty (including future\ntime extensions), (iii) in any current or future medium and for any number\nof copies, and (iv) for any purpose whatsoever, including without\nlimitation commercial, advertising or promotional purposes (the\n\"License\"). The License shall be deemed effective as of the date CC0 was\napplied by Affirmer to the Work. Should any part of the License for any\nreason be judged legally invalid or ineffective under applicable law, such\npartial invalidity or ineffectiveness shall not invalidate the remainder\nof the License, and in such case Affirmer hereby affirms that he or she\nwill not (i) exercise any of his or her remaining Copyright and Related\nRights in the Work or (ii) assert any associated claims and causes of\naction with respect to the Work, in either case contrary to Affirmer's\nexpress Statement of Purpose.\n\n4. Limitations and Disclaimers.\n\n a. No trademark or patent rights held by Affirmer are waived, abandoned,\n surrendered, licensed or otherwise affected by this document.\n b. Affirmer offers the Work as-is and makes no representations or\n warranties of any kind concerning the Work, express, implied,\n statutory or otherwise, including without limitation warranties of\n title, merchantability, fitness for a particular purpose, non\n infringement, or the absence of latent or other defects, accuracy, or\n the present or absence of errors, whether or not discoverable, all to\n the greatest extent permissible under applicable law.\n c. Affirmer disclaims responsibility for clearing rights of other persons\n that may apply to the Work or any use thereof, including without\n limitation any person's Copyright and Related Rights in the Work.\n Further, Affirmer disclaims responsibility for obtaining any necessary\n consents, permissions or other rights required for any use of the\n Work.\n d. Affirmer understands and acknowledges that Creative Commons is not a\n party to this document and has no duty or obligation with respect to\n this CC0 or use of the Work.\n" }, + { + "name": "gitlab.com/gitlab-org/api/client-go", + "path": "gitlab.com/gitlab-org/api/client-go/LICENSE", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, { "name": "go.etcd.io/bbolt", "path": "go.etcd.io/bbolt/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2013 Ben Johnson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, - { - "name": "go.opentelemetry.io/otel", - "path": "go.opentelemetry.io/otel/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, - { - "name": "go.opentelemetry.io/otel/trace", - "path": "go.opentelemetry.io/otel/trace/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, { "name": "go.uber.org/atomic", "path": "go.uber.org/atomic/LICENSE.txt", @@ -1204,6 +1159,11 @@ "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", @@ -1212,7 +1172,7 @@ { "name": "golang.org/x/image", "path": "golang.org/x/image/LICENSE", - "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "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/mod/semver", @@ -1227,7 +1187,7 @@ { "name": "golang.org/x/oauth2", "path": "golang.org/x/oauth2/LICENSE", - "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "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/sync", @@ -1247,7 +1207,7 @@ { "name": "golang.org/x/time/rate", "path": "golang.org/x/time/rate/LICENSE", - "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "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", @@ -1264,11 +1224,6 @@ "path": "google.golang.org/protobuf/LICENSE", "licenseText": "Copyright (c) 2018 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "gopkg.in/gomail.v2", - "path": "gopkg.in/gomail.v2/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014 Alexandre Cesaro\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, { "name": "gopkg.in/ini.v1", "path": "gopkg.in/ini.v1/LICENSE", diff --git a/build/generate-emoji.go b/build/generate-emoji.go index 17a9670f06..446ab5f440 100644 --- a/build/generate-emoji.go +++ b/build/generate-emoji.go @@ -53,8 +53,6 @@ func (e Emoji) MarshalJSON() ([]byte, error) { } func main() { - var err error - flag.Parse() // generate data @@ -83,8 +81,6 @@ var replacer = strings.NewReplacer( var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`) func generate() ([]byte, error) { - var err error - // load gemoji data res, err := http.Get(gemojiURL) if err != nil { diff --git a/build/generate-licenses.go b/build/generate-licenses.go deleted file mode 100644 index 66e1d37755..0000000000 --- a/build/generate-licenses.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build ignore - -package main - -import ( - "archive/tar" - "compress/gzip" - "crypto/md5" - "encoding/hex" - "flag" - "fmt" - "io" - "log" - "net/http" - "os" - "path" - "path/filepath" - "strings" - - "code.gitea.io/gitea/build/license" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/util" -) - -func main() { - var ( - prefix = "gitea-licenses" - url = "https://api.github.com/repos/spdx/license-list-data/tarball" - githubApiToken = "" - githubUsername = "" - destination = "" - ) - - flag.StringVar(&destination, "dest", "options/license/", "destination for the licenses") - flag.StringVar(&githubUsername, "username", "", "github username") - flag.StringVar(&githubApiToken, "token", "", "github api token") - flag.Parse() - - file, err := os.CreateTemp(os.TempDir(), prefix) - if err != nil { - log.Fatalf("Failed to create temp file. %s", err) - } - - defer util.Remove(file.Name()) - - if err := os.RemoveAll(destination); err != nil { - log.Fatalf("Cannot clean destination folder: %v", err) - } - - if err := os.MkdirAll(destination, 0o755); err != nil { - log.Fatalf("Cannot create destination: %v", err) - } - - req, err := http.NewRequest("GET", url, nil) - if err != nil { - log.Fatalf("Failed to download archive. %s", err) - } - - if len(githubApiToken) > 0 && len(githubUsername) > 0 { - req.SetBasicAuth(githubUsername, githubApiToken) - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - log.Fatalf("Failed to download archive. %s", err) - } - - defer resp.Body.Close() - - if _, err := io.Copy(file, resp.Body); err != nil { - log.Fatalf("Failed to copy archive to file. %s", err) - } - - if _, err := file.Seek(0, 0); err != nil { - log.Fatalf("Failed to reset seek on archive. %s", err) - } - - gz, err := gzip.NewReader(file) - if err != nil { - log.Fatalf("Failed to gunzip the archive. %s", err) - } - - tr := tar.NewReader(gz) - aliasesFiles := make(map[string][]string) - for { - hdr, err := tr.Next() - - if err == io.EOF { - break - } - - if err != nil { - log.Fatalf("Failed to iterate archive. %s", err) - } - - if !strings.Contains(hdr.Name, "/text/") { - continue - } - - if filepath.Ext(hdr.Name) != ".txt" { - continue - } - - fileBaseName := filepath.Base(hdr.Name) - licenseName := strings.TrimSuffix(fileBaseName, ".txt") - - if strings.HasPrefix(fileBaseName, "README") { - continue - } - - if strings.HasPrefix(fileBaseName, "deprecated_") { - continue - } - out, err := os.Create(path.Join(destination, licenseName)) - if err != nil { - log.Fatalf("Failed to create new file. %s", err) - } - - defer out.Close() - - // some license files have same content, so we need to detect these files and create a convert map into a json file - // Later we use this convert map to avoid adding same license content with different license name - h := md5.New() - // calculate md5 and write file in the same time - r := io.TeeReader(tr, h) - if _, err := io.Copy(out, r); err != nil { - log.Fatalf("Failed to write new file. %s", err) - } else { - fmt.Printf("Written %s\n", out.Name()) - - md5 := hex.EncodeToString(h.Sum(nil)) - aliasesFiles[md5] = append(aliasesFiles[md5], licenseName) - } - } - - // generate convert license name map - licenseAliases := make(map[string]string) - for _, fileNames := range aliasesFiles { - if len(fileNames) > 1 { - licenseName := license.GetLicenseNameFromAliases(fileNames) - if licenseName == "" { - // license name should not be empty as expected - // if it is empty, we need to rewrite the logic of GetLicenseNameFromAliases - log.Fatalf("GetLicenseNameFromAliases: license name is empty") - } - for _, fileName := range fileNames { - licenseAliases[fileName] = licenseName - } - } - } - // save convert license name map to file - b, err := json.Marshal(licenseAliases) - if err != nil { - log.Fatalf("Failed to create json bytes. %s", err) - } - - licenseAliasesDestination := filepath.Join(destination, "etc", "license-aliases.json") - if err := os.MkdirAll(filepath.Dir(licenseAliasesDestination), 0o755); err != nil { - log.Fatalf("Failed to create directory for license aliases json file. %s", err) - } - - f, err := os.Create(licenseAliasesDestination) - if err != nil { - log.Fatalf("Failed to create license aliases json file. %s", err) - } - defer f.Close() - - if _, err = f.Write(b); err != nil { - log.Fatalf("Failed to write license aliases json file. %s", err) - } - - fmt.Println("Done") -} diff --git a/build/license/aliasgenerator.go b/build/license/aliasgenerator.go deleted file mode 100644 index 7de1e6fbd6..0000000000 --- a/build/license/aliasgenerator.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package license - -import "strings" - -func GetLicenseNameFromAliases(fnl []string) string { - if len(fnl) == 0 { - return "" - } - - shortestItem := func(list []string) string { - s := list[0] - for _, l := range list[1:] { - if len(l) < len(s) { - s = l - } - } - return s - } - allHasPrefix := func(list []string, s string) bool { - for _, l := range list { - if !strings.HasPrefix(l, s) { - return false - } - } - return true - } - - sl := shortestItem(fnl) - slv := strings.Split(sl, "-") - var result string - for i := len(slv); i >= 0; i-- { - result = strings.Join(slv[:i], "-") - if allHasPrefix(fnl, result) { - return result - } - } - return "" -} diff --git a/build/license/aliasgenerator_test.go b/build/license/aliasgenerator_test.go deleted file mode 100644 index 239181b736..0000000000 --- a/build/license/aliasgenerator_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package license - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetLicenseNameFromAliases(t *testing.T) { - tests := []struct { - target string - inputs []string - }{ - { - // real case which you can find in license-aliases.json - target: "AGPL-1.0", - inputs: []string{ - "AGPL-1.0-only", - "AGPL-1.0-or-late", - }, - }, - { - target: "", - inputs: []string{ - "APSL-1.0", - "AGPL-1.0-only", - "AGPL-1.0-or-late", - }, - }, - } - - for _, tt := range tests { - result := GetLicenseNameFromAliases(tt.inputs) - assert.Equal(t, result, tt.target) - } -} diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index 106d14b25a..5e03d6ca3f 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -31,6 +31,11 @@ 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", @@ -69,10 +74,30 @@ var microcmdUserCreate = &cli.Command{ } func runCreateUser(c *cli.Context) error { + // this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first + // duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future. + setting.LoadSettings() + if err := argsSet(c, "email"); err != nil { 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") } @@ -114,16 +139,19 @@ func runCreateUser(c *cli.Context) error { return err } fmt.Printf("generated random password is '%s'\n", password) - } else { + } else if userType == user_model.UserTypeIndividual { 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 { + } else if userType == user_model.UserTypeIndividual { // check whether there are users in the database hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{}) if err != nil { @@ -147,8 +175,9 @@ func runCreateUser(c *cli.Context) error { u := &user_model.User{ Name: username, Email: c.String("email"), - Passwd: password, IsAdmin: isAdmin, + Type: userType, + Passwd: password, MustChangePassword: mustChangePassword, Visibility: visibility, } diff --git a/cmd/admin_user_create_test.go b/cmd/admin_user_create_test.go index 83754e97b1..d8044e8de7 100644 --- a/cmd/admin_user_create_test.go +++ b/cmd/admin_user_create_test.go @@ -13,32 +13,54 @@ 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() { - assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{})) - assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{})) + require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{})) + require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{})) } - 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") + 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") - 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: false}, createCheck("u", "--admin"), "first admin user doesn't need to change password") - 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")) + 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) + }) } diff --git a/cmd/doctor.go b/cmd/doctor.go index e433f4adc5..52699cc4dd 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -4,6 +4,7 @@ package cmd import ( + "context" "fmt" golog "log" "os" @@ -130,8 +131,8 @@ func runRecreateTable(ctx *cli.Context) error { } recreateTables := migrate_base.RecreateTables(beans...) - return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error { - if err := migrations.EnsureUpToDate(x); err != nil { + return db.InitEngineWithMigration(stdCtx, func(ctx context.Context, x *xorm.Engine) error { + if err := migrations.EnsureUpToDate(ctx, x); err != nil { return err } return recreateTables(x) diff --git a/cmd/hook.go b/cmd/hook.go index 578380ab40..41e3c3ce34 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -316,7 +316,7 @@ func runHookPostReceive(c *cli.Context) error { setup(ctx, c.Bool("debug")) // First of all run update-server-info no matter what - if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil { + if _, _, err := git.NewCommand("update-server-info").RunStdString(ctx, nil); err != nil { return fmt.Errorf("Failed to call 'git update-server-info': %w", err) } diff --git a/cmd/hook_test.go b/cmd/hook_test.go index 91f24ff2b4..86cd4834f2 100644 --- a/cmd/hook_test.go +++ b/cmd/hook_test.go @@ -6,7 +6,6 @@ package cmd import ( "bufio" "bytes" - "context" "strings" "testing" @@ -15,7 +14,7 @@ import ( func TestPktLine(t *testing.T) { // test read - ctx := context.Background() + ctx := t.Context() 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 fd648946ef..7251bd09a3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -165,6 +165,7 @@ 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 c182b44019..3ec584d323 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -6,7 +6,6 @@ package cmd import ( "fmt" "io" - "os" "path/filepath" "strings" "testing" @@ -113,37 +112,17 @@ func TestCliCmd(t *testing.T) { _, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) return nil }) - var envBackup []string - for _, s := range os.Environ() { - if strings.HasPrefix(s, "GITEA_") && strings.Contains(s, "=") { - envBackup = append(envBackup, s) - } - } - clearGiteaEnv := func() { - for _, s := range os.Environ() { - if strings.HasPrefix(s, "GITEA_") { - _ = os.Unsetenv(s) - } - } - } - 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) + t.Run(c.cmd, func(t *testing.T) { + for k, v := range c.env { + t.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.go b/cmd/migrate.go index 4e4dd45af3..25d8b50c45 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -7,9 +7,9 @@ import ( "context" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/migrations" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/versioned_migration" "github.com/urfave/cli/v2" ) @@ -18,7 +18,7 @@ import ( var CmdMigrate = &cli.Command{ Name: "migrate", Usage: "Migrate the database", - Description: "This is a command for migrating the database, so that you can run gitea admin create-user before starting the server.", + Description: `This is a command for migrating the database, so that you can run "gitea admin create user" before starting the server.`, Action: runMigrate, } @@ -36,7 +36,7 @@ func runMigrate(ctx *cli.Context) error { log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) - if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { + if err := db.InitEngineWithMigration(context.Background(), versioned_migration.Migrate); err != nil { log.Fatal("Failed to initialize ORM engine: %v", err) return err } diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 6ece4bf661..f9ed140395 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -13,7 +13,6 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" - "code.gitea.io/gitea/models/migrations" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -21,6 +20,7 @@ import ( packages_module "code.gitea.io/gitea/modules/packages" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/services/versioned_migration" "github.com/urfave/cli/v2" ) @@ -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 == int64(actions_model.ArtifactStatusExpired) { + if artifact.Status == actions_model.ArtifactStatusExpired { return nil } @@ -227,7 +227,7 @@ func runMigrateStorage(ctx *cli.Context) error { log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) - if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { + if err := db.InitEngineWithMigration(context.Background(), versioned_migration.Migrate); err != nil { log.Fatal("Failed to initialize ORM engine: %v", err) return err } diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go index 5d8c867993..f8fa95a927 100644 --- a/cmd/migrate_storage_test.go +++ b/cmd/migrate_storage_test.go @@ -4,7 +4,6 @@ package cmd import ( - "context" "os" "strings" "testing" @@ -53,7 +52,7 @@ func TestMigratePackages(t *testing.T) { assert.NotNil(t, v) assert.NotNil(t, f) - ctx := context.Background() + ctx := t.Context() p := t.TempDir() diff --git a/cmd/serv.go b/cmd/serv.go index 2d2df8aa23..476fd9a2ea 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -104,19 +104,20 @@ 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, "") - _, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage) + // 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:") if logMsgFmt != "" { logMsg := fmt.Sprintf(logMsgFmt, args...) if !setting.IsProd { _, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg) } - if userMessage != "" { - if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) { - logMsg = userMessage + " " + logMsg - } else { - logMsg = userMessage + ". " + logMsg - } + if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) { + logMsg = userMessage + " " + logMsg + } else { + logMsg = userMessage + ". " + logMsg } _ = private.SSHLog(ctx, true, logMsg) } @@ -288,10 +289,10 @@ func runServ(c *cli.Context) error { if allowedCommands.Contains(verb) { if allowedCommandsLfs.Contains(verb) { if !setting.LFS.StartServer { - return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled") + return fail(ctx, "LFS Server is not enabled", "") } if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH { - return fail(ctx, "Unknown git command", "LFS SSH transfer connection denied, pure SSH protocol is disabled") + return fail(ctx, "LFS SSH transfer is not enabled", "") } if len(words) > 2 { lfsVerb = words[2] diff --git a/cmd/web.go b/cmd/web.go index 2e70f90f63..28fe051ffb 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -12,15 +12,18 @@ import ( "path/filepath" "strconv" "strings" + "time" _ "net/http/pprof" // Used for debugging if enabled and a web server is running "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" @@ -115,6 +118,16 @@ func showWebStartupMessage(msg string) { log.Info("* CustomPath: %s", setting.CustomPath) log.Info("* ConfigFile: %s", setting.CustomConf) log.Info("%s", msg) // show startup message + + if setting.CORSConfig.Enabled { + log.Info("CORS Service Enabled") + } + if setting.DefaultUILocation != time.Local { + log.Info("Default UI Location is %v", setting.DefaultUILocation.String()) + } + if setting.MailService != nil { + log.Info("Mail Service Enabled: RegisterEmailConfirm=%v, Service.EnableNotifyMail=%v", setting.Service.RegisterEmailConfirm, setting.Service.EnableNotifyMail) + } } func serveInstall(ctx *cli.Context) error { @@ -208,6 +221,8 @@ 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/cmd/web_acme.go b/cmd/web_acme.go index 90e4a02764..172dde913b 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/caddyserver/certmagic" ) @@ -54,8 +55,6 @@ func runACME(listenAddr string, m http.Handler) error { altTLSALPNPort = p } - magic := certmagic.NewDefault() - magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory} // Try to use private CA root if provided, otherwise defaults to system's trust var certPool *x509.CertPool if setting.AcmeCARoot != "" { @@ -65,8 +64,20 @@ func runACME(listenAddr string, m http.Handler) error { log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) } } - myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{ - CA: setting.AcmeURL, + // FIXME: this path is not right, it uses "AppWorkPath" incorrectly, and writes the data into "AppWorkPath/https" + // Ideally it should migrate to AppDataPath write to "AppDataPath/https" + // And one more thing, no idea why we should set the global default variables here + // But it seems that the current ACME code needs these global variables to make renew work. + // Otherwise, "renew" will use incorrect storage path + oldDefaultACME := certmagic.DefaultACME + certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory} + certmagic.DefaultACME = certmagic.ACMEIssuer{ + // try to use the default values provided by DefaultACME + CA: util.IfZero(setting.AcmeURL, oldDefaultACME.CA), + TestCA: oldDefaultACME.TestCA, + Logger: oldDefaultACME.Logger, + HTTPProxy: oldDefaultACME.HTTPProxy, + TrustedRoots: certPool, Email: setting.AcmeEmail, Agreed: setting.AcmeTOS, @@ -75,8 +86,10 @@ func runACME(listenAddr string, m http.Handler) error { ListenHost: setting.HTTPAddr, AltTLSALPNPort: altTLSALPNPort, AltHTTPPort: altHTTPPort, - }) + } + magic := certmagic.NewDefault() + myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME) magic.Issuers = []certmagic.Issuer{myACME} // this obtains certificates or renews them if necessary diff --git a/contrib/fixtures/fixture_generation.go b/contrib/fixtures/fixture_generation.go deleted file mode 100644 index 31797cc800..0000000000 --- a/contrib/fixtures/fixture_generation.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//nolint:forbidigo -package main - -import ( - "context" - "fmt" - "os" - "path/filepath" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/unittest" -) - -// To generate derivative fixtures, execute the following from Gitea's repository base dir: -// go run -tags 'sqlite sqlite_unlock_notify' contrib/fixtures/fixture_generation.go [fixture...] - -var ( - generators = []struct { - gen func(ctx context.Context) (string, error) - name string - }{ - { - models.GetYamlFixturesAccess, "access", - }, - } - fixturesDir string -) - -func main() { - pathToGiteaRoot := "." - fixturesDir = filepath.Join(pathToGiteaRoot, "models", "fixtures") - if err := unittest.CreateTestEngine(unittest.FixturesOptions{ - Dir: fixturesDir, - }); err != nil { - fmt.Printf("CreateTestEngine: %+v", err) - os.Exit(1) - } - if err := unittest.PrepareTestDatabase(); err != nil { - fmt.Printf("PrepareTestDatabase: %+v\n", err) - os.Exit(1) - } - ctx := context.Background() - if len(os.Args) == 0 { - for _, r := range os.Args { - if err := generate(ctx, r); err != nil { - fmt.Printf("generate '%s': %+v\n", r, err) - os.Exit(1) - } - } - } else { - for _, g := range generators { - if err := generate(ctx, g.name); err != nil { - fmt.Printf("generate '%s': %+v\n", g.name, err) - os.Exit(1) - } - } - } -} - -func generate(ctx context.Context, name string) error { - for _, g := range generators { - if g.name == name { - data, err := g.gen(ctx) - if err != nil { - return err - } - path := filepath.Join(fixturesDir, name+".yml") - if err := os.WriteFile(path, []byte(data), 0o644); err != nil { - return fmt.Errorf("%s: %+v", path, err) - } - fmt.Printf("%s created.\n", path) - return nil - } - } - - return fmt.Errorf("generator not found") -} diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 0c76bbc6cd..0fc49accef 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -78,8 +78,9 @@ RUN_USER = ; git ;; Set the domain for the server ;DOMAIN = localhost ;; -;; Overwrite the automatically generated public URL. Necessary for proxies and docker. -;ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ +;; 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 = ;; ;; 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!!! @@ -103,8 +104,8 @@ RUN_USER = ; git ;REDIRECT_OTHER_PORT = false ;PORT_TO_REDIRECT = 80 ;; -;; expect PROXY protocol header on connections to https redirector. -;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s +;; expect PROXY protocol header on connections to https redirector, defaults to USE_PROXY_PROTOCOL +;REDIRECTOR_USE_PROXY_PROTOCOL = ;; Minimum and maximum supported TLS versions ;SSL_MIN_VERSION=TLSv1.2 ;SSL_MAX_VERSION= @@ -128,13 +129,14 @@ 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)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/ +;; 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 = ;; -;; When making local connections pass the PROXY protocol header. -;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s +;; When making local connections pass the PROXY protocol header, defaults to USE_PROXY_PROTOCOL +;LOCAL_USE_PROXY_PROTOCOL = ;; ;; Disable SSH feature when not available ;DISABLE_SSH = false @@ -146,13 +148,17 @@ 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 = %(RUN_USER)s +;BUILTIN_SSH_SERVER_USER = ;; -;; Domain name to be exposed in clone URL -;SSH_DOMAIN = %(DOMAIN)s +;; Domain name to be exposed in clone URL, defaults to DOMAIN or the domain part of ROOT_URL +;SSH_DOMAIN = ;; -;; SSH username displayed in clone URLs. -;SSH_USER = %(BUILTIN_SSH_SERVER_USER)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 = ;; ;; The network interface the builtin SSH server should listen on ;SSH_LISTEN_HOST = @@ -160,8 +166,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 -;SSH_LISTEN_PORT = %(SSH_PORT)s +;; The port number the builtin SSH server should listen on, defaults to SSH_PORT +;SSH_LISTEN_PORT = ;; ;; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. ;SSH_ROOT_PATH = @@ -188,7 +194,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)s +;; relative paths are made absolute relative to the APP_DATA_PATH ;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa ;; ;; Directory to create temporary files in when testing public keys using ssh-keygen, @@ -324,6 +330,10 @@ RUN_USER = ; git ;; Maximum number of locks returned per page ;LFS_LOCKS_PAGING_NUM = 50 ;; +;; When clients make lfs batch requests, reject them if there are more pointers than this number +;; zero means 'unlimited' +;LFS_MAX_BATCH_SIZE = 0 +;; ;; Allow graceful restarts using SIGHUP to fork ;ALLOW_GRACEFUL_RESTARTS = true ;; @@ -578,7 +588,7 @@ ENABLED = true [log] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Root path for the log files - defaults to %(GITEA_WORK_DIR)/log +;; Root path for the log files - defaults to "{AppWorkPath}/log" ;ROOT_PATH = ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -678,8 +688,8 @@ LEVEL = Info ;; The path of git executable. If empty, Gitea searches through the PATH environment. ;PATH = ;; -;; The HOME directory for Git -;HOME_PATH = %(APP_DATA_PATH)s/home +;; The HOME directory for Git, defaults to "{APP_DATA_PATH}/home" +;HOME_PATH = ;; ;; Disables highlight of added and removed changes ;DISABLE_DIFF_HIGHLIGHT = false @@ -780,6 +790,13 @@ 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. +;; 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. @@ -938,8 +955,8 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[repository] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; 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 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 = ;; ;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. @@ -1003,6 +1020,14 @@ LEVEL = Info ;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS. ;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls ;; +;; Comma separated list of default mirror repo units. +;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS. +;DEFAULT_MIRROR_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.wiki,repo.projects,repo.packages +;; +;; Comma separated list of default template repo units. +;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS. +;DEFAULT_TEMPLATE_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages +;; ;; Prefix archive files by placing them in a directory named after the repository ;PREFIX_ARCHIVE_FILES = true ;; @@ -1024,9 +1049,13 @@ LEVEL = Info ;; Don't allow download source archive files from UI ;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false -;; Allow fork repositories without maximum number limit +;; Allow to fork repositories without maximum number limit ;ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT = true +;; Allow to fork repositories into the same owner (user or organization) +;; This feature is experimental, not fully tested, and may be changed in the future +;ALLOW_FORK_INTO_SAME_OWNER = false + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[repository.editor] @@ -1100,6 +1129,9 @@ 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 ;; @@ -1262,6 +1294,9 @@ LEVEL = Info ;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css" ;THEMES = ;; +;; The icons for file list (basic/material), this is a temporary option which will be replaced by a user setting in the future. +;FILE_ICON_THEME = material +;; ;; All available reactions users can choose on issues/prs and comments. ;; Values can be emoji alias (:smile:) or a unicode emoji. ;; For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png @@ -1319,6 +1354,9 @@ 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] @@ -1462,6 +1500,10 @@ LEVEL = Info ;REPO_INDEXER_EXCLUDE = ;; ;MAX_FILE_SIZE = 1048576 +;; +;; Bleve engine has performance problems with fuzzy search, so we limit the fuzziness to 0 by default to disable it. +;; If you'd like to enable it, you can set it to a value between 0 and 2. +;TYPE_BLEVE_MAX_FUZZINESS = 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1479,7 +1521,8 @@ 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. -;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`. +;; Relative paths will be made absolute against "APP_DATA_PATH" +;DATADIR = queues/ ;; ;; Default queue length before a channel queue will block ;LENGTH = 100000 @@ -1727,6 +1770,9 @@ LEVEL = Info ;; ;; convert \r\n to \n for Sendmail ;SENDMAIL_CONVERT_CRLF = true +;; +;; convert links of attached images to inline images. Only for images hosted in this gitea instance. +;EMBED_ATTACHMENT_IMAGES = false ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1900,7 +1946,7 @@ LEVEL = Info ;ENABLED = true ;; ;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. -;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip +;ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip ;; ;; Max size of each file. Defaults to 2048MB ;MAX_SIZE = 2048 @@ -1932,6 +1978,13 @@ LEVEL = Info ;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` ;MINIO_SECRET_ACCESS_KEY = ;; +;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`. +;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables +;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, +;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION), +;; or the DefaultIAMRoleEndpoint if not provided otherwise. +;MINIO_IAM_ENDPOINT = +;; ;; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` ;MINIO_BUCKET = gitea ;; @@ -2638,6 +2691,16 @@ LEVEL = Info ;; override the azure blob base path if storage type is azureblob ;AZURE_BLOB_BASE_PATH = lfs/ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; settings for Gitea's LFS client (eg: mirroring an upstream lfs endpoint) +;; +;[lfs_client] +;; Limit the number of pointers in each batch request to this number +;BATCH_SIZE = 20 +;; Limit the number of concurrent upload/download operations within a batch +;BATCH_OPERATION_CONCURRENCY = 8 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; settings for packages, will override storage setting @@ -2666,6 +2729,13 @@ LEVEL = Info ;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` ;MINIO_SECRET_ACCESS_KEY = ;; +;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`. +;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables +;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, +;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION), +;; or the DefaultIAMRoleEndpoint if not provided otherwise. +;MINIO_IAM_ENDPOINT = +;; ;; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` ;MINIO_BUCKET = gitea ;; diff --git a/docker/root/usr/bin/entrypoint b/docker/root/usr/bin/entrypoint index d9dbb3ebe0..08587fc4f4 100755 --- a/docker/root/usr/bin/entrypoint +++ b/docker/root/usr/bin/entrypoint @@ -37,5 +37,5 @@ done if [ $# -gt 0 ]; then exec "$@" else - exec /bin/s6-svscan /etc/s6 + exec /usr/bin/s6-svscan /etc/s6 fi diff --git a/flake.lock b/flake.lock index 9eadad2b94..2f7b86359b 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720542800, - "narHash": "sha256-ZgnNHuKV6h2+fQ5LuqnUaqZey1Lqqt5dTUAiAnqH0QQ=", + "lastModified": 1739214665, + "narHash": "sha256-26L8VAu3/1YRxS8MHgBOyOM8xALdo6N0I04PgorE7UM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "feb2849fdeb70028c70d73b848214b00d324a497", + "rev": "64e75cd44acf21c7933d61d7721e812eac1b5a0a", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e2f273e341..1b930649d0 100644 --- a/flake.nix +++ b/flake.nix @@ -22,17 +22,21 @@ gzip # frontend - nodejs_20 + nodejs_22 # linting python312 poetry # backend - go_1_22 + 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 1005176d29..0a544a9100 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.gitea.io/gitea -go 1.23 +go 1.24 // 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: @@ -8,11 +8,11 @@ go 1.23 godebug x509negativeserial=1 require ( - code.gitea.io/actions-proto-go v0.4.0 + code.gitea.io/actions-proto-go v0.4.1 code.gitea.io/gitea-vet v0.2.3 - code.gitea.io/sdk/gitea v0.17.1 + code.gitea.io/sdk/gitea v0.20.0 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 - connectrpc.com/connect v1.15.0 + connectrpc.com/connect v1.18.1 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 @@ -20,21 +20,20 @@ require ( gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 github.com/42wim/httpsig v1.2.2 - github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.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/go-ntlmssp v0.0.0-20221128193559-754e69321358 - github.com/ProtonMail/go-crypto v1.0.0 - github.com/PuerkitoBio/goquery v1.9.2 - github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 - github.com/alecthomas/chroma/v2 v2.14.0 - github.com/aws/aws-sdk-go v1.43.21 - github.com/aws/aws-sdk-go-v2/credentials v1.17.30 - github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1 + github.com/ProtonMail/go-crypto v1.1.6 + github.com/PuerkitoBio/goquery v1.10.2 + 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/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.4.2 - github.com/buildkite/terminal-to-html/v3 v3.12.1 - github.com/caddyserver/certmagic v0.21.3 + github.com/buildkite/terminal-to-html/v3 v3.16.6 + github.com/caddyserver/certmagic v0.21.7 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,53 +45,50 @@ require ( github.com/emersion/go-imap v1.2.1 github.com/emirpasic/gods v1.18.1 github.com/ethantkoenig/rupture v1.0.1 - github.com/felixge/fgprof v0.9.4 - github.com/fsnotify/fsnotify v1.7.0 - github.com/gliderlabs/ssh v0.3.7 - github.com/go-ap/activitypub v0.0.0-20240408091739-ba76b44c2594 + github.com/felixge/fgprof v0.9.5 + github.com/fsnotify/fsnotify v1.8.0 + github.com/gliderlabs/ssh v0.3.8 + github.com/go-ap/activitypub v0.0.0-20250212090640-aeb6499ba581 github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 - github.com/go-chi/chi/v5 v5.0.13 + github.com/go-chi/chi/v5 v5.2.1 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.1 - github.com/go-git/go-billy/v5 v5.5.0 - github.com/go-git/go-git/v5 v5.12.0 - github.com/go-ldap/ldap/v3 v3.4.6 + 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-redsync/redsync/v4 v4.13.0 - github.com/go-sql-driver/mysql v1.8.1 + github.com/go-sql-driver/mysql v1.9.0 github.com/go-swagger/go-swagger v0.31.0 - github.com/go-testfixtures/testfixtures/v3 v3.11.0 - github.com/go-webauthn/webauthn v0.10.2 + github.com/go-webauthn/webauthn v0.11.2 github.com/gobwas/glob v0.2.3 github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v5 v5.2.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-20240618054019-d3b898a103f8 + github.com/google/pprof v0.0.0-20250208200701-d0013a598941 github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.2.0 - github.com/gorilla/sessions v1.3.0 - github.com/h2non/gock v1.2.0 + github.com/gorilla/sessions v1.4.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 github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 - github.com/jhillyerd/enmime v1.2.0 + 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/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 - github.com/klauspost/compress v1.17.9 - github.com/klauspost/cpuid/v2 v2.2.8 + github.com/klauspost/compress v1.18.0 + github.com/klauspost/cpuid/v2 v2.2.9 github.com/lib/pq v1.10.9 github.com/markbates/goth v1.80.0 github.com/mattn/go-isatty v0.0.20 - github.com/mattn/go-sqlite3 v1.14.22 - github.com/meilisearch/meilisearch-go v0.26.3 + github.com/mattn/go-sqlite3 v1.14.24 + 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.26 - github.com/microsoft/go-mssqldb v1.7.2 - github.com/minio/minio-go/v7 v7.0.77 + 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/msteinert/pam v1.2.0 github.com/nektos/act v0.2.63 github.com/niklasfasching/go-org v1.7.0 @@ -101,69 +97,68 @@ 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.19.1 + github.com/prometheus/client_golang v1.21.0 github.com/quasoft/websspi v1.1.2 - github.com/redis/go-redis/v9 v9.6.0 + github.com/redis/go-redis/v9 v9.7.0 github.com/robfig/cron/v3 v3.0.1 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/sassoftware/go-rpmutils v0.4.0 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/syndtr/goleveldb v1.0.0 github.com/tstranex/u2f v1.0.0 github.com/ulikunitz/xz v0.5.12 - github.com/urfave/cli/v2 v2.27.2 - github.com/xanzy/go-gitlab v0.105.0 + github.com/urfave/cli/v2 v2.27.5 + github.com/wneessen/go-mail v0.6.2 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yohcop/openid-go v1.0.1 - github.com/yuin/goldmark v1.7.2 + 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 - golang.org/x/crypto v0.26.0 - golang.org/x/image v0.18.0 - golang.org/x/net v0.28.0 - golang.org/x/oauth2 v0.21.0 - golang.org/x/sys v0.24.0 - golang.org/x/text v0.17.0 - golang.org/x/tools v0.24.0 - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.34.2 - gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + 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.36.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 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 - mvdan.cc/xurls/v2 v2.5.0 + mvdan.cc/xurls/v2 v2.6.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.3.0 // indirect - dario.cat/mergo v1.0.0 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // 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.9.0 // indirect - github.com/ClickHouse/ch-go v0.61.5 // indirect - github.com/ClickHouse/clickhouse-go/v2 v2.25.0 // indirect - github.com/DataDog/zstd v1.5.5 // 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.2.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Masterminds/semver/v3 v3.3.1 // 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.0 // indirect - github.com/andybalholm/cascadia v1.3.2 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/andybalholm/cascadia v1.3.3 // 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.30.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect - github.com/aws/smithy-go v1.20.4 // 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/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.13.0 // indirect - github.com/blevesearch/bleve_index_api v1.1.10 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // 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-porterstemmer v1.0.3 // indirect @@ -180,31 +175,30 @@ require ( 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/boombuler/barcode v1.0.1 // indirect + github.com/bmatcuk/doublestar/v4 v4.8.1 // 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.3.9 // indirect + github.com/cloudflare/circl v1.6.0 // indirect github.com/couchbase/go-couchbase v0.1.1 // indirect - github.com/couchbase/gomemcached v0.3.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.4 // indirect - github.com/cyphar/filepath-securejoin v0.2.5 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect + github.com/cyphar/filepath-securejoin v0.4.1 // 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.0 // indirect - github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect - github.com/fatih/color v1.17.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // 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.6.0 // 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-20240304112515-6077fa9c17b0 // indirect + github.com/go-ap/errors v0.0.0-20250124135319-3da8adefd4a9 // 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-faster/city v1.0.1 // indirect - github.com/go-faster/errors v0.7.1 // indirect github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-ini/ini v1.67.0 // indirect @@ -219,44 +213,44 @@ 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.9 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/go-webauthn/x v0.1.16 // indirect + github.com/goccy/go-json v0.10.5 // 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 github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // 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.0 // indirect + github.com/google/go-tpm v0.9.3 // 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 github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/jessevdk/go-flags v1.5.0 // indirect + github.com/jessevdk/go-flags v1.6.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/libdns/libdns v0.2.2 // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/libdns/libdns v0.2.3 // indirect + github.com/magiconair/properties v1.8.9 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/markbates/going v1.0.3 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/mholt/acmez/v2 v2.0.1 // indirect - github.com/miekg/dns v1.1.61 // indirect + github.com/mattn/go-colorable v0.1.14 // 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/minio/md5-simd v1.1.2 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -270,38 +264,33 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/gomega v1.33.1 // indirect - github.com/paulmach/orb v0.11.1 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/pierrec/lz4/v4 v4.1.21 // indirect - github.com/pjbgf/sha1cd v0.3.0 // 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rhysd/actionlint v1.7.1 // indirect + github.com/rhysd/actionlint v1.7.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a // indirect github.com/rs/xid v1.6.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/segmentio/asm v1.2.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.2.2 // indirect + github.com/skeema/knownhosts v1.3.1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.18.2 // indirect + github.com/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/viper v1.19.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect github.com/unknwon/com v1.0.1 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/fastjson v1.6.4 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect @@ -309,20 +298,18 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect - go.etcd.io/bbolt v1.3.10 // indirect - go.mongodb.org/mongo-driver v1.14.0 // indirect - go.opentelemetry.io/otel v1.27.0 // indirect - go.opentelemetry.io/otel/trace v1.27.0 // 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.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect - golang.org/x/mod v0.20.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect - gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // 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 gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) @@ -331,8 +318,9 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/gitea/act v0.261.3 +replace github.com/nektos/act => gitea.com/gitea/act v0.261.4 +// TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 // TODO: This could be removed after https://github.com/mholt/archiver/pull/396 merged diff --git a/go.sum b/go.sum index f8d0287dd2..6e0b0bde07 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,23 @@ -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -code.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= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +code.gitea.io/actions-proto-go v0.4.1 h1:l0EYhjsgpUe/1VABo2eK7zcoNX2W44WOnb0MSLrKfls= +code.gitea.io/actions-proto-go v0.4.1/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.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8= -code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM= +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= 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.15.0 h1:lFdeCbZrVVDydAqwr4xGV2y+ULn+0Z73s5JBj2LikWo= -connectrpc.com/connect v1.15.0/go.mod h1:bQmjpDY8xItMnttnurVgOkHUBMRT9cpsNi2O4AjKhmA= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= +connectrpc.com/connect v1.18.1/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= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= -gitea.com/gitea/act v0.261.3 h1:BhiYpGJQKGq0XMYYICCYAN4KnsEWHyLbA6dxhZwFcV4= -gitea.com/gitea/act v0.261.3/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= +gitea.com/gitea/act v0.261.4 h1:Tf9eLlvsYFtKcpuxlMvf9yT3g4Hshb2Beqw6C1STuH8= +gitea.com/gitea/act v0.261.4/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits= gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso= @@ -36,74 +36,68 @@ gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGq gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= github.com/42wim/httpsig v1.2.2 h1:ofAYoHUNs/MJOLqQ8hIxeyz2QxOz8qdSVvp3PX/oPgA= github.com/42wim/httpsig v1.2.2/go.mod h1:P/UYo7ytNBFwc+dg35IubuAUIs8zj5zzFIgUCEl55WY= -github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H+XXKmDA1dfFMIN1AislhlA/ps= -github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU= +github.com/42wim/sshsig v0.0.0-20240818000253-e3a6333df815 h1:5EoemV++kUK2Sw98yWP/RWyduvP7IaBgWWHe+4BWcSw= +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.12.0 h1:1nGuui+4POelzDwI7RG56yfQJHCnKvwfMoU7VsEp+Zg= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 h1:FDif4R1+UUR+00q6wquyX90K7A8dN+R5E8GEadoP7sU= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A= +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/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= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= 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.3.2 h1:YUUxeiOWgdAQE3pXt2H7QXzZs0q8UBjgRbl56qo8GYM= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2/go.mod h1:dmXQgZuiSubAecswZE+Sm8jkvEa7kQgTPVRvwL/nd0E= +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/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.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4= -github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= -github.com/ClickHouse/clickhouse-go/v2 v2.25.0 h1:rKscwqgQHzWBTZySZDcHKxgs0Ad+xFULfZvo26W5UlY= -github.com/ClickHouse/clickhouse-go/v2 v2.25.0/go.mod h1:iDTViXk2Fgvf1jn2dbJd1ys+fBkdD1UMRnXlwmhijhQ= -github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= -github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +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.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/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/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.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= -github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE= -github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= +github.com/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/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= github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= -github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 h1:cSXom2MoKJ9KPPw29RoZtHvUETY4F4n/kXl8m9btnQ0= -github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2/go.mod h1:JitQWJ8JuV4Y87l8VsHiiwhb3cgdyn68mX40s7NT6PA= -github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= -github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3 h1:BP0HiyNT3AQEYi+if3wkRcIdQFHtsw6xX3Kx0glckgA= +github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3/go.mod h1:hMNtySovKkn2gdDuLqnqveP+mfhUSaBdoBcr2I7Zt0E= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= -github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= +github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc= +github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/anchore/archiver/v3 v3.5.2 h1:Bjemm2NzuRhmHy3m0lRe5tNoClB9A4zYyDV58PaB6aA= github.com/anchore/archiver/v3 v3.5.2/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= -github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= +github.com/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/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= @@ -111,20 +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 v1.43.21 h1:E4S2eX3d2gKJyI/ISrcIrSwXwqjIvCK85gtBMt4sAPE= -github.com/aws/aws-sdk-go v1.43.21/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= -github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= -github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1 h1:mOOALIM4JzhYkq3voCBbmZqmyEVEhHsfasMTbVxLkNs= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1/go.mod h1:6zf5j3mIUXKM0s2iz5ttR2Qwq+o47D0jotpAyaKgZRA= -github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= -github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +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/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= @@ -132,16 +124,16 @@ 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.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= -github.com/bits-and-blooms/bitset v1.13.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/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= github.com/blevesearch/bleve/v2 v2.4.2 h1:NooYP1mb3c0StkiY9/xviiq2LGSaE8BQBCc/pirMx0U= github.com/blevesearch/bleve/v2 v2.4.2/go.mod h1:ATNKj7Yl2oJv/lGuF4kx39bST2dveX6w0th2FFYLkc8= github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= -github.com/blevesearch/bleve_index_api v1.1.10 h1:PDLFhVjrjQWr6jCuU7TwlmByQVCSEURADHdCqVS9+g0= -github.com/blevesearch/bleve_index_api v1.1.10/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8= +github.com/blevesearch/bleve_index_api v1.1.12 h1:P4bw9/G/5rulOF7SJ9l4FsDoo7UFJ+5kexNy1RXfegY= +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= @@ -185,20 +177,21 @@ github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wy 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/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4= +github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/buildkite/terminal-to-html/v3 v3.12.1 h1:Wwec2uOu35zNPEQTzDyXQPyr/VUW6lzEwiYede1CaoE= -github.com/buildkite/terminal-to-html/v3 v3.12.1/go.mod h1:PfNtCsLnMZs7X9X2gcngOutmgSp7/oGBUIpVzRnD09A= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= -github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI= +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/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= @@ -213,34 +206,31 @@ 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.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= -github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= +github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= +github.com/cloudflare/circl v1.6.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= github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= github.com/couchbase/go-couchbase v0.1.1 h1:ClFXELcKj/ojyoTYbsY34QUrrYCBi/1G749sXSCkdhk= github.com/couchbase/go-couchbase v0.1.1/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A= -github.com/couchbase/gomemcached v0.3.1 h1:jfspNuQIXgWy+5GUPQrsQ6yC5uJCfMmd/JKvK6C26r8= -github.com/couchbase/gomemcached v0.3.1/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo= +github.com/couchbase/gomemcached v0.3.2 h1:08rxiOoNcv0x5LTxgcYhnx1aPvV7iEtfeyUgqsJyPk0= +github.com/couchbase/gomemcached v0.3.2/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo= github.com/couchbase/goutils v0.1.2 h1:gWr8B6XNWPIhfalHNog3qQKfGiYyh4K4VhO3P2o9BCs= github.com/couchbase/goutils v0.1.2/go.mod h1:h89Ek/tiOxxqjz30nPPlwZdQbdB8BwgnuBxeoUe/ViE= github.com/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.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= -github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= -github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= -github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 h1:PdsjTl0Cg+ZJgOx/CFV5NNgO1ThTreqdgKYiDCMHJwA= @@ -253,8 +243,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.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.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/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= @@ -264,23 +254,23 @@ 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 v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/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/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= github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= -github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY= -github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= +github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 h1:oP4q0fw+fOSWn3DfFi4EXdT+B+gTtzx8GC9xsc26Znk= +github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/ethantkoenig/rupture v1.0.1 h1:6aAXghmvtnngMgQzy7SMGdicMvkV86V4n9fT0meE5E4= github.com/ethantkoenig/rupture v1.0.1/go.mod h1:Sjqo/nbffZp1pVVXNGhpugIjsWmuS9KiIB4GtpEBur4= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= -github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= -github.com/felixge/fgprof v0.9.4/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= +github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -289,55 +279,49 @@ 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.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.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= -github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +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/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= github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1/go.mod h1:fenKRzpXDjNpsIBhuhUzvjCKlDjKam0boRAenTE0Q6A= -github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= -github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/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-20240408091739-ba76b44c2594 h1:er3GvGCm7bJwHostjZlsRy7uiUuCquUVF9Fe0TrwiPI= -github.com/go-ap/activitypub v0.0.0-20240408091739-ba76b44c2594/go.mod h1:yRUfFCoZY6C1CWalauqEQ5xYgSckzEBEO/2MBC6BOME= -github.com/go-ap/errors v0.0.0-20240304112515-6077fa9c17b0 h1:H9MGShwybHLSln6K8RxHPMHiLcD86Lru+5TVW2TcXHY= -github.com/go-ap/errors v0.0.0-20240304112515-6077fa9c17b0/go.mod h1:5x8a6P/dhmMGFxWLcyYlyOuJ2lRNaHGhRv+yu8BaTSI= +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/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.0.13 h1:JlH2F2M8qnwl0N1+JFFzlX9TlKJYas3aPXdiuTmJL+w= -github.com/go-chi/chi/v5 v5.0.13/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/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.1 h1:G9iDteJ/Mc0F4Di5NeQknf83R2OkRbwY9cAYmcqVG6U= -github.com/go-enry/go-enry/v2 v2.9.1/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= +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-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-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= -github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= -github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= -github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= -github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8= github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-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-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.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= -github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= +github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= +github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= -github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= +github.com/go-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-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= @@ -368,33 +352,30 @@ 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.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +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-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= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-testfixtures/testfixtures/v3 v3.11.0 h1:XxQr8AnPORcZkyNd7go5UNLPD3dULN8ixYISlzrlfEQ= -github.com/go-testfixtures/testfixtures/v3 v3.11.0/go.mod h1:THmudHF1Ixq++J2/UodcJpxUphfyEd77m83TvDtryqE= -github.com/go-webauthn/webauthn v0.10.2 h1:OG7B+DyuTytrEPFmTX503K77fqs3HDK/0Iv+z8UYbq4= -github.com/go-webauthn/webauthn v0.10.2/go.mod h1:Gd1IDsGAybuvK1NkwUTLbGmeksxuRJjVN2PE/xsPxHs= -github.com/go-webauthn/x v0.1.9 h1:v1oeLmoaa+gPOaZqUdDentu6Rl7HkSSsmOT6gxEQHhE= -github.com/go-webauthn/x v0.1.9/go.mod h1:pJNMlIMP1SU7cN8HNlKJpLEnFHCygLCvaLZ8a1xeoQA= +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/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.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +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/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= @@ -403,8 +384,8 @@ github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/geo v0.0.0-20230421003525-6adc56603217 h1:HKlyj6in2JV6wVkmQ4XmG/EIm+SCYlPZ+V4GWit7Z+I= github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1IxZfeH3/5I97CI8i5cLGsYe7xNhQGs9U= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -413,7 +394,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -423,8 +403,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -436,18 +416,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.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= -github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= +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/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-20240618054019-d3b898a103f8 h1:ASJ/LAqdCHOyMYI+dwNxn7Rd8FscNkMyTr1KZU1JI/M= -github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/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/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= @@ -470,12 +448,9 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg= -github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= -github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE= -github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= -github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= -github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/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/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= @@ -487,6 +462,9 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -494,43 +472,30 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= -github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= -github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= -github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= -github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jhillyerd/enmime v1.2.0 h1:dIu1IPEymQgoT2dzuB//ttA/xcV40NMPpQtmd4wslHk= -github.com/jhillyerd/enmime v1.2.0/go.mod h1:FRFuUPCLh8PByQv+8xRcLO9QHqaqTqreYhopv5eyk4I= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= +github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= +github.com/jhillyerd/enmime v1.3.0 h1:LV5kzfLidiOr8qRGIpYYmUZCnhrPbcFAnAFUnWn99rw= +github.com/jhillyerd/enmime v1.3.0/go.mod h1:6c6jg5HdRRV2FtvVL69LjiX1M8oE0xDX9VEhV3oy4gs= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -542,22 +507,14 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4= -github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/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/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.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -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/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= 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= @@ -576,51 +533,53 @@ 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.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= -github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +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/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.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/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= +github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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.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-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 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.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/meilisearch/meilisearch-go v0.26.3 h1:EYt+C1n7IvjKzgXM3xqce5iJzNBq33F7ayZOKx96TKY= -github.com/meilisearch/meilisearch-go v0.26.3/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= -github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k= -github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U= -github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= -github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= -github.com/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.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= -github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= +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/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/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.77 h1:GaGghJRg9nwDVlNbwYjSDJT1rqltQkBFDsypWX1v3Bw= -github.com/minio/minio-go/v7 v7.0.77/go.mod h1:AVM3IUN6WwKzmwBxVdjzhH8xq+f57JSbbvzqvUzR6eg= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +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/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= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -628,7 +587,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 h1:j2kD3MT1z4PXCiUllUJF9mWUESr9TWKS7iEKsQ/IipM= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= @@ -638,8 +596,6 @@ 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= @@ -662,25 +618,22 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= -github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= -github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= -github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +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.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.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= -github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +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/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= @@ -691,25 +644,25 @@ 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.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +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_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.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw= github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.6.0 h1:NLck+Rab3AOTHw21CGRpvQpgTrAU4sgdCswqGtlhGRA= -github.com/redis/go-redis/v9 v9.6.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= 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.1 h1:WJaDzyT1StBWVKGSsZPYnbV0HF9Y9/vD6KFdZQL42qE= -github.com/rhysd/actionlint v1.7.1/go.mod h1:lNjNNlZY0BdBl8l837Z9ZiBpu8v+5lzfoJQFdSk4xss= +github.com/rhysd/actionlint v1.7.7 h1:0KgkoNTrYY7vmOCs9BW2AHxLvvpoY9nEUzgBHiPUr0k= +github.com/rhysd/actionlint v1.7.7/go.mod h1:AE6I6vJEkNaIfWqC2GNE5spIJNhxf8NCtLEKU4NnUXg= 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= @@ -719,28 +672,25 @@ 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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +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/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.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg= github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= -github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= -github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= @@ -748,8 +698,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.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= -github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= 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= @@ -759,20 +709,19 @@ 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.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +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/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/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.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +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/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc= @@ -780,27 +729,23 @@ github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= @@ -813,26 +758,17 @@ github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= -github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/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/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.105.0 h1:3nyLq0ESez0crcaM19o5S//SvezOQguuIHZ3wgX64hM= -github.com/xanzy/go-gitlab v0.105.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -845,36 +781,33 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMx github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js= github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.2 h1:NjGd7lO7zrUn/A7eKwn5PEOt4ONYGqpxSEeZuduvgxc= -github.com/yuin/goldmark v1.7.2/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= +github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= -github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/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.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= -go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= -go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= -go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= -go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= -go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= -go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= -go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +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.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= @@ -884,65 +817,73 @@ 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= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw= -golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= -golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +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/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= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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/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= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= +golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= +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= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.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= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -960,83 +901,74 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.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= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/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.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/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= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +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/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-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +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/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.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= -gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +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= 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= @@ -1044,8 +976,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -1082,8 +1012,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.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8= -mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= +mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI= +mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk= 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/main_timezones.go b/main_timezones.go new file mode 100644 index 0000000000..e1233007c6 --- /dev/null +++ b/main_timezones.go @@ -0,0 +1,16 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build windows + +package main + +// Golang has the ability to load OS's timezone data from most UNIX systems (https://github.com/golang/go/blob/master/src/time/zoneinfo_unix.go) +// Even if the timezone data is missing, users could install the related packages to get it. +// But on Windows, although `zoneinfo_windows.go` tries to load the timezone data from Windows registry, +// some users still suffer from the issue that the timezone data is missing: https://github.com/go-gitea/gitea/issues/33235 +// So we import the tzdata package to make sure the timezone data is included in the binary. +// +// For non-Windows package builders, they could still use the "TAGS=timetzdata" to include the tzdata package in the binary. +// If we decided to add the tzdata for other platforms, modify the "go:build" directive above. +import _ "time/tzdata" diff --git a/models/actions/artifact.go b/models/actions/artifact.go index 0bc66ba24e..524224f070 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 int64 `xorm:"index"` // The status of the artifact, uploading, expired or need-delete + Status ArtifactStatus `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: int64(ArtifactStatusUploadPending), + Status: ArtifactStatusUploadPending, ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays), } if _, err := db.GetEngine(ctx).Insert(artifact); err != nil { @@ -108,12 +108,19 @@ func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) erro type FindArtifactsOptions struct { db.ListOptions - RepoID int64 - RunID int64 - ArtifactName string - Status int + RepoID int64 + RunID int64 + ArtifactName string + Status int + FinalizedArtifactsV4 bool } +func (opts FindArtifactsOptions) ToOrders() string { + return "id" +} + +var _ db.FindOptionsOrder = (*FindArtifactsOptions)(nil) + func (opts FindArtifactsOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { @@ -128,11 +135,15 @@ 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 } -// ActionArtifactMeta is the meta data of an artifact +// ActionArtifactMeta is the meta-data of an artifact type ActionArtifactMeta struct { ArtifactName string FileSize int64 @@ -166,18 +177,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: int64(ArtifactStatusExpired)}) + _, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: 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: int64(ArtifactStatusPendingDeletion)}) + _, err := db.GetEngine(ctx).Where("run_id=? AND artifact_name=? AND status = ?", runID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: 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: int64(ArtifactStatusDeleted)}) + _, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusDeleted}) return err } diff --git a/models/actions/run.go b/models/actions/run.go index 37064520a2..89f7f3e640 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -37,6 +37,7 @@ type ActionRun struct { TriggerUser *user_model.User `xorm:"-"` ScheduleID int64 Ref string `xorm:"index"` // the commit/tag/… that caused the run + IsRefDeleted bool `xorm:"-"` CommitSHA string IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow. NeedApproval bool // may need approval if it's a fork pull request @@ -87,7 +88,7 @@ func (run *ActionRun) RefLink() string { if refName.IsPull() { return run.Repo.Link() + "/pulls/" + refName.ShortName() } - return git.RefURL(run.Repo.Link(), run.Ref) + return run.Repo.Link() + "/src/" + refName.RefWebLinkPath() } // PrettyRef return #id for pull ref or ShortName for others @@ -153,7 +154,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) { } func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) { - if run.Event == webhook_module.HookEventPullRequest || run.Event == webhook_module.HookEventPullRequestSync { + if run.Event.IsPullRequest() { var payload api.PullRequestPayload if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil { return nil, err @@ -193,7 +194,7 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err // CancelPreviousJobs cancels all previous jobs of the same repository, reference, workflow, and event. // It's useful when a new run is triggered, and all previous runs needn't be continued anymore. -func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) error { +func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) ([]*ActionRunJob, error) { // Find all runs in the specified repository, reference, and workflow with non-final status runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{ RepoID: repoID, @@ -203,14 +204,16 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin Status: []Status{StatusRunning, StatusWaiting, StatusBlocked}, }) if err != nil { - return err + return nil, err } // If there are no runs found, there's no need to proceed with cancellation, so return nil. if total == 0 { - return nil + return nil, nil } + cancelledJobs := make([]*ActionRunJob, 0, total) + // Iterate over each found run and cancel its associated jobs. for _, run := range runs { // Find all jobs associated with the current run. @@ -218,7 +221,7 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin RunID: run.ID, }) if err != nil { - return err + return cancelledJobs, err } // Iterate over each job and attempt to cancel it. @@ -237,30 +240,33 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin // Update the job's status and stopped time in the database. n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}, "status", "stopped") if err != nil { - return err + return cancelledJobs, err } // If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again. if n == 0 { - return fmt.Errorf("job has changed, try again") + return cancelledJobs, fmt.Errorf("job has changed, try again") } + cancelledJobs = append(cancelledJobs, job) // Continue with the next job. continue } // If the job has an associated task, try to stop the task, effectively cancelling the job. if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil { - return err + return cancelledJobs, err } + cancelledJobs = append(cancelledJobs, job) } } // Return nil to indicate successful cancellation of all running and waiting jobs. - return nil + return cancelledJobs, nil } // InsertRun inserts a run +// The title will be cut off at 255 characters if it's longer than 255 characters. func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error { ctx, committer, err := db.TxContext(ctx) if err != nil { @@ -273,6 +279,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork return err } run.Index = index + run.Title = util.EllipsisDisplayString(run.Title, 255) if err := db.Insert(ctx, run); err != nil { return err @@ -305,7 +312,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork } else { hasWaiting = true } - job.Name, _ = util.SplitStringAtByteN(job.Name, 255) + job.Name = util.EllipsisDisplayString(job.Name, 255) runJobs = append(runJobs, &ActionRunJob{ RunID: run.ID, RepoID: run.RepoID, @@ -399,6 +406,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) affected, err := sess.Update(run) if err != nil { return err diff --git a/models/actions/run_job.go b/models/actions/run_job.go index 4b8664077d..de4b6aab66 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -137,7 +137,7 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col if err != nil { return 0, err } - run.Status = aggregateJobStatus(jobs) + run.Status = AggregateJobStatus(jobs) if run.Started.IsZero() && run.Status.IsRunning() { run.Started = timeutil.TimeStampNow() } @@ -152,29 +152,35 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col return affected, nil } -func aggregateJobStatus(jobs []*ActionRunJob) Status { - allDone := true - allWaiting := true - hasFailure := false +func AggregateJobStatus(jobs []*ActionRunJob) Status { + allSuccessOrSkipped := len(jobs) != 0 + allSkipped := len(jobs) != 0 + var hasFailure, hasCancelled, hasWaiting, hasRunning, hasBlocked bool for _, job := range jobs { - if !job.Status.IsDone() { - allDone = false - } - if job.Status != StatusWaiting && !job.Status.IsDone() { - allWaiting = false - } - if job.Status == StatusFailure || job.Status == StatusCancelled { - hasFailure = true - } + allSuccessOrSkipped = allSuccessOrSkipped && (job.Status == StatusSuccess || job.Status == StatusSkipped) + allSkipped = allSkipped && job.Status == StatusSkipped + hasFailure = hasFailure || job.Status == StatusFailure + hasCancelled = hasCancelled || job.Status == StatusCancelled + hasWaiting = hasWaiting || job.Status == StatusWaiting + hasRunning = hasRunning || job.Status == StatusRunning + hasBlocked = hasBlocked || job.Status == StatusBlocked } - if allDone { - if hasFailure { - return StatusFailure - } + switch { + case allSkipped: + return StatusSkipped + case allSuccessOrSkipped: return StatusSuccess - } - if allWaiting { + case hasCancelled: + return StatusCancelled + case hasFailure: + return StatusFailure + case hasRunning: + return StatusRunning + case hasWaiting: return StatusWaiting + case hasBlocked: + return StatusBlocked + default: + return StatusUnknown // it shouldn't happen } - return StatusRunning } diff --git a/models/actions/run_job_status_test.go b/models/actions/run_job_status_test.go new file mode 100644 index 0000000000..523d38327e --- /dev/null +++ b/models/actions/run_job_status_test.go @@ -0,0 +1,85 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAggregateJobStatus(t *testing.T) { + testStatuses := func(expected Status, statuses []Status) { + t.Helper() + var jobs []*ActionRunJob + for _, v := range statuses { + jobs = append(jobs, &ActionRunJob{Status: v}) + } + actual := AggregateJobStatus(jobs) + if !assert.Equal(t, expected, actual) { + var statusStrings []string + for _, s := range statuses { + statusStrings = append(statusStrings, s.String()) + } + t.Errorf("AggregateJobStatus(%v) = %v, want %v", statusStrings, statusNames[actual], statusNames[expected]) + } + } + + cases := []struct { + statuses []Status + expected Status + }{ + // unknown cases, maybe it shouldn't happen in real world + {[]Status{}, StatusUnknown}, + {[]Status{StatusUnknown, StatusSuccess}, StatusUnknown}, + {[]Status{StatusUnknown, StatusSkipped}, StatusUnknown}, + {[]Status{StatusUnknown, StatusFailure}, StatusFailure}, + {[]Status{StatusUnknown, StatusCancelled}, StatusCancelled}, + {[]Status{StatusUnknown, StatusWaiting}, StatusWaiting}, + {[]Status{StatusUnknown, StatusRunning}, StatusRunning}, + {[]Status{StatusUnknown, StatusBlocked}, StatusBlocked}, + + // success with other status + {[]Status{StatusSuccess}, StatusSuccess}, + {[]Status{StatusSuccess, StatusSkipped}, StatusSuccess}, // skipped doesn't affect success + {[]Status{StatusSuccess, StatusFailure}, StatusFailure}, + {[]Status{StatusSuccess, StatusCancelled}, StatusCancelled}, + {[]Status{StatusSuccess, StatusWaiting}, StatusWaiting}, + {[]Status{StatusSuccess, StatusRunning}, StatusRunning}, + {[]Status{StatusSuccess, StatusBlocked}, StatusBlocked}, + + // any cancelled, then cancelled + {[]Status{StatusCancelled}, StatusCancelled}, + {[]Status{StatusCancelled, StatusSuccess}, StatusCancelled}, + {[]Status{StatusCancelled, StatusSkipped}, StatusCancelled}, + {[]Status{StatusCancelled, StatusFailure}, StatusCancelled}, + {[]Status{StatusCancelled, StatusWaiting}, StatusCancelled}, + {[]Status{StatusCancelled, StatusRunning}, StatusCancelled}, + {[]Status{StatusCancelled, StatusBlocked}, StatusCancelled}, + + // failure with other status, fail fast + // Should "running" win? Maybe no: old code does make "running" win, but GitHub does fail fast. + {[]Status{StatusFailure}, StatusFailure}, + {[]Status{StatusFailure, StatusSuccess}, StatusFailure}, + {[]Status{StatusFailure, StatusSkipped}, StatusFailure}, + {[]Status{StatusFailure, StatusCancelled}, StatusCancelled}, + {[]Status{StatusFailure, StatusWaiting}, StatusFailure}, + {[]Status{StatusFailure, StatusRunning}, StatusFailure}, + {[]Status{StatusFailure, StatusBlocked}, StatusFailure}, + + // skipped with other status + // "all skipped" is also considered as "mergeable" by "services/actions.toCommitStatus", the same as GitHub + {[]Status{StatusSkipped}, StatusSkipped}, + {[]Status{StatusSkipped, StatusSuccess}, StatusSuccess}, + {[]Status{StatusSkipped, StatusFailure}, StatusFailure}, + {[]Status{StatusSkipped, StatusCancelled}, StatusCancelled}, + {[]Status{StatusSkipped, StatusWaiting}, StatusWaiting}, + {[]Status{StatusSkipped, StatusRunning}, StatusRunning}, + {[]Status{StatusSkipped, StatusBlocked}, StatusBlocked}, + } + + for _, c := range cases { + testStatuses(c.expected, c.statuses) + } +} diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 4046c7d369..b9b9324e07 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -10,6 +10,7 @@ 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" @@ -112,14 +113,14 @@ type StatusInfo struct { } // GetStatusInfoList returns a slice of StatusInfo -func GetStatusInfoList(ctx context.Context) []StatusInfo { +func GetStatusInfoList(ctx context.Context, lang translation.Locale) []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.String(), + DisplayedStatus: s.LocaleString(lang), }) } return statusInfoList diff --git a/models/actions/runner.go b/models/actions/runner.go index 2023ba4f99..97db0ca7ea 100644 --- a/models/actions/runner.go +++ b/models/actions/runner.go @@ -167,6 +167,7 @@ func init() { type FindRunnerOptions struct { db.ListOptions + IDs []int64 RepoID int64 OwnerID int64 // it will be ignored if RepoID is set Sort string @@ -178,6 +179,14 @@ type FindRunnerOptions struct { func (opts FindRunnerOptions) ToConds() builder.Cond { cond := builder.NewCond() + if len(opts.IDs) > 0 { + if len(opts.IDs) == 1 { + cond = cond.And(builder.Eq{"id": opts.IDs[0]}) + } else { + cond = cond.And(builder.In("id", opts.IDs)) + } + } + if opts.RepoID > 0 { c := builder.NewCond().And(builder.Eq{"repo_id": opts.RepoID}) if opts.WithAvailable { @@ -252,6 +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) var err error if len(cols) == 0 { _, err = e.ID(r.ID).AllCols().Update(r) @@ -278,6 +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) return db.Insert(ctx, t) } @@ -326,3 +337,17 @@ func FixRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) { } return res.RowsAffected() } + +func CountWrongRepoLevelRunners(ctx context.Context) (int64, error) { + var result int64 + _, err := db.GetEngine(ctx).SQL("SELECT count(`id`) FROM `action_runner` WHERE `repo_id` > 0 AND `owner_id` > 0").Get(&result) + return result, err +} + +func UpdateWrongRepoLevelRunners(ctx context.Context) (int64, error) { + result, err := db.GetEngine(ctx).Exec("UPDATE `action_runner` SET `owner_id` = 0 WHERE `repo_id` > 0 AND `owner_id` > 0") + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/models/actions/runner_token.go b/models/actions/runner_token.go index fd6ba7ecad..bbd2af73b6 100644 --- a/models/actions/runner_token.go +++ b/models/actions/runner_token.go @@ -51,7 +51,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 %q: %w", token, util.ErrNotExist) + return nil, fmt.Errorf(`runner token "%s...": %w`, util.TruncateRunes(token, 3), util.ErrNotExist) } return &runnerToken, nil } @@ -68,19 +68,15 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string return err } -// NewRunnerToken creates a new active runner token and invalidate all old tokens +// NewRunnerTokenWithValue creates a new active runner token and invalidate all old tokens // ownerID will be ignored and treated as 0 if repoID is non-zero. -func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { +func NewRunnerTokenWithValue(ctx context.Context, ownerID, repoID int64, token string) (*ActionRunnerToken, error) { if ownerID != 0 && repoID != 0 { // It's trying to create a runner token that belongs to a repository, but OwnerID has been set accidentally. // Remove OwnerID to avoid confusion; it's not worth returning an error here. ownerID = 0 } - token, err := util.CryptoRandomString(40) - if err != nil { - return nil, err - } runnerToken := &ActionRunnerToken{ OwnerID: ownerID, RepoID: repoID, @@ -95,11 +91,19 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo return err } - _, err = db.GetEngine(ctx).Insert(runnerToken) + _, err := db.GetEngine(ctx).Insert(runnerToken) return err }) } +func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { + token, err := util.CryptoRandomString(40) + if err != nil { + return nil, err + } + return NewRunnerTokenWithValue(ctx, ownerID, repoID, token) +} + // GetLatestRunnerToken returns the latest runner token func GetLatestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { if ownerID != 0 && repoID != 0 { diff --git a/models/actions/runner_token_test.go b/models/actions/runner_token_test.go index e85e99abe5..159805e5f7 100644 --- a/models/actions/runner_token_test.go +++ b/models/actions/runner_token_test.go @@ -17,7 +17,7 @@ func TestGetLatestRunnerToken(t *testing.T) { token := unittest.AssertExistsAndLoadBean(t, &ActionRunnerToken{ID: 3}) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) assert.NoError(t, err) - assert.EqualValues(t, token, expectedToken) + assert.EqualValues(t, expectedToken, token) } func TestNewRunnerToken(t *testing.T) { @@ -26,7 +26,7 @@ func TestNewRunnerToken(t *testing.T) { assert.NoError(t, err) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) assert.NoError(t, err) - assert.EqualValues(t, token, expectedToken) + assert.EqualValues(t, expectedToken, token) } func TestUpdateRunnerToken(t *testing.T) { @@ -36,5 +36,5 @@ func TestUpdateRunnerToken(t *testing.T) { assert.NoError(t, UpdateRunnerToken(db.DefaultContext, token)) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) assert.NoError(t, err) - assert.EqualValues(t, token, expectedToken) + assert.EqualValues(t, expectedToken, token) } diff --git a/models/actions/schedule.go b/models/actions/schedule.go index c751ef51ca..2edf483fe0 100644 --- a/models/actions/schedule.go +++ b/models/actions/schedule.go @@ -12,6 +12,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" ) @@ -42,15 +43,12 @@ func init() { // GetSchedulesMapByIDs returns the schedules by given id slice. func GetSchedulesMapByIDs(ctx context.Context, ids []int64) (map[int64]*ActionSchedule, error) { schedules := make(map[int64]*ActionSchedule, len(ids)) + if len(ids) == 0 { + return schedules, nil + } return schedules, db.GetEngine(ctx).In("id", ids).Find(&schedules) } -// GetReposMapByIDs returns the repos by given id slice. -func GetReposMapByIDs(ctx context.Context, ids []int64) (map[int64]*repo_model.Repository, error) { - repos := make(map[int64]*repo_model.Repository, len(ids)) - return repos, db.GetEngine(ctx).In("id", ids).Find(&repos) -} - // CreateScheduleTask creates new schedule task. func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error { // Return early if there are no rows to insert @@ -67,6 +65,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) // Create new schedule row if err = db.Insert(ctx, row); err != nil { return err @@ -118,21 +117,22 @@ func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error { return committer.Commit() } -func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) error { +func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) ([]*ActionRunJob, error) { // If actions disabled when there is schedule task, this will remove the outdated schedule tasks // There is no other place we can do this because the app.ini will be changed manually if err := DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil { - return fmt.Errorf("DeleteCronTaskByRepo: %v", err) + return nil, fmt.Errorf("DeleteCronTaskByRepo: %v", err) } // cancel running cron jobs of this repository and delete old schedules - if err := CancelPreviousJobs( + jobs, err := CancelPreviousJobs( ctx, repo.ID, repo.DefaultBranch, "", webhook_module.HookEventSchedule, - ); err != nil { - return fmt.Errorf("CancelPreviousJobs: %v", err) + ) + if err != nil { + return jobs, fmt.Errorf("CancelPreviousJobs: %v", err) } - return nil + return jobs, nil } diff --git a/models/actions/schedule_spec_list.go b/models/actions/schedule_spec_list.go index f7dac72f8b..e26b2c1120 100644 --- a/models/actions/schedule_spec_list.go +++ b/models/actions/schedule_spec_list.go @@ -32,7 +32,7 @@ func (specs SpecList) LoadSchedules(ctx context.Context) error { } repoIDs := specs.GetRepoIDs() - repos, err := GetReposMapByIDs(ctx, repoIDs) + repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs) if err != nil { return err } diff --git a/models/actions/schedule_spec_test.go b/models/actions/schedule_spec_test.go index 0c26fce4b2..57221461df 100644 --- a/models/actions/schedule_spec_test.go +++ b/models/actions/schedule_spec_test.go @@ -7,19 +7,17 @@ import ( "testing" "time" + "code.gitea.io/gitea/modules/test" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestActionScheduleSpec_Parse(t *testing.T) { // Mock the local timezone is not UTC - local := time.Local tz, err := time.LoadLocation("Asia/Shanghai") require.NoError(t, err) - defer func() { - time.Local = local - }() - time.Local = tz + defer test.MockVariableValue(&time.Local, tz)() now, err := time.Parse(time.RFC3339, "2024-07-31T15:47:55+08:00") require.NoError(t, err) diff --git a/models/actions/task.go b/models/actions/task.go index b62a0c351b..9f13ff94c9 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.SplitStringAtByteN(v.String(), 255) + name := util.EllipsisDisplayString(v.String(), 255) steps[i] = &ActionTaskStep{ Name: name, TaskID: task.ID, @@ -341,7 +341,7 @@ func UpdateTask(ctx context.Context, task *ActionTask, cols ...string) error { // UpdateTaskByState updates the task by the state. // It will always update the task if the state is not final, even there is no change. // So it will update ActionTask.Updated to avoid the task being judged as a zombie task. -func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionTask, error) { +func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.TaskState) (*ActionTask, error) { stepStates := map[int64]*runnerv1.StepState{} for _, v := range state.Steps { stepStates[v.Id] = v @@ -360,6 +360,8 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT return nil, err } else if !has { return nil, util.ErrNotExist + } else if runnerID != task.RunnerID { + return nil, fmt.Errorf("invalid runner for task") } if task.Status.IsDone() { diff --git a/models/actions/variable.go b/models/actions/variable.go index d0f917d923..1929cffbd8 100644 --- a/models/actions/variable.go +++ b/models/actions/variable.go @@ -58,6 +58,7 @@ func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data strin type FindVariablesOpts struct { db.ListOptions + IDs []int64 RepoID int64 OwnerID int64 // it will be ignored if RepoID is set Name string @@ -65,6 +66,15 @@ type FindVariablesOpts struct { func (opts FindVariablesOpts) ToConds() builder.Cond { cond := builder.NewCond() + + if len(opts.IDs) > 0 { + if len(opts.IDs) == 1 { + cond = cond.And(builder.Eq{"id": opts.IDs[0]}) + } else { + cond = cond.And(builder.In("id", opts.IDs)) + } + } + // Since we now support instance-level variables, // there is no need to check for null values for `owner_id` and `repo_id` cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) @@ -85,12 +95,12 @@ func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariab return db.Find[ActionVariable](ctx, opts) } -func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) { - count, err := db.GetEngine(ctx).ID(variable.ID).Cols("name", "data"). - Update(&ActionVariable{ - Name: variable.Name, - Data: variable.Data, - }) +func UpdateVariableCols(ctx context.Context, variable *ActionVariable, cols ...string) (bool, error) { + variable.Name = strings.ToUpper(variable.Name) + count, err := db.GetEngine(ctx). + ID(variable.ID). + Cols(cols...). + Update(variable) return count != 0, err } @@ -137,3 +147,17 @@ func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, return variables, nil } + +func CountWrongRepoLevelVariables(ctx context.Context) (int64, error) { + var result int64 + _, err := db.GetEngine(ctx).SQL("SELECT count(`id`) FROM `action_variable` WHERE `repo_id` > 0 AND `owner_id` > 0").Get(&result) + return result, err +} + +func UpdateWrongRepoLevelVariables(ctx context.Context) (int64, error) { + result, err := db.GetEngine(ctx).Exec("UPDATE `action_variable` SET `owner_id` = 0 WHERE `repo_id` > 0 AND `owner_id` > 0") + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/models/activities/action.go b/models/activities/action.go index 9b4ffd7725..c16c49c0ac 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -16,16 +16,14 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" - access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/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" @@ -72,9 +70,9 @@ func (at ActionType) String() string { case ActionRenameRepo: return "rename_repo" case ActionStarRepo: - return "star_repo" + return "star_repo" // will not displayed in feeds.tmpl case ActionWatchRepo: - return "watch_repo" + return "watch_repo" // will not displayed in feeds.tmpl case ActionCommitRepo: return "commit_repo" case ActionCreateIssue: @@ -171,7 +169,10 @@ func (a *Action) TableIndices() []*schemas.Index { cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType) cudIndex.AddColumn("created_unix", "user_id", "is_deleted") - indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex} + cuIndex := schemas.NewIndex("c_u", schemas.IndexType) + cuIndex.AddColumn("user_id", "is_deleted") + + indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex} return indices } @@ -197,15 +198,13 @@ func (a *Action) LoadActUser(ctx context.Context) { } } -func (a *Action) loadRepo(ctx context.Context) { +func (a *Action) LoadRepo(ctx context.Context) error { if a.Repo != nil { - return + return nil } var err error a.Repo, err = repo_model.GetRepositoryByID(ctx, a.RepoID) - if err != nil { - log.Error("repo_model.GetRepositoryByID(%d): %v", a.RepoID, err) - } + return err } // GetActFullName gets the action's user full name. @@ -223,7 +222,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 base.EllipsisString(a.GetActUserName(ctx), 20) + return util.EllipsisDisplayString(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. @@ -247,26 +246,32 @@ func (a *Action) GetActDisplayNameTitle(ctx context.Context) string { // GetRepoUserName returns the name of the action repository owner. func (a *Action) GetRepoUserName(ctx context.Context) string { - a.loadRepo(ctx) + _ = a.LoadRepo(ctx) + if a.Repo == nil { + return "(non-existing-repo)" + } return a.Repo.OwnerName } // ShortRepoUserName returns the name of the action repository owner // trimmed to max 20 chars. func (a *Action) ShortRepoUserName(ctx context.Context) string { - return base.EllipsisString(a.GetRepoUserName(ctx), 20) + return util.EllipsisDisplayString(a.GetRepoUserName(ctx), 20) } // GetRepoName returns the name of the action repository. func (a *Action) GetRepoName(ctx context.Context) string { - a.loadRepo(ctx) + _ = a.LoadRepo(ctx) + if a.Repo == nil { + return "(non-existing-repo)" + } return a.Repo.Name } // ShortRepoName returns the name of the action repository // trimmed to max 33 chars. func (a *Action) ShortRepoName(ctx context.Context) string { - return base.EllipsisString(a.GetRepoName(ctx), 33) + return util.EllipsisDisplayString(a.GetRepoName(ctx), 33) } // GetRepoPath returns the virtual path to the action repository. @@ -346,7 +351,7 @@ func (a *Action) GetBranch() string { // GetRefLink returns the action's ref link. func (a *Action) GetRefLink(ctx context.Context) string { - return git.RefURL(a.GetRepoLink(ctx), a.RefName) + return a.GetRepoLink(ctx) + "/src/" + git.RefName(a.RefName).RefWebLinkPath() } // GetTag returns the action's repository tag. @@ -439,65 +444,31 @@ type GetFeedsOptions struct { Date string // the day we want activity for: YYYY-MM-DD } -// GetFeeds returns actions according to the provided options -func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) { - if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil { - return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") - } - - cond, err := activityQueryCondition(ctx, opts) - if err != nil { - return nil, 0, err - } - - actions := make([]*Action, 0, opts.PageSize) - var count int64 - opts.SetDefaultValues() - - if opts.Page < 10 { // TODO: why it's 10 but other values? It's an experience value. - sess := db.GetEngine(ctx).Where(cond) - sess = db.SetSessionPagination(sess, &opts) - - count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions) - if err != nil { - return nil, 0, fmt.Errorf("FindAndCount: %w", err) - } - } else { - // First, only query which IDs are necessary, and only then query all actions to speed up the overall query - sess := db.GetEngine(ctx).Where(cond).Select("`action`.id") - sess = db.SetSessionPagination(sess, &opts) - - actionIDs := make([]int64, 0, opts.PageSize) - if err := sess.Table("action").Desc("`action`.created_unix").Find(&actionIDs); err != nil { - return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err) - } - - count, err = db.GetEngine(ctx).Where(cond). - Table("action"). - Cols("`action`.id").Count() - if err != nil { - return nil, 0, fmt.Errorf("Count: %w", err) - } - - if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil { - return nil, 0, fmt.Errorf("Find: %w", err) - } - } - - if err := ActionList(actions).LoadAttributes(ctx); err != nil { - return nil, 0, fmt.Errorf("LoadAttributes: %w", err) - } - - return actions, count, nil -} - // ActivityReadable return whether doer can read activities of user func ActivityReadable(user, doer *user_model.User) bool { return !user.KeepActivityPrivate || doer != nil && (doer.IsAdmin || user.ID == doer.ID) } -func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) { +func FeedDateCond(opts GetFeedsOptions) builder.Cond { + cond := builder.NewCond() + if opts.Date == "" { + return cond + } + + dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation) + if err != nil { + log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err) + } else { + dateHigh := dateLow.Add(86399000000000) // 23h59m59s + + cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()}) + cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()}) + } + return cond +} + +func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) { cond := builder.NewCond() if opts.RequestedTeam != nil && opts.RequestedUser == nil { @@ -554,8 +525,8 @@ func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder. } if opts.RequestedTeam != nil { - env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam) - teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos) + env := repo_model.AccessibleTeamReposEnv(organization.OrgFromUser(opts.RequestedUser), opts.RequestedTeam) + teamRepoIDs, err := env.RepoIDs(ctx, 1, opts.RequestedUser.NumRepos) if err != nil { return nil, fmt.Errorf("GetTeamRepositories: %w", err) } @@ -577,17 +548,7 @@ func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder. cond = cond.And(builder.Eq{"is_deleted": false}) } - if opts.Date != "" { - dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation) - if err != nil { - log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err) - } else { - dateHigh := dateLow.Add(86399000000000) // 23h59m59s - - cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()}) - cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()}) - } - } + cond = cond.And(FeedDateCond(opts)) return cond, nil } @@ -602,130 +563,6 @@ func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error) return err } -// NotifyWatchers creates batch of actions for every watcher. -// It could insert duplicate actions for a repository action, like this: -// * Original action: UserID=1 (the real actor), ActUserID=1 -// * Organization action: UserID=100 (the repo's org), ActUserID=1 -// * Watcher action: UserID=20 (a user who is watching a repo), ActUserID=1 -func NotifyWatchers(ctx context.Context, actions ...*Action) error { - var watchers []*repo_model.Watch - var repo *repo_model.Repository - var err error - var permCode []bool - var permIssue []bool - var permPR []bool - - e := db.GetEngine(ctx) - - for _, act := range actions { - repoChanged := repo == nil || repo.ID != act.RepoID - - if repoChanged { - // Add feeds for user self and all watchers. - watchers, err = repo_model.GetWatchers(ctx, act.RepoID) - if err != nil { - return fmt.Errorf("get watchers: %w", err) - } - } - - // Add feed for actioner. - act.UserID = act.ActUserID - if _, err = e.Insert(act); err != nil { - return fmt.Errorf("insert new actioner: %w", err) - } - - if repoChanged { - act.loadRepo(ctx) - repo = act.Repo - - // check repo owner exist. - if err := act.Repo.LoadOwner(ctx); err != nil { - return fmt.Errorf("can't get repo owner: %w", err) - } - } else if act.Repo == nil { - act.Repo = repo - } - - // Add feed for organization - if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID { - act.ID = 0 - act.UserID = act.Repo.Owner.ID - if err = db.Insert(ctx, act); err != nil { - return fmt.Errorf("insert new actioner: %w", err) - } - } - - if repoChanged { - permCode = make([]bool, len(watchers)) - permIssue = make([]bool, len(watchers)) - permPR = make([]bool, len(watchers)) - for i, watcher := range watchers { - user, err := user_model.GetUserByID(ctx, watcher.UserID) - if err != nil { - permCode[i] = false - permIssue[i] = false - permPR[i] = false - continue - } - perm, err := access_model.GetUserRepoPermission(ctx, repo, user) - if err != nil { - permCode[i] = false - permIssue[i] = false - permPR[i] = false - continue - } - permCode[i] = perm.CanRead(unit.TypeCode) - permIssue[i] = perm.CanRead(unit.TypeIssues) - permPR[i] = perm.CanRead(unit.TypePullRequests) - } - } - - for i, watcher := range watchers { - if act.ActUserID == watcher.UserID { - continue - } - act.ID = 0 - act.UserID = watcher.UserID - act.Repo.Units = nil - - switch act.OpType { - case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionPublishRelease, ActionDeleteBranch: - if !permCode[i] { - continue - } - case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue: - if !permIssue[i] { - continue - } - case ActionCreatePullRequest, ActionCommentPull, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest, ActionAutoMergePullRequest: - if !permPR[i] { - continue - } - } - - if err = db.Insert(ctx, act); err != nil { - return fmt.Errorf("insert new action: %w", err) - } - } - } - return nil -} - -// NotifyWatchersActions creates batch of actions for every watcher. -func NotifyWatchersActions(ctx context.Context, acts []*Action) error { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - for _, act := range acts { - if err := NotifyWatchers(ctx, act); err != nil { - return err - } - } - return committer.Commit() -} - // DeleteIssueActions delete all actions related with issueID func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) error { // delete actions assigned to this issue @@ -761,7 +598,7 @@ func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) // CountActionCreatedUnixString count actions where created_unix is an empty string func CountActionCreatedUnixString(ctx context.Context) (int64, error) { if setting.Database.Type.IsSQLite3() { - return db.GetEngine(ctx).Where(`created_unix = ""`).Count(new(Action)) + return db.GetEngine(ctx).Where(`created_unix = ''`).Count(new(Action)) } return 0, nil } @@ -769,7 +606,7 @@ func CountActionCreatedUnixString(ctx context.Context) (int64, error) { // FixActionCreatedUnixString set created_unix to zero if it is an empty string func FixActionCreatedUnixString(ctx context.Context) (int64, error) { if setting.Database.Type.IsSQLite3() { - res, err := db.GetEngine(ctx).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`) + res, err := db.GetEngine(ctx).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ''`) if err != nil { return 0, err } diff --git a/models/activities/action_list.go b/models/activities/action_list.go index aafb7f8a26..f7ea48f03e 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -201,3 +201,77 @@ func (actions ActionList) LoadIssues(ctx context.Context) error { } return nil } + +// GetFeeds returns actions according to the provided options +func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) { + if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil { + return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") + } + + var err error + var cond builder.Cond + // if the actor is the requested user or is an administrator, we can skip the ActivityQueryCondition + if opts.Actor != nil && opts.RequestedUser != nil && (opts.Actor.IsAdmin || opts.Actor.ID == opts.RequestedUser.ID) { + cond = builder.Eq{ + "user_id": opts.RequestedUser.ID, + }.And( + FeedDateCond(opts), + ) + + if !opts.IncludeDeleted { + cond = cond.And(builder.Eq{"is_deleted": false}) + } + + if !opts.IncludePrivate { + cond = cond.And(builder.Eq{"is_private": false}) + } + if opts.OnlyPerformedBy { + cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID}) + } + } else { + cond, err = ActivityQueryCondition(ctx, opts) + if err != nil { + return nil, 0, err + } + } + + actions := make([]*Action, 0, opts.PageSize) + var count int64 + opts.SetDefaultValues() + + if opts.Page < 10 { // TODO: why it's 10 but other values? It's an experience value. + sess := db.GetEngine(ctx).Where(cond) + sess = db.SetSessionPagination(sess, &opts) + + count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions) + if err != nil { + return nil, 0, fmt.Errorf("FindAndCount: %w", err) + } + } else { + // First, only query which IDs are necessary, and only then query all actions to speed up the overall query + sess := db.GetEngine(ctx).Where(cond).Select("`action`.id") + sess = db.SetSessionPagination(sess, &opts) + + actionIDs := make([]int64, 0, opts.PageSize) + if err := sess.Table("action").Desc("`action`.created_unix").Find(&actionIDs); err != nil { + return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err) + } + + count, err = db.GetEngine(ctx).Where(cond). + Table("action"). + Cols("`action`.id").Count() + if err != nil { + return nil, 0, fmt.Errorf("Count: %w", err) + } + + if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil { + return nil, 0, fmt.Errorf("Find: %w", err) + } + } + + if err := ActionList(actions).LoadAttributes(ctx); err != nil { + return nil, 0, fmt.Errorf("LoadAttributes: %w", err) + } + + return actions, count, nil +} diff --git a/models/activities/action_test.go b/models/activities/action_test.go index e5dee33ae0..ee2a225a3e 100644 --- a/models/activities/action_test.go +++ b/models/activities/action_test.go @@ -42,114 +42,6 @@ func TestAction_GetRepoLink(t *testing.T) { assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext)) } -func TestGetFeeds(t *testing.T) { - // test with an individual user - assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - - actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedUser: user, - Actor: user, - IncludePrivate: true, - OnlyPerformedBy: false, - IncludeDeleted: true, - }) - assert.NoError(t, err) - if assert.Len(t, actions, 1) { - assert.EqualValues(t, 1, actions[0].ID) - assert.EqualValues(t, user.ID, actions[0].UserID) - } - assert.Equal(t, int64(1), count) - - actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedUser: user, - Actor: user, - IncludePrivate: false, - OnlyPerformedBy: false, - }) - assert.NoError(t, err) - assert.Len(t, actions, 0) - assert.Equal(t, int64(0), count) -} - -func TestGetFeedsForRepos(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}) - - // private repo & no login - actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedRepo: privRepo, - IncludePrivate: true, - }) - assert.NoError(t, err) - assert.Len(t, actions, 0) - assert.Equal(t, int64(0), count) - - // public repo & no login - actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedRepo: pubRepo, - IncludePrivate: true, - }) - assert.NoError(t, err) - assert.Len(t, actions, 1) - assert.Equal(t, int64(1), count) - - // private repo and login - actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedRepo: privRepo, - IncludePrivate: true, - Actor: user, - }) - assert.NoError(t, err) - assert.Len(t, actions, 1) - assert.Equal(t, int64(1), count) - - // public repo & login - actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedRepo: pubRepo, - IncludePrivate: true, - Actor: user, - }) - assert.NoError(t, err) - assert.Len(t, actions, 1) - assert.Equal(t, int64(1), count) -} - -func TestGetFeeds2(t *testing.T) { - // test with an organization user - assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - - actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedUser: org, - Actor: user, - IncludePrivate: true, - OnlyPerformedBy: false, - IncludeDeleted: true, - }) - assert.NoError(t, err) - assert.Len(t, actions, 1) - if assert.Len(t, actions, 1) { - assert.EqualValues(t, 2, actions[0].ID) - assert.EqualValues(t, org.ID, actions[0].UserID) - } - assert.Equal(t, int64(1), count) - - actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedUser: org, - Actor: user, - IncludePrivate: false, - OnlyPerformedBy: false, - IncludeDeleted: true, - }) - assert.NoError(t, err) - assert.Len(t, actions, 0) - assert.Equal(t, int64(0), count) -} - func TestActivityReadable(t *testing.T) { tt := []struct { desc string @@ -190,63 +82,6 @@ func TestActivityReadable(t *testing.T) { } } -func TestNotifyWatchers(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - action := &activities_model.Action{ - ActUserID: 8, - RepoID: 1, - OpType: activities_model.ActionStarRepo, - } - assert.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action)) - - // One watchers are inactive, thus action is only created for user 8, 1, 4, 11 - unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ - ActUserID: action.ActUserID, - UserID: 8, - RepoID: action.RepoID, - OpType: action.OpType, - }) - unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ - ActUserID: action.ActUserID, - UserID: 1, - RepoID: action.RepoID, - OpType: action.OpType, - }) - unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ - ActUserID: action.ActUserID, - UserID: 4, - RepoID: action.RepoID, - OpType: action.OpType, - }) - unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ - ActUserID: action.ActUserID, - UserID: 11, - RepoID: action.RepoID, - OpType: action.OpType, - }) -} - -func TestGetFeedsCorrupted(t *testing.T) { - // Now we will not check for corrupted data in the feeds - // users should run doctor to fix their data - assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ - ID: 8, - RepoID: 1700, - }) - - actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedUser: user, - Actor: user, - IncludePrivate: true, - }) - assert.NoError(t, err) - assert.Len(t, actions, 1) - assert.Equal(t, int64(1), count) -} - func TestConsistencyUpdateAction(t *testing.T) { if !setting.Database.Type.IsSQLite3() { t.Skip("Test is only for SQLite database.") @@ -256,7 +91,7 @@ func TestConsistencyUpdateAction(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ ID: int64(id), }) - _, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id) + _, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = '' WHERE id = ?`, id) assert.NoError(t, err) actions := make([]*activities_model.Action, 0, 1) // @@ -322,24 +157,3 @@ func TestDeleteIssueActions(t *testing.T) { assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index)) unittest.AssertCount(t, &activities_model.Action{}, 0) } - -func TestRepoActions(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - _ = db.TruncateBeans(db.DefaultContext, &activities_model.Action{}) - for i := 0; i < 3; i++ { - _ = db.Insert(db.DefaultContext, &activities_model.Action{ - UserID: 2 + int64(i), - ActUserID: 2, - RepoID: repo.ID, - OpType: activities_model.ActionCommentIssue, - }) - } - count, _ := db.Count[activities_model.Action](db.DefaultContext, &db.ListOptions{}) - assert.EqualValues(t, 3, count) - actions, _, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ - RequestedRepo: repo, - }) - assert.NoError(t, err) - assert.Len(t, actions, 1) -} diff --git a/models/activities/notification.go b/models/activities/notification.go index b888adeb60..6dde26fd53 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" + "xorm.io/xorm/schemas" ) type ( @@ -50,25 +51,64 @@ const ( // Notification represents a notification type Notification struct { ID int64 `xorm:"pk autoincr"` - UserID int64 `xorm:"INDEX NOT NULL"` - RepoID int64 `xorm:"INDEX NOT NULL"` + UserID int64 `xorm:"NOT NULL"` + RepoID int64 `xorm:"NOT NULL"` - Status NotificationStatus `xorm:"SMALLINT INDEX NOT NULL"` - Source NotificationSource `xorm:"SMALLINT INDEX NOT NULL"` + Status NotificationStatus `xorm:"SMALLINT NOT NULL"` + Source NotificationSource `xorm:"SMALLINT NOT NULL"` - IssueID int64 `xorm:"INDEX NOT NULL"` - CommitID string `xorm:"INDEX"` + IssueID int64 `xorm:"NOT NULL"` + CommitID string CommentID int64 - UpdatedBy int64 `xorm:"INDEX NOT NULL"` + UpdatedBy int64 `xorm:"NOT NULL"` Issue *issues_model.Issue `xorm:"-"` Repository *repo_model.Repository `xorm:"-"` Comment *issues_model.Comment `xorm:"-"` User *user_model.User `xorm:"-"` - CreatedUnix timeutil.TimeStamp `xorm:"created INDEX NOT NULL"` - UpdatedUnix timeutil.TimeStamp `xorm:"updated INDEX NOT NULL"` + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` +} + +// TableIndices implements xorm's TableIndices interface +func (n *Notification) TableIndices() []*schemas.Index { + indices := make([]*schemas.Index, 0, 8) + usuuIndex := schemas.NewIndex("u_s_uu", schemas.IndexType) + usuuIndex.AddColumn("user_id", "status", "updated_unix") + indices = append(indices, usuuIndex) + + // Add the individual indices that were previously defined in struct tags + userIDIndex := schemas.NewIndex("idx_notification_user_id", schemas.IndexType) + userIDIndex.AddColumn("user_id") + indices = append(indices, userIDIndex) + + repoIDIndex := schemas.NewIndex("idx_notification_repo_id", schemas.IndexType) + repoIDIndex.AddColumn("repo_id") + indices = append(indices, repoIDIndex) + + statusIndex := schemas.NewIndex("idx_notification_status", schemas.IndexType) + statusIndex.AddColumn("status") + indices = append(indices, statusIndex) + + sourceIndex := schemas.NewIndex("idx_notification_source", schemas.IndexType) + sourceIndex.AddColumn("source") + indices = append(indices, sourceIndex) + + issueIDIndex := schemas.NewIndex("idx_notification_issue_id", schemas.IndexType) + issueIDIndex.AddColumn("issue_id") + indices = append(indices, issueIDIndex) + + commitIDIndex := schemas.NewIndex("idx_notification_commit_id", schemas.IndexType) + commitIDIndex.AddColumn("commit_id") + indices = append(indices, commitIDIndex) + + updatedByIndex := schemas.NewIndex("idx_notification_updated_by", schemas.IndexType) + updatedByIndex.AddColumn("updated_by") + indices = append(indices, updatedByIndex) + + return indices } func init() { diff --git a/models/activities/repo_activity.go b/models/activities/repo_activity.go index 3ffad035b7..3ccdbd47d3 100644 --- a/models/activities/repo_activity.go +++ b/models/activities/repo_activity.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" + "xorm.io/builder" "xorm.io/xorm" ) @@ -337,8 +338,10 @@ func newlyCreatedIssues(ctx context.Context, repoID int64, fromTime time.Time) * func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session { sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID). And("issue.is_pull = ?", false). - And("issue.created_unix >= ?", fromTime.Unix()). - Or("issue.closed_unix >= ?", fromTime.Unix()) + And(builder.Or( + builder.Gte{"issue.created_unix": fromTime.Unix()}, + builder.Gte{"issue.closed_unix": fromTime.Unix()}, + )) return sess } diff --git a/models/activities/user_heatmap.go b/models/activities/user_heatmap.go index 78fcd76d43..1f8f0f590e 100644 --- a/models/activities/user_heatmap.go +++ b/models/activities/user_heatmap.go @@ -47,7 +47,7 @@ func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organi groupByName = groupBy } - cond, err := activityQueryCondition(ctx, GetFeedsOptions{ + cond, err := ActivityQueryCondition(ctx, GetFeedsOptions{ RequestedUser: user, RequestedTeam: team, Actor: doer, diff --git a/models/activities/user_heatmap_test.go b/models/activities/user_heatmap_test.go index b7babcbde1..380045d3c5 100644 --- a/models/activities/user_heatmap_test.go +++ b/models/activities/user_heatmap_test.go @@ -4,7 +4,6 @@ package activities_test import ( - "fmt" "testing" "time" @@ -65,11 +64,9 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { for _, tc := range testCases { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID}) - doer := &user_model.User{ID: tc.doerID} - _, err := unittest.LoadBeanIfExists(doer) - assert.NoError(t, err) - if tc.doerID == 0 { - doer = nil + var doer *user_model.User + if tc.doerID != 0 { + doer = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.doerID}) } // get the action for comparison @@ -91,11 +88,11 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { assert.NoError(t, err) assert.Len(t, actions, contributions, "invalid action count: did the test data became too old?") assert.Equal(t, count, int64(contributions)) - assert.Equal(t, tc.CountResult, contributions, fmt.Sprintf("testcase '%s'", tc.desc)) + assert.Equal(t, tc.CountResult, contributions, "testcase '%s'", tc.desc) // Test JSON rendering jsonData, err := json.Marshal(heatmap) assert.NoError(t, err) - assert.Equal(t, tc.JSONResult, string(jsonData)) + assert.JSONEq(t, tc.JSONResult, string(jsonData)) } } diff --git a/models/admin/task.go b/models/admin/task.go index 10f8e6d570..0541a8ec78 100644 --- a/models/admin/task.go +++ b/models/admin/task.go @@ -44,7 +44,7 @@ func init() { // TranslatableMessage represents JSON struct that can be translated with a Locale type TranslatableMessage struct { Format string - Args []any `json:"omitempty"` + Args []any `json:",omitempty"` } // LoadRepo loads repository of the task diff --git a/models/asymkey/error.go b/models/asymkey/error.go index 03bc82302f..1ed6edd71a 100644 --- a/models/asymkey/error.go +++ b/models/asymkey/error.go @@ -25,7 +25,7 @@ func (err ErrKeyUnableVerify) Error() string { } // ErrKeyIsPrivate is returned when the provided key is a private key not a public key -var ErrKeyIsPrivate = util.NewSilentWrapErrorf(util.ErrInvalidArgument, "the provided key is a private key") +var ErrKeyIsPrivate = util.ErrorWrap(util.ErrInvalidArgument, "the provided key is a private key") // ErrKeyNotExist represents a "KeyNotExist" kind of error. type ErrKeyNotExist struct { @@ -217,6 +217,7 @@ func (err ErrGPGKeyAccessDenied) Unwrap() error { // ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. type ErrKeyAccessDenied struct { UserID int64 + RepoID int64 KeyID int64 Note string } @@ -228,8 +229,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, key_id: %d, note: %s]", - err.UserID, err.KeyID, err.Note) + 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) } func (err ErrKeyAccessDenied) Unwrap() error { diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go index 5236b2d450..7f35a96a59 100644 --- a/models/asymkey/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -13,8 +13,8 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" - "github.com/keybase/go-crypto/openpgp" - "github.com/keybase/go-crypto/openpgp/packet" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/packet" "xorm.io/builder" ) @@ -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 } @@ -141,7 +141,11 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified // Parse Subkeys subkeys := make([]*GPGKey, len(e.Subkeys)) for i, k := range e.Subkeys { - subs, err := parseSubGPGKey(ownerID, pubkey.KeyIdString(), k.PublicKey, expiry) + subkeyExpiry := expiry + if k.Sig.KeyLifetimeSecs != nil { + subkeyExpiry = k.PublicKey.CreationTime.Add(time.Duration(*k.Sig.KeyLifetimeSecs) * time.Second) + } + subs, err := parseSubGPGKey(ownerID, pubkey.KeyIdString(), k.PublicKey, subkeyExpiry) if err != nil { return nil, ErrGPGKeyParsing{ParseError: err} } @@ -156,7 +160,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified emails := make([]*user_model.EmailAddress, 0, len(e.Identities)) for _, ident := range e.Identities { - if ident.Revocation != nil { + if ident.Revoked(time.Now()) { continue } email := strings.ToLower(strings.TrimSpace(ident.UserId.Email)) @@ -179,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 } @@ -235,33 +239,3 @@ 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 11124b1366..ec2031088a 100644 --- a/models/asymkey/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" - "github.com/keybase/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp" ) // __________________ ________ ____ __. @@ -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 } @@ -83,12 +83,12 @@ func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature str verified := false // Handle provided signature if signature != "" { - signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature)) + signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature), nil) if err != nil { - signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature)) + signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature), nil) } if err != nil { - signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature)) + signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature), nil) } if err != nil { log.Error("Unable to validate token signature. Error: %v", err) diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 26fad3bb3f..1591cd5068 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -4,19 +4,14 @@ 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/keybase/go-crypto/openpgp/packet" + "github.com/ProtonMail/go-crypto/openpgp/packet" ) // __________________ ________ ____ __. @@ -70,263 +65,6 @@ 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 { @@ -369,7 +107,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{ @@ -392,78 +130,6 @@ 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 28cb8f4e76..1291cbc542 100644 --- a/models/asymkey/gpg_key_common.go +++ b/models/asymkey/gpg_key_common.go @@ -13,9 +13,9 @@ import ( "strings" "time" - "github.com/keybase/go-crypto/openpgp" - "github.com/keybase/go-crypto/openpgp/armor" - "github.com/keybase/go-crypto/openpgp/packet" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/armor" + "github.com/ProtonMail/go-crypto/openpgp/packet" ) // __________________ ________ ____ __. @@ -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 { @@ -80,7 +80,7 @@ func base64DecPubKey(content string) (*packet.PublicKey, error) { return pkey, nil } -// getExpiryTime extract the expire time of primary key based on sig +// getExpiryTime extract the expiry time of primary key based on sig func getExpiryTime(e *openpgp.Entity) time.Time { expiry := time.Time{} // Extract self-sign for expire date based on : https://github.com/golang/crypto/blob/master/openpgp/keys.go#L165 @@ -88,12 +88,12 @@ func getExpiryTime(e *openpgp.Entity) time.Time { for _, ident := range e.Identities { if selfSig == nil { selfSig = ident.SelfSignature - } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { + } else if ident.SelfSignature != nil && ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { selfSig = ident.SelfSignature break } } - if selfSig.KeyLifetimeSecs != nil { + if selfSig != nil && selfSig.KeyLifetimeSecs != nil { expiry = e.PrimaryKey.CreationTime.Add(time.Duration(*selfSig.KeyLifetimeSecs) * time.Second) } return expiry @@ -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 d3fbb01d82..408cf15763 100644 --- a/models/asymkey/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -13,8 +13,10 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" - "github.com/keybase/go-crypto/openpgp/packet" + "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) { @@ -49,7 +51,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 } @@ -70,7 +72,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 } @@ -106,15 +108,14 @@ Av844q/BfRuVsJsK1NDNG09LC30B0l3LKBqlrRmRTUMHtgchdX2dY+p7GPOoSzlR MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg== =i9b7 -----END PGP PUBLIC KEY BLOCK-----` - keys, err := checkArmoredGPGKeyString(testGPGArmor) - if !assert.NotEmpty(t, keys) { - return - } + keys, err := CheckArmoredGPGKeyString(testGPGArmor) + require.NotEmpty(t, keys) + 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{ @@ -175,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 @@ -385,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] @@ -395,11 +396,33 @@ 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}, })) } + +func TestParseGPGKey(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + assert.NoError(t, db.Insert(db.DefaultContext, &user_model.EmailAddress{UID: 1, Email: "email1@example.com", IsActivated: true})) + + // create a key for test email + e, err := openpgp.NewEntity("name", "comment", "email1@example.com", nil) + require.NoError(t, err) + k, err := parseGPGKey(db.DefaultContext, 1, e, true) + require.NoError(t, err) + assert.NotEmpty(t, k.KeyID) + assert.NotEmpty(t, k.Emails) // the key is valid, matches the email + + // then revoke the key + for _, id := range e.Identities { + 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.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 01812a2d54..6eedb5b7ba 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 897ff3fc9e..0e5b2e96e6 100644 --- a/models/auth/access_token_scope.go +++ b/models/auth/access_token_scope.go @@ -5,6 +5,7 @@ package auth import ( "fmt" + "slices" "strings" "code.gitea.io/gitea/models/perm" @@ -14,7 +15,7 @@ import ( type AccessTokenScopeCategory int const ( - AccessTokenScopeCategoryActivityPub = iota + AccessTokenScopeCategoryActivityPub AccessTokenScopeCategory = iota AccessTokenScopeCategoryAdmin AccessTokenScopeCategoryMisc // WARN: this is now just a placeholder, don't remove it which will change the following values AccessTokenScopeCategoryNotification @@ -193,6 +194,14 @@ 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)) @@ -270,6 +279,9 @@ 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 a6097e45d7..9e4aa83633 100644 --- a/models/auth/access_token_scope_test.go +++ b/models/auth/access_token_scope_test.go @@ -17,6 +17,7 @@ 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}, @@ -25,7 +26,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 []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} { + for _, scope := range GetAccessTokenCategories() { 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}, @@ -59,7 +60,7 @@ func TestAccessTokenScope_HasScope(t *testing.T) { {"public-only", "read:issue", false, nil}, } - for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} { + for _, scope := range GetAccessTokenCategories() { 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 0829d31d51..fa89a58b14 100644 --- a/models/auth/oauth2_test.go +++ b/models/auth/oauth2_test.go @@ -18,14 +18,14 @@ func TestOAuth2Application_GenerateClientSecret(t *testing.T) { app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1}) secret, err := app.GenerateClientSecret(db.DefaultContext) assert.NoError(t, err) - assert.True(t, len(secret) > 0) + assert.NotEmpty(t, secret) unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1, ClientSecret: app.ClientSecret}) } func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) { assert.NoError(b, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1}) - for i := 0; i < b.N; i++ { + for b.Loop() { _, _ = app.GenerateClientSecret(db.DefaultContext) } } @@ -165,7 +165,7 @@ func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) { code, err := grant.GenerateNewAuthorizationCode(db.DefaultContext, "https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256") assert.NoError(t, err) assert.NotNil(t, code) - assert.True(t, len(code.Code) > 32) // secret length > 32 + assert.Greater(t, len(code.Code), 32) // secret length > 32 } func TestOAuth2Grant_TableName(t *testing.T) { diff --git a/models/auth/source_test.go b/models/auth/source_test.go index 36e76d5e28..84aede0a6b 100644 --- a/models/auth/source_test.go +++ b/models/auth/source_test.go @@ -13,6 +13,8 @@ import ( "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "xorm.io/xorm" "xorm.io/xorm/schemas" ) @@ -54,7 +56,8 @@ func TestDumpAuthSource(t *testing.T) { sb := new(strings.Builder) - db.DumpTables([]*schemas.Table{authSourceSchema}, sb) - + // 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)) assert.Contains(t, sb.String(), `"Provider":"ConvertibleSourceName"`) } diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go index 553130ee2e..6d8b542957 100644 --- a/models/auth/webauthn.go +++ b/models/auth/webauthn.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" ) @@ -89,14 +90,33 @@ func (cred *WebAuthnCredential) AfterLoad() { // WebAuthnCredentialList is a list of *WebAuthnCredential type WebAuthnCredentialList []*WebAuthnCredential +// newCredentialFlagsFromAuthenticatorFlags is copied from https://github.com/go-webauthn/webauthn/pull/337 +// to convert protocol.AuthenticatorFlags to webauthn.CredentialFlags +func newCredentialFlagsFromAuthenticatorFlags(flags protocol.AuthenticatorFlags) webauthn.CredentialFlags { + return webauthn.CredentialFlags{ + UserPresent: flags.HasUserPresent(), + UserVerified: flags.HasUserVerified(), + BackupEligible: flags.HasBackupEligible(), + BackupState: flags.HasBackupState(), + } +} + // ToCredentials will convert all WebAuthnCredentials to webauthn.Credentials -func (list WebAuthnCredentialList) ToCredentials() []webauthn.Credential { +func (list WebAuthnCredentialList) ToCredentials(defaultAuthFlags ...protocol.AuthenticatorFlags) []webauthn.Credential { + // TODO: at the moment, Gitea doesn't store or check the flags + // so we need to use the default flags from the authenticator to make the login validation pass + // In the future, we should: + // 1. store the flags when registering the credential + // 2. provide the stored flags when converting the credentials (for login) + // 3. for old users, still use this fallback to the default flags + defAuthFlags := util.OptionalArg(defaultAuthFlags) creds := make([]webauthn.Credential, 0, len(list)) for _, cred := range list { creds = append(creds, webauthn.Credential{ ID: cred.CredentialID, PublicKey: cred.PublicKey, AttestationType: cred.AttestationType, + Flags: newCredentialFlagsFromAuthenticatorFlags(defAuthFlags), Authenticator: webauthn.Authenticator{ AAGUID: cred.AAGUID, SignCount: cred.SignCount, diff --git a/models/auth/webauthn_test.go b/models/auth/webauthn_test.go index f1cf398adf..654427e974 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.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1}) + unittest.AssertExistsAndLoadBean(t, &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.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff}) + unittest.AssertExistsAndLoadBean(t, &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.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1}) + unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1}) } diff --git a/models/db/collation.go b/models/db/collation.go index c128cf5029..79ade87380 100644 --- a/models/db/collation.go +++ b/models/db/collation.go @@ -68,7 +68,8 @@ func CheckCollations(x *xorm.Engine) (*CheckCollationsResult, error) { var candidateCollations []string if x.Dialect().URI().DBType == schemas.MYSQL { - if _, err = x.SQL("SELECT @@collation_database").Get(&res.DatabaseCollation); err != nil { + _, err = x.SQL("SELECT DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?", setting.Database.Name).Get(&res.DatabaseCollation) + if err != nil { return nil, err } res.IsCollationCaseSensitive = func(s string) bool { @@ -139,7 +140,7 @@ func CheckCollations(x *xorm.Engine) (*CheckCollationsResult, error) { } func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) { - return CheckCollations(x) + return CheckCollations(xormEngine) } func alterDatabaseCollation(x *xorm.Engine, collation string) error { diff --git a/models/db/context.go b/models/db/context.go index 43f612518a..4b98796ef0 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -6,6 +6,12 @@ package db import ( "context" "database/sql" + "errors" + "runtime" + "slices" + "sync" + + "code.gitea.io/gitea/modules/setting" "xorm.io/builder" "xorm.io/xorm" @@ -15,45 +21,23 @@ import ( // will be overwritten by Init with HammerContext var DefaultContext context.Context -// contextKey is a value for use with context.WithValue. -type contextKey struct { - name string -} +type engineContextKeyType struct{} -// enginedContextKey is a context key. It is used with context.Value() to get the current Engined for the context -var ( - enginedContextKey = &contextKey{"engined"} - _ Engined = &Context{} -) +var engineContextKey = engineContextKeyType{} // Context represents a db context type Context struct { context.Context - e Engine - transaction bool + engine Engine } -func newContext(ctx context.Context, e Engine, transaction bool) *Context { - return &Context{ - Context: ctx, - e: e, - transaction: transaction, - } -} - -// InTransaction if context is in a transaction -func (ctx *Context) InTransaction() bool { - return ctx.transaction -} - -// Engine returns db engine -func (ctx *Context) Engine() Engine { - return ctx.e +func newContext(ctx context.Context, e Engine) *Context { + return &Context{Context: ctx, engine: e} } // Value shadows Value for context.Context but allows us to get ourselves and an Engined object func (ctx *Context) Value(key any) any { - if key == enginedContextKey { + if key == engineContextKey { return ctx } return ctx.Context.Value(key) @@ -61,30 +45,66 @@ func (ctx *Context) Value(key any) any { // WithContext returns this engine tied to this context func (ctx *Context) WithContext(other context.Context) *Context { - return newContext(ctx, ctx.e.Context(other), ctx.transaction) + return newContext(ctx, ctx.engine.Context(other)) } -// Engined structs provide an Engine -type Engined interface { - Engine() Engine +var ( + contextSafetyOnce sync.Once + contextSafetyDeniedFuncPCs []uintptr +) + +func contextSafetyCheck(e Engine) { + if setting.IsProd && !setting.IsInTesting { + return + } + if e == nil { + return + } + // Only do this check for non-end-users. If the problem could be fixed in the future, this code could be removed. + contextSafetyOnce.Do(func() { + // try to figure out the bad functions to deny + type m struct{} + _ = e.SQL("SELECT 1").Iterate(&m{}, func(int, any) error { + callers := make([]uintptr, 32) + callerNum := runtime.Callers(1, callers) + for i := 0; i < callerNum; i++ { + if funcName := runtime.FuncForPC(callers[i]).Name(); funcName == "xorm.io/xorm.(*Session).Iterate" { + contextSafetyDeniedFuncPCs = append(contextSafetyDeniedFuncPCs, callers[i]) + } + } + return nil + }) + if len(contextSafetyDeniedFuncPCs) != 1 { + panic(errors.New("unable to determine the functions to deny")) + } + }) + + // it should be very fast: xxxx ns/op + callers := make([]uintptr, 32) + callerNum := runtime.Callers(3, callers) // skip 3: runtime.Callers, contextSafetyCheck, GetEngine + for i := 0; i < callerNum; i++ { + if slices.Contains(contextSafetyDeniedFuncPCs, callers[i]) { + panic(errors.New("using database context in an iterator would cause corrupted results")) + } + } } -// GetEngine will get a db Engine from this context or return an Engine restricted to this context +// GetEngine gets an existing db Engine/Statement or creates a new Session func GetEngine(ctx context.Context) Engine { - if e := getEngine(ctx); e != nil { + if e := getExistingEngine(ctx); e != nil { return e } - return x.Context(ctx) + return xormEngine.Context(ctx) } -// getEngine will get a db Engine from this context or return nil -func getEngine(ctx context.Context) Engine { - if engined, ok := ctx.(Engined); ok { - return engined.Engine() +// getExistingEngine gets an existing db Engine/Statement from this context or returns nil +func getExistingEngine(ctx context.Context) (e Engine) { + defer func() { contextSafetyCheck(e) }() + if engined, ok := ctx.(*Context); ok { + return engined.engine } - enginedInterface := ctx.Value(enginedContextKey) - if enginedInterface != nil { - return enginedInterface.(Engined).Engine() + if engined, ok := ctx.Value(engineContextKey).(*Context); ok { + return engined.engine } return nil } @@ -132,23 +152,23 @@ func (c *halfCommitter) Close() error { // d. It doesn't mean rollback is forbidden, but always do it only when there is an error, and you do want to rollback. func TxContext(parentCtx context.Context) (*Context, Committer, error) { if sess, ok := inTransaction(parentCtx); ok { - return newContext(parentCtx, sess, true), &halfCommitter{committer: sess}, nil + return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil } - sess := x.NewSession() + sess := xormEngine.NewSession() if err := sess.Begin(); err != nil { - sess.Close() + _ = sess.Close() return nil, nil, err } - return newContext(DefaultContext, sess, true), sess, nil + return newContext(DefaultContext, sess), sess, nil } // WithTx represents executing database operations on a transaction, if the transaction exist, // this function will reuse it otherwise will create a new one and close it when finished. func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error { if sess, ok := inTransaction(parentCtx); ok { - err := f(newContext(parentCtx, sess, true)) + err := f(newContext(parentCtx, sess)) if err != nil { // rollback immediately, in case the caller ignores returned error and tries to commit the transaction. _ = sess.Close() @@ -159,13 +179,13 @@ 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 := x.NewSession() + sess := xormEngine.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err } - if err := f(newContext(parentCtx, sess, true)); err != nil { + if err := f(newContext(parentCtx, sess)); err != nil { return err } @@ -269,6 +289,9 @@ func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([ // DecrByIDs decreases the given column for entities of the "bean" type with one of the given ids by one // Timestamps of the entities won't be updated func DecrByIDs(ctx context.Context, ids []int64, decrCol string, bean any) error { + if len(ids) == 0 { + return nil + } _, err := GetEngine(ctx).Decr(decrCol).In("id", ids).NoAutoCondition().NoAutoTime().Update(bean) return err } @@ -302,7 +325,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 x.TableName(bean) + return xormEngine.TableName(bean) } // InTransaction returns true if the engine is in a transaction otherwise return false @@ -312,7 +335,7 @@ func InTransaction(ctx context.Context) bool { } func inTransaction(ctx context.Context) (*xorm.Session, bool) { - e := getEngine(ctx) + e := getExistingEngine(ctx) if e == nil { return nil, false } diff --git a/models/db/context_committer_test.go b/models/db/context_committer_test.go index 38e91f22ed..849c5dea41 100644 --- a/models/db/context_committer_test.go +++ b/models/db/context_committer_test.go @@ -4,7 +4,7 @@ package db // it's not db_test, because this file is for testing the private type halfCommitter import ( - "fmt" + "errors" "testing" "github.com/stretchr/testify/assert" @@ -80,7 +80,7 @@ func Test_halfCommitter(t *testing.T) { testWithCommitter(mockCommitter, func(committer Committer) error { defer committer.Close() if true { - return fmt.Errorf("error") + return errors.New("error") } return committer.Commit() }) @@ -94,7 +94,7 @@ func Test_halfCommitter(t *testing.T) { testWithCommitter(mockCommitter, func(committer Committer) error { committer.Close() committer.Commit() - return fmt.Errorf("error") + return errors.New("error") }) mockCommitter.Assert(t) diff --git a/models/db/context_test.go b/models/db/context_test.go index 95a01d4a26..e8c6b74d93 100644 --- a/models/db/context_test.go +++ b/models/db/context_test.go @@ -84,3 +84,47 @@ func TestTxContext(t *testing.T) { })) } } + +func TestContextSafety(t *testing.T) { + type TestModel1 struct { + ID int64 + } + type TestModel2 struct { + ID int64 + } + assert.NoError(t, unittest.GetXORMEngine().Sync(&TestModel1{}, &TestModel2{})) + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &TestModel1{}, &TestModel2{})) + testCount := 10 + for i := 1; i <= testCount; i++ { + assert.NoError(t, db.Insert(db.DefaultContext, &TestModel1{ID: int64(i)})) + assert.NoError(t, db.Insert(db.DefaultContext, &TestModel2{ID: int64(-i)})) + } + + actualCount := 0 + // here: db.GetEngine(db.DefaultContext) is a new *Session created from *Engine + _ = db.WithTx(db.DefaultContext, func(ctx context.Context) error { + _ = db.GetEngine(ctx).Iterate(&TestModel1{}, func(i int, bean any) error { + // here: db.GetEngine(ctx) is always the unclosed "Iterate" *Session with autoResetStatement=false, + // and the internal states (including "cond" and others) are always there and not be reset in this callback. + m1 := bean.(*TestModel1) + assert.EqualValues(t, i+1, m1.ID) + + // here: XORM bug, it fails because the SQL becomes "WHERE id=-1", "WHERE id=-1 AND id=-2", "WHERE id=-1 AND id=-2 AND id=-3" ... + // and it conflicts with the "Iterate"'s internal states. + // has, err := db.GetEngine(ctx).Get(&TestModel2{ID: -m1.ID}) + + actualCount++ + return nil + }) + return nil + }) + assert.EqualValues(t, testCount, actualCount) + + // deny the bad usages + assert.PanicsWithError(t, "using database context in an iterator would cause corrupted results", func() { + _ = unittest.GetXORMEngine().Iterate(&TestModel1{}, func(i int, bean any) error { + _ = db.GetEngine(db.DefaultContext) + return nil + }) + }) +} diff --git a/models/db/convert.go b/models/db/convert.go index 8c124471ab..80b0f7b04b 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 x.Dialect().URI().DBType != schemas.MYSQL { + if xormEngine.Dialect().URI().DBType != schemas.MYSQL { return nil } - r, err := CheckCollations(x) + r, err := CheckCollations(xormEngine) if err != nil { return err } - _, err = x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", setting.Database.Name, r.ExpectedCollation)) + _, err = xormEngine.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", setting.Database.Name, r.ExpectedCollation)) if err != nil { return err } - tables, err := x.DBMetas() + tables, err := xormEngine.DBMetas() if err != nil { return err } for _, table := range tables { - if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic", table.Name)); err != nil { + if _, err := xormEngine.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic", table.Name)); err != nil { return err } - if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE %s", table.Name, r.ExpectedCollation)); err != nil { + if _, err := xormEngine.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 x.Dialect().URI().DBType != schemas.MSSQL { + if xormEngine.Dialect().URI().DBType != schemas.MSSQL { return nil } - sess := x.NewSession() + sess := xormEngine.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 847ba58c26..91015f7038 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -8,17 +8,10 @@ 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 @@ -27,9 +20,9 @@ import ( ) var ( - x *xorm.Engine - tables []any - initFuncs []func() error + xormEngine *xorm.Engine + registeredModels []any + registeredInitFuncs []func() error ) // Engine represents a xorm engine or session. @@ -70,167 +63,38 @@ type Engine interface { // TableInfo returns table's information via an object func TableInfo(v any) (*schemas.Table, error) { - return x.TableInfo(v) + return xormEngine.TableInfo(v) } -// 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 +// RegisterModel registers model, if initFuncs provided, it will be invoked after data model sync func RegisterModel(bean any, initFunc ...func() error) { - tables = append(tables, bean) - if len(initFuncs) > 0 && initFunc[0] != nil { - initFuncs = append(initFuncs, initFunc[0]) + registeredModels = append(registeredModels, bean) + if len(registeredInitFuncs) > 0 && initFunc[0] != nil { + registeredInitFuncs = append(registeredInitFuncs, 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 := x.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ + _, err := xormEngine.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ WarnIfDatabaseColumnMissed: true, - }, tables...) + }, registeredModels...) 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 { - 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, - e: 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, tables...) + beans = append(beans, registeredModels...) return beans, nil } // Need to map provided names to beans... beanMap := make(map[string]any) - for _, bean := range tables { + for _, bean := range registeredModels { beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean - beanMap[strings.ToLower(x.TableName(bean))] = bean - beanMap[strings.ToLower(x.TableName(bean, true))] = bean + beanMap[strings.ToLower(xormEngine.TableName(bean))] = bean + beanMap[strings.ToLower(xormEngine.TableName(bean, true))] = bean } gotBean := make(map[any]bool) @@ -247,36 +111,9 @@ 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 := x.TableInfo(bean) + t, err := xormEngine.TableInfo(bean) if err != nil { return 50 } @@ -285,18 +122,18 @@ func MaxBatchInsertSize(bean any) int { // IsTableNotEmpty returns true if table has at least one record func IsTableNotEmpty(beanOrTableName any) (bool, error) { - return x.Table(beanOrTableName).Exist() + return xormEngine.Table(beanOrTableName).Exist() } // DeleteAllRecords will delete all the records of this table func DeleteAllRecords(tableName string) error { - _, err := x.Exec(fmt.Sprintf("DELETE FROM %s", tableName)) + _, err := xormEngine.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 = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) + _, err = xormEngine.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) return maxID, err } @@ -308,24 +145,3 @@ 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 new file mode 100644 index 0000000000..63f2d4e093 --- /dev/null +++ b/models/db/engine_dump.go @@ -0,0 +1,33 @@ +// 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 new file mode 100644 index 0000000000..8709a2c2a1 --- /dev/null +++ b/models/db/engine_hook.go @@ -0,0 +1,47 @@ +// 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.Event{Level: 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 new file mode 100644 index 0000000000..7a071fa29b --- /dev/null +++ b/models/db/engine_init.go @@ -0,0 +1,140 @@ +// 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(context.Context, *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(ctx, 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 e3dbfbdc24..10a1a33ff0 100644 --- a/models/db/engine_test.go +++ b/models/db/engine_test.go @@ -15,6 +15,7 @@ import ( _ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestDumpDatabase(t *testing.T) { @@ -62,9 +63,7 @@ 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() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) whitelist := map[string]string{ "the_table_name_to_skip_checking": "Write a note here to explain why", @@ -79,8 +78,6 @@ func TestPrimaryKeys(t *testing.T) { t.Logf("ignore %q because %q", table.Name, why) continue } - if len(table.PrimaryKeys) == 0 { - t.Errorf("table %q has no primary key", table.Name) - } + assert.NotEmpty(t, table.PrimaryKeys, "table %q has no primary key", table.Name) } } diff --git a/models/db/install/db.go b/models/db/install/db.go index d4c1139637..1b3b2ec3e9 100644 --- a/models/db/install/db.go +++ b/models/db/install/db.go @@ -11,7 +11,7 @@ import ( ) func getXORMEngine() *xorm.Engine { - return db.DefaultContext.(*db.Context).Engine().(*xorm.Engine) + return db.GetEngine(db.DefaultContext).(*xorm.Engine) } // CheckDatabaseConnection checks the database connection diff --git a/models/db/iterate.go b/models/db/iterate.go index e1caefa72b..481be1b4b7 100644 --- a/models/db/iterate.go +++ b/models/db/iterate.go @@ -11,7 +11,7 @@ import ( "xorm.io/builder" ) -// Iterate iterate all the Bean object +// Iterate iterates all the Bean object func Iterate[Bean any](ctx context.Context, cond builder.Cond, f func(ctx context.Context, bean *Bean) error) error { var start int batchSize := setting.Database.IterateBufferSize diff --git a/models/db/iterate_test.go b/models/db/iterate_test.go index 0f6ba2cc94..e9f2790671 100644 --- a/models/db/iterate_test.go +++ b/models/db/iterate_test.go @@ -38,8 +38,6 @@ func TestIterate(t *testing.T) { if !has { return db.ErrNotExist{Resource: "repo_unit", ID: repoUnit.ID} } - assert.EqualValues(t, repoUnit.RepoID, repoUnit.RepoID) - assert.EqualValues(t, repoUnit.CreatedUnix, repoUnit.CreatedUnix) return nil }) assert.NoError(t, err) diff --git a/models/db/log.go b/models/db/log.go index 307788ea2e..a9df6f541d 100644 --- a/models/db/log.go +++ b/models/db/log.go @@ -29,7 +29,7 @@ const stackLevel = 8 // Log a message with defined skip and at logging level func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...any) { - l.logger.Log(skip+1, level, format, v...) + l.logger.Log(skip+1, &log.Event{Level: level}, format, v...) } // Debug show debug log diff --git a/models/db/name.go b/models/db/name.go index 51be33a8bc..0e11c78372 100644 --- a/models/db/name.go +++ b/models/db/name.go @@ -5,21 +5,12 @@ 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 @@ -82,20 +73,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 prefix or suffix match with placeholder '*'. -func IsUsableName(names, patterns []string, name string) error { +// Names are exact match, patterns can be a prefix or suffix match with placeholder '*'. +func IsUsableName(reservedNames, reservedPatterns []string, name string) error { name = strings.TrimSpace(strings.ToLower(name)) if utf8.RuneCountInString(name) == 0 { - return ErrNameEmpty + return util.NewInvalidArgumentErrorf("name is empty") } - for i := range names { - if name == names[i] { + for i := range reservedNames { + if name == reservedNames[i] { return ErrNameReserved{name} } } - for _, pat := range patterns { + for _, pat := range reservedPatterns { 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/search.go b/models/db/search.go index 37565f45e1..e0a1b6bde9 100644 --- a/models/db/search.go +++ b/models/db/search.go @@ -26,8 +26,10 @@ const ( SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" ) -const ( - // Which means a condition to filter the records which don't match any id. - // It's different from zero which means the condition could be ignored. - NoConditionID = -1 -) +// NoConditionID means a condition to filter the records which don't match any id. +// eg: "milestone_id=-1" means "find the items without any milestone. +const NoConditionID int64 = -1 + +// NonExistingID means a condition to match no result (eg: a non-existing user) +// It doesn't use -1 or -2 because they are used as builtin users. +const NonExistingID int64 = -1000000 diff --git a/models/db/sequence.go b/models/db/sequence.go index f49ad935de..9adc5113ac 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 := x.NewSession() + sess := xormEngine.NewSession() defer sess.Close() var sequences []string - schema := x.Dialect().URI().Schema + schema := xormEngine.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 := x.NewSession() + sess := xormEngine.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err diff --git a/models/error.go b/models/error.go deleted file mode 100644 index 75c53245de..0000000000 --- a/models/error.go +++ /dev/null @@ -1,552 +0,0 @@ -// 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/fixture_generation.go b/models/fixture_generation.go deleted file mode 100644 index 6234caefad..0000000000 --- a/models/fixture_generation.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package models - -import ( - "context" - "fmt" - "strings" - - "code.gitea.io/gitea/models/db" - access_model "code.gitea.io/gitea/models/perm/access" - repo_model "code.gitea.io/gitea/models/repo" -) - -// GetYamlFixturesAccess returns a string containing the contents -// for the access table, as recalculated using repo.RecalculateAccesses() -func GetYamlFixturesAccess(ctx context.Context) (string, error) { - repos := make([]*repo_model.Repository, 0, 50) - if err := db.GetEngine(ctx).Find(&repos); err != nil { - return "", err - } - - for _, repo := range repos { - repo.MustOwner(ctx) - if err := access_model.RecalculateAccesses(ctx, repo); err != nil { - return "", err - } - } - - var b strings.Builder - - accesses := make([]*access_model.Access, 0, 200) - if err := db.GetEngine(ctx).OrderBy("user_id, repo_id").Find(&accesses); err != nil { - return "", err - } - - for i, a := range accesses { - fmt.Fprintf(&b, "-\n") - fmt.Fprintf(&b, " id: %d\n", i+1) - fmt.Fprintf(&b, " user_id: %d\n", a.UserID) - fmt.Fprintf(&b, " repo_id: %d\n", a.RepoID) - fmt.Fprintf(&b, " mode: %d\n", a.Mode) - if i < len(accesses)-1 { - fmt.Fprintf(&b, "\n") - } - } - - return b.String(), nil -} diff --git a/models/fixture_test.go b/models/fixture_test.go deleted file mode 100644 index de5f412388..0000000000 --- a/models/fixture_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package models - -import ( - "context" - "os" - "path/filepath" - "testing" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/util" - - "github.com/stretchr/testify/assert" -) - -func TestFixtureGeneration(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - test := func(ctx context.Context, gen func(ctx context.Context) (string, error), name string) { - expected, err := gen(ctx) - if !assert.NoError(t, err) { - return - } - p := filepath.Join(unittest.FixturesDir(), name+".yml") - bytes, err := os.ReadFile(p) - if !assert.NoError(t, err) { - return - } - data := string(util.NormalizeEOL(bytes)) - assert.EqualValues(t, expected, data, "Differences detected for %s", p) - } - - test(db.DefaultContext, GetYamlFixturesAccess, "access") -} diff --git a/models/fixtures/access.yml b/models/fixtures/access.yml index 4171e31fef..596046e950 100644 --- a/models/fixtures/access.yml +++ b/models/fixtures/access.yml @@ -171,3 +171,9 @@ 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 new file mode 100644 index 0000000000..485474108f --- /dev/null +++ b/models/fixtures/action_artifact.yml @@ -0,0 +1,89 @@ +- + id: 1 + run_id: 791 + runner_id: 1 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "26/1/1712166500347189545.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "" + artifact_path: "abc.txt" + artifact_name: "artifact-download" + status: 1 + created_unix: 1712338649 + updated_unix: 1712338649 + expired_unix: 1720114649 + +- + id: 19 + run_id: 791 + runner_id: 1 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "26/19/1712348022422036662.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "" + artifact_path: "abc.txt" + artifact_name: "multi-file-download" + status: 2 + created_unix: 1712348022 + updated_unix: 1712348022 + expired_unix: 1720124022 + +- + id: 20 + run_id: 791 + runner_id: 1 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "26/20/1712348022423431524.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "" + artifact_path: "xyz/def.txt" + artifact_name: "multi-file-download" + status: 2 + created_unix: 1712348022 + updated_unix: 1712348022 + expired_unix: 1720124022 + +- + id: 22 + run_id: 792 + runner_id: 1 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "27/5/1730330775594233150.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "application/zip" + artifact_path: "artifact-v4-download.zip" + artifact_name: "artifact-v4-download" + status: 2 + created_unix: 1730330775 + updated_unix: 1730330775 + expired_unix: 1738106775 + +- + 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/action_run.yml b/models/fixtures/action_run.yml index a42ab77ca5..1db849352f 100644 --- a/models/fixtures/action_run.yml +++ b/models/fixtures/action_run.yml @@ -36,3 +36,41 @@ updated: 1683636626 need_approval: 0 approved_by: 0 +- + id: 793 + title: "job output" + repo_id: 4 + owner_id: 1 + workflow_id: "test.yaml" + index: 189 + trigger_user_id: 1 + ref: "refs/heads/master" + commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" + event: "push" + is_fork_pull_request: 0 + status: 1 + started: 1683636528 + stopped: 1683636626 + created: 1683636108 + updated: 1683636626 + need_approval: 0 + approved_by: 0 +- + id: 794 + title: "job output" + repo_id: 4 + owner_id: 1 + workflow_id: "test.yaml" + index: 190 + trigger_user_id: 1 + ref: "refs/heads/test" + commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" + event: "push" + is_fork_pull_request: 0 + status: 1 + started: 1683636528 + stopped: 1683636626 + created: 1683636108 + updated: 1683636626 + need_approval: 0 + approved_by: 0 diff --git a/models/fixtures/action_run_job.yml b/models/fixtures/action_run_job.yml index fd90f4fd5d..8837e6ec2d 100644 --- a/models/fixtures/action_run_job.yml +++ b/models/fixtures/action_run_job.yml @@ -26,3 +26,46 @@ status: 1 started: 1683636528 stopped: 1683636626 +- + id: 194 + run_id: 793 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job1 (1) + attempt: 1 + job_id: job1 + task_id: 49 + status: 1 + started: 1683636528 + stopped: 1683636626 +- + id: 195 + run_id: 793 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job1 (2) + attempt: 1 + job_id: job1 + task_id: 50 + status: 1 + started: 1683636528 + stopped: 1683636626 +- + id: 196 + run_id: 793 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job2 + attempt: 1 + job_id: job2 + needs: '["job1"]' + task_id: 51 + status: 5 + started: 1683636528 + stopped: 1683636626 diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml index 443effe08c..506a47d8a0 100644 --- a/models/fixtures/action_task.yml +++ b/models/fixtures/action_task.yml @@ -1,3 +1,22 @@ +- + id: 46 + attempt: 3 + runner_id: 1 + status: 3 # 3 is the status code for "cancelled" + started: 1683636528 + stopped: 1683636626 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: 6d8ef48297195edcc8e22c70b3020eaa06c52976db67d39b4260c64a69a2cc1508825121b7b8394e48e00b1bf8718b2aaaaa + token_salt: eeeeeeee + token_last_eight: eeeeeeee + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 - id: 47 job_id: 192 @@ -38,3 +57,63 @@ log_length: 707 log_size: 90179 log_expired: 0 +- + id: 49 + job_id: 194 + attempt: 1 + runner_id: 1 + status: 1 # success + started: 1683636528 + stopped: 1683636626 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784220 + token_salt: ffffffffff + token_last_eight: ffffffff + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 +- + id: 50 + job_id: 195 + attempt: 1 + runner_id: 1 + status: 1 # success + started: 1683636528 + stopped: 1683636626 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784221 + token_salt: ffffffffff + token_last_eight: ffffffff + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 +- + id: 51 + job_id: 196 + attempt: 1 + runner_id: 1 + status: 6 # running + started: 1683636528 + stopped: 1683636626 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784222 + token_salt: ffffffffff + token_last_eight: ffffffff + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 diff --git a/models/fixtures/action_task_output.yml b/models/fixtures/action_task_output.yml new file mode 100644 index 0000000000..314e9f7115 --- /dev/null +++ b/models/fixtures/action_task_output.yml @@ -0,0 +1,20 @@ +- + id: 1 + task_id: 49 + output_key: output_a + output_value: abc +- + id: 2 + task_id: 49 + output_key: output_b + output_value: '' +- + id: 3 + task_id: 50 + output_key: output_a + output_value: '' +- + id: 4 + task_id: 50 + output_key: output_b + output_value: bbb diff --git a/models/fixtures/branch.yml b/models/fixtures/branch.yml index c7bdff7733..17b1869ab6 100644 --- a/models/fixtures/branch.yml +++ b/models/fixtures/branch.yml @@ -81,3 +81,15 @@ is_deleted: false deleted_by_id: 0 deleted_unix: 0 + +- + id: 15 + repo_id: 4 + name: 'master' + commit_id: 'c7cd3cd144e6d23c9d6f3d07e52b2c1a956e0338' + commit_message: 'add Readme' + commit_time: 1588147171 + pusher_id: 13 + is_deleted: false + deleted_by_id: 0 + deleted_unix: 0 diff --git a/models/fixtures/issue_pin.yml b/models/fixtures/issue_pin.yml new file mode 100644 index 0000000000..14b7a72d84 --- /dev/null +++ b/models/fixtures/issue_pin.yml @@ -0,0 +1,6 @@ +- + id: 1 + repo_id: 2 + issue_id: 4 + is_pull: false + pin_order: 1 diff --git a/models/fixtures/label.yml b/models/fixtures/label.yml index 2242b90dcd..acfac74968 100644 --- a/models/fixtures/label.yml +++ b/models/fixtures/label.yml @@ -96,3 +96,14 @@ num_issues: 0 num_closed_issues: 0 archived_unix: 0 + +- + id: 10 + repo_id: 3 + org_id: 0 + name: repo3label1 + color: '#112233' + exclusive: false + num_issues: 0 + num_closed_issues: 0 + archived_unix: 0 diff --git a/models/fixtures/lfs_meta_object.yml b/models/fixtures/lfs_meta_object.yml index 1c29e02d44..ae5ae56542 100644 --- a/models/fixtures/lfs_meta_object.yml +++ b/models/fixtures/lfs_meta_object.yml @@ -11,7 +11,7 @@ id: 2 oid: 2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c - size: 107 + size: 2048 repository_id: 54 created_unix: 1671607299 diff --git a/models/fixtures/org_user.yml b/models/fixtures/org_user.yml index cf21b84aa9..73a3e9dba9 100644 --- a/models/fixtures/org_user.yml +++ b/models/fixtures/org_user.yml @@ -129,3 +129,9 @@ uid: 2 org_id: 35 is_public: true + +- + id: 23 + uid: 20 + org_id: 17 + is_public: false diff --git a/models/fixtures/protected_tag.yml b/models/fixtures/protected_tag.yml index dbec52c0c2..1944e7bd84 100644 --- a/models/fixtures/protected_tag.yml +++ b/models/fixtures/protected_tag.yml @@ -2,23 +2,23 @@ id: 1 repo_id: 4 name_pattern: /v.+/ - allowlist_user_i_ds: [] - allowlist_team_i_ds: [] + allowlist_user_i_ds: "[]" + allowlist_team_i_ds: "[]" created_unix: 1715596037 updated_unix: 1715596037 - id: 2 repo_id: 1 name_pattern: v-* - allowlist_user_i_ds: [] - allowlist_team_i_ds: [] + allowlist_user_i_ds: "[]" + allowlist_team_i_ds: "[]" created_unix: 1715596037 updated_unix: 1715596037 - id: 3 repo_id: 1 name_pattern: v-1.1 - allowlist_user_i_ds: [2] - allowlist_team_i_ds: [] + allowlist_user_i_ds: "[2]" + allowlist_team_i_ds: "[]" created_unix: 1715596037 updated_unix: 1715596037 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index b7970cb7c8..552a78cbd2 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -26,7 +26,7 @@ fork_id: 0 is_template: false template_id: 0 - size: 8478 + size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false @@ -1694,19 +1694,6 @@ 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/review.yml b/models/fixtures/review.yml index 0438ceadae..5b8bbceca9 100644 --- a/models/fixtures/review.yml +++ b/models/fixtures/review.yml @@ -4,6 +4,7 @@ reviewer_id: 1 issue_id: 2 content: "Demo Review" + original_author_id: 0 updated_unix: 946684810 created_unix: 946684810 - @@ -12,6 +13,7 @@ reviewer_id: 534543 issue_id: 534543 content: "Invalid Review #1" + original_author_id: 0 updated_unix: 946684810 created_unix: 946684810 - @@ -20,6 +22,7 @@ reviewer_id: 1 issue_id: 343545 content: "Invalid Review #2" + original_author_id: 0 updated_unix: 946684810 created_unix: 946684810 - @@ -28,6 +31,7 @@ reviewer_id: 1 issue_id: 2 content: "Pending Review" + original_author_id: 0 updated_unix: 946684810 created_unix: 946684810 - @@ -36,6 +40,7 @@ reviewer_id: 1 issue_id: 3 content: "New review 1" + original_author_id: 0 updated_unix: 946684810 created_unix: 946684810 - @@ -61,8 +66,8 @@ type: 1 reviewer_id: 4 issue_id: 3 - original_author_id: 0 content: "New review 5" + original_author_id: 0 commit_id: 8091a55037cd59e47293aca02981b5a67076b364 stale: true updated_unix: 946684813 @@ -73,9 +78,9 @@ reviewer_id: 2 issue_id: 3 content: "New review 3 rejected" + original_author_id: 0 updated_unix: 946684814 created_unix: 946684814 - original_author_id: 0 - id: 10 @@ -83,6 +88,7 @@ reviewer_id: 100 issue_id: 3 content: "a deleted user's review" + original_author_id: 0 official: true updated_unix: 946684815 created_unix: 946684815 @@ -112,6 +118,7 @@ reviewer_id: 5 issue_id: 11 content: "old review from user5" + original_author_id: 0 updated_unix: 946684820 created_unix: 946684820 @@ -121,6 +128,7 @@ reviewer_id: 5 issue_id: 11 content: "duplicate review from user5 (latest)" + original_author_id: 0 updated_unix: 946684830 created_unix: 946684830 @@ -130,6 +138,7 @@ reviewer_id: 6 issue_id: 11 content: "singular review from org6 and final review for this pr" + original_author_id: 0 updated_unix: 946684831 created_unix: 946684831 @@ -139,6 +148,7 @@ reviewer_id: 20 issue_id: 20 content: "review request for user20" + original_author_id: 0 updated_unix: 946684832 created_unix: 946684832 @@ -148,6 +158,7 @@ reviewer_id: 20 issue_id: 20 content: "review approved by user20" + original_author_id: 0 updated_unix: 946684833 created_unix: 946684833 @@ -158,6 +169,7 @@ reviewer_team_id: 5 issue_id: 20 content: "review request for team5" + original_author_id: 0 updated_unix: 946684834 created_unix: 946684834 @@ -168,6 +180,7 @@ reviewer_team_id: 0 issue_id: 20 content: "review request for user15" + original_author_id: 0 updated_unix: 946684835 created_unix: 946684835 @@ -177,6 +190,7 @@ reviewer_id: 1 issue_id: 2 content: "Review Comment" + original_author_id: 0 updated_unix: 946684810 created_unix: 946684810 @@ -186,6 +200,7 @@ reviewer_id: 5 issue_id: 3 content: "reviewed by user5" + original_author_id: 0 commit_id: 4a357436d925b5c974181ff12a994538ddc5a269 updated_unix: 946684816 created_unix: 946684816 @@ -196,5 +211,6 @@ reviewer_id: 5 issue_id: 3 content: "review request for user5" + original_author_id: 0 updated_unix: 946684817 created_unix: 946684817 diff --git a/models/fixtures/system_setting.yml b/models/fixtures/system_setting.yml index 30542bc82a..dcad176c89 100644 --- a/models/fixtures/system_setting.yml +++ b/models/fixtures/system_setting.yml @@ -1,7 +1,7 @@ - id: 1 setting_key: 'picture.disable_gravatar' - setting_value: 'false' + setting_value: 'true' version: 1 created: 1653533198 updated: 1653533198 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index c0296deec5..976a236011 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -23,9 +23,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar1 + avatar: "" avatar_email: user1@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -60,13 +60,14 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar2 + avatar: "" avatar_email: user2@example.com + # cause a random avatar to be generated when referenced for test purposes use_custom_avatar: false num_followers: 2 num_following: 1 num_stars: 2 - num_repos: 15 + num_repos: 14 num_teams: 0 num_members: 0 visibility: 0 @@ -97,9 +98,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar3 + avatar: "" avatar_email: org3@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -134,9 +135,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar4 + avatar: "" avatar_email: user4@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 1 num_stars: 0 @@ -171,9 +172,9 @@ allow_import_local: false allow_create_organization: false prohibit_login: false - avatar: avatar5 + avatar: "" avatar_email: user5@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -208,9 +209,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar6 + avatar: "" avatar_email: org6@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -245,9 +246,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar7 + avatar: "" avatar_email: org7@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -282,9 +283,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar8 + avatar: "" avatar_email: user8@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 1 num_following: 1 num_stars: 0 @@ -319,9 +320,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar9 + avatar: "" avatar_email: user9@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -332,6 +333,7 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false + created_unix: 1730468968 - id: 10 @@ -356,9 +358,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar10 + avatar: "" avatar_email: user10@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 2 @@ -393,9 +395,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar11 + avatar: "" avatar_email: user11@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -430,9 +432,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar12 + avatar: "" avatar_email: user12@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -467,9 +469,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar13 + avatar: "" avatar_email: user13@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -504,9 +506,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar14 + avatar: "" avatar_email: user13@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -541,9 +543,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar15 + avatar: "" avatar_email: user15@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -578,9 +580,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar16 + avatar: "" avatar_email: user16@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -615,15 +617,15 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar17 + avatar: "" avatar_email: org17@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 num_repos: 2 num_teams: 3 - num_members: 4 + num_members: 5 visibility: 0 repo_admin_change_team_access: false theme: "" @@ -652,9 +654,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar18 + avatar: "" avatar_email: user18@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -689,9 +691,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar19 + avatar: "" avatar_email: org19@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -726,9 +728,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar20 + avatar: "" avatar_email: user20@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -763,9 +765,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar21 + avatar: "" avatar_email: user21@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -800,9 +802,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar22 + avatar: "" avatar_email: limited_org@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -837,9 +839,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar23 + avatar: "" avatar_email: privated_org@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -874,9 +876,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar24 + avatar: "" avatar_email: user24@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -911,9 +913,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar25 + avatar: "" avatar_email: org25@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -948,9 +950,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar26 + avatar: "" avatar_email: org26@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -985,9 +987,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar27 + avatar: "" avatar_email: user27@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1022,9 +1024,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar28 + avatar: "" avatar_email: user28@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1059,9 +1061,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar29 + avatar: "" avatar_email: user29@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1096,9 +1098,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar29 + avatar: "" avatar_email: user30@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1133,9 +1135,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar31 + avatar: "" avatar_email: user31@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 1 num_stars: 0 @@ -1170,9 +1172,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar32 + avatar: "" avatar_email: user30@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1207,9 +1209,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar33 + avatar: "" avatar_email: user33@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 1 num_following: 0 num_stars: 0 @@ -1245,7 +1247,7 @@ allow_import_local: false allow_create_organization: false prohibit_login: false - avatar: avatar34 + avatar: "" avatar_email: user34@example.com use_custom_avatar: true num_followers: 0 @@ -1282,9 +1284,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar35 + avatar: "" avatar_email: private_org35@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1319,9 +1321,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar22 + avatar: "" avatar_email: abcde@gitea.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1356,9 +1358,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: true - avatar: avatar29 + avatar: "" avatar_email: user37@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1393,9 +1395,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar38 + avatar: "" avatar_email: user38@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1430,9 +1432,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar39 + avatar: "" avatar_email: user39@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1467,9 +1469,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar40 + avatar: "" avatar_email: user40@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1504,9 +1506,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar41 + avatar: "" avatar_email: org41@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 @@ -1541,9 +1543,9 @@ allow_import_local: false allow_create_organization: true prohibit_login: false - avatar: avatar42 + avatar: "" avatar_email: org42@example.com - use_custom_avatar: false + use_custom_avatar: true num_followers: 0 num_following: 0 num_stars: 0 diff --git a/models/fixtures/webhook.yml b/models/fixtures/webhook.yml index f62bae1f31..ebc4062b60 100644 --- a/models/fixtures/webhook.yml +++ b/models/fixtures/webhook.yml @@ -22,6 +22,7 @@ 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 @@ -29,3 +30,23 @@ 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/branch.go b/models/git/branch.go index ba1ada5517..d1caa35947 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -12,6 +12,7 @@ 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/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" @@ -166,12 +167,28 @@ func GetBranch(ctx context.Context, repoID int64, branchName string) (*Branch, e BranchName: branchName, } } + // FIXME: this design is not right: it doesn't check `branch.IsDeleted`, it doesn't make sense to make callers to check IsDeleted again and again. + // It causes inconsistency with `GetBranches` and `git.GetBranch`, and will lead to strange bugs + // In the future, there should be 2 functions: `GetBranchExisting` and `GetBranchWithDeleted` return &branch, nil } -func GetBranches(ctx context.Context, repoID int64, branchNames []string) ([]*Branch, error) { +func GetBranches(ctx context.Context, repoID int64, branchNames []string, includeDeleted bool) ([]*Branch, error) { branches := make([]*Branch, 0, len(branchNames)) - return branches, db.GetEngine(ctx).Where("repo_id=?", repoID).In("name", branchNames).Find(&branches) + + sess := db.GetEngine(ctx).Where("repo_id=?", repoID).In("name", branchNames) + if !includeDeleted { + sess.And("is_deleted=?", false) + } + return branches, sess.Find(&branches) +} + +func BranchesToNamesSet(branches []*Branch) container.Set[string] { + names := make(container.Set[string], len(branches)) + for _, branch := range branches { + names.Add(branch.Name) + } + return names } func AddBranches(ctx context.Context, branches []*Branch) error { @@ -426,6 +443,8 @@ type FindRecentlyPushedNewBranchesOptions struct { } type RecentlyPushedNewBranch struct { + BranchRepo *repo_model.Repository + BranchName string BranchDisplayName string BranchLink string BranchCompareURL string @@ -526,7 +545,9 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o branchDisplayName = fmt.Sprintf("%s:%s", branch.Repo.FullName(), branchDisplayName) } newBranches = append(newBranches, &RecentlyPushedNewBranch{ + BranchRepo: branch.Repo, BranchDisplayName: branchDisplayName, + BranchName: branch.Name, BranchLink: fmt.Sprintf("%s/src/branch/%s", branch.Repo.Link(), util.PathEscapeSegments(branch.Name)), BranchCompareURL: branch.Repo.ComposeBranchCompareURL(opts.BaseRepo, branch.Name), CommitTime: branch.CommitTime, diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 0579a41209..5432eea55e 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -496,47 +496,11 @@ 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/git/commit_status_test.go b/models/git/commit_status_test.go index 7ac4da6810..37d785e938 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -34,7 +34,7 @@ func TestGetCommitStatuses(t *testing.T) { SHA: sha1, }) assert.NoError(t, err) - assert.Equal(t, int(maxResults), 5) + assert.Equal(t, 5, int(maxResults)) assert.Len(t, statuses, 5) assert.Equal(t, "ci/awesomeness", statuses[0].Context) @@ -63,7 +63,7 @@ func TestGetCommitStatuses(t *testing.T) { SHA: sha1, }) assert.NoError(t, err) - assert.Equal(t, int(maxResults), 5) + assert.Equal(t, 5, int(maxResults)) assert.Empty(t, statuses) } diff --git a/models/git/lfs.go b/models/git/lfs.go index 837dc9fd31..bb6361050a 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -136,8 +136,6 @@ var ErrLFSObjectNotExist = db.ErrNotExist{Resource: "LFS Meta object"} // NewLFSMetaObject stores a given populated LFSMetaObject structure in the database // if it is not already present. func NewLFSMetaObject(ctx context.Context, repoID int64, p lfs.Pointer) (*LFSMetaObject, error) { - var err error - ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err diff --git a/models/git/protected_branch.go b/models/git/protected_branch.go index 0033a42d4e..a3caed73c4 100644 --- a/models/git/protected_branch.go +++ b/models/git/protected_branch.go @@ -34,6 +34,7 @@ type ProtectedBranch struct { RepoID int64 `xorm:"UNIQUE(s)"` Repo *repo_model.Repository `xorm:"-"` RuleName string `xorm:"'branch_name' UNIQUE(s)"` // a branch name or a glob match to branch name + Priority int64 `xorm:"NOT NULL DEFAULT 0"` globRule glob.Glob `xorm:"-"` isPlainName bool `xorm:"-"` CanPush bool `xorm:"NOT NULL DEFAULT false"` @@ -84,14 +85,20 @@ func IsRuleNameSpecial(ruleName string) bool { } func (protectBranch *ProtectedBranch) loadGlob() { - if protectBranch.globRule == nil { - var err error - protectBranch.globRule, err = glob.Compile(protectBranch.RuleName, '/') - if err != nil { - log.Warn("Invalid glob rule for ProtectedBranch[%d]: %s %v", protectBranch.ID, protectBranch.RuleName, err) - protectBranch.globRule = glob.MustCompile(glob.QuoteMeta(protectBranch.RuleName), '/') - } - protectBranch.isPlainName = !IsRuleNameSpecial(protectBranch.RuleName) + if protectBranch.isPlainName || protectBranch.globRule != nil { + return + } + // detect if it is not glob + if !IsRuleNameSpecial(protectBranch.RuleName) { + protectBranch.isPlainName = true + return + } + // now we load the glob + var err error + protectBranch.globRule, err = glob.Compile(protectBranch.RuleName, '/') + if err != nil { + log.Warn("Invalid glob rule for ProtectedBranch[%d]: %s %v", protectBranch.ID, protectBranch.RuleName, err) + protectBranch.globRule = glob.MustCompile(glob.QuoteMeta(protectBranch.RuleName), '/') } } @@ -407,14 +414,27 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote } protectBranch.ApprovalsWhitelistTeamIDs = whitelist - // Make sure protectBranch.ID is not 0 for whitelists + // Looks like it's a new rule if protectBranch.ID == 0 { + // as it's a new rule and if priority was not set, we need to calc it. + if protectBranch.Priority == 0 { + var lowestPrio int64 + // because of mssql we can not use builder or save xorm syntax, so raw sql it is + if _, err := db.GetEngine(ctx).SQL(`SELECT MAX(priority) FROM protected_branch WHERE repo_id = ?`, protectBranch.RepoID). + Get(&lowestPrio); err != nil { + return err + } + log.Trace("Create new ProtectedBranch at repo[%d] and detect current lowest priority '%d'", protectBranch.RepoID, lowestPrio) + protectBranch.Priority = lowestPrio + 1 + } + if _, err = db.GetEngine(ctx).Insert(protectBranch); err != nil { return fmt.Errorf("Insert: %v", err) } return nil } + // update the rule if _, err = db.GetEngine(ctx).ID(protectBranch.ID).AllCols().Update(protectBranch); err != nil { return fmt.Errorf("Update: %v", err) } @@ -422,6 +442,24 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote return nil } +func UpdateProtectBranchPriorities(ctx context.Context, repo *repo_model.Repository, ids []int64) error { + prio := int64(1) + return db.WithTx(ctx, func(ctx context.Context) error { + for _, id := range ids { + if _, err := db.GetEngine(ctx). + ID(id).Where("repo_id = ?", repo.ID). + Cols("priority"). + Update(&ProtectedBranch{ + Priority: prio, + }); err != nil { + return err + } + prio++ + } + return nil + }) +} + // updateApprovalWhitelist checks whether the user whitelist changed and returns a whitelist with // the users from newWhitelist which have explicit read or write access to the repo. func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { diff --git a/models/git/protected_branch_list.go b/models/git/protected_branch_list.go index 613333a5a2..16f8500672 100644 --- a/models/git/protected_branch_list.go +++ b/models/git/protected_branch_list.go @@ -28,6 +28,13 @@ func (rules ProtectedBranchRules) sort() { sort.Slice(rules, func(i, j int) bool { rules[i].loadGlob() rules[j].loadGlob() + + // if priority differ, use that to sort + if rules[i].Priority != rules[j].Priority { + return rules[i].Priority < rules[j].Priority + } + + // now we sort the old way if rules[i].isPlainName != rules[j].isPlainName { return rules[i].isPlainName // plain name comes first, so plain name means "less" } diff --git a/models/git/protected_banch_list_test.go b/models/git/protected_branch_list_test.go similarity index 63% rename from models/git/protected_banch_list_test.go rename to models/git/protected_branch_list_test.go index 4bb3136d58..a46402c543 100644 --- a/models/git/protected_banch_list_test.go +++ b/models/git/protected_branch_list_test.go @@ -74,3 +74,66 @@ func TestBranchRuleMatchPriority(t *testing.T) { } } } + +func TestBranchRuleSortLegacy(t *testing.T) { + in := []*ProtectedBranch{{ + RuleName: "b", + CreatedUnix: 1, + }, { + RuleName: "b/*", + CreatedUnix: 3, + }, { + RuleName: "a/*", + CreatedUnix: 2, + }, { + RuleName: "c", + CreatedUnix: 0, + }, { + RuleName: "a", + CreatedUnix: 4, + }} + expect := []string{"c", "b", "a", "a/*", "b/*"} + + pbr := ProtectedBranchRules(in) + pbr.sort() + + var got []string + for i := range pbr { + got = append(got, pbr[i].RuleName) + } + assert.Equal(t, expect, got) +} + +func TestBranchRuleSortPriority(t *testing.T) { + in := []*ProtectedBranch{{ + RuleName: "b", + CreatedUnix: 1, + Priority: 4, + }, { + RuleName: "b/*", + CreatedUnix: 3, + Priority: 2, + }, { + RuleName: "a/*", + CreatedUnix: 2, + Priority: 1, + }, { + RuleName: "c", + CreatedUnix: 0, + Priority: 0, + }, { + RuleName: "a", + CreatedUnix: 4, + Priority: 3, + }} + expect := []string{"c", "a/*", "b/*", "a", "b"} + + pbr := ProtectedBranchRules(in) + pbr.sort() + + var got []string + for i := range pbr { + got = append(got, pbr[i].RuleName) + } + assert.Equal(t, expect, got) +} diff --git a/models/git/protected_branch_test.go b/models/git/protected_branch_test.go index 1962859a8c..e1c91d927d 100644 --- a/models/git/protected_branch_test.go +++ b/models/git/protected_branch_test.go @@ -4,9 +4,12 @@ package git import ( - "fmt" "testing" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + "github.com/stretchr/testify/assert" ) @@ -72,7 +75,81 @@ func TestBranchRuleMatch(t *testing.T) { infact = " not" } assert.EqualValues(t, kase.ExpectedMatch, pb.Match(kase.BranchName), - fmt.Sprintf("%s should%s match %s but it is%s", kase.BranchName, should, kase.Rule, infact), + "%s should%s match %s but it is%s", kase.BranchName, should, kase.Rule, infact, ) } } + +func TestUpdateProtectBranchPriorities(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + + // Create some test protected branches with initial priorities + protectedBranches := []*ProtectedBranch{ + { + RepoID: repo.ID, + RuleName: "master", + Priority: 1, + }, + { + RepoID: repo.ID, + RuleName: "develop", + Priority: 2, + }, + { + RepoID: repo.ID, + RuleName: "feature/*", + Priority: 3, + }, + } + + for _, pb := range protectedBranches { + _, err := db.GetEngine(db.DefaultContext).Insert(pb) + assert.NoError(t, err) + } + + // Test updating priorities + newPriorities := []int64{protectedBranches[2].ID, protectedBranches[0].ID, protectedBranches[1].ID} + err := UpdateProtectBranchPriorities(db.DefaultContext, repo, newPriorities) + assert.NoError(t, err) + + // Verify new priorities + pbs, err := FindRepoProtectedBranchRules(db.DefaultContext, repo.ID) + assert.NoError(t, err) + + expectedPriorities := map[string]int64{ + "feature/*": 1, + "master": 2, + "develop": 3, + } + + for _, pb := range pbs { + assert.Equal(t, expectedPriorities[pb.RuleName], pb.Priority) + } +} + +func TestNewProtectBranchPriority(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + + err := UpdateProtectBranch(db.DefaultContext, repo, &ProtectedBranch{ + RepoID: repo.ID, + RuleName: "branch-1", + Priority: 1, + }, WhitelistOptions{}) + assert.NoError(t, err) + + newPB := &ProtectedBranch{ + RepoID: repo.ID, + RuleName: "branch-2", + // Priority intentionally omitted + } + + err = UpdateProtectBranch(db.DefaultContext, repo, newPB, WhitelistOptions{}) + assert.NoError(t, err) + + savedPB2, err := GetFirstMatchProtectedBranchRule(db.DefaultContext, repo.ID, "branch-2") + assert.NoError(t, err) + assert.Equal(t, int64(2), savedPB2.Priority) +} diff --git a/models/issues/comment.go b/models/issues/comment.go index 48b8e335d4..ab9b2042f3 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -19,8 +19,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/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" @@ -112,8 +110,10 @@ 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 - CommentTypeUnpin // 37 unpin Issue + CommentTypePin // 36 pin Issue/PullRequest + CommentTypeUnpin // 37 unpin Issue/PullRequest + + CommentTypeChangeTimeEstimate // 38 Change time estimate ) var commentStrings = []string{ @@ -155,6 +155,7 @@ var commentStrings = []string{ "pull_cancel_scheduled_merge", "pin", "unpin", + "change_time_estimate", } func (t CommentType) String() string { @@ -194,6 +195,20 @@ func (t CommentType) HasMailReplySupport() bool { return false } +func (t CommentType) CountedAsConversation() bool { + for _, ct := range ConversationCountedCommentType() { + if t == ct { + return true + } + } + return false +} + +// ConversationCountedCommentType returns the comment types that are counted as a conversation +func ConversationCountedCommentType() []CommentType { + return []CommentType{CommentTypeComment, CommentTypeReview} +} + // RoleInRepo presents the user's participation in the repo type RoleInRepo string @@ -589,26 +604,26 @@ func (c *Comment) LoadAttachments(ctx context.Context) error { 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 +// UpdateCommentAttachments update attachments by UUIDs for the comment +func UpdateCommentAttachments(ctx context.Context, c *Comment, uuids []string) error { + if len(uuids) == 0 { + return nil } - 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) + 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) } - } - return committer.Commit() + 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 + }) } // LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees @@ -757,41 +772,6 @@ 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) @@ -875,7 +855,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment // Check comment type. switch opts.Type { case CommentTypeCode: - if err = updateAttachments(ctx, opts, comment); err != nil { + if err = UpdateCommentAttachments(ctx, comment, opts.Attachments); err != nil { return err } if comment.ReviewID != 0 { @@ -890,12 +870,12 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment } fallthrough case CommentTypeComment: - if _, err = db.Exec(ctx, "UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil { + if err := UpdateIssueNumComments(ctx, opts.Issue.ID); err != nil { return err } fallthrough case CommentTypeReview: - if err = updateAttachments(ctx, opts, comment); err != nil { + if err = UpdateCommentAttachments(ctx, comment, opts.Attachments); err != nil { return err } case CommentTypeReopen, CommentTypeClose: @@ -907,23 +887,6 @@ 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 @@ -1108,7 +1071,7 @@ func FindComments(ctx context.Context, opts *FindCommentsOptions) (CommentList, sess.Join("INNER", "issue", "issue.id = comment.issue_id") } - if opts.Page != 0 { + if opts.Page > 0 { sess = db.SetSessionPagination(sess, opts) } @@ -1179,8 +1142,8 @@ func DeleteComment(ctx context.Context, comment *Comment) error { return err } - if comment.Type == CommentTypeComment { - if _, err := e.ID(comment.IssueID).Decr("num_comments").Update(new(Issue)); err != nil { + if comment.Type.CountedAsConversation() { + if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil { return err } } @@ -1297,6 +1260,21 @@ func (c *Comment) HasOriginalAuthor() bool { return c.OriginalAuthor != "" && c.OriginalAuthorID != 0 } +func UpdateIssueNumCommentsBuilder(issueID int64) *builder.Builder { + subQuery := builder.Select("COUNT(*)").From("`comment`").Where( + builder.Eq{"issue_id": issueID}.And( + builder.In("`type`", ConversationCountedCommentType()), + )) + + return builder.Update(builder.Eq{"num_comments": subQuery}). + From("`issue`").Where(builder.Eq{"id": issueID}) +} + +func UpdateIssueNumComments(ctx context.Context, issueID int64) error { + _, err := db.GetEngine(ctx).Exec(UpdateIssueNumCommentsBuilder(issueID)) + return err +} + // InsertIssueComments inserts many comments of issues. func InsertIssueComments(ctx context.Context, comments []*Comment) error { if len(comments) == 0 { @@ -1329,8 +1307,7 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error { } for _, issueID := range issueIDs { - if _, err := db.Exec(ctx, "UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ? AND `type`=?) WHERE id = ?", - issueID, CommentTypeComment, issueID); err != nil { + if err := UpdateIssueNumComments(ctx, issueID); err != nil { return err } } diff --git a/models/issues/comment_code.go b/models/issues/comment_code.go index 6f23d3326a..b562aab500 100644 --- a/models/issues/comment_code.go +++ b/models/issues/comment_code.go @@ -7,8 +7,8 @@ import ( "context" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/renderhelper" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "xorm.io/builder" @@ -86,8 +86,10 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu ids = append(ids, comment.ReviewID) } } - if err := e.In("id", ids).Find(&reviews); err != nil { - return nil, err + if len(ids) > 0 { + if err := e.In("id", ids).Find(&reviews); err != nil { + return nil, err + } } n := 0 @@ -112,14 +114,8 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu } var err error - if comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{ - Ctx: ctx, - Repo: issue.Repo, - Links: markup.Links{ - Base: issue.Repo.Link(), - }, - Metas: issue.Repo.ComposeMetas(ctx), - }, comment.Content); err != nil { + rctx := renderhelper.NewRenderContextRepoComment(ctx, issue.Repo) + if comment.RenderedContent, err = markdown.RenderString(rctx, comment.Content); err != nil { return nil, err } } diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go index 61ac1c8f56..c483ada75a 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 := getPostersByIDs(ctx, posterIDs) + posterMaps, err := user_model.GetUsersMapByIDs(ctx, posterIDs) if err != nil { return err } for _, comment := range comments { if comment.Poster == nil { - comment.Poster = getPoster(comment.PosterID, posterMaps) + comment.Poster = user_model.GetPossibleUserFromMap(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 + return comment.LabelID, comment.LabelID > 0 && comment.Label == nil }) } @@ -51,6 +51,9 @@ 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 { @@ -118,8 +121,8 @@ func (comments CommentList) loadMilestones(ctx context.Context) error { milestoneIDs = milestoneIDs[limit:] } - for _, issue := range comments { - issue.Milestone = milestoneMaps[issue.MilestoneID] + for _, comment := range comments { + comment.Milestone = milestoneMaps[comment.MilestoneID] } return nil } @@ -175,6 +178,9 @@ 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 { @@ -301,6 +307,9 @@ 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 { @@ -427,6 +436,9 @@ 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 c5bbfdedc2..ae0bc3ce17 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -45,6 +45,24 @@ 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()) @@ -64,7 +82,7 @@ func TestFetchCodeComments(t *testing.T) { } func TestAsCommentType(t *testing.T) { - assert.Equal(t, issues_model.CommentType(0), issues_model.CommentTypeComment) + assert.Equal(t, issues_model.CommentTypeComment, issues_model.CommentType(0)) assert.Equal(t, issues_model.CommentTypeUndefined, issues_model.AsCommentType("")) assert.Equal(t, issues_model.CommentTypeUndefined, issues_model.AsCommentType("nonsense")) assert.Equal(t, issues_model.CommentTypeComment, issues_model.AsCommentType("comment")) @@ -97,3 +115,12 @@ func TestMigrate_InsertIssueComments(t *testing.T) { unittest.CheckConsistencyFor(t, &issues_model.Issue{}) } + +func Test_UpdateIssueNumComments(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + + assert.NoError(t, issues_model.UpdateIssueNumComments(db.DefaultContext, issue2.ID)) + issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + assert.EqualValues(t, 1, issue2.NumComments) +} diff --git a/models/issues/dependency_test.go b/models/issues/dependency_test.go index 6eed483cc9..67418039de 100644 --- a/models/issues/dependency_test.go +++ b/models/issues/dependency_test.go @@ -49,9 +49,13 @@ func TestCreateIssueDependency(t *testing.T) { assert.False(t, left) // Close #2 and check again - _, err = issues_model.ChangeIssueStatus(db.DefaultContext, issue2, user1, true) + _, err = issues_model.CloseIssue(db.DefaultContext, issue2, user1) 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) @@ -59,4 +63,11 @@ 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 9ccf2859ea..5204f27faf 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -17,6 +17,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -46,23 +47,6 @@ 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 @@ -78,22 +62,6 @@ 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. @@ -125,8 +93,11 @@ type Issue struct { IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not. PullRequest *PullRequest `xorm:"-"` NumComments int - Ref string - PinOrder int `xorm:"DEFAULT 0"` + + // TODO: RemoveIssueRef: see "repo/issue/branch_selector_field.tmpl" + Ref string + + PinOrder int `xorm:"-"` // 0 means not loaded, -1 means loaded but not pinned DeadlineUnix timeutil.TimeStamp `xorm:"INDEX"` @@ -147,6 +118,9 @@ type Issue struct { // For view issue page. ShowRole RoleDescriptor `xorm:"-"` + + // Time estimate + TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"` } var ( @@ -265,6 +239,9 @@ 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 } @@ -314,6 +291,23 @@ 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 { @@ -353,6 +347,10 @@ 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 } @@ -365,6 +363,14 @@ 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 @@ -525,6 +531,45 @@ func GetIssueByIndex(ctx context.Context, repoID, index int64) (*Issue, error) { return issue, nil } +func isPullToCond(isPull optional.Option[bool]) builder.Cond { + if isPull.Has() { + return builder.Eq{"is_pull": isPull.Value()} + } + return builder.NewCond() +} + +func FindLatestUpdatedIssues(ctx context.Context, repoID int64, isPull optional.Option[bool], pageSize int) (IssueList, error) { + issues := make([]*Issue, 0, pageSize) + err := db.GetEngine(ctx).Where("repo_id = ?", repoID). + And(isPullToCond(isPull)). + OrderBy("updated_unix DESC"). + Limit(pageSize). + Find(&issues) + return issues, err +} + +func FindIssuesSuggestionByKeyword(ctx context.Context, repoID int64, keyword string, isPull optional.Option[bool], excludedID int64, pageSize int) (IssueList, error) { + cond := builder.NewCond() + if excludedID > 0 { + cond = cond.And(builder.Neq{"`id`": excludedID}) + } + + // It seems that GitHub searches both title and content (maybe sorting by the search engine's ranking system?) + // The first PR (https://github.com/go-gitea/gitea/pull/32327) uses "search indexer" to search "name(title) + content" + // But it seems that searching "content" (especially LIKE by DB engine) generates worse (unusable) results. + // So now (https://github.com/go-gitea/gitea/pull/33538) it only searches "name(title)", leave the improvements to the future. + cond = cond.And(db.BuildCaseInsensitiveLike("`name`", keyword)) + + issues := make([]*Issue, 0, pageSize) + err := db.GetEngine(ctx).Where("repo_id = ?", repoID). + And(isPullToCond(isPull)). + And(cond). + OrderBy("updated_unix DESC, `index` DESC"). + Limit(pageSize). + Find(&issues) + return issues, err +} + // GetIssueWithAttrsByIndex returns issue by index in a repository. func GetIssueWithAttrsByIndex(ctx context.Context, repoID, index int64) (*Issue, error) { issue, err := GetIssueByIndex(ctx, repoID, index) @@ -550,6 +595,9 @@ func GetIssueByID(ctx context.Context, id int64) (*Issue, error) { // If keepOrder is true, the order of the returned issues will be the same as the given IDs. func GetIssuesByIDs(ctx context.Context, issueIDs []int64, keepOrder ...bool) (IssueList, error) { issues := make([]*Issue, 0, len(issueIDs)) + if len(issueIDs) == 0 { + return issues, nil + } if err := db.GetEngine(ctx).In("id", issueIDs).Find(&issues); err != nil { return nil, err @@ -641,7 +689,7 @@ func (issue *Issue) BlockedByDependencies(ctx context.Context, opts db.ListOptio Where("issue_id = ?", issue.ID). // sort by repo id then created date, with the issues of the same repo at the beginning of the list OrderBy("CASE WHEN issue.repo_id = ? THEN 0 ELSE issue.repo_id END, issue.created_unix DESC", issue.RepoID) - if opts.Page != 0 { + if opts.Page > 0 { sess = db.SetSessionPagination(sess, &opts) } err = sess.Find(&issueDeps) @@ -704,190 +752,6 @@ 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) @@ -934,3 +798,28 @@ func insertIssue(ctx context.Context, issue *Issue) error { return nil } + +// ChangeIssueTimeEstimate changes the plan time of this issue, as the given user. +func ChangeIssueTimeEstimate(ctx context.Context, issue *Issue, doer *user_model.User, timeEstimate int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { + if err := UpdateIssueCols(ctx, &Issue{ID: issue.ID, TimeEstimate: timeEstimate}, "time_estimate"); err != nil { + return fmt.Errorf("updateIssueCols: %w", err) + } + + if err := issue.LoadRepo(ctx); err != nil { + return fmt.Errorf("loadRepo: %w", err) + } + + opts := &CreateCommentOptions{ + Type: CommentTypeChangeTimeEstimate, + Doer: doer, + Repo: issue.Repo, + Issue: issue, + Content: fmt.Sprintf("%d", timeEstimate), + } + if _, err := CreateComment(ctx, opts); err != nil { + return fmt.Errorf("createComment: %w", err) + } + return nil + }) +} diff --git a/models/issues/issue_index.go b/models/issues/issue_index.go index 16274d0ef0..2eb61858bf 100644 --- a/models/issues/issue_index.go +++ b/models/issues/issue_index.go @@ -18,12 +18,12 @@ func RecalculateIssueIndexForRepo(ctx context.Context, repoID int64) error { } defer committer.Close() - var max int64 - if _, err = db.GetEngine(ctx).Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&max); err != nil { + var maxIndex int64 + if _, err = db.GetEngine(ctx).Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&maxIndex); err != nil { return err } - if err = db.SyncMaxResourceIndex(ctx, "issue_index", repoID, max); err != nil { + if err = db.SyncMaxResourceIndex(ctx, "issue_index", repoID, maxIndex); err != nil { return err } diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 22a4548adc..6c74b533b3 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -81,53 +81,19 @@ func (issues IssueList) LoadPosters(ctx context.Context) error { return issue.PosterID, issue.Poster == nil && issue.PosterID > 0 }) - posterMaps, err := getPostersByIDs(ctx, posterIDs) + posterMaps, err := user_model.GetUsersMapByIDs(ctx, posterIDs) if err != nil { return err } for _, issue := range issues { if issue.Poster == nil { - issue.Poster = getPoster(issue.PosterID, posterMaps) + issue.Poster = user_model.GetPossibleUserFromMap(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 { @@ -540,6 +506,39 @@ 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 new file mode 100644 index 0000000000..ae6195b05d --- /dev/null +++ b/models/issues/issue_pin.go @@ -0,0 +1,246 @@ +// 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_project.go b/models/issues/issue_project.go index c4515fd898..0185244783 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -38,13 +38,30 @@ func (issue *Issue) projectID(ctx context.Context) int64 { } // ProjectColumnID return project column id if issue was assigned to one -func (issue *Issue) ProjectColumnID(ctx context.Context) int64 { +func (issue *Issue) ProjectColumnID(ctx context.Context) (int64, error) { var ip project_model.ProjectIssue has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip) - if err != nil || !has { - return 0 + if err != nil { + return 0, err + } else if !has { + return 0, nil } - return ip.ProjectColumnID + return ip.ProjectColumnID, nil +} + +func LoadProjectIssueColumnMap(ctx context.Context, projectID, defaultColumnID int64) (map[int64]int64, error) { + issues := make([]project_model.ProjectIssue, 0) + if err := db.GetEngine(ctx).Where("project_id=?", projectID).Find(&issues); err != nil { + return nil, err + } + result := make(map[int64]int64, len(issues)) + for _, issue := range issues { + if issue.ProjectColumnID == 0 { + issue.ProjectColumnID = defaultColumnID + } + result[issue.IssueID] = issue.ProjectColumnID + } + return result, nil } // LoadIssuesFromColumn load issues assigned to this column @@ -59,11 +76,11 @@ func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, opts *Is } if b.Default { - issues, err := Issues(ctx, &IssuesOptions{ - ProjectColumnID: db.NoConditionID, - ProjectID: b.ProjectID, - SortType: "project-column-sorting", - }) + issues, err := Issues(ctx, opts.Copy(func(o *IssuesOptions) { + o.ProjectColumnID = db.NoConditionID + o.ProjectID = b.ProjectID + o.SortType = "project-column-sorting" + })) if err != nil { return nil, err } @@ -77,19 +94,6 @@ func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, opts *Is return issueList, nil } -// LoadIssuesFromColumnList load issues assigned to the columns -func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList, opts *IssuesOptions) (map[int64]IssueList, error) { - issuesMap := make(map[int64]IssueList, len(bs)) - for i := range bs { - il, err := LoadIssuesFromColumn(ctx, bs[i], opts) - if err != nil { - return nil, err - } - issuesMap[bs[i].ID] = il - } - return issuesMap, nil -} - // IssueAssignOrRemoveProject changes the project associated with an issue // If newProjectID is 0, the issue is removed from the project func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID, newColumnID int64) error { @@ -110,7 +114,7 @@ func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_mo return util.NewPermissionDeniedErrorf("issue %d can't be accessed by project %d", issue.ID, newProject.ID) } if newColumnID == 0 { - newDefaultColumn, err := newProject.GetDefaultColumn(ctx) + newDefaultColumn, err := newProject.MustDefaultColumn(ctx) if err != nil { return err } diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 5948a67d4e..694b918755 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -27,8 +27,8 @@ type IssuesOptions struct { //nolint RepoIDs []int64 // overwrites RepoCond if the length is not 0 AllPublic bool // include also all public repositories RepoCond builder.Cond - AssigneeID int64 - PosterID int64 + AssigneeID optional.Option[int64] + PosterID optional.Option[int64] MentionedID int64 ReviewRequestedID int64 ReviewedID int64 @@ -49,9 +49,9 @@ type IssuesOptions struct { //nolint // prioritize issues from this repo PriorityRepoID int64 IsArchived optional.Option[bool] - Org *organization.Organization // issues permission scope - Team *organization.Team // issues permission scope - User *user_model.User // issues permission scope + Owner *user_model.User // issues permission scope, it could be an organization or a user + Team *organization.Team // issues permission scope + Doer *user_model.User // issues permission scope } // Copy returns a copy of the options. @@ -231,15 +231,8 @@ func applyConditions(sess *xorm.Session, opts *IssuesOptions) { sess.And("issue.is_closed=?", opts.IsClosed.Value()) } - if opts.AssigneeID > 0 { - applyAssigneeCondition(sess, opts.AssigneeID) - } else if opts.AssigneeID == db.NoConditionID { - sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_assignees)") - } - - if opts.PosterID > 0 { - applyPosterCondition(sess, opts.PosterID) - } + applyAssigneeCondition(sess, opts.AssigneeID) + applyPosterCondition(sess, opts.PosterID) if opts.MentionedID > 0 { applyMentionedCondition(sess, opts.MentionedID) @@ -280,8 +273,12 @@ func applyConditions(sess *xorm.Session, opts *IssuesOptions) { applyLabelsCondition(sess, opts) - if opts.User != nil { - sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.Value())) + if opts.Owner != nil { + sess.And(repo_model.UserOwnedRepoCond(opts.Owner.ID)) + } + + if opts.Doer != nil && !opts.Doer.IsAdmin { + sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.Doer.ID, opts.Owner, opts.Team, opts.IsPull.Value())) } } @@ -328,20 +325,20 @@ func teamUnitsRepoCond(id string, userID, orgID, teamID int64, units ...unit.Typ } // issuePullAccessibleRepoCond userID must not be zero, this condition require join repository table -func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organization.Organization, team *organization.Team, isPull bool) builder.Cond { +func issuePullAccessibleRepoCond(repoIDstr string, userID int64, owner *user_model.User, team *organization.Team, isPull bool) builder.Cond { cond := builder.NewCond() unitType := unit.TypeIssues if isPull { unitType = unit.TypePullRequests } - if org != nil { + if owner != nil && owner.IsOrganization() { if team != nil { - cond = cond.And(teamUnitsRepoCond(repoIDstr, userID, org.ID, team.ID, unitType)) // special team member repos + cond = cond.And(teamUnitsRepoCond(repoIDstr, userID, owner.ID, team.ID, unitType)) // special team member repos } else { cond = cond.And( builder.Or( - repo_model.UserOrgUnitRepoCond(repoIDstr, userID, org.ID, unitType), // team member repos - repo_model.UserOrgPublicUnitRepoCond(userID, org.ID), // user org public non-member repos, TODO: check repo has issues + repo_model.UserOrgUnitRepoCond(repoIDstr, userID, owner.ID, unitType), // team member repos + repo_model.UserOrgPublicUnitRepoCond(userID, owner.ID), // user org public non-member repos, TODO: check repo has issues ), ) } @@ -359,13 +356,27 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organizati return cond } -func applyAssigneeCondition(sess *xorm.Session, assigneeID int64) { - sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). - And("issue_assignees.assignee_id = ?", assigneeID) +func applyAssigneeCondition(sess *xorm.Session, assigneeID optional.Option[int64]) { + // old logic: 0 is also treated as "not filtering assignee", because the "assignee" was read as FormInt64 + if !assigneeID.Has() || assigneeID.Value() == 0 { + return + } + if assigneeID.Value() == db.NoConditionID { + sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_assignees)") + } else { + sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", assigneeID.Value()) + } } -func applyPosterCondition(sess *xorm.Session, posterID int64) { - sess.And("issue.poster_id=?", posterID) +func applyPosterCondition(sess *xorm.Session, posterID optional.Option[int64]) { + if !posterID.Has() { + return + } + // poster doesn't need to support db.NoConditionID(-1), so just use the value as-is + if posterID.Has() { + sess.And("issue.poster_id=?", posterID.Value()) + } } func applyMentionedCondition(sess *xorm.Session, mentionedID int64) { diff --git a/models/issues/issue_stats.go b/models/issues/issue_stats.go index 39326616f8..50409fbbd8 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.OpenCount += stats.MentionCount + accum.MentionCount += stats.MentionCount accum.ReviewRequestedCount += stats.ReviewRequestedCount accum.ReviewedCount += stats.ReviewedCount i = chunk @@ -151,15 +151,9 @@ func applyIssuesOptions(sess *xorm.Session, opts *IssuesOptions, issueIDs []int6 applyProjectCondition(sess, opts) - if opts.AssigneeID > 0 { - applyAssigneeCondition(sess, opts.AssigneeID) - } else if opts.AssigneeID == db.NoConditionID { - sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_assignees)") - } + applyAssigneeCondition(sess, opts.AssigneeID) - if opts.PosterID > 0 { - applyPosterCondition(sess, opts.PosterID) - } + applyPosterCondition(sess, opts.PosterID) if opts.MentionedID > 0 { applyMentionedCondition(sess, opts.MentionedID) diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index 1bbc0eee56..3f76a81bb6 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -4,7 +4,6 @@ package issues_test import ( - "context" "fmt" "sort" "sync" @@ -16,6 +15,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" @@ -155,7 +155,7 @@ func TestIssues(t *testing.T) { }{ { issues_model.IssuesOptions{ - AssigneeID: 1, + AssigneeID: optional.Some(int64(1)), SortType: "oldest", }, []int64{1, 6}, @@ -325,7 +325,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(context.TODO(), &issues_model.IssuesOptions{ + issues, err := issues_model.Issues(t.Context(), &issues_model.IssuesOptions{ Paginator: &db.ListOptions{ PageSize: issueAmount, }, @@ -433,7 +433,7 @@ func assertCreateIssues(t *testing.T, isPull bool) { owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) - assert.EqualValues(t, milestone.ID, 1) + assert.EqualValues(t, 1, milestone.ID) reaction := &issues_model.Reaction{ Type: "heart", UserID: owner.ID, diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 31d76be5e0..7b3fe04aa5 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -21,44 +21,47 @@ import ( "code.gitea.io/gitea/modules/references" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) // UpdateIssueCols updates cols of issue func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error { - if _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue); err != nil { - return err - } - return nil + _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue) + return err } -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 - } +// ErrIssueIsClosed is used when close a closed issue +type ErrIssueIsClosed struct { + ID int64 + RepoID int64 + Index int64 + IsPull bool +} - // 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, +// 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, } } - 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.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) { + if 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 { @@ -70,16 +73,63 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use } } - if issue.IsClosed { - issue.ClosedUnix = timeutil.TimeStampNow() - } else { - issue.ClosedUnix = 0 - } + issue.IsClosed = true + issue.ClosedUnix = timeutil.TimeStampNow() - if err := UpdateIssueCols(ctx, issue, "is_closed", "closed_unix"); err != nil { + if cnt, err := db.GetEngine(ctx).ID(issue.ID).Cols("is_closed", "closed_unix"). + Where("is_closed = ?", false). + Update(issue); 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 @@ -102,14 +152,6 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use 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, @@ -118,8 +160,8 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use }) } -// ChangeIssueStatus changes issue status to open or closed. -func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed bool) (*Comment, error) { +// CloseIssue changes issue status to closed. +func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) { if err := issue.LoadRepo(ctx); err != nil { return nil, err } @@ -127,7 +169,45 @@ func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, return nil, err } - return changeIssueStatus(ctx, issue, doer, isClosed, false) + 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 } // ChangeIssueTitle changes the title of this issue, as the given user. @@ -138,6 +218,7 @@ func ChangeIssueTitle(ctx context.Context, issue *Issue, doer *user_model.User, } defer committer.Close() + issue.Title = util.EllipsisDisplayString(issue.Title, 255) if err = UpdateIssueCols(ctx, issue, "name"); err != nil { return fmt.Errorf("updateIssueCols: %w", err) } @@ -365,19 +446,10 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue 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 := UpdateIssueAttachments(ctx, opts.Issue.ID, opts.Attachments); err != nil { + return err } + if err = opts.Issue.LoadAttributes(ctx); err != nil { return err } @@ -386,6 +458,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue } // NewIssue creates new issue with labels for repository. +// The title will be cut off at 255 characters if it's longer than 255 characters. func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { ctx, committer, err := db.TxContext(ctx) if err != nil { @@ -399,6 +472,7 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, la } issue.Index = idx + issue.Title = util.EllipsisDisplayString(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 ce47adb53a..7c21aa15ee 100644 --- a/models/issues/issue_user_test.go +++ b/models/issues/issue_user_test.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_NewIssueUsers(t *testing.T) { @@ -27,9 +28,8 @@ func Test_NewIssueUsers(t *testing.T) { } // artificially insert new issue - unittest.AssertSuccessfulInsert(t, newIssue) - - assert.NoError(t, issues_model.NewIssueUsers(db.DefaultContext, repo, newIssue)) + require.NoError(t, db.Insert(db.DefaultContext, newIssue)) + require.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_watch.go b/models/issues/issue_watch.go index 9e616a0eb1..560be17eb6 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -105,7 +105,7 @@ func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOpt And("`user`.prohibit_login = ?", false). Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id") - if listOptions.Page != 0 { + if listOptions.Page > 0 { sess = db.SetSessionPagination(sess, &listOptions) watches := make([]*IssueWatch, 0, listOptions.PageSize) return watches, sess.Find(&watches) diff --git a/models/issues/issue_watch_test.go b/models/issues/issue_watch_test.go index d4ce8d8d3d..fad94e243e 100644 --- a/models/issues/issue_watch_test.go +++ b/models/issues/issue_watch_test.go @@ -48,17 +48,17 @@ func TestGetIssueWatchers(t *testing.T) { iws, err := issues_model.GetIssueWatchers(db.DefaultContext, 1, db.ListOptions{}) assert.NoError(t, err) // Watcher is inactive, thus 0 - assert.Len(t, iws, 0) + assert.Empty(t, iws) iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 2, db.ListOptions{}) assert.NoError(t, err) // Watcher is explicit not watching - assert.Len(t, iws, 0) + assert.Empty(t, iws) iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 5, db.ListOptions{}) assert.NoError(t, err) // Issue has no Watchers - assert.Len(t, iws, 0) + assert.Empty(t, iws) iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 7, db.ListOptions{}) assert.NoError(t, err) diff --git a/models/issues/issue_xref_test.go b/models/issues/issue_xref_test.go index f1b1bb2a6b..7f257330b7 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.ChangeIssueStatus(db.DefaultContext, i3, d, true) + _, err := issues_model.CloseIssue(db.DefaultContext, i3, d) assert.NoError(t, err) pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index)) diff --git a/models/issues/label.go b/models/issues/label.go index 2530f71004..8a5d9321cc 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -299,6 +299,9 @@ func GetLabelByID(ctx context.Context, labelID int64) (*Label, error) { // GetLabelsByIDs returns a list of labels by IDs func GetLabelsByIDs(ctx context.Context, labelIDs []int64, cols ...string) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) + if len(labelIDs) == 0 { + return labels, nil + } return labels, db.GetEngine(ctx).Table("label"). In("id", labelIDs). Asc("name"). @@ -349,6 +352,17 @@ func GetLabelIDsInRepoByNames(ctx context.Context, repoID int64, labelNames []st Find(&labelIDs) } +// GetLabelIDsInOrgByNames returns a list of labelIDs by names in a given org. +func GetLabelIDsInOrgByNames(ctx context.Context, orgID int64, labelNames []string) ([]int64, error) { + labelIDs := make([]int64, 0, len(labelNames)) + return labelIDs, db.GetEngine(ctx).Table("label"). + Where("org_id = ?", orgID). + In("name", labelNames). + Asc("name"). + Cols("id"). + Find(&labelIDs) +} + // BuildLabelNamesIssueIDsCondition returns a builder where get issue ids match label names func BuildLabelNamesIssueIDsCondition(labelNames []string) *builder.Builder { return builder.Select("issue_label.issue_id"). @@ -364,6 +378,9 @@ func BuildLabelNamesIssueIDsCondition(labelNames []string) *builder.Builder { // it silently ignores label IDs that do not belong to the repository. func GetLabelsInRepoByIDs(ctx context.Context, repoID int64, labelIDs []int64) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) + if len(labelIDs) == 0 { + return labels, nil + } return labels, db.GetEngine(ctx). Where("repo_id = ?", repoID). In("id", labelIDs). @@ -390,7 +407,7 @@ func GetLabelsByRepoID(ctx context.Context, repoID int64, sortType string, listO sess.Asc("name") } - if listOptions.Page != 0 { + if listOptions.Page > 0 { sess = db.SetSessionPagination(sess, &listOptions) } @@ -436,6 +453,9 @@ func GetLabelInOrgByID(ctx context.Context, orgID, labelID int64) (*Label, error // it silently ignores label IDs that do not belong to the organization. func GetLabelsInOrgByIDs(ctx context.Context, orgID int64, labelIDs []int64) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) + if len(labelIDs) == 0 { + return labels, nil + } return labels, db.GetEngine(ctx). Where("org_id = ?", orgID). In("id", labelIDs). @@ -462,7 +482,7 @@ func GetLabelsByOrgID(ctx context.Context, orgID int64, sortType string, listOpt sess.Asc("name") } - if listOptions.Page != 0 { + if listOptions.Page > 0 { sess = db.SetSessionPagination(sess, &listOptions) } diff --git a/models/issues/label_test.go b/models/issues/label_test.go index 396de809e1..185fa11bbc 100644 --- a/models/issues/label_test.go +++ b/models/issues/label_test.go @@ -31,12 +31,12 @@ func TestLabel_LoadSelectedLabelsAfterClick(t *testing.T) { // First test : with negative and scope label.LoadSelectedLabelsAfterClick([]int64{1, -8}, []string{"", "scope"}) assert.Equal(t, "1", label.QueryString) - assert.Equal(t, true, label.IsSelected) + assert.True(t, label.IsSelected) // Second test : with duplicates label.LoadSelectedLabelsAfterClick([]int64{1, 7, 1, 7, 7}, []string{"", "scope", "", "scope", "scope"}) assert.Equal(t, "1,8", label.QueryString) - assert.Equal(t, false, label.IsSelected) + assert.False(t, label.IsSelected) // Third test : empty set label.LoadSelectedLabelsAfterClick([]int64{}, []string{}) @@ -229,8 +229,7 @@ func TestGetLabelsByOrgID(t *testing.T) { testSuccess(3, "reversealphabetically", []int64{4, 3}) testSuccess(3, "default", []int64{3, 4}) - var err error - _, err = issues_model.GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{}) + _, err := issues_model.GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{}) assert.True(t, issues_model.IsErrOrgLabelNotExist(err)) _, err = issues_model.GetLabelsByOrgID(db.DefaultContext, -1, "leastissues", db.ListOptions{}) @@ -249,7 +248,7 @@ func TestGetLabelsByIssueID(t *testing.T) { labels, err = issues_model.GetLabelsByIssueID(db.DefaultContext, unittest.NonexistentID) assert.NoError(t, err) - assert.Len(t, labels, 0) + assert.Empty(t, labels) } func TestUpdateLabel(t *testing.T) { @@ -272,7 +271,7 @@ func TestUpdateLabel(t *testing.T) { assert.EqualValues(t, label.Color, newLabel.Color) assert.EqualValues(t, label.Name, newLabel.Name) assert.EqualValues(t, label.Description, newLabel.Description) - assert.EqualValues(t, newLabel.ArchivedUnix, 0) + assert.EqualValues(t, 0, newLabel.ArchivedUnix) unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{}) } @@ -388,7 +387,7 @@ func TestDeleteIssueLabel(t *testing.T) { expectedNumIssues := label.NumIssues expectedNumClosedIssues := label.NumClosedIssues - if unittest.BeanExists(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID}) { + if unittest.GetBean(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID}) != nil { expectedNumIssues-- if issue.IsClosed { expectedNumClosedIssues-- @@ -407,7 +406,7 @@ func TestDeleteIssueLabel(t *testing.T) { PosterID: doerID, IssueID: issueID, LabelID: labelID, - }, `content=""`) + }, `content=''`) label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}) assert.EqualValues(t, expectedNumIssues, label.NumIssues) assert.EqualValues(t, expectedNumClosedIssues, label.NumClosedIssues) diff --git a/models/issues/milestone.go b/models/issues/milestone.go index db0312adf0..4c9bae58f7 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -84,10 +84,9 @@ func (m *Milestone) BeforeUpdate() { // this object. func (m *Milestone) AfterLoad() { m.NumOpenIssues = m.NumIssues - m.NumClosedIssues - if m.DeadlineUnix.Year() == 9999 { + if m.DeadlineUnix == 0 { return } - m.DeadlineString = m.DeadlineUnix.FormatDate() if m.IsClosed { m.IsOverdue = m.ClosedDateUnix >= m.DeadlineUnix diff --git a/models/issues/milestone_test.go b/models/issues/milestone_test.go index e5f6f15ca2..28cd0c028b 100644 --- a/models/issues/milestone_test.go +++ b/models/issues/milestone_test.go @@ -87,7 +87,7 @@ func TestGetMilestonesByRepoID(t *testing.T) { IsClosed: optional.Some(false), }) assert.NoError(t, err) - assert.Len(t, milestones, 0) + assert.Empty(t, milestones) } func TestGetMilestones(t *testing.T) { diff --git a/models/issues/pull.go b/models/issues/pull.go index 4475ab3a4f..e3af00224d 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -80,22 +80,6 @@ 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 @@ -301,7 +285,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error { return nil } - reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID) + reviews, _, err := GetReviewsByIssueID(ctx, pr.Issue.ID) if err != nil { return err } @@ -320,7 +304,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error { // LoadRequestedReviewersTeams loads the requested reviewers teams. func (pr *PullRequest) LoadRequestedReviewersTeams(ctx context.Context) error { - reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID) + reviews, _, err := GetReviewsByIssueID(ctx, pr.Issue.ID) if err != nil { return err } @@ -499,65 +483,6 @@ 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) @@ -572,6 +497,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Iss } issue.Index = idx + issue.Title = util.EllipsisDisplayString(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 9155ea0834..b685175f8e 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" + "xorm.io/builder" "xorm.io/xorm" ) @@ -27,11 +28,16 @@ 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": @@ -55,7 +61,7 @@ func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullR } // GetUnmergedPullRequestsByHeadInfo returns all pull requests that are open and has not been merged -func GetUnmergedPullRequestsByHeadInfo(ctx context.Context, repoID int64, branch string) ([]*PullRequest, error) { +func GetUnmergedPullRequestsByHeadInfo(ctx context.Context, repoID int64, branch string) (PullRequestList, error) { prs := make([]*PullRequest, 0, 2) sess := db.GetEngine(ctx). Join("INNER", "issue", "issue.id = pull_request.issue_id"). @@ -110,7 +116,7 @@ func HasUnmergedPullRequestsByHeadInfo(ctx context.Context, repoID int64, branch // GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged // by given base information (repo and branch). -func GetUnmergedPullRequestsByBaseInfo(ctx context.Context, repoID int64, branch string) ([]*PullRequest, error) { +func GetUnmergedPullRequestsByBaseInfo(ctx context.Context, repoID int64, branch string) (PullRequestList, error) { prs := make([]*PullRequest, 0, 2) return prs, db.GetEngine(ctx). Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?", @@ -165,6 +171,23 @@ 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)) @@ -240,6 +263,64 @@ func (prs PullRequestList) GetIssueIDs() []int64 { }) } +func (prs PullRequestList) LoadReviewCommentsCounts(ctx context.Context) (map[int64]int, error) { + issueIDs := prs.GetIssueIDs() + countsMap := make(map[int64]int, len(issueIDs)) + counts := make([]struct { + IssueID int64 + Count int + }, 0, len(issueIDs)) + if err := db.GetEngine(ctx).Select("issue_id, count(*) as count"). + Table("comment").In("issue_id", issueIDs).And("type = ?", CommentTypeReview). + GroupBy("issue_id").Find(&counts); err != nil { + return nil, err + } + for _, c := range counts { + countsMap[c.IssueID] = c.Count + } + return countsMap, nil +} + +func (prs PullRequestList) LoadReviews(ctx context.Context) (ReviewList, error) { + issueIDs := prs.GetIssueIDs() + reviews := make([]*Review, 0, len(issueIDs)) + + subQuery := builder.Select("max(id) as id"). + From("review"). + Where(builder.In("issue_id", issueIDs)). + And(builder.In("`type`", ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest)). + And(builder.Eq{ + "dismissed": false, + "original_author_id": 0, + "reviewer_team_id": 0, + }). + GroupBy("issue_id, reviewer_id") + // Get latest review of each reviewer, sorted in order they were made + if err := db.GetEngine(ctx).In("id", subQuery).OrderBy("review.updated_unix ASC").Find(&reviews); err != nil { + return nil, err + } + + teamReviewRequests := make([]*Review, 0, 5) + subQueryTeam := builder.Select("max(id) as id"). + From("review"). + Where(builder.In("issue_id", issueIDs)). + And(builder.Eq{ + "original_author_id": 0, + }).And(builder.Neq{ + "reviewer_team_id": 0, + }). + GroupBy("issue_id, reviewer_team_id") + if err := db.GetEngine(ctx).In("id", subQueryTeam).OrderBy("review.updated_unix ASC").Find(&teamReviewRequests); err != nil { + return nil, err + } + + if len(teamReviewRequests) > 0 { + reviews = append(reviews, teamReviewRequests...) + } + + return reviews, nil +} + // HasMergedPullRequestInRepo returns whether the user(poster) has merged pull-request in the repo func HasMergedPullRequestInRepo(ctx context.Context, repoID, posterID int64) (bool, error) { return db.GetEngine(ctx). diff --git a/models/issues/pull_list_test.go b/models/issues/pull_list_test.go new file mode 100644 index 0000000000..f5553e7885 --- /dev/null +++ b/models/issues/pull_list_test.go @@ -0,0 +1,64 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package issues_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestPullRequestList_LoadAttributes(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + prs := issues_model.PullRequestList{ + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}), + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}), + } + assert.NoError(t, prs.LoadAttributes(db.DefaultContext)) + for _, pr := range prs { + assert.NotNil(t, pr.Issue) + assert.Equal(t, pr.IssueID, pr.Issue.ID) + } + + assert.NoError(t, issues_model.PullRequestList([]*issues_model.PullRequest{}).LoadAttributes(db.DefaultContext)) +} + +func TestPullRequestList_LoadReviewCommentsCounts(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + prs := issues_model.PullRequestList{ + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}), + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}), + } + reviewComments, err := prs.LoadReviewCommentsCounts(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, reviewComments, 2) + for _, pr := range prs { + assert.EqualValues(t, 1, reviewComments[pr.IssueID]) + } +} + +func TestPullRequestList_LoadReviews(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + prs := issues_model.PullRequestList{ + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}), + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}), + } + reviewList, err := prs.LoadReviews(db.DefaultContext) + assert.NoError(t, err) + // 1, 7, 8, 9, 10, 22 + assert.Len(t, reviewList, 6) + assert.EqualValues(t, 1, reviewList[0].ID) + assert.EqualValues(t, 7, reviewList[1].ID) + assert.EqualValues(t, 8, reviewList[2].ID) + assert.EqualValues(t, 9, reviewList[3].ID) + assert.EqualValues(t, 10, reviewList[4].ID) + assert.EqualValues(t, 22, reviewList[5].ID) +} diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go index 675c90527d..090659864a 100644 --- a/models/issues/pull_test.go +++ b/models/issues/pull_test.go @@ -79,11 +79,11 @@ func TestPullRequestsNewest(t *testing.T) { func TestLoadRequestedReviewers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) + pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) assert.NoError(t, pull.LoadIssue(db.DefaultContext)) issue := pull.Issue assert.NoError(t, issue.LoadRepo(db.DefaultContext)) - assert.Len(t, pull.RequestedReviewers, 0) + assert.Empty(t, pull.RequestedReviewers) user1, err := user_model.GetUserByID(db.DefaultContext, 1) assert.NoError(t, err) @@ -93,7 +93,7 @@ func TestLoadRequestedReviewers(t *testing.T) { assert.NotNil(t, comment) assert.NoError(t, pull.LoadRequestedReviewers(db.DefaultContext)) - assert.Len(t, pull.RequestedReviewers, 1) + assert.Len(t, pull.RequestedReviewers, 6) comment, err = issues_model.RemoveReviewRequest(db.DefaultContext, issue, user1, &user_model.User{}) assert.NoError(t, err) @@ -234,22 +234,6 @@ func TestPullRequest_UpdateCols(t *testing.T) { unittest.CheckConsistencyFor(t, pr) } -func TestPullRequestList_LoadAttributes(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - prs := []*issues_model.PullRequest{ - unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}), - unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}), - } - assert.NoError(t, issues_model.PullRequestList(prs).LoadAttributes(db.DefaultContext)) - for _, pr := range prs { - assert.NotNil(t, pr.Issue) - assert.Equal(t, pr.IssueID, pr.Issue.ID) - } - - assert.NoError(t, issues_model.PullRequestList([]*issues_model.PullRequest{}).LoadAttributes(db.DefaultContext)) -} - // TODO TestAddTestPullRequestTask func TestPullRequest_IsWorkInProgress(t *testing.T) { diff --git a/models/issues/reaction.go b/models/issues/reaction.go index eb7faefc79..f24001fd23 100644 --- a/models/issues/reaction.go +++ b/models/issues/reaction.go @@ -7,6 +7,7 @@ import ( "bytes" "context" "fmt" + "strings" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" @@ -163,7 +164,7 @@ func FindReactions(ctx context.Context, opts FindReactionsOptions) (ReactionList Where(opts.toConds()). In("reaction.`type`", setting.UI.Reactions). Asc("reaction.issue_id", "reaction.comment_id", "reaction.created_unix", "reaction.id") - if opts.Page != 0 { + if opts.Page > 0 { sess = db.SetSessionPagination(sess, &opts) reactions := make([]*Reaction, 0, opts.PageSize) @@ -321,6 +322,11 @@ 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 { @@ -338,7 +344,7 @@ func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Reposit for _, reaction := range list { if reaction.OriginalAuthor != "" { - reaction.User = user_model.NewReplaceUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name())) + reaction.User = newMigrationOriginalUser(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 8b345e5fd8..1c5c2ee30a 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -639,6 +639,10 @@ func InsertReviews(ctx context.Context, reviews []*Review) error { return err } } + + if err := UpdateIssueNumComments(ctx, review.IssueID); err != nil { + return err + } } return committer.Commit() @@ -926,17 +930,19 @@ 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 , offfcial reviewer and poster can do it +// the PR writer , official 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/review_list.go b/models/issues/review_list.go index a5ceb21791..928f24fb2d 100644 --- a/models/issues/review_list.go +++ b/models/issues/review_list.go @@ -5,6 +5,8 @@ package issues import ( "context" + "slices" + "sort" "code.gitea.io/gitea/models/db" organization_model "code.gitea.io/gitea/models/organization" @@ -47,14 +49,9 @@ func (reviews ReviewList) LoadReviewersTeams(ctx context.Context) error { } } - teamsMap := make(map[int64]*organization_model.Team, 0) - for _, teamID := range reviewersTeamsIDs { - team, err := organization_model.GetTeamByID(ctx, teamID) - if err != nil { - return err - } - - teamsMap[teamID] = team + teamsMap, err := organization_model.GetTeamsByIDs(ctx, reviewersTeamsIDs) + if err != nil { + return err } for _, review := range reviews { @@ -158,43 +155,60 @@ func CountReviews(ctx context.Context, opts FindReviewOptions) (int64, error) { return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{}) } -// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request -func GetReviewersFromOriginalAuthorsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) { - reviews := make([]*Review, 0, 10) - - // Get latest review of each reviewer, sorted in order they were made - if err := db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC", - issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest). - Find(&reviews); err != nil { - return nil, err - } - - return reviews, nil -} - // GetReviewsByIssueID gets the latest review of each reviewer for a pull request -func GetReviewsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) { +// The first returned parameter is the latest review of each individual reviewer or team +// The second returned parameter is the latest review of each original author which is migrated from other systems +// The reviews are sorted by updated time +func GetReviewsByIssueID(ctx context.Context, issueID int64) (latestReviews, migratedOriginalReviews ReviewList, err error) { reviews := make([]*Review, 0, 10) - sess := db.GetEngine(ctx) - - // Get latest review of each reviewer, sorted in order they were made - if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC", - issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, false). - Find(&reviews); err != nil { - return nil, err + // Get all reviews for the issue id + if err := db.GetEngine(ctx).Where("issue_id=?", issueID).OrderBy("updated_unix ASC").Find(&reviews); err != nil { + return nil, nil, err } + // filter them in memory to get the latest review of each reviewer + // Since the reviews should not be too many for one issue, less than 100 commonly, it's acceptable to do this in memory + // And since there are too less indexes in review table, it will be very slow to filter in the database + reviewersMap := make(map[int64][]*Review) // key is reviewer id + originalReviewersMap := make(map[int64][]*Review) // key is original author id + reviewTeamsMap := make(map[int64][]*Review) // key is reviewer team id + countedReivewTypes := []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest} + for _, review := range reviews { + if review.ReviewerTeamID == 0 && slices.Contains(countedReivewTypes, review.Type) && !review.Dismissed { + if review.OriginalAuthorID != 0 { + originalReviewersMap[review.OriginalAuthorID] = append(originalReviewersMap[review.OriginalAuthorID], review) + } else { + reviewersMap[review.ReviewerID] = append(reviewersMap[review.ReviewerID], review) + } + } else if review.ReviewerTeamID != 0 && review.OriginalAuthorID == 0 { + reviewTeamsMap[review.ReviewerTeamID] = append(reviewTeamsMap[review.ReviewerTeamID], review) + } + } + + individualReviews := make([]*Review, 0, 10) + for _, reviews := range reviewersMap { + individualReviews = append(individualReviews, reviews[len(reviews)-1]) + } + sort.Slice(individualReviews, func(i, j int) bool { + return individualReviews[i].UpdatedUnix < individualReviews[j].UpdatedUnix + }) + + originalReviews := make([]*Review, 0, 10) + for _, reviews := range originalReviewersMap { + originalReviews = append(originalReviews, reviews[len(reviews)-1]) + } + sort.Slice(originalReviews, func(i, j int) bool { + return originalReviews[i].UpdatedUnix < originalReviews[j].UpdatedUnix + }) + teamReviewRequests := make([]*Review, 0, 5) - if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id <> 0 AND original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC", - issueID). - Find(&teamReviewRequests); err != nil { - return nil, err + for _, reviews := range reviewTeamsMap { + teamReviewRequests = append(teamReviewRequests, reviews[len(reviews)-1]) } + sort.Slice(teamReviewRequests, func(i, j int) bool { + return teamReviewRequests[i].UpdatedUnix < teamReviewRequests[j].UpdatedUnix + }) - if len(teamReviewRequests) > 0 { - reviews = append(reviews, teamReviewRequests...) - } - - return reviews, nil + return append(individualReviews, teamReviewRequests...), originalReviews, nil } diff --git a/models/issues/review_test.go b/models/issues/review_test.go index 942121fd8f..2588b8ba41 100644 --- a/models/issues/review_test.go +++ b/models/issues/review_test.go @@ -126,42 +126,49 @@ func TestGetReviewersByIssueID(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) expectedReviews := []*issues_model.Review{} expectedReviews = append(expectedReviews, &issues_model.Review{ + ID: 7, Reviewer: org3, Type: issues_model.ReviewTypeReject, UpdatedUnix: 946684812, }, &issues_model.Review{ + ID: 8, Reviewer: user4, Type: issues_model.ReviewTypeApprove, UpdatedUnix: 946684813, }, &issues_model.Review{ + ID: 9, Reviewer: user2, Type: issues_model.ReviewTypeReject, UpdatedUnix: 946684814, - }) + }, + &issues_model.Review{ + ID: 10, + Reviewer: user_model.NewGhostUser(), + Type: issues_model.ReviewTypeReject, + UpdatedUnix: 946684815, + }, + &issues_model.Review{ + ID: 22, + Reviewer: user5, + Type: issues_model.ReviewTypeRequest, + UpdatedUnix: 946684817, + }, + ) - allReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID) + allReviews, migratedReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID) assert.NoError(t, err) + assert.Empty(t, migratedReviews) for _, review := range allReviews { assert.NoError(t, review.LoadReviewer(db.DefaultContext)) } - if assert.Len(t, allReviews, 3) { - for i, review := range allReviews { - assert.Equal(t, expectedReviews[i].Reviewer, review.Reviewer) - assert.Equal(t, expectedReviews[i].Type, review.Type) - assert.Equal(t, expectedReviews[i].UpdatedUnix, review.UpdatedUnix) - } - } - - allReviews, err = issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID) - assert.NoError(t, err) - assert.NoError(t, allReviews.LoadReviewers(db.DefaultContext)) - if assert.Len(t, allReviews, 3) { + if assert.Len(t, allReviews, 5) { for i, review := range allReviews { assert.Equal(t, expectedReviews[i].Reviewer, review.Reviewer) assert.Equal(t, expectedReviews[i].Type, review.Type) diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index fd9c7d7875..7c05a3a883 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -46,11 +46,6 @@ 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.SecToTime(s.Seconds()) -} - func getStopwatch(ctx context.Context, userID, issueID int64) (sw *Stopwatch, exists bool, err error) { sw = new(Stopwatch) exists, err = db.GetEngine(ctx). @@ -96,7 +91,7 @@ func GetUIDsAndStopwatch(ctx context.Context) ([]*UserStopwatch, error) { func GetUserStopwatches(ctx context.Context, userID int64, listOptions db.ListOptions) ([]*Stopwatch, error) { sws := make([]*Stopwatch, 0, 8) sess := db.GetEngine(ctx).Where("stopwatch.user_id = ?", userID) - if listOptions.Page != 0 { + if listOptions.Page > 0 { sess = db.SetSessionPagination(sess, &listOptions) } @@ -201,7 +196,7 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss Doer: user, Issue: issue, Repo: issue.Repo, - Content: util.SecToTime(timediff), + Content: util.SecToHours(timediff), Type: CommentTypeStopTracking, TimeID: tt.ID, }); err != nil { diff --git a/models/issues/stopwatch_test.go b/models/issues/stopwatch_test.go index 39958a7f36..a1bf9dc931 100644 --- a/models/issues/stopwatch_test.go +++ b/models/issues/stopwatch_test.go @@ -32,7 +32,7 @@ func TestCancelStopwatch(t *testing.T) { _ = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeCancelTracking, PosterID: user1.ID, IssueID: issue1.ID}) - assert.Nil(t, issues_model.CancelStopwatch(db.DefaultContext, user1, issue2)) + assert.NoError(t, issues_model.CancelStopwatch(db.DefaultContext, user1, issue2)) } func TestStopwatchExists(t *testing.T) { diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index caa582a9fc..ea404d36cd 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -139,7 +139,7 @@ func (opts *FindTrackedTimesOptions) toSession(e db.Engine) db.Engine { sess = sess.Where(opts.ToConds()) - if opts.Page != 0 { + if opts.Page > 0 { sess = db.SetSessionPagination(sess, opts) } diff --git a/models/issues/tracked_time_test.go b/models/issues/tracked_time_test.go index d82bff967a..44054a1b83 100644 --- a/models/issues/tracked_time_test.go +++ b/models/issues/tracked_time_test.go @@ -50,7 +50,7 @@ func TestGetTrackedTimes(t *testing.T) { times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: -1}) assert.NoError(t, err) - assert.Len(t, times, 0) + assert.Empty(t, times) // by User times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{UserID: 1}) @@ -60,7 +60,7 @@ func TestGetTrackedTimes(t *testing.T) { times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{UserID: 3}) assert.NoError(t, err) - assert.Len(t, times, 0) + assert.Empty(t, times) // by Repo times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{RepositoryID: 2}) @@ -69,7 +69,7 @@ func TestGetTrackedTimes(t *testing.T) { assert.Equal(t, int64(1), times[0].Time) issue, err := issues_model.GetIssueByID(db.DefaultContext, times[0].IssueID) assert.NoError(t, err) - assert.Equal(t, issue.RepoID, int64(2)) + assert.Equal(t, int64(2), issue.RepoID) times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{RepositoryID: 1}) assert.NoError(t, err) @@ -77,7 +77,7 @@ func TestGetTrackedTimes(t *testing.T) { times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{RepositoryID: 10}) assert.NoError(t, err) - assert.Len(t, times, 0) + assert.Empty(t, times) } func TestTotalTimesForEachUser(t *testing.T) { diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index 676504e530..754024b86d 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -8,19 +8,17 @@ import ( "context" "fmt" "os" - "path" "path/filepath" "runtime" "testing" "code.gitea.io/gitea/models/unittest" - "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/test" "code.gitea.io/gitea/modules/testlogger" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "xorm.io/xorm" ) @@ -35,35 +33,15 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu ourSkip := 2 ourSkip += skip deferFn := testlogger.PrintCurrentTest(t, ourSkip) - assert.NoError(t, os.RemoveAll(setting.RepoRootPath)) - assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath)) - ownerDirs, err := os.ReadDir(setting.RepoRootPath) - if err != nil { - assert.NoError(t, err, "unable to read the new repo root: %v\n", err) - } - for _, ownerDir := range ownerDirs { - if !ownerDir.Type().IsDir() { - continue - } - repoDirs, err := os.ReadDir(filepath.Join(setting.RepoRootPath, ownerDir.Name())) - if err != nil { - assert.NoError(t, err, "unable to read the new repo root: %v\n", err) - } - for _, repoDir := range repoDirs { - _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "pack"), 0o755) - _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "info"), 0o755) - _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "heads"), 0o755) - _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "tag"), 0o755) - } - } + require.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath)) if err := deleteDB(); err != nil { - t.Errorf("unable to reset database: %v", err) + t.Fatalf("unable to reset database: %v", err) return nil, deferFn } x, err := newXORMEngine() - assert.NoError(t, err) + require.NoError(t, err) if x != nil { oldDefer := deferFn deferFn = func() { @@ -98,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(x); err != nil { + if err := unittest.LoadFixtures(); err != nil { t.Errorf("error whilst loading fixtures from %s: %v", fixturesDir, err) return x, deferFn } @@ -112,39 +90,33 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu } func MainTest(m *testing.M) { - log.RegisterEventWriter("test", testlogger.NewTestLoggerWriter) + testlogger.Init() - giteaRoot := base.SetupGiteaRoot() - if giteaRoot == "" { - fmt.Println("Environment variable $GITEA_ROOT not set") - os.Exit(1) - } + giteaRoot := test.SetupGiteaRoot() giteaBinary := "gitea" if runtime.GOOS == "windows" { giteaBinary += ".exe" } - setting.AppPath = path.Join(giteaRoot, giteaBinary) + setting.AppPath = filepath.Join(giteaRoot, giteaBinary) if _, err := os.Stat(setting.AppPath); err != nil { - fmt.Printf("Could not find gitea binary at %s\n", setting.AppPath) - os.Exit(1) + testlogger.Fatalf("Could not find gitea binary at %s\n", setting.AppPath) } giteaConf := os.Getenv("GITEA_CONF") if giteaConf == "" { - giteaConf = path.Join(filepath.Dir(setting.AppPath), "tests/sqlite.ini") + giteaConf = filepath.Join(filepath.Dir(setting.AppPath), "tests/sqlite.ini") fmt.Printf("Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf) } - if !path.IsAbs(giteaConf) { - setting.CustomConf = path.Join(giteaRoot, giteaConf) + if !filepath.IsAbs(giteaConf) { + setting.CustomConf = filepath.Join(giteaRoot, giteaConf) } else { setting.CustomConf = giteaConf } tmpDataPath, err := os.MkdirTemp(setting.TempDir(), "data") if err != nil { - fmt.Printf("Unable to create temporary data path %v\n", err) - os.Exit(1) + testlogger.Fatalf("Unable to create temporary data path %v\n", err) } setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom") @@ -152,8 +124,7 @@ func MainTest(m *testing.M) { unittest.InitSettings() if err = git.InitFull(context.Background()); err != nil { - fmt.Printf("Unable to InitFull: %v\n", err) - os.Exit(1) + testlogger.Fatalf("Unable to InitFull: %v\n", err) } setting.LoadDBSetting() setting.InitLoggersForTest() diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ddf20d9542..5f79a873f1 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -22,6 +22,7 @@ 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" @@ -364,6 +365,16 @@ func prepareMigrationTasks() []*migration { newMigration(304, "Add index for release sha1", v1_23.AddIndexForReleaseSha1), newMigration(305, "Add Repository Licenses", v1_23.AddRepositoryLicenses), newMigration(306, "Add BlockAdminMergeOverride to ProtectedBranch", v1_23.AddBlockAdminMergeOverrideBranchProtection), + newMigration(307, "Fix milestone deadline_unix when there is no due date", v1_23.FixMilestoneNoDueDate), + newMigration(308, "Add index(user_id, is_deleted) for action table", v1_23.AddNewIndexForUserDashboard), + 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), + newMigration(314, "Update OwnerID as zero for repository level action tables", v1_24.UpdateOwnerIDOfRepoLevelActionsTables), } return preparedMigrations } @@ -402,7 +413,7 @@ func ExpectedDBVersion() int64 { } // EnsureUpToDate will check if the db is at the correct version -func EnsureUpToDate(x *xorm.Engine) error { +func EnsureUpToDate(ctx context.Context, x *xorm.Engine) error { currentDB, err := GetCurrentDBVersion(x) if err != nil { return err diff --git a/models/migrations/v1_12/v128.go b/models/migrations/v1_12/v128.go index 44d44a26c5..cba64711d0 100644 --- a/models/migrations/v1_12/v128.go +++ b/models/migrations/v1_12/v128.go @@ -82,17 +82,17 @@ func FixMergeBase(x *xorm.Engine) error { if !pr.HasMerged { var err error - pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, "merge-base").AddDashesAndList(pr.BaseBranch, gitRefName).RunStdString(&git.RunOpts{Dir: repoPath}) + pr.MergeBase, _, err = git.NewCommand("merge-base").AddDashesAndList(pr.BaseBranch, gitRefName).RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath}) if err != nil { var err2 error - pr.MergeBase, _, err2 = git.NewCommand(git.DefaultContext, "rev-parse").AddDynamicArguments(git.BranchPrefix + pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath}) + pr.MergeBase, _, err2 = git.NewCommand("rev-parse").AddDynamicArguments(git.BranchPrefix+pr.BaseBranch).RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath}) if err2 != nil { log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2) continue } } } else { - parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath}) + parentsString, _, err := git.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath}) if err != nil { log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) continue @@ -104,9 +104,9 @@ func FixMergeBase(x *xorm.Engine) error { refs := append([]string{}, parents[1:]...) refs = append(refs, gitRefName) - cmd := git.NewCommand(git.DefaultContext, "merge-base").AddDashesAndList(refs...) + cmd := git.NewCommand("merge-base").AddDashesAndList(refs...) - pr.MergeBase, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath}) + pr.MergeBase, _, err = cmd.RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath}) if err != nil { log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) continue diff --git a/models/migrations/v1_12/v134.go b/models/migrations/v1_12/v134.go index 3d1c82f09e..a918d38757 100644 --- a/models/migrations/v1_12/v134.go +++ b/models/migrations/v1_12/v134.go @@ -79,7 +79,7 @@ func RefixMergeBase(x *xorm.Engine) error { gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index) - parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath}) + parentsString, _, err := git.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath}) if err != nil { log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) continue @@ -92,9 +92,9 @@ func RefixMergeBase(x *xorm.Engine) error { // we should recalculate refs := append([]string{}, parents[1:]...) refs = append(refs, gitRefName) - cmd := git.NewCommand(git.DefaultContext, "merge-base").AddDashesAndList(refs...) + cmd := git.NewCommand("merge-base").AddDashesAndList(refs...) - pr.MergeBase, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath}) + pr.MergeBase, _, err = cmd.RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath}) if err != nil { log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) continue diff --git a/models/migrations/v1_16/v193_test.go b/models/migrations/v1_16/v193_test.go index d99bbc2962..b279967a2c 100644 --- a/models/migrations/v1_16/v193_test.go +++ b/models/migrations/v1_16/v193_test.go @@ -56,8 +56,8 @@ func Test_AddRepoIDForAttachment(t *testing.T) { err := x.Table("attachment").Where("issue_id > 0").Find(&issueAttachments) assert.NoError(t, err) for _, attach := range issueAttachments { - assert.Greater(t, attach.RepoID, int64(0)) - assert.Greater(t, attach.IssueID, int64(0)) + assert.Positive(t, attach.RepoID) + assert.Positive(t, attach.IssueID) var issue Issue has, err := x.ID(attach.IssueID).Get(&issue) assert.NoError(t, err) @@ -69,8 +69,8 @@ func Test_AddRepoIDForAttachment(t *testing.T) { err = x.Table("attachment").Where("release_id > 0").Find(&releaseAttachments) assert.NoError(t, err) for _, attach := range releaseAttachments { - assert.Greater(t, attach.RepoID, int64(0)) - assert.Greater(t, attach.ReleaseID, int64(0)) + assert.Positive(t, attach.RepoID) + assert.Positive(t, attach.ReleaseID) var release Release has, err := x.ID(attach.ReleaseID).Get(&release) assert.NoError(t, err) diff --git a/models/migrations/v1_21/v276.go b/models/migrations/v1_21/v276.go index ed1bc3bda5..9d22c9052e 100644 --- a/models/migrations/v1_21/v276.go +++ b/models/migrations/v1_21/v276.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/git" giturl "code.gitea.io/gitea/modules/git/url" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "xorm.io/xorm" ) @@ -163,13 +164,15 @@ func migratePushMirrors(x *xorm.Engine) error { func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) { repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(ownerName), strings.ToLower(repoName)+".git") - + if exist, _ := util.IsExist(repoPath); !exist { + return "", nil + } remoteURL, err := git.GetRemoteAddress(context.Background(), repoPath, remoteName) if err != nil { return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err) } - u, err := giturl.Parse(remoteURL) + u, err := giturl.ParseGitURL(remoteURL) if err != nil { return "", err } diff --git a/models/migrations/v1_22/v286_test.go b/models/migrations/v1_22/v286_test.go index a19c9396e2..1f213ddb6e 100644 --- a/models/migrations/v1_22/v286_test.go +++ b/models/migrations/v1_22/v286_test.go @@ -107,12 +107,12 @@ func Test_RepositoryFormat(t *testing.T) { repo = new(Repository) ok, err := x.ID(2).Get(repo) assert.NoError(t, err) - assert.EqualValues(t, true, ok) + assert.True(t, ok) assert.EqualValues(t, "sha1", repo.ObjectFormatName) repo = new(Repository) ok, err = x.ID(id).Get(repo) assert.NoError(t, err) - assert.EqualValues(t, true, ok) + assert.True(t, ok) assert.EqualValues(t, "sha256", repo.ObjectFormatName) } diff --git a/models/migrations/v1_22/v294_test.go b/models/migrations/v1_22/v294_test.go index 82a3bcd602..a1d702cb77 100644 --- a/models/migrations/v1_22/v294_test.go +++ b/models/migrations/v1_22/v294_test.go @@ -39,7 +39,7 @@ func Test_AddUniqueIndexForProjectIssue(t *testing.T) { tables, err := x.DBMetas() assert.NoError(t, err) - assert.EqualValues(t, 1, len(tables)) + assert.Len(t, tables, 1) found := false for _, index := range tables[0].Indexes { if index.Type == schemas.UniqueType { diff --git a/models/migrations/v1_23/v307.go b/models/migrations/v1_23/v307.go new file mode 100644 index 0000000000..ef7f5f2c3f --- /dev/null +++ b/models/migrations/v1_23/v307.go @@ -0,0 +1,21 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" +) + +func FixMilestoneNoDueDate(x *xorm.Engine) error { + type Milestone struct { + DeadlineUnix timeutil.TimeStamp + } + // Wednesday, December 1, 9999 12:00:00 AM GMT+00:00 + _, err := x.Table("milestone").Where("deadline_unix > 253399622400"). + Cols("deadline_unix"). + Update(&Milestone{DeadlineUnix: 0}) + return err +} diff --git a/models/migrations/v1_23/v308.go b/models/migrations/v1_23/v308.go new file mode 100644 index 0000000000..1e8a9b0af2 --- /dev/null +++ b/models/migrations/v1_23/v308.go @@ -0,0 +1,52 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +type improveActionTableIndicesAction struct { + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"INDEX"` // Receiver user id. + OpType int + ActUserID int64 // Action user id. + RepoID int64 + CommentID int64 `xorm:"INDEX"` + IsDeleted bool `xorm:"NOT NULL DEFAULT false"` + RefName string + IsPrivate bool `xorm:"NOT NULL DEFAULT false"` + Content string `xorm:"TEXT"` + CreatedUnix timeutil.TimeStamp `xorm:"created"` +} + +// TableName sets the name of this table +func (*improveActionTableIndicesAction) TableName() string { + return "action" +} + +func (a *improveActionTableIndicesAction) TableIndices() []*schemas.Index { + repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType) + repoIndex.AddColumn("repo_id", "user_id", "is_deleted") + + actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType) + actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted") + + cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType) + cudIndex.AddColumn("created_unix", "user_id", "is_deleted") + + cuIndex := schemas.NewIndex("c_u", schemas.IndexType) + cuIndex.AddColumn("user_id", "is_deleted") + + indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex} + + return indices +} + +func AddNewIndexForUserDashboard(x *xorm.Engine) error { + return x.Sync(new(improveActionTableIndicesAction)) +} diff --git a/models/migrations/v1_23/v309.go b/models/migrations/v1_23/v309.go new file mode 100644 index 0000000000..5b39398443 --- /dev/null +++ b/models/migrations/v1_23/v309.go @@ -0,0 +1,77 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +type improveNotificationTableIndicesAction struct { + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"NOT NULL"` + RepoID int64 `xorm:"NOT NULL"` + + Status uint8 `xorm:"SMALLINT NOT NULL"` + Source uint8 `xorm:"SMALLINT NOT NULL"` + + IssueID int64 `xorm:"NOT NULL"` + CommitID string + CommentID int64 + + UpdatedBy int64 `xorm:"NOT NULL"` + + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` +} + +// TableName sets the name of this table +func (*improveNotificationTableIndicesAction) TableName() string { + return "notification" +} + +// TableIndices implements xorm's TableIndices interface +func (*improveNotificationTableIndicesAction) TableIndices() []*schemas.Index { + indices := make([]*schemas.Index, 0, 8) + usuuIndex := schemas.NewIndex("u_s_uu", schemas.IndexType) + usuuIndex.AddColumn("user_id", "status", "updated_unix") + indices = append(indices, usuuIndex) + + // Add the individual indices that were previously defined in struct tags + userIDIndex := schemas.NewIndex("idx_notification_user_id", schemas.IndexType) + userIDIndex.AddColumn("user_id") + indices = append(indices, userIDIndex) + + repoIDIndex := schemas.NewIndex("idx_notification_repo_id", schemas.IndexType) + repoIDIndex.AddColumn("repo_id") + indices = append(indices, repoIDIndex) + + statusIndex := schemas.NewIndex("idx_notification_status", schemas.IndexType) + statusIndex.AddColumn("status") + indices = append(indices, statusIndex) + + sourceIndex := schemas.NewIndex("idx_notification_source", schemas.IndexType) + sourceIndex.AddColumn("source") + indices = append(indices, sourceIndex) + + issueIDIndex := schemas.NewIndex("idx_notification_issue_id", schemas.IndexType) + issueIDIndex.AddColumn("issue_id") + indices = append(indices, issueIDIndex) + + commitIDIndex := schemas.NewIndex("idx_notification_commit_id", schemas.IndexType) + commitIDIndex.AddColumn("commit_id") + indices = append(indices, commitIDIndex) + + updatedByIndex := schemas.NewIndex("idx_notification_updated_by", schemas.IndexType) + updatedByIndex.AddColumn("updated_by") + indices = append(indices, updatedByIndex) + + return indices +} + +func ImproveNotificationTableIndices(x *xorm.Engine) error { + return x.Sync(&improveNotificationTableIndicesAction{}) +} diff --git a/models/migrations/v1_23/v310.go b/models/migrations/v1_23/v310.go new file mode 100644 index 0000000000..394417f5a0 --- /dev/null +++ b/models/migrations/v1_23/v310.go @@ -0,0 +1,16 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "xorm.io/xorm" +) + +func AddPriorityToProtectedBranch(x *xorm.Engine) error { + type ProtectedBranch struct { + Priority int64 `xorm:"NOT NULL DEFAULT 0"` + } + + return x.Sync(new(ProtectedBranch)) +} diff --git a/models/migrations/v1_23/v311.go b/models/migrations/v1_23/v311.go new file mode 100644 index 0000000000..0fc1ac8c0e --- /dev/null +++ b/models/migrations/v1_23/v311.go @@ -0,0 +1,16 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "xorm.io/xorm" +) + +func AddTimeEstimateColumnToIssueTable(x *xorm.Engine) error { + type Issue struct { + TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"` + } + + return x.Sync(new(Issue)) +} diff --git a/models/migrations/v1_24/v312.go b/models/migrations/v1_24/v312.go new file mode 100644 index 0000000000..9766dc1ccf --- /dev/null +++ b/models/migrations/v1_24/v312.go @@ -0,0 +1,21 @@ +// 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 new file mode 100644 index 0000000000..ee9d479340 --- /dev/null +++ b/models/migrations/v1_24/v313.go @@ -0,0 +1,31 @@ +// 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/migrations/v1_24/v314.go b/models/migrations/v1_24/v314.go new file mode 100644 index 0000000000..e537be13b5 --- /dev/null +++ b/models/migrations/v1_24/v314.go @@ -0,0 +1,19 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_24 //nolint + +import ( + "xorm.io/xorm" +) + +func UpdateOwnerIDOfRepoLevelActionsTables(x *xorm.Engine) error { + if _, err := x.Exec("UPDATE `action_runner` SET `owner_id` = 0 WHERE `repo_id` > 0 AND `owner_id` > 0"); err != nil { + return err + } + if _, err := x.Exec("UPDATE `action_variable` SET `owner_id` = 0 WHERE `repo_id` > 0 AND `owner_id` > 0"); err != nil { + return err + } + _, err := x.Exec("UPDATE `secret` SET `owner_id` = 0 WHERE `repo_id` > 0 AND `owner_id` > 0") + return err +} diff --git a/models/organization/mini_org.go b/models/organization/mini_org.go deleted file mode 100644 index b1b24624c5..0000000000 --- a/models/organization/mini_org.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package organization - -import ( - "context" - "fmt" - "strings" - - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" - - "xorm.io/builder" -) - -// MinimalOrg represents a simple organization with only the needed columns -type MinimalOrg = Organization - -// GetUserOrgsList returns all organizations the given user has access to -func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, error) { - schema, err := db.TableInfo(new(user_model.User)) - if err != nil { - return nil, err - } - - outputCols := []string{ - "id", - "name", - "full_name", - "visibility", - "avatar", - "avatar_email", - "use_custom_avatar", - } - - groupByCols := &strings.Builder{} - for _, col := range outputCols { - fmt.Fprintf(groupByCols, "`%s`.%s,", schema.Name, col) - } - groupByStr := groupByCols.String() - groupByStr = groupByStr[0 : len(groupByStr)-1] - - sess := db.GetEngine(ctx) - sess = sess.Select(groupByStr+", count(distinct repo_id) as org_count"). - Table("user"). - Join("INNER", "team", "`team`.org_id = `user`.id"). - Join("INNER", "team_user", "`team`.id = `team_user`.team_id"). - Join("LEFT", builder. - Select("id as repo_id, owner_id as repo_owner_id"). - From("repository"). - Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), "`repository`.repo_owner_id = `team`.org_id"). - Where("`team_user`.uid = ?", user.ID). - GroupBy(groupByStr) - - type OrgCount struct { - Organization `xorm:"extends"` - OrgCount int - } - - orgCounts := make([]*OrgCount, 0, 10) - - if err := sess. - Asc("`user`.name"). - Find(&orgCounts); err != nil { - return nil, err - } - - orgs := make([]*MinimalOrg, len(orgCounts)) - for i, orgCount := range orgCounts { - orgCount.Organization.NumRepos = orgCount.OrgCount - orgs[i] = &orgCount.Organization - } - - return orgs, nil -} diff --git a/models/organization/org.go b/models/organization/org.go index b33d15d29c..3e55a36758 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -9,11 +9,8 @@ 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" @@ -22,15 +19,9 @@ import ( "code.gitea.io/gitea/modules/util" "xorm.io/builder" + "xorm.io/xorm" ) -// ________ .__ __ .__ -// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____ -// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \ -// / | \ | \/ /_/ > __ \| | \ |/ / / __ \| | | ( <_> ) | \ -// \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| / -// \/ /_____/ \/ \/ \/ \/ \/ - // ErrOrgNotExist represents a "OrgNotExist" kind of error. type ErrOrgNotExist struct { ID int64 @@ -141,8 +132,9 @@ func (org *Organization) LoadTeams(ctx context.Context) ([]*Team, error) { } // GetMembers returns all members of organization. -func (org *Organization) GetMembers(ctx context.Context) (user_model.UserList, map[int64]bool, error) { +func (org *Organization) GetMembers(ctx context.Context, doer *user_model.User) (user_model.UserList, map[int64]bool, error) { return FindOrgMembers(ctx, &FindOrgMembersOpts{ + Doer: doer, OrgID: org.ID, }) } @@ -195,16 +187,39 @@ func (org *Organization) CanCreateRepo() bool { // FindOrgMembersOpts represensts find org members conditions type FindOrgMembersOpts struct { db.ListOptions - OrgID int64 - PublicOnly bool + Doer *user_model.User + IsDoerMember bool + OrgID int64 +} + +func (opts FindOrgMembersOpts) PublicOnly() bool { + return opts.Doer == nil || !(opts.IsDoerMember || opts.Doer.IsAdmin) +} + +// applyTeamMatesOnlyFilter make sure restricted users only see public team members and there own team mates +func (opts FindOrgMembersOpts) applyTeamMatesOnlyFilter(sess *xorm.Session) { + if opts.Doer != nil && opts.IsDoerMember && opts.Doer.IsRestricted { + teamMates := builder.Select("DISTINCT team_user.uid"). + From("team_user"). + Where(builder.In("team_user.team_id", getUserTeamIDsQueryBuilder(opts.OrgID, opts.Doer.ID))). + And(builder.Eq{"team_user.org_id": opts.OrgID}) + + sess.And( + builder.In("org_user.uid", teamMates). + Or(builder.Eq{"org_user.is_public": true}), + ) + } } // CountOrgMembers counts the organization's members func CountOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (int64, error) { sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID) - if opts.PublicOnly { - sess.And("is_public = ?", true) + if opts.PublicOnly() { + sess = sess.And("is_public = ?", true) + } else { + opts.applyTeamMatesOnlyFilter(sess) } + return sess.Count(new(OrgUser)) } @@ -389,33 +404,6 @@ 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 @@ -440,42 +428,6 @@ func GetUsersWhoCanCreateOrgRepo(ctx context.Context, orgID int64) (map[int64]*u And("team_user.org_id = ?", orgID).Find(&users) } -// SearchOrganizationsOptions options to filter organizations -type SearchOrganizationsOptions struct { - db.ListOptions - All bool -} - -// FindOrgOptions finds orgs options -type FindOrgOptions struct { - db.ListOptions - UserID int64 - IncludePrivate bool -} - -func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder { - cond := builder.Eq{"uid": userID} - if !includePrivate { - cond["is_public"] = true - } - return builder.Select("org_id").From("org_user").Where(cond) -} - -func (opts FindOrgOptions) ToConds() builder.Cond { - var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeOrganization} - if opts.UserID > 0 { - cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate))) - } - if !opts.IncludePrivate { - cond = cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}) - } - return cond -} - -func (opts FindOrgOptions) ToOrders() string { - return "`user`.name ASC" -} - // HasOrgOrUserVisible tells if the given user can see the given org or user func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool { // If user is nil, it's an anonymous user/request. @@ -508,26 +460,15 @@ func HasOrgsVisible(ctx context.Context, orgs []*Organization, user *user_model. return false } -// GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID -// are allowed to create repos. -func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organization, error) { - orgs := make([]*Organization, 0, 10) - - return orgs, db.GetEngine(ctx).Where(builder.In("id", builder.Select("`user`.id").From("`user`"). - Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id"). - Join("INNER", "`team`", "`team`.id = `team_user`.team_id"). - Where(builder.Eq{"`team_user`.uid": userID}). - And(builder.Eq{"`team`.authorize": perm.AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})))). - Asc("`user`.name"). - Find(&orgs) -} - // GetOrgUsersByOrgID returns all organization-user relations by organization ID. func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) { sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID) - if opts.PublicOnly { - sess.And("is_public = ?", true) + if opts.PublicOnly() { + sess = sess.And("is_public = ?", true) + } else { + opts.applyTeamMatesOnlyFilter(sess) } + if opts.ListOptions.PageSize > 0 { sess = db.SetSessionPagination(sess, opts) @@ -633,7 +574,9 @@ func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error { return err } -func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) { +// 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) { teams := make([]*Team, 0, org.NumTeams) return teams, db.GetEngine(ctx). Where("`team_user`.org_id = ?", org.ID). @@ -645,7 +588,8 @@ func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols .. Find(&teams) } -func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) { +// 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) { teamIDs := make([]int64, 0, org.NumTeams) return teamIDs, db.GetEngine(ctx). Table("team"). @@ -656,179 +600,16 @@ func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]in Find(&teamIDs) } +func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder { + return builder.Select("team.id").From("team"). + InnerJoin("team_user", "team_user.team_id = team.id"). + Where(builder.Eq{ + "team_user.org_id": orgID, + "team_user.uid": userID, + }) +} + // TeamsWithAccessToRepo returns all teams that have given access level to the repository. 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 new file mode 100644 index 0000000000..78ac0e704a --- /dev/null +++ b/models/organization/org_list.go @@ -0,0 +1,164 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package organization + +import ( + "context" + "fmt" + "strings" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/structs" + + "xorm.io/builder" +) + +type OrgList []*Organization + +func (orgs OrgList) LoadTeams(ctx context.Context) (map[int64]TeamList, error) { + if len(orgs) == 0 { + return map[int64]TeamList{}, nil + } + + orgIDs := make([]int64, len(orgs)) + for i, org := range orgs { + orgIDs[i] = org.ID + } + + teams, err := GetTeamsByOrgIDs(ctx, orgIDs) + if err != nil { + return nil, err + } + + teamMap := make(map[int64]TeamList, len(orgs)) + for _, team := range teams { + teamMap[team.OrgID] = append(teamMap[team.OrgID], team) + } + + return teamMap, nil +} + +// SearchOrganizationsOptions options to filter organizations +type SearchOrganizationsOptions struct { + db.ListOptions + All bool +} + +// FindOrgOptions finds orgs options +type FindOrgOptions struct { + db.ListOptions + UserID int64 + IncludePrivate bool +} + +func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder { + cond := builder.Eq{"uid": userID} + if !includePrivate { + cond["is_public"] = true + } + return builder.Select("org_id").From("org_user").Where(cond) +} + +func (opts FindOrgOptions) ToConds() builder.Cond { + var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeOrganization} + if opts.UserID > 0 { + cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate))) + } + if !opts.IncludePrivate { + cond = cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}) + } + return cond +} + +func (opts FindOrgOptions) ToOrders() string { + return "`user`.lower_name ASC" +} + +// GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID +// are allowed to create repos. +func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organization, error) { + orgs := make([]*Organization, 0, 10) + + return orgs, db.GetEngine(ctx).Where(builder.In("id", builder.Select("`user`.id").From("`user`"). + Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id"). + Join("INNER", "`team`", "`team`.id = `team_user`.team_id"). + Where(builder.Eq{"`team_user`.uid": userID}). + And(builder.Eq{"`team`.authorize": perm.AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})))). + Asc("`user`.name"). + Find(&orgs) +} + +// MinimalOrg represents a simple organization with only the needed columns +type MinimalOrg = Organization + +// GetUserOrgsList returns all organizations the given user has access to +func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, error) { + schema, err := db.TableInfo(new(user_model.User)) + if err != nil { + return nil, err + } + + outputCols := []string{ + "id", + "name", + "full_name", + "visibility", + "avatar", + "avatar_email", + "use_custom_avatar", + } + + selectColumns := &strings.Builder{} + for i, col := range outputCols { + fmt.Fprintf(selectColumns, "`%s`.%s", schema.Name, col) + if i < len(outputCols)-1 { + selectColumns.WriteString(", ") + } + } + columnsStr := selectColumns.String() + + var orgs []*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 + } + + type orgCount struct { + OrgID int64 + RepoCount int + } + var orgCounts []orgCount + if err := db.GetEngine(ctx). + Select("owner_id AS org_id, COUNT(DISTINCT(repository.id)) as repo_count"). + Table("repository"). + Join("INNER", "org_user", "owner_id = org_user.org_id"). + Where("org_user.uid = ?", user.ID). + And(builder.Or( + builder.Eq{"repository.is_private": false}, + builder.In("repository.id", builder.Select("repo_id").From("team_repo"). + InnerJoin("team_user", "team_user.team_id = team_repo.team_id"). + Where(builder.Eq{"team_user.uid": user.ID})), + builder.In("repository.id", builder.Select("repo_id").From("collaboration"). + Where(builder.Eq{"user_id": user.ID})), + )). + GroupBy("owner_id").Find(&orgCounts); err != nil { + return nil, err + } + + orgCountMap := make(map[int64]int, len(orgCounts)) + for _, orgCount := range orgCounts { + orgCountMap[orgCount.OrgID] = orgCount.RepoCount + } + + for _, org := range orgs { + org.NumRepos = orgCountMap[org.ID] + } + + return orgs, nil +} diff --git a/models/organization/org_list_test.go b/models/organization/org_list_test.go new file mode 100644 index 0000000000..0f0f8a4bcd --- /dev/null +++ b/models/organization/org_list_test.go @@ -0,0 +1,73 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package organization_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + + "github.com/stretchr/testify/assert" +) + +func TestCountOrganizations(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&organization.Organization{}) + assert.NoError(t, err) + cnt, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true}) + assert.NoError(t, err) + assert.Equal(t, expected, cnt) +} + +func TestFindOrgs(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + orgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ + UserID: 4, + IncludePrivate: true, + }) + assert.NoError(t, err) + if assert.Len(t, orgs, 1) { + assert.EqualValues(t, 3, orgs[0].ID) + } + + orgs, err = db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ + UserID: 4, + IncludePrivate: false, + }) + assert.NoError(t, err) + assert.Empty(t, orgs) + + total, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ + UserID: 4, + IncludePrivate: true, + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, total) +} + +func TestGetUserOrgsList(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + orgs, err := organization.GetUserOrgsList(db.DefaultContext, &user_model.User{ID: 4}) + assert.NoError(t, err) + if assert.Len(t, orgs, 1) { + assert.EqualValues(t, 3, orgs[0].ID) + // repo_id: 3 is in the team, 32 is public, 5 is private with no team + assert.EqualValues(t, 2, orgs[0].NumRepos) + } +} + +func TestLoadOrgListTeams(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + orgs, err := organization.GetUserOrgsList(db.DefaultContext, &user_model.User{ID: 4}) + assert.NoError(t, err) + assert.Len(t, orgs, 1) + teamsMap, err := organization.OrgList(orgs).LoadTeams(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, teamsMap, 1) + assert.Len(t, teamsMap[3], 5) +} diff --git a/models/organization/org_repo.go b/models/organization/org_repo.go deleted file mode 100644 index f7e59928f4..0000000000 --- a/models/organization/org_repo.go +++ /dev/null @@ -1,17 +0,0 @@ -// 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 23ef22e2fb..6638abd8e0 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -4,6 +4,8 @@ package organization_test import ( + "slices" + "sort" "testing" "code.gitea.io/gitea/models/db" @@ -14,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestUser_IsOwnedBy(t *testing.T) { @@ -103,7 +106,7 @@ func TestUser_GetTeams(t *testing.T) { func TestUser_GetMembers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) - members, _, err := org.GetMembers(db.DefaultContext) + members, _, err := org.GetMembers(db.DefaultContext, &user_model.User{IsAdmin: true}) assert.NoError(t, err) if assert.Len(t, members, 3) { assert.Equal(t, int64(2), members[0].ID) @@ -127,15 +130,6 @@ func TestGetOrgByName(t *testing.T) { assert.True(t, organization.IsErrOrgNotExist(err)) } -func TestCountOrganizations(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&organization.Organization{}) - assert.NoError(t, err) - cnt, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true}) - assert.NoError(t, err) - assert.Equal(t, expected, cnt) -} - func TestIsOrganizationOwner(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(orgID, userID int64, expected bool) { @@ -180,70 +174,116 @@ func TestIsPublicMembership(t *testing.T) { test(unittest.NonexistentID, unittest.NonexistentID, false) } -func TestFindOrgs(t *testing.T) { +func TestRestrictedUserOrgMembers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - orgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ - UserID: 4, - IncludePrivate: true, + restrictedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ + ID: 29, + IsRestricted: true, }) - assert.NoError(t, err) - if assert.Len(t, orgs, 1) { - assert.EqualValues(t, 3, orgs[0].ID) + // ensure fixtures return restricted user + require.True(t, restrictedUser.IsRestricted) + + testCases := []struct { + name string + opts *organization.FindOrgMembersOpts + expectedUIDs []int64 + }{ + { + name: "restricted user sees public members and teammates", + opts: &organization.FindOrgMembersOpts{ + OrgID: 17, // org17 where user29 is in team9 + Doer: restrictedUser, + IsDoerMember: true, + }, + expectedUIDs: []int64{2, 15, 20, 29}, // Public members (2) + teammates in team9 (15, 20, 29) + }, + { + name: "restricted user sees only public members when not member", + opts: &organization.FindOrgMembersOpts{ + OrgID: 3, // org3 where user29 is not a member + Doer: restrictedUser, + }, + expectedUIDs: []int64{2, 28}, // Only public members + }, + { + name: "non logged in only shows public members", + opts: &organization.FindOrgMembersOpts{ + OrgID: 3, + }, + expectedUIDs: []int64{2, 28}, // Only public members + }, + { + name: "non restricted user sees all members", + opts: &organization.FindOrgMembersOpts{ + OrgID: 17, + Doer: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}), + IsDoerMember: true, + }, + expectedUIDs: []int64{2, 15, 18, 20, 29}, // All members + }, } - orgs, err = db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ - UserID: 4, - IncludePrivate: false, - }) - assert.NoError(t, err) - assert.Len(t, orgs, 0) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + count, err := organization.CountOrgMembers(db.DefaultContext, tc.opts) + assert.NoError(t, err) + assert.EqualValues(t, len(tc.expectedUIDs), count) - total, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ - UserID: 4, - IncludePrivate: true, - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, total) + members, err := organization.GetOrgUsersByOrgID(db.DefaultContext, tc.opts) + assert.NoError(t, err) + memberUIDs := make([]int64, 0, len(members)) + for _, member := range members { + memberUIDs = append(memberUIDs, member.UID) + } + slices.Sort(memberUIDs) + assert.EqualValues(t, tc.expectedUIDs, memberUIDs) + }) + } } func TestGetOrgUsersByOrgID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - orgUsers, err := organization.GetOrgUsersByOrgID(db.DefaultContext, &organization.FindOrgMembersOpts{ - ListOptions: db.ListOptions{}, - OrgID: 3, - PublicOnly: false, - }) - assert.NoError(t, err) - if assert.Len(t, orgUsers, 3) { - assert.Equal(t, organization.OrgUser{ - ID: orgUsers[0].ID, - OrgID: 3, - UID: 2, - IsPublic: true, - }, *orgUsers[0]) - assert.Equal(t, organization.OrgUser{ - ID: orgUsers[1].ID, - OrgID: 3, - UID: 4, - IsPublic: false, - }, *orgUsers[1]) - assert.Equal(t, organization.OrgUser{ - ID: orgUsers[2].ID, - OrgID: 3, - UID: 28, - IsPublic: true, - }, *orgUsers[2]) + opts := &organization.FindOrgMembersOpts{ + Doer: &user_model.User{IsAdmin: true}, + OrgID: 3, } + assert.False(t, opts.PublicOnly()) + orgUsers, err := organization.GetOrgUsersByOrgID(db.DefaultContext, opts) + assert.NoError(t, err) + sort.Slice(orgUsers, func(i, j int) bool { + return orgUsers[i].ID < orgUsers[j].ID + }) + assert.EqualValues(t, []*organization.OrgUser{{ + ID: 1, + OrgID: 3, + UID: 2, + IsPublic: true, + }, { + ID: 2, + OrgID: 3, + UID: 4, + IsPublic: false, + }, { + ID: 9, + OrgID: 3, + UID: 28, + IsPublic: true, + }}, orgUsers) + + opts = &organization.FindOrgMembersOpts{OrgID: 3} + assert.True(t, opts.PublicOnly()) + orgUsers, err = organization.GetOrgUsersByOrgID(db.DefaultContext, opts) + assert.NoError(t, err) + assert.Len(t, orgUsers, 2) orgUsers, err = organization.GetOrgUsersByOrgID(db.DefaultContext, &organization.FindOrgMembersOpts{ ListOptions: db.ListOptions{}, OrgID: unittest.NonexistentID, - PublicOnly: false, }) assert.NoError(t, err) - assert.Len(t, orgUsers, 0) + assert.Empty(t, orgUsers) } func TestChangeOrgUserStatus(t *testing.T) { @@ -278,9 +318,9 @@ 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 := organization.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) - count, err := env.CountRepos() + count, err := env.CountRepos(db.DefaultContext) assert.NoError(t, err) assert.EqualValues(t, expectedCount, count) } @@ -292,9 +332,9 @@ 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 := organization.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) - repoIDs, err := env.RepoIDs(1, 100) + repoIDs, err := env.RepoIDs(db.DefaultContext, 1, 100) assert.NoError(t, err) assert.Equal(t, expectedRepoIDs, repoIDs) } @@ -306,9 +346,9 @@ 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 := organization.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) - repos, err := env.Repos(1, 100) + repos, err := env.Repos(db.DefaultContext, 1, 100) assert.NoError(t, err) expectedRepos := make(repo_model.RepositoryList, len(expectedRepoIDs)) for i, repoID := range expectedRepoIDs { @@ -325,9 +365,9 @@ 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 := organization.AccessibleReposEnv(db.DefaultContext, org, userID) + env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) - repos, err := env.MirrorRepos() + repos, err := env.MirrorRepos(db.DefaultContext) assert.NoError(t, err) expectedRepos := make(repo_model.RepositoryList, len(expectedRepoIDs)) for i, repoID := range expectedRepoIDs { diff --git a/models/organization/org_user.go b/models/organization/org_user.go index 1d3b2fab44..08d936d922 100644 --- a/models/organization/org_user.go +++ b/models/organization/org_user.go @@ -36,6 +36,21 @@ 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 cf7acdf83b..c5110b2a34 100644 --- a/models/organization/org_user_test.go +++ b/models/organization/org_user_test.go @@ -94,7 +94,7 @@ func TestUserListIsPublicMember(t *testing.T) { func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) { org, err := organization.GetOrgByID(db.DefaultContext, orgID) assert.NoError(t, err) - _, membersIsPublic, err := org.GetMembers(db.DefaultContext) + _, membersIsPublic, err := org.GetMembers(db.DefaultContext, &user_model.User{IsAdmin: true}) assert.NoError(t, err) assert.Equal(t, expected, membersIsPublic) } @@ -121,7 +121,7 @@ func TestUserListIsUserOrgOwner(t *testing.T) { func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) { org, err := organization.GetOrgByID(db.DefaultContext, orgID) assert.NoError(t, err) - members, _, err := org.GetMembers(db.DefaultContext) + members, _, err := org.GetMembers(db.DefaultContext, &user_model.User{IsAdmin: true}) assert.NoError(t, err) assert.Equal(t, expected, organization.IsUserOrgOwner(db.DefaultContext, members, orgID)) } @@ -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.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) { + if unittest.GetBean(t, &organization.OrgUser{OrgID: orgID, UID: userID}) == nil { expectedNumMembers++ } assert.NoError(t, organization.AddOrgUser(db.DefaultContext, orgID, userID)) diff --git a/models/organization/org_worktime.go b/models/organization/org_worktime.go new file mode 100644 index 0000000000..7b57182a8a --- /dev/null +++ b/models/organization/org_worktime.go @@ -0,0 +1,103 @@ +// 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 fb7f0c0493..96666da39a 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -11,7 +11,6 @@ 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" @@ -78,9 +77,8 @@ type Team struct { LowerName string Name string Description string - AccessMode perm.AccessMode `xorm:"'authorize'"` - Repos []*repo_model.Repository `xorm:"-"` - Members []*user_model.User `xorm:"-"` + AccessMode perm.AccessMode `xorm:"'authorize'"` + Members []*user_model.User `xorm:"-"` NumRepos int NumMembers int Units []*TeamUnit `xorm:"-"` @@ -155,17 +153,6 @@ 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 5b45429acf..0274f9c5ba 100644 --- a/models/organization/team_list.go +++ b/models/organization/team_list.go @@ -9,7 +9,6 @@ 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" @@ -98,11 +97,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, repo *repo_model.Repository) (teams TeamList, err error) { +func GetRepoTeams(ctx context.Context, orgID, repoID int64) (teams TeamList, err error) { return teams, db.GetEngine(ctx). Join("INNER", "team_repo", "team_repo.team_id = team.id"). - Where("team.org_id = ?", repo.OwnerID). - And("team_repo.repo_id=?", repo.ID). + Where("team.org_id = ?", orgID). + And("team_repo.repo_id=?", repoID). OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END"). Find(&teams) } @@ -126,3 +125,16 @@ func GetUserRepoTeams(ctx context.Context, orgID, userID, repoID int64) (teams T And("team_repo.repo_id=?", repoID). Find(&teams) } + +func GetTeamsByOrgIDs(ctx context.Context, orgIDs []int64) (TeamList, error) { + teams := make([]*Team, 0, 10) + return teams, db.GetEngine(ctx).Where(builder.In("org_id", orgIDs)).Find(&teams) +} + +func GetTeamsByIDs(ctx context.Context, teamIDs []int64) (map[int64]*Team, error) { + teams := make(map[int64]*Team, len(teamIDs)) + if len(teamIDs) == 0 { + return teams, nil + } + return teams, db.GetEngine(ctx).Where(builder.In("`id`", teamIDs)).Find(&teams) +} diff --git a/models/organization/team_list_test.go b/models/organization/team_list_test.go new file mode 100644 index 0000000000..5526446e22 --- /dev/null +++ b/models/organization/team_list_test.go @@ -0,0 +1,25 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package organization_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + org_model "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func Test_GetTeamsByIDs(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // 1 owner team, 2 normal team + teams, err := org_model.GetTeamsByIDs(db.DefaultContext, []int64{1, 2}) + assert.NoError(t, err) + assert.Len(t, teams, 2) + assert.Equal(t, "Owners", teams[1].Name) + assert.Equal(t, "team1", teams[2].Name) +} diff --git a/models/organization/team_repo.go b/models/organization/team_repo.go index 1184e39263..53edd203a8 100644 --- a/models/organization/team_repo.go +++ b/models/organization/team_repo.go @@ -8,9 +8,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" - repo_model "code.gitea.io/gitea/models/repo" - - "xorm.io/builder" + "code.gitea.io/gitea/models/unit" ) // TeamRepo represents an team-repository relation. @@ -31,29 +29,6 @@ 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{ @@ -83,3 +58,16 @@ func GetTeamsWithAccessToRepo(ctx context.Context, orgID, repoID int64, mode per OrderBy("name"). Find(&teams) } + +// GetTeamsWithAccessToRepoUnit returns all teams in an organization that have given access level to the repository special unit. +func GetTeamsWithAccessToRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type) ([]*Team, error) { + teams := make([]*Team, 0, 5) + return teams, db.GetEngine(ctx).Where("team_unit.access_mode >= ?", mode). + Join("INNER", "team_repo", "team_repo.team_id = team.id"). + Join("INNER", "team_unit", "team_unit.team_id = team.id"). + And("team_repo.org_id = ?", orgID). + And("team_repo.repo_id = ?", repoID). + And("team_unit.type = ?", unitType). + OrderBy("name"). + Find(&teams) +} diff --git a/models/organization/team_repo_test.go b/models/organization/team_repo_test.go new file mode 100644 index 0000000000..c0d6750df9 --- /dev/null +++ b/models/organization/team_repo_test.go @@ -0,0 +1,31 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package organization_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/perm" + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestGetTeamsWithAccessToRepoUnit(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + org41 := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 41}) + repo61 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 61}) + + teams, err := organization.GetTeamsWithAccessToRepoUnit(db.DefaultContext, org41.ID, repo61.ID, perm.AccessModeRead, unit.TypePullRequests) + assert.NoError(t, err) + if assert.Len(t, teams, 2) { + assert.EqualValues(t, 21, teams[0].ID) + assert.EqualValues(t, 22, teams[1].ID) + } +} diff --git a/models/organization/team_test.go b/models/organization/team_test.go index 23a6affe24..deaabbfa2c 100644 --- a/models/organization/team_test.go +++ b/models/organization/team_test.go @@ -8,6 +8,7 @@ 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" @@ -42,9 +43,12 @@ func TestTeam_GetRepositories(t *testing.T) { test := func(teamID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, team.LoadRepositories(db.DefaultContext)) - assert.Len(t, team.Repos, team.NumRepos) - for _, repo := range team.Repos { + 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 { unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID}) } } @@ -197,3 +201,8 @@ func TestUsersInTeamsCount(t *testing.T) { test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2) // userid 2,4 test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3) // userid 2,4,5 } + +func TestIsUsableTeamName(t *testing.T) { + assert.NoError(t, organization.IsUsableTeamName("usable")) + assert.True(t, db.IsErrNameReserved(organization.IsUsableTeamName("new"))) +} diff --git a/models/packages/arch/search.go b/models/packages/arch/search.go new file mode 100644 index 0000000000..f35c037b23 --- /dev/null +++ b/models/packages/arch/search.go @@ -0,0 +1,38 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package arch + +import ( + "context" + + packages_model "code.gitea.io/gitea/models/packages" + arch_module "code.gitea.io/gitea/modules/packages/arch" +) + +// GetRepositories gets all available repositories +func GetRepositories(ctx context.Context, ownerID int64) ([]string, error) { + return packages_model.GetDistinctPropertyValues( + ctx, + packages_model.TypeArch, + ownerID, + packages_model.PropertyTypeFile, + arch_module.PropertyRepository, + nil, + ) +} + +// GetArchitectures gets all available architectures for the given repository +func GetArchitectures(ctx context.Context, ownerID int64, repository string) ([]string, error) { + return packages_model.GetDistinctPropertyValues( + ctx, + packages_model.TypeArch, + ownerID, + packages_model.PropertyTypeFile, + arch_module.PropertyArchitecture, + &packages_model.DistinctPropertyDependency{ + Name: arch_module.PropertyRepository, + Value: repository, + }, + ) +} diff --git a/models/packages/debian/search.go b/models/packages/debian/search.go index 77c4a18462..5333d0c6e4 100644 --- a/models/packages/debian/search.go +++ b/models/packages/debian/search.go @@ -75,26 +75,27 @@ func ExistPackages(ctx context.Context, opts *PackageSearchOptions) (bool, error } // SearchPackages gets the packages matching the search options -func SearchPackages(ctx context.Context, opts *PackageSearchOptions, iter func(*packages.PackageFileDescriptor)) error { - return db.GetEngine(ctx). +func SearchPackages(ctx context.Context, opts *PackageSearchOptions) ([]*packages.PackageFileDescriptor, error) { + var pkgFiles []*packages.PackageFile + err := db.GetEngine(ctx). Table("package_file"). Select("package_file.*"). Join("INNER", "package_version", "package_version.id = package_file.version_id"). Join("INNER", "package", "package.id = package_version.package_id"). Where(opts.toCond()). - Asc("package.lower_name", "package_version.created_unix"). - Iterate(new(packages.PackageFile), func(_ int, bean any) error { - pf := bean.(*packages.PackageFile) - - pfd, err := packages.GetPackageFileDescriptor(ctx, pf) - if err != nil { - return err - } - - iter(pfd) - - return nil - }) + Asc("package.lower_name", "package_version.created_unix").Find(&pkgFiles) + if err != nil { + return nil, err + } + pfds := make([]*packages.PackageFileDescriptor, 0, len(pkgFiles)) + for _, pf := range pkgFiles { + pfd, err := packages.GetPackageFileDescriptor(ctx, pf) + if err != nil { + return nil, err + } + pfds = append(pfds, pfd) + } + return pfds, nil } // GetDistributions gets all available distributions diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go index b8ef698d38..d251fcc4a9 100644 --- a/models/packages/descriptor.go +++ b/models/packages/descriptor.go @@ -13,6 +13,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/packages/alpine" + "code.gitea.io/gitea/modules/packages/arch" "code.gitea.io/gitea/modules/packages/cargo" "code.gitea.io/gitea/modules/packages/chef" "code.gitea.io/gitea/modules/packages/composer" @@ -109,9 +110,12 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc if err != nil { return nil, err } - repository, err := repo_model.GetRepositoryByID(ctx, p.RepoID) - if err != nil && !repo_model.IsErrRepoNotExist(err) { - 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 + } } creator, err := user_model.GetUserByID(ctx, pv.CreatorID) if err != nil { @@ -150,6 +154,8 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc switch p.Type { case TypeAlpine: metadata = &alpine.VersionMetadata{} + case TypeArch: + metadata = &arch.VersionMetadata{} case TypeCargo: metadata = &cargo.Metadata{} case TypeChef: diff --git a/models/packages/package.go b/models/packages/package.go index 65a2574150..8935dbaa1c 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -31,6 +31,7 @@ type Type string // List of supported packages const ( TypeAlpine Type = "alpine" + TypeArch Type = "arch" TypeCargo Type = "cargo" TypeChef Type = "chef" TypeComposer Type = "composer" @@ -55,6 +56,7 @@ const ( var TypeList = []Type{ TypeAlpine, + TypeArch, TypeCargo, TypeChef, TypeComposer, @@ -82,6 +84,8 @@ func (pt Type) Name() string { switch pt { case TypeAlpine: return "Alpine" + case TypeArch: + return "Arch" case TypeCargo: return "Cargo" case TypeChef: @@ -131,6 +135,8 @@ func (pt Type) SVGName() string { switch pt { case TypeAlpine: return "gitea-alpine" + case TypeArch: + return "gitea-arch" case TypeCargo: return "gitea-cargo" case TypeChef: @@ -222,6 +228,11 @@ 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{}) @@ -242,6 +253,18 @@ func GetPackageByID(ctx context.Context, packageID int64) (*Package, error) { return p, nil } +// UpdatePackageNameByID updates the package's name, it is only for internal usage, for example: rename some legacy packages +func UpdatePackageNameByID(ctx context.Context, ownerID int64, packageType Type, packageID int64, name string) error { + var cond builder.Cond = builder.Eq{ + "package.id": packageID, + "package.owner_id": ownerID, + "package.type": packageType, + "package.is_internal": false, + } + _, err := db.GetEngine(ctx).Where(cond).Update(&Package{Name: name, LowerName: strings.ToLower(name)}) + return err +} + // GetPackageByName gets a package by name func GetPackageByName(ctx context.Context, ownerID int64, packageType Type, name string) (*Package, error) { var cond builder.Cond = builder.Eq{ @@ -295,6 +318,21 @@ 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/packages/package_file.go b/models/packages/package_file.go index 1bb6b57a34..270cb32fdf 100644 --- a/models/packages/package_file.go +++ b/models/packages/package_file.go @@ -221,6 +221,11 @@ func SearchFiles(ctx context.Context, opts *PackageFileSearchOptions) ([]*Packag return pfs, count, err } +// HasFiles tests if there are files of packages matching the search options +func HasFiles(ctx context.Context, opts *PackageFileSearchOptions) (bool, error) { + return db.Exist[PackageFile](ctx, opts.toConds()) +} + // CalculateFileSize sums up all blob sizes matching the search options. // It does NOT respect the deduplication of blobs. func CalculateFileSize(ctx context.Context, opts *PackageFileSearchOptions) (int64, error) { diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 0ed116a132..5e7ecb31ea 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 { @@ -187,17 +193,40 @@ func applyEveryoneRepoPermission(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 { - applyEveryoneRepoPermission(user, &perm) - } - if log.IsTrace() { - log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm) + finalProcessRepoUnitPermission(user, &perm) } + log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm) }() if err = repo.LoadUnits(ctx); err != nil { @@ -294,16 +323,6 @@ 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 50070c4368..9862da0673 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}, }, } - applyEveryoneRepoPermission(nil, &perm) + finalProcessRepoUnitPermission(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}, }, } - applyEveryoneRepoPermission(&user_model.User{ID: 0}, &perm) + finalProcessRepoUnitPermission(&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}, }, } - applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) + finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm) assert.True(t, perm.CanRead(unit.TypeWiki)) perm = Permission{ @@ -77,20 +77,22 @@ func TestApplyEveryoneRepoPermission(t *testing.T) { {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, }, } - applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) + finalProcessRepoUnitPermission(&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, }, } - applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) + finalProcessRepoUnitPermission(&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/perm/access_mode.go b/models/perm/access_mode.go index 0364191e2e..6baeb5531a 100644 --- a/models/perm/access_mode.go +++ b/models/perm/access_mode.go @@ -60,3 +60,6 @@ func ParseAccessMode(permission string, allowed ...AccessMode) AccessMode { } return util.Iif(slices.Contains(allowed, m), m, AccessModeNone) } + +// ErrInvalidAccessMode is returned when an invalid access mode is used +var ErrInvalidAccessMode = util.NewInvalidArgumentErrorf("Invalid access mode") diff --git a/models/perm/access_mode_test.go b/models/perm/access_mode_test.go index 982fceee5a..c4c7d483fb 100644 --- a/models/perm/access_mode_test.go +++ b/models/perm/access_mode_test.go @@ -15,7 +15,7 @@ func TestAccessMode(t *testing.T) { m := ParseAccessMode(name) assert.Equal(t, AccessMode(i), m) } - assert.Equal(t, AccessMode(4), AccessModeOwner) + assert.Equal(t, AccessModeOwner, AccessMode(4)) assert.Equal(t, "owner", AccessModeOwner.ToString()) assert.Equal(t, AccessModeNone, ParseAccessMode("owner")) assert.Equal(t, AccessModeNone, ParseAccessMode("invalid")) diff --git a/models/project/column.go b/models/project/column.go index 222f448599..77ff5ef83e 100644 --- a/models/project/column.go +++ b/models/project/column.go @@ -48,6 +48,8 @@ type Column struct { ProjectID int64 `xorm:"INDEX NOT NULL"` CreatorID int64 `xorm:"NOT NULL"` + NumIssues int64 `xorm:"-"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` } @@ -57,20 +59,6 @@ func (Column) TableName() string { return "project_board" // TODO: the legacy table name should be project_column } -// NumIssues return counter of all issues assigned to the column -func (c *Column) NumIssues(ctx context.Context) int { - total, err := db.GetEngine(ctx).Table("project_issue"). - Where("project_id=?", c.ProjectID). - And("project_board_id=?", c.ID). - GroupBy("issue_id"). - Cols("issue_id"). - Count() - if err != nil { - return 0 - } - return int(total) -} - func (c *Column) GetIssues(ctx context.Context) ([]*ProjectIssue, error) { issues := make([]*ProjectIssue, 0, 5) if err := db.GetEngine(ctx).Where("project_id=?", c.ProjectID). @@ -192,7 +180,7 @@ func deleteColumnByID(ctx context.Context, columnID int64) error { if err != nil { return err } - defaultColumn, err := project.GetDefaultColumn(ctx) + defaultColumn, err := project.MustDefaultColumn(ctx) if err != nil { return err } @@ -257,8 +245,8 @@ func (p *Project) GetColumns(ctx context.Context) (ColumnList, error) { return columns, nil } -// GetDefaultColumn return default column and ensure only one exists -func (p *Project) GetDefaultColumn(ctx context.Context) (*Column, error) { +// getDefaultColumn return default column and ensure only one exists +func (p *Project) getDefaultColumn(ctx context.Context) (*Column, error) { var column Column has, err := db.GetEngine(ctx). Where("project_id=? AND `default` = ?", p.ID, true). @@ -270,6 +258,33 @@ func (p *Project) GetDefaultColumn(ctx context.Context) (*Column, error) { if has { return &column, nil } + return nil, ErrProjectColumnNotExist{ColumnID: 0} +} + +// MustDefaultColumn returns the default column for a project. +// If one exists, it is returned +// If none exists, the first column will be elevated to the default column of this project +func (p *Project) MustDefaultColumn(ctx context.Context) (*Column, error) { + c, err := p.getDefaultColumn(ctx) + if err != nil && !IsErrProjectColumnNotExist(err) { + return nil, err + } + if c != nil { + return c, nil + } + + var column Column + has, err := db.GetEngine(ctx).Where("project_id=?", p.ID).OrderBy("sorting, id").Get(&column) + if err != nil { + return nil, err + } + if has { + column.Default = true + if _, err := db.GetEngine(ctx).ID(column.ID).Cols("`default`").Update(&column); err != nil { + return nil, err + } + return &column, nil + } // create a default column if none is found column = Column{ @@ -321,6 +336,9 @@ func UpdateColumnSorting(ctx context.Context, cl ColumnList) error { func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (ColumnList, error) { columns := make([]*Column, 0, 5) + if len(columnsIDs) == 0 { + return columns, nil + } if err := db.GetEngine(ctx). Where("project_id =?", projectID). In("id", columnsIDs). diff --git a/models/project/column_test.go b/models/project/column_test.go index 911649fb72..66db23a3e4 100644 --- a/models/project/column_test.go +++ b/models/project/column_test.go @@ -5,7 +5,6 @@ package project import ( "fmt" - "strings" "testing" "code.gitea.io/gitea/models/db" @@ -21,19 +20,19 @@ func TestGetDefaultColumn(t *testing.T) { assert.NoError(t, err) // check if default column was added - column, err := projectWithoutDefault.GetDefaultColumn(db.DefaultContext) + column, err := projectWithoutDefault.MustDefaultColumn(db.DefaultContext) assert.NoError(t, err) assert.Equal(t, int64(5), column.ProjectID) - assert.Equal(t, "Uncategorized", column.Title) + assert.Equal(t, "Done", column.Title) projectWithMultipleDefaults, err := GetProjectByID(db.DefaultContext, 6) assert.NoError(t, err) // check if multiple defaults were removed - column, err = projectWithMultipleDefaults.GetDefaultColumn(db.DefaultContext) + column, err = projectWithMultipleDefaults.MustDefaultColumn(db.DefaultContext) assert.NoError(t, err) assert.Equal(t, int64(6), column.ProjectID) - assert.Equal(t, int64(9), column.ID) + assert.Equal(t, int64(9), column.ID) // there are 2 default columns in the test data, use the latest one // set 8 as default column assert.NoError(t, SetDefaultColumn(db.DefaultContext, column.ProjectID, 8)) @@ -66,7 +65,7 @@ func Test_moveIssuesToAnotherColumn(t *testing.T) { issues, err = column1.GetIssues(db.DefaultContext) assert.NoError(t, err) - assert.Len(t, issues, 0) + assert.Empty(t, issues) issues, err = column2.GetIssues(db.DefaultContext) assert.NoError(t, err) @@ -123,5 +122,5 @@ func Test_NewColumn(t *testing.T) { ProjectID: project1.ID, }) assert.Error(t, err) - assert.True(t, strings.Contains(err.Error(), "maximum number of columns reached")) + assert.Contains(t, err.Error(), "maximum number of columns reached") } diff --git a/models/project/issue.go b/models/project/issue.go index b4347a9c2b..98eed2a213 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -8,7 +8,6 @@ import ( "fmt" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" ) @@ -34,48 +33,6 @@ func deleteProjectIssuesByProjectID(ctx context.Context, projectID int64) error return err } -// NumIssues return counter of all issues assigned to a project -func (p *Project) NumIssues(ctx context.Context) int { - c, err := db.GetEngine(ctx).Table("project_issue"). - Where("project_id=?", p.ID). - GroupBy("issue_id"). - Cols("issue_id"). - Count() - if err != nil { - log.Error("NumIssues: %v", err) - return 0 - } - return int(c) -} - -// NumClosedIssues return counter of closed issues assigned to a project -func (p *Project) NumClosedIssues(ctx context.Context) int { - c, err := db.GetEngine(ctx).Table("project_issue"). - Join("INNER", "issue", "project_issue.issue_id=issue.id"). - Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, true). - Cols("issue_id"). - Count() - if err != nil { - log.Error("NumClosedIssues: %v", err) - return 0 - } - return int(c) -} - -// NumOpenIssues return counter of open issues assigned to a project -func (p *Project) NumOpenIssues(ctx context.Context) int { - c, err := db.GetEngine(ctx).Table("project_issue"). - Join("INNER", "issue", "project_issue.issue_id=issue.id"). - Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false). - Cols("issue_id"). - Count() - if err != nil { - log.Error("NumOpenIssues: %v", err) - return 0 - } - return int(c) -} - func (c *Column) moveIssuesToAnotherColumn(ctx context.Context, newColumn *Column) error { if c.ProjectID != newColumn.ProjectID { return fmt.Errorf("columns have to be in the same project") diff --git a/models/project/project.go b/models/project/project.go index 050ccf44e0..d27e053094 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -97,6 +97,9 @@ type Project struct { Type Type RenderedContent template.HTML `xorm:"-"` + NumOpenIssues int64 `xorm:"-"` + NumClosedIssues int64 `xorm:"-"` + NumIssues int64 `xorm:"-"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` @@ -126,6 +129,14 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) { return err } +func ProjectLinkForOrg(org *user_model.User, projectID int64) string { //nolint + return fmt.Sprintf("%s/-/projects/%d", org.HomeLink(), projectID) +} + +func ProjectLinkForRepo(repo *repo_model.Repository, projectID int64) string { //nolint + return fmt.Sprintf("%s/projects/%d", repo.Link(), projectID) +} + // Link returns the project's relative URL. func (p *Project) Link(ctx context.Context) string { if p.OwnerID > 0 { @@ -134,7 +145,7 @@ func (p *Project) Link(ctx context.Context) string { log.Error("LoadOwner: %v", err) return "" } - return fmt.Sprintf("%s/-/projects/%d", p.Owner.HomeLink(), p.ID) + return ProjectLinkForOrg(p.Owner, p.ID) } if p.RepoID > 0 { err := p.LoadRepo(ctx) @@ -142,7 +153,7 @@ func (p *Project) Link(ctx context.Context) string { log.Error("LoadRepo: %v", err) return "" } - return fmt.Sprintf("%s/projects/%d", p.Repo.Link(), p.ID) + return ProjectLinkForRepo(p.Repo, p.ID) } return "" } @@ -236,12 +247,17 @@ 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 } } // NewProject creates a new Project +// The title will be cut off at 255 characters if it's longer than 255 characters. func NewProject(ctx context.Context, p *Project) error { if !IsTemplateTypeValid(p.TemplateType) { p.TemplateType = TemplateTypeNone @@ -255,6 +271,8 @@ func NewProject(ctx context.Context, p *Project) error { return util.NewInvalidArgumentErrorf("project type is not valid") } + p.Title = util.EllipsisDisplayString(p.Title, 255) + return db.WithTx(ctx, func(ctx context.Context) error { if err := db.Insert(ctx, p); err != nil { return err @@ -308,6 +326,7 @@ func UpdateProject(ctx context.Context, p *Project) error { p.CardType = CardTypeTextOnly } + p.Title = util.EllipsisDisplayString(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 f69fcb60d1..3cafacc3a4 100644 --- a/models/pull/automerge.go +++ b/models/pull/automerge.go @@ -15,13 +15,14 @@ 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"` - 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"` + DeleteBranchAfterMerge bool + CreatedUnix timeutil.TimeStamp `xorm:"created"` } // TableName return database table name for xorm @@ -49,7 +50,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) error { +func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64, style repo_model.MergeStyle, message string, deleteBranchAfterMerge bool) error { // Check if we already have a merge scheduled for that pull request if exists, _, err := GetScheduledMergeByPullID(ctx, pullID); err != nil { return err @@ -58,10 +59,11 @@ 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, + DoerID: doer.ID, + PullID: pullID, + MergeStyle: style, + Message: message, + DeleteBranchAfterMerge: deleteBranchAfterMerge, }) return err } diff --git a/models/renderhelper/commit_checker.go b/models/renderhelper/commit_checker.go new file mode 100644 index 0000000000..4815643e67 --- /dev/null +++ b/models/renderhelper/commit_checker.go @@ -0,0 +1,53 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package renderhelper + +import ( + "context" + "io" + + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/log" +) + +type commitChecker struct { + ctx context.Context + commitCache map[string]bool + gitRepoFacade gitrepo.Repository + + gitRepo *git.Repository + gitRepoCloser io.Closer +} + +func newCommitChecker(ctx context.Context, gitRepo gitrepo.Repository) *commitChecker { + return &commitChecker{ctx: ctx, commitCache: make(map[string]bool), gitRepoFacade: gitRepo} +} + +func (c *commitChecker) Close() error { + if c != nil && c.gitRepoCloser != nil { + return c.gitRepoCloser.Close() + } + return nil +} + +func (c *commitChecker) IsCommitIDExisting(commitID string) bool { + exist, inCache := c.commitCache[commitID] + if inCache { + return exist + } + + if c.gitRepo == nil { + r, closer, err := gitrepo.RepositoryFromContextOrOpen(c.ctx, c.gitRepoFacade) + if err != nil { + log.Error("unable to open repository: %s Error: %v", gitrepo.RepoGitURL(c.gitRepoFacade), err) + return false + } + c.gitRepo, c.gitRepoCloser = r, closer + } + + exist = c.gitRepo.IsReferenceExist(commitID) // Don't use IsObjectExist since it doesn't support short hashs with gogit edition. + c.commitCache[commitID] = exist + return exist +} diff --git a/models/renderhelper/main_test.go b/models/renderhelper/main_test.go new file mode 100644 index 0000000000..331450172a --- /dev/null +++ b/models/renderhelper/main_test.go @@ -0,0 +1,27 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package renderhelper + +import ( + "context" + "testing" + + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/markup" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m, &unittest.TestOptions{ + FixtureFiles: []string{"repository.yml", "user.yml"}, + SetUp: func() error { + markup.RenderBehaviorForTesting.DisableAdditionalAttributes = true + markup.Init(&markup.RenderHelperFuncs{ + IsUsernameMentionable: func(ctx context.Context, username string) bool { + return username == "user2" + }, + }) + return nil + }, + }) +} diff --git a/models/renderhelper/repo_comment.go b/models/renderhelper/repo_comment.go new file mode 100644 index 0000000000..6bd5e91ad1 --- /dev/null +++ b/models/renderhelper/repo_comment.go @@ -0,0 +1,73 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package renderhelper + +import ( + "context" + "fmt" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/util" +) + +type RepoComment struct { + ctx *markup.RenderContext + opts RepoCommentOptions + + commitChecker *commitChecker + repoLink string +} + +func (r *RepoComment) CleanUp() { + _ = r.commitChecker.Close() +} + +func (r *RepoComment) IsCommitIDExisting(commitID string) bool { + return r.commitChecker.IsCommitIDExisting(commitID) +} + +func (r *RepoComment) ResolveLink(link string, likeType markup.LinkType) (finalLink string) { + switch likeType { + case markup.LinkTypeApp: + finalLink = r.ctx.ResolveLinkApp(link) + default: + finalLink = r.ctx.ResolveLinkRelative(r.repoLink, r.opts.CurrentRefPath, link) + } + return finalLink +} + +var _ markup.RenderHelper = (*RepoComment)(nil) + +type RepoCommentOptions struct { + DeprecatedRepoName string // it is only a patch for the non-standard "markup" api + DeprecatedOwnerName string // it is only a patch for the non-standard "markup" api + CurrentRefPath string // eg: "branch/main" or "commit/11223344" +} + +func NewRenderContextRepoComment(ctx context.Context, repo *repo_model.Repository, opts ...RepoCommentOptions) *markup.RenderContext { + helper := &RepoComment{ + repoLink: repo.Link(), + opts: util.OptionalArg(opts), + } + rctx := markup.NewRenderContext(ctx) + helper.ctx = rctx + if repo != nil { + helper.repoLink = repo.Link() + helper.commitChecker = newCommitChecker(ctx, repo) + rctx = rctx.WithMetas(repo.ComposeMetas(ctx)) + } else { + // this is almost dead code, only to pass the incorrect tests + helper.repoLink = fmt.Sprintf("%s/%s", helper.opts.DeprecatedOwnerName, helper.opts.DeprecatedRepoName) + rctx = rctx.WithMetas(map[string]string{ + "user": helper.opts.DeprecatedOwnerName, + "repo": helper.opts.DeprecatedRepoName, + + "markdownLineBreakStyle": "comment", + "markupAllowShortIssuePattern": "true", + }) + } + rctx = rctx.WithHelper(helper) + return rctx +} diff --git a/models/renderhelper/repo_comment_test.go b/models/renderhelper/repo_comment_test.go new file mode 100644 index 0000000000..776152db96 --- /dev/null +++ b/models/renderhelper/repo_comment_test.go @@ -0,0 +1,75 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package renderhelper + +import ( + "testing" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/markdown" + + "github.com/stretchr/testify/assert" +) + +func TestRepoComment(t *testing.T) { + unittest.PrepareTestEnv(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) + rendered, err := markup.RenderString(rctx, ` +65f1bf27bc3bf70f64657658635e66094edbcb4d +#1 +@user2 +`) + assert.NoError(t, err) + assert.Equal(t, + `

65f1bf27bc
+#1
+@user2

+`, rendered) + }) + + t.Run("AbsoluteAndRelative", func(t *testing.T) { + rctx := NewRenderContextRepoComment(t.Context(), 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 + rendered, err := markup.RenderString(rctx, ` +[/test](/test) +[./test](./test) +![/image](/image) +![./image](./image) +`) + assert.NoError(t, err) + assert.Equal(t, + `

/test
+./test
+/image
+./image

+`, rendered) + }) + + t.Run("WithCurrentRefPath", func(t *testing.T) { + rctx := NewRenderContextRepoComment(t.Context(), 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 + rendered, err := markup.RenderString(rctx, ` +[/test](/test) +[./test](./test) +![/image](/image) +![./image](./image) +`) + assert.NoError(t, err) + assert.Equal(t, `

/test
+./test
+/image
+./image

+`, rendered) + }) +} diff --git a/models/renderhelper/repo_file.go b/models/renderhelper/repo_file.go new file mode 100644 index 0000000000..794828c617 --- /dev/null +++ b/models/renderhelper/repo_file.go @@ -0,0 +1,77 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package renderhelper + +import ( + "context" + "fmt" + "path" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/util" +) + +type RepoFile struct { + ctx *markup.RenderContext + opts RepoFileOptions + + commitChecker *commitChecker + repoLink string +} + +func (r *RepoFile) CleanUp() { + _ = r.commitChecker.Close() +} + +func (r *RepoFile) IsCommitIDExisting(commitID string) bool { + return r.commitChecker.IsCommitIDExisting(commitID) +} + +func (r *RepoFile) ResolveLink(link string, likeType markup.LinkType) string { + finalLink := link + switch likeType { + case markup.LinkTypeApp: + finalLink = r.ctx.ResolveLinkApp(link) + case markup.LinkTypeDefault: + finalLink = r.ctx.ResolveLinkRelative(path.Join(r.repoLink, "src", r.opts.CurrentRefPath), r.opts.CurrentTreePath, link) + case markup.LinkTypeRaw: + finalLink = r.ctx.ResolveLinkRelative(path.Join(r.repoLink, "raw", r.opts.CurrentRefPath), r.opts.CurrentTreePath, link) + case markup.LinkTypeMedia: + finalLink = r.ctx.ResolveLinkRelative(path.Join(r.repoLink, "media", r.opts.CurrentRefPath), r.opts.CurrentTreePath, link) + } + return finalLink +} + +var _ markup.RenderHelper = (*RepoFile)(nil) + +type RepoFileOptions struct { + DeprecatedRepoName string // it is only a patch for the non-standard "markup" api + DeprecatedOwnerName string // it is only a patch for the non-standard "markup" api + + CurrentRefPath string // eg: "branch/main" + CurrentTreePath string // eg: "path/to/file" in the repo +} + +func NewRenderContextRepoFile(ctx context.Context, repo *repo_model.Repository, opts ...RepoFileOptions) *markup.RenderContext { + helper := &RepoFile{opts: util.OptionalArg(opts)} + rctx := markup.NewRenderContext(ctx) + helper.ctx = rctx + if repo != nil { + helper.repoLink = repo.Link() + helper.commitChecker = newCommitChecker(ctx, repo) + rctx = rctx.WithMetas(repo.ComposeDocumentMetas(ctx)) + } else { + // this is almost dead code, only to pass the incorrect tests + helper.repoLink = fmt.Sprintf("%s/%s", helper.opts.DeprecatedOwnerName, helper.opts.DeprecatedRepoName) + rctx = rctx.WithMetas(map[string]string{ + "user": helper.opts.DeprecatedOwnerName, + "repo": helper.opts.DeprecatedRepoName, + + "markdownLineBreakStyle": "document", + }) + } + rctx = rctx.WithHelper(helper) + return rctx +} diff --git a/models/renderhelper/repo_file_test.go b/models/renderhelper/repo_file_test.go new file mode 100644 index 0000000000..29cb45f6f7 --- /dev/null +++ b/models/renderhelper/repo_file_test.go @@ -0,0 +1,121 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package renderhelper + +import ( + "testing" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/markdown" + + _ "code.gitea.io/gitea/modules/markup/orgmode" + + "github.com/stretchr/testify/assert" +) + +func TestRepoFile(t *testing.T) { + unittest.PrepareTestEnv(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) + rendered, err := markup.RenderString(rctx, ` +65f1bf27bc3bf70f64657658635e66094edbcb4d +#1 +@user2 +`) + assert.NoError(t, err) + assert.Equal(t, + `

65f1bf27bc +#1 +@user2

+`, rendered) + }) + + t.Run("AbsoluteAndRelative", func(t *testing.T) { + rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefPath: "branch/main"}). + WithMarkupType(markdown.MarkupName) + rendered, err := markup.RenderString(rctx, ` +[/test](/test) +[./test](./test) +![/image](/image) +![./image](./image) +`) + assert.NoError(t, err) + assert.Equal(t, + `

/test +./test +/image +./image

+`, rendered) + }) + + t.Run("WithCurrentRefPath", func(t *testing.T) { + rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefPath: "/commit/1234"}). + WithMarkupType(markdown.MarkupName) + rendered, err := markup.RenderString(rctx, ` +[/test](/test) +![/image](/image) +`) + assert.NoError(t, err) + assert.Equal(t, `

/test +/image

+`, rendered) + }) + + t.Run("WithCurrentRefPathByTag", func(t *testing.T) { + rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{ + CurrentRefPath: "/commit/1234", + CurrentTreePath: "my-dir", + }). + WithMarkupType(markdown.MarkupName) + rendered, err := markup.RenderString(rctx, ` + +