mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-13 00:45:25 +02:00
Merge branch 'main' into add-file-tree-to-file-view-page
This commit is contained in:
commit
07fb84f830
999
.eslintrc.cjs
Normal file
999
.eslintrc.cjs
Normal file
@ -0,0 +1,999 @@
|
|||||||
|
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-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: ['*.config.*'],
|
||||||
|
rules: {
|
||||||
|
'import-x/no-unused-modules': [0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.d.ts'],
|
||||||
|
rules: {
|
||||||
|
'import-x/no-unused-modules': [0],
|
||||||
|
'@typescript-eslint/consistent-type-definitions': [0],
|
||||||
|
'@typescript-eslint/consistent-type-imports': [0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['web_src/js/types.ts'],
|
||||||
|
rules: {
|
||||||
|
'import-x/no-unused-modules': [0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.test.*', 'web_src/js/test/setup.ts'],
|
||||||
|
env: {
|
||||||
|
'vitest-globals/env': true,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'vitest/consistent-test-filename': [0],
|
||||||
|
'vitest/consistent-test-it': [0],
|
||||||
|
'vitest/expect-expect': [0],
|
||||||
|
'vitest/max-expects': [0],
|
||||||
|
'vitest/max-nested-describe': [0],
|
||||||
|
'vitest/no-alias-methods': [0],
|
||||||
|
'vitest/no-commented-out-tests': [0],
|
||||||
|
'vitest/no-conditional-expect': [0],
|
||||||
|
'vitest/no-conditional-in-test': [0],
|
||||||
|
'vitest/no-conditional-tests': [0],
|
||||||
|
'vitest/no-disabled-tests': [0],
|
||||||
|
'vitest/no-done-callback': [0],
|
||||||
|
'vitest/no-duplicate-hooks': [0],
|
||||||
|
'vitest/no-focused-tests': [0],
|
||||||
|
'vitest/no-hooks': [0],
|
||||||
|
'vitest/no-identical-title': [2],
|
||||||
|
'vitest/no-interpolation-in-snapshots': [0],
|
||||||
|
'vitest/no-large-snapshots': [0],
|
||||||
|
'vitest/no-mocks-import': [0],
|
||||||
|
'vitest/no-restricted-matchers': [0],
|
||||||
|
'vitest/no-restricted-vi-methods': [0],
|
||||||
|
'vitest/no-standalone-expect': [0],
|
||||||
|
'vitest/no-test-prefixes': [0],
|
||||||
|
'vitest/no-test-return-statement': [0],
|
||||||
|
'vitest/prefer-called-with': [0],
|
||||||
|
'vitest/prefer-comparison-matcher': [0],
|
||||||
|
'vitest/prefer-each': [0],
|
||||||
|
'vitest/prefer-equality-matcher': [0],
|
||||||
|
'vitest/prefer-expect-resolves': [0],
|
||||||
|
'vitest/prefer-hooks-in-order': [0],
|
||||||
|
'vitest/prefer-hooks-on-top': [2],
|
||||||
|
'vitest/prefer-lowercase-title': [0],
|
||||||
|
'vitest/prefer-mock-promise-shorthand': [0],
|
||||||
|
'vitest/prefer-snapshot-hint': [0],
|
||||||
|
'vitest/prefer-spy-on': [0],
|
||||||
|
'vitest/prefer-strict-equal': [0],
|
||||||
|
'vitest/prefer-to-be': [0],
|
||||||
|
'vitest/prefer-to-be-falsy': [0],
|
||||||
|
'vitest/prefer-to-be-object': [0],
|
||||||
|
'vitest/prefer-to-be-truthy': [0],
|
||||||
|
'vitest/prefer-to-contain': [0],
|
||||||
|
'vitest/prefer-to-have-length': [0],
|
||||||
|
'vitest/prefer-todo': [0],
|
||||||
|
'vitest/require-hook': [0],
|
||||||
|
'vitest/require-to-throw-message': [0],
|
||||||
|
'vitest/require-top-level-describe': [0],
|
||||||
|
'vitest/valid-describe-callback': [2],
|
||||||
|
'vitest/valid-expect': [2],
|
||||||
|
'vitest/valid-title': [2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['web_src/js/modules/fetch.ts', 'web_src/js/standalone/**/*'],
|
||||||
|
rules: {
|
||||||
|
'no-restricted-syntax': [2, ...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': [0],
|
||||||
|
'@typescript-eslint/no-useless-constructor': [0],
|
||||||
|
'@typescript-eslint/no-useless-empty-export': [0],
|
||||||
|
'@typescript-eslint/no-wrapper-object-types': [2],
|
||||||
|
'@typescript-eslint/non-nullable-type-assertion-style': [0],
|
||||||
|
'@typescript-eslint/only-throw-error': [2],
|
||||||
|
'@typescript-eslint/parameter-properties': [0],
|
||||||
|
'@typescript-eslint/prefer-as-const': [2],
|
||||||
|
'@typescript-eslint/prefer-destructuring': [0],
|
||||||
|
'@typescript-eslint/prefer-enum-initializers': [0],
|
||||||
|
'@typescript-eslint/prefer-find': [2],
|
||||||
|
'@typescript-eslint/prefer-for-of': [2],
|
||||||
|
'@typescript-eslint/prefer-function-type': [2],
|
||||||
|
'@typescript-eslint/prefer-includes': [2],
|
||||||
|
'@typescript-eslint/prefer-literal-enum-member': [0],
|
||||||
|
'@typescript-eslint/prefer-namespace-keyword': [0],
|
||||||
|
'@typescript-eslint/prefer-nullish-coalescing': [0],
|
||||||
|
'@typescript-eslint/prefer-optional-chain': [2, {requireNullish: true}],
|
||||||
|
'@typescript-eslint/prefer-promise-reject-errors': [0],
|
||||||
|
'@typescript-eslint/prefer-readonly': [0],
|
||||||
|
'@typescript-eslint/prefer-readonly-parameter-types': [0],
|
||||||
|
'@typescript-eslint/prefer-reduce-type-parameter': [0],
|
||||||
|
'@typescript-eslint/prefer-regexp-exec': [0],
|
||||||
|
'@typescript-eslint/prefer-return-this-type': [0],
|
||||||
|
'@typescript-eslint/prefer-string-starts-ends-with': [2, {allowSingleElementEquality: 'always'}],
|
||||||
|
'@typescript-eslint/promise-function-async': [0],
|
||||||
|
'@typescript-eslint/require-array-sort-compare': [0],
|
||||||
|
'@typescript-eslint/require-await': [0],
|
||||||
|
'@typescript-eslint/restrict-plus-operands': [2],
|
||||||
|
'@typescript-eslint/restrict-template-expressions': [0],
|
||||||
|
'@typescript-eslint/return-await': [0],
|
||||||
|
'@typescript-eslint/strict-boolean-expressions': [0],
|
||||||
|
'@typescript-eslint/switch-exhaustiveness-check': [0],
|
||||||
|
'@typescript-eslint/triple-slash-reference': [2],
|
||||||
|
'@typescript-eslint/typedef': [0],
|
||||||
|
'@typescript-eslint/unbound-method': [0], // too many false-positives
|
||||||
|
'@typescript-eslint/unified-signatures': [2],
|
||||||
|
'accessor-pairs': [2],
|
||||||
|
'array-callback-return': [2, {checkForEach: true}],
|
||||||
|
'array-func/avoid-reverse': [2],
|
||||||
|
'array-func/from-map': [2],
|
||||||
|
'array-func/no-unnecessary-this-arg': [2],
|
||||||
|
'array-func/prefer-array-from': [2],
|
||||||
|
'array-func/prefer-flat-map': [0], // handled by unicorn/prefer-array-flat-map
|
||||||
|
'array-func/prefer-flat': [0], // handled by unicorn/prefer-array-flat
|
||||||
|
'arrow-body-style': [0],
|
||||||
|
'block-scoped-var': [2],
|
||||||
|
'camelcase': [0],
|
||||||
|
'capitalized-comments': [0],
|
||||||
|
'class-methods-use-this': [0],
|
||||||
|
'complexity': [0],
|
||||||
|
'consistent-return': [0],
|
||||||
|
'consistent-this': [0],
|
||||||
|
'constructor-super': [2],
|
||||||
|
'curly': [0],
|
||||||
|
'default-case-last': [2],
|
||||||
|
'default-case': [0],
|
||||||
|
'default-param-last': [0],
|
||||||
|
'dot-notation': [0],
|
||||||
|
'eqeqeq': [2],
|
||||||
|
'for-direction': [2],
|
||||||
|
'func-name-matching': [2],
|
||||||
|
'func-names': [0],
|
||||||
|
'func-style': [0],
|
||||||
|
'getter-return': [2],
|
||||||
|
'github/a11y-aria-label-is-well-formatted': [0],
|
||||||
|
'github/a11y-no-title-attribute': [0],
|
||||||
|
'github/a11y-no-visually-hidden-interactive-element': [0],
|
||||||
|
'github/a11y-role-supports-aria-props': [0],
|
||||||
|
'github/a11y-svg-has-accessible-name': [0],
|
||||||
|
'github/array-foreach': [0],
|
||||||
|
'github/async-currenttarget': [2],
|
||||||
|
'github/async-preventdefault': [2],
|
||||||
|
'github/authenticity-token': [0],
|
||||||
|
'github/get-attribute': [0],
|
||||||
|
'github/js-class-name': [0],
|
||||||
|
'github/no-blur': [0],
|
||||||
|
'github/no-d-none': [0],
|
||||||
|
'github/no-dataset': [2],
|
||||||
|
'github/no-dynamic-script-tag': [2],
|
||||||
|
'github/no-implicit-buggy-globals': [2],
|
||||||
|
'github/no-inner-html': [0],
|
||||||
|
'github/no-innerText': [2],
|
||||||
|
'github/no-then': [2],
|
||||||
|
'github/no-useless-passive': [2],
|
||||||
|
'github/prefer-observers': [2],
|
||||||
|
'github/require-passive-events': [2],
|
||||||
|
'github/unescaped-html-literal': [0],
|
||||||
|
'grouped-accessor-pairs': [2],
|
||||||
|
'guard-for-in': [0],
|
||||||
|
'id-blacklist': [0],
|
||||||
|
'id-length': [0],
|
||||||
|
'id-match': [0],
|
||||||
|
'import-x/consistent-type-specifier-style': [0],
|
||||||
|
'import-x/default': [0],
|
||||||
|
'import-x/dynamic-import-chunkname': [0],
|
||||||
|
'import-x/export': [2],
|
||||||
|
'import-x/exports-last': [0],
|
||||||
|
'import-x/extensions': [2, 'always', {ignorePackages: true}],
|
||||||
|
'import-x/first': [2],
|
||||||
|
'import-x/group-exports': [0],
|
||||||
|
'import-x/max-dependencies': [0],
|
||||||
|
'import-x/named': [2],
|
||||||
|
'import-x/namespace': [0],
|
||||||
|
'import-x/newline-after-import': [0],
|
||||||
|
'import-x/no-absolute-path': [0],
|
||||||
|
'import-x/no-amd': [2],
|
||||||
|
'import-x/no-anonymous-default-export': [0],
|
||||||
|
'import-x/no-commonjs': [2],
|
||||||
|
'import-x/no-cycle': [2, {ignoreExternal: true, maxDepth: 1}],
|
||||||
|
'import-x/no-default-export': [0],
|
||||||
|
'import-x/no-deprecated': [0],
|
||||||
|
'import-x/no-dynamic-require': [0],
|
||||||
|
'import-x/no-empty-named-blocks': [2],
|
||||||
|
'import-x/no-extraneous-dependencies': [2],
|
||||||
|
'import-x/no-import-module-exports': [0],
|
||||||
|
'import-x/no-internal-modules': [0],
|
||||||
|
'import-x/no-mutable-exports': [0],
|
||||||
|
'import-x/no-named-as-default-member': [0],
|
||||||
|
'import-x/no-named-as-default': [0],
|
||||||
|
'import-x/no-named-default': [0],
|
||||||
|
'import-x/no-named-export': [0],
|
||||||
|
'import-x/no-namespace': [0],
|
||||||
|
'import-x/no-nodejs-modules': [0],
|
||||||
|
'import-x/no-relative-packages': [0],
|
||||||
|
'import-x/no-relative-parent-imports': [0],
|
||||||
|
'import-x/no-restricted-paths': [0],
|
||||||
|
'import-x/no-self-import': [2],
|
||||||
|
'import-x/no-unassigned-import': [0],
|
||||||
|
'import-x/no-unresolved': [2, {commonjs: true, ignore: ['\\?.+$']}],
|
||||||
|
'import-x/no-unused-modules': [2, {unusedExports: true}],
|
||||||
|
'import-x/no-useless-path-segments': [2, {commonjs: true}],
|
||||||
|
'import-x/no-webpack-loader-syntax': [2],
|
||||||
|
'import-x/order': [0],
|
||||||
|
'import-x/prefer-default-export': [0],
|
||||||
|
'import-x/unambiguous': [0],
|
||||||
|
'init-declarations': [0],
|
||||||
|
'line-comment-position': [0],
|
||||||
|
'logical-assignment-operators': [0],
|
||||||
|
'max-classes-per-file': [0],
|
||||||
|
'max-depth': [0],
|
||||||
|
'max-lines-per-function': [0],
|
||||||
|
'max-lines': [0],
|
||||||
|
'max-nested-callbacks': [0],
|
||||||
|
'max-params': [0],
|
||||||
|
'max-statements': [0],
|
||||||
|
'multiline-comment-style': [2, 'separate-lines'],
|
||||||
|
'new-cap': [0],
|
||||||
|
'no-alert': [0],
|
||||||
|
'no-array-constructor': [0], // handled by @typescript-eslint/no-array-constructor
|
||||||
|
'no-async-promise-executor': [0],
|
||||||
|
'no-await-in-loop': [0],
|
||||||
|
'no-bitwise': [0],
|
||||||
|
'no-buffer-constructor': [0],
|
||||||
|
'no-caller': [2],
|
||||||
|
'no-case-declarations': [2],
|
||||||
|
'no-class-assign': [2],
|
||||||
|
'no-compare-neg-zero': [2],
|
||||||
|
'no-cond-assign': [2, 'except-parens'],
|
||||||
|
'no-console': [1, {allow: ['debug', 'info', 'warn', 'error']}],
|
||||||
|
'no-const-assign': [2],
|
||||||
|
'no-constant-binary-expression': [2],
|
||||||
|
'no-constant-condition': [0],
|
||||||
|
'no-constructor-return': [2],
|
||||||
|
'no-continue': [0],
|
||||||
|
'no-control-regex': [0],
|
||||||
|
'no-debugger': [1],
|
||||||
|
'no-delete-var': [2],
|
||||||
|
'no-div-regex': [0],
|
||||||
|
'no-dupe-args': [2],
|
||||||
|
'no-dupe-class-members': [2],
|
||||||
|
'no-dupe-else-if': [2],
|
||||||
|
'no-dupe-keys': [2],
|
||||||
|
'no-duplicate-case': [2],
|
||||||
|
'no-duplicate-imports': [0],
|
||||||
|
'no-else-return': [2],
|
||||||
|
'no-empty-character-class': [2],
|
||||||
|
'no-empty-function': [0],
|
||||||
|
'no-empty-pattern': [2],
|
||||||
|
'no-empty-static-block': [2],
|
||||||
|
'no-empty': [2, {allowEmptyCatch: true}],
|
||||||
|
'no-eq-null': [2],
|
||||||
|
'no-eval': [2],
|
||||||
|
'no-ex-assign': [2],
|
||||||
|
'no-extend-native': [2],
|
||||||
|
'no-extra-bind': [2],
|
||||||
|
'no-extra-boolean-cast': [2],
|
||||||
|
'no-extra-label': [0],
|
||||||
|
'no-fallthrough': [2],
|
||||||
|
'no-func-assign': [2],
|
||||||
|
'no-global-assign': [2],
|
||||||
|
'no-implicit-coercion': [2],
|
||||||
|
'no-implicit-globals': [0],
|
||||||
|
'no-implied-eval': [0], // handled by @typescript-eslint/no-implied-eval
|
||||||
|
'no-import-assign': [2],
|
||||||
|
'no-inline-comments': [0],
|
||||||
|
'no-inner-declarations': [2],
|
||||||
|
'no-invalid-regexp': [2],
|
||||||
|
'no-invalid-this': [0],
|
||||||
|
'no-irregular-whitespace': [2],
|
||||||
|
'no-iterator': [2],
|
||||||
|
'no-jquery/no-ajax-events': [2],
|
||||||
|
'no-jquery/no-ajax': [2],
|
||||||
|
'no-jquery/no-and-self': [2],
|
||||||
|
'no-jquery/no-animate-toggle': [2],
|
||||||
|
'no-jquery/no-animate': [2],
|
||||||
|
'no-jquery/no-append-html': [2],
|
||||||
|
'no-jquery/no-attr': [2],
|
||||||
|
'no-jquery/no-bind': [2],
|
||||||
|
'no-jquery/no-box-model': [2],
|
||||||
|
'no-jquery/no-browser': [2],
|
||||||
|
'no-jquery/no-camel-case': [2],
|
||||||
|
'no-jquery/no-class-state': [2],
|
||||||
|
'no-jquery/no-class': [0],
|
||||||
|
'no-jquery/no-clone': [2],
|
||||||
|
'no-jquery/no-closest': [0],
|
||||||
|
'no-jquery/no-constructor-attributes': [2],
|
||||||
|
'no-jquery/no-contains': [2],
|
||||||
|
'no-jquery/no-context-prop': [2],
|
||||||
|
'no-jquery/no-css': [2],
|
||||||
|
'no-jquery/no-data': [0],
|
||||||
|
'no-jquery/no-deferred': [2],
|
||||||
|
'no-jquery/no-delegate': [2],
|
||||||
|
'no-jquery/no-done-fail': [2],
|
||||||
|
'no-jquery/no-each-collection': [0],
|
||||||
|
'no-jquery/no-each-util': [0],
|
||||||
|
'no-jquery/no-each': [0],
|
||||||
|
'no-jquery/no-error-shorthand': [2],
|
||||||
|
'no-jquery/no-error': [2],
|
||||||
|
'no-jquery/no-escape-selector': [2],
|
||||||
|
'no-jquery/no-event-shorthand': [2],
|
||||||
|
'no-jquery/no-extend': [2],
|
||||||
|
'no-jquery/no-fade': [2],
|
||||||
|
'no-jquery/no-filter': [0],
|
||||||
|
'no-jquery/no-find-collection': [0],
|
||||||
|
'no-jquery/no-find-util': [2],
|
||||||
|
'no-jquery/no-find': [0],
|
||||||
|
'no-jquery/no-fx-interval': [2],
|
||||||
|
'no-jquery/no-fx': [2],
|
||||||
|
'no-jquery/no-global-eval': [2],
|
||||||
|
'no-jquery/no-global-selector': [0],
|
||||||
|
'no-jquery/no-grep': [2],
|
||||||
|
'no-jquery/no-has': [2],
|
||||||
|
'no-jquery/no-hold-ready': [2],
|
||||||
|
'no-jquery/no-html': [0],
|
||||||
|
'no-jquery/no-in-array': [2],
|
||||||
|
'no-jquery/no-is-array': [2],
|
||||||
|
'no-jquery/no-is-empty-object': [2],
|
||||||
|
'no-jquery/no-is-function': [2],
|
||||||
|
'no-jquery/no-is-numeric': [2],
|
||||||
|
'no-jquery/no-is-plain-object': [2],
|
||||||
|
'no-jquery/no-is-window': [2],
|
||||||
|
'no-jquery/no-is': [2],
|
||||||
|
'no-jquery/no-jquery-constructor': [0],
|
||||||
|
'no-jquery/no-live': [2],
|
||||||
|
'no-jquery/no-load-shorthand': [2],
|
||||||
|
'no-jquery/no-load': [2],
|
||||||
|
'no-jquery/no-map-collection': [0],
|
||||||
|
'no-jquery/no-map-util': [2],
|
||||||
|
'no-jquery/no-map': [2],
|
||||||
|
'no-jquery/no-merge': [2],
|
||||||
|
'no-jquery/no-node-name': [2],
|
||||||
|
'no-jquery/no-noop': [2],
|
||||||
|
'no-jquery/no-now': [2],
|
||||||
|
'no-jquery/no-on-ready': [2],
|
||||||
|
'no-jquery/no-other-methods': [0],
|
||||||
|
'no-jquery/no-other-utils': [2],
|
||||||
|
'no-jquery/no-param': [2],
|
||||||
|
'no-jquery/no-parent': [0],
|
||||||
|
'no-jquery/no-parents': [2],
|
||||||
|
'no-jquery/no-parse-html-literal': [2],
|
||||||
|
'no-jquery/no-parse-html': [2],
|
||||||
|
'no-jquery/no-parse-json': [2],
|
||||||
|
'no-jquery/no-parse-xml': [2],
|
||||||
|
'no-jquery/no-prop': [2],
|
||||||
|
'no-jquery/no-proxy': [2],
|
||||||
|
'no-jquery/no-ready-shorthand': [2],
|
||||||
|
'no-jquery/no-ready': [2],
|
||||||
|
'no-jquery/no-selector-prop': [2],
|
||||||
|
'no-jquery/no-serialize': [2],
|
||||||
|
'no-jquery/no-size': [2],
|
||||||
|
'no-jquery/no-sizzle': [2],
|
||||||
|
'no-jquery/no-slide': [2],
|
||||||
|
'no-jquery/no-sub': [2],
|
||||||
|
'no-jquery/no-support': [2],
|
||||||
|
'no-jquery/no-text': [2],
|
||||||
|
'no-jquery/no-trigger': [0],
|
||||||
|
'no-jquery/no-trim': [2],
|
||||||
|
'no-jquery/no-type': [2],
|
||||||
|
'no-jquery/no-unique': [2],
|
||||||
|
'no-jquery/no-unload-shorthand': [2],
|
||||||
|
'no-jquery/no-val': [0],
|
||||||
|
'no-jquery/no-visibility': [2],
|
||||||
|
'no-jquery/no-when': [2],
|
||||||
|
'no-jquery/no-wrap': [2],
|
||||||
|
'no-jquery/variable-pattern': [2],
|
||||||
|
'no-label-var': [2],
|
||||||
|
'no-labels': [0], // handled by no-restricted-syntax
|
||||||
|
'no-lone-blocks': [2],
|
||||||
|
'no-lonely-if': [0],
|
||||||
|
'no-loop-func': [0],
|
||||||
|
'no-loss-of-precision': [2],
|
||||||
|
'no-magic-numbers': [0],
|
||||||
|
'no-misleading-character-class': [2],
|
||||||
|
'no-multi-assign': [0],
|
||||||
|
'no-multi-str': [2],
|
||||||
|
'no-negated-condition': [0],
|
||||||
|
'no-nested-ternary': [0],
|
||||||
|
'no-new-func': [2],
|
||||||
|
'no-new-native-nonconstructor': [2],
|
||||||
|
'no-new-object': [2],
|
||||||
|
'no-new-symbol': [2],
|
||||||
|
'no-new-wrappers': [2],
|
||||||
|
'no-new': [0],
|
||||||
|
'no-nonoctal-decimal-escape': [2],
|
||||||
|
'no-obj-calls': [2],
|
||||||
|
'no-octal-escape': [2],
|
||||||
|
'no-octal': [2],
|
||||||
|
'no-param-reassign': [0],
|
||||||
|
'no-plusplus': [0],
|
||||||
|
'no-promise-executor-return': [0],
|
||||||
|
'no-proto': [2],
|
||||||
|
'no-prototype-builtins': [2],
|
||||||
|
'no-redeclare': [0], // must be disabled for typescript overloads
|
||||||
|
'no-regex-spaces': [2],
|
||||||
|
'no-restricted-exports': [0],
|
||||||
|
'no-restricted-globals': [2, 'addEventListener', 'blur', 'close', 'closed', 'confirm', 'defaultStatus', 'defaultstatus', 'error', 'event', 'external', 'find', 'focus', 'frameElement', 'frames', 'history', 'innerHeight', 'innerWidth', 'isFinite', 'isNaN', 'length', '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': [0],
|
||||||
|
'no-undefined': [0],
|
||||||
|
'no-underscore-dangle': [0],
|
||||||
|
'no-unexpected-multiline': [2],
|
||||||
|
'no-unmodified-loop-condition': [2],
|
||||||
|
'no-unneeded-ternary': [2],
|
||||||
|
'no-unreachable-loop': [2],
|
||||||
|
'no-unreachable': [2],
|
||||||
|
'no-unsafe-finally': [2],
|
||||||
|
'no-unsafe-negation': [2],
|
||||||
|
'no-unused-expressions': [2],
|
||||||
|
'no-unused-labels': [2],
|
||||||
|
'no-unused-private-class-members': [2],
|
||||||
|
'no-unused-vars': [0], // handled by @typescript-eslint/no-unused-vars
|
||||||
|
'no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true}],
|
||||||
|
'no-use-extend-native/no-use-extend-native': [2],
|
||||||
|
'no-useless-backreference': [2],
|
||||||
|
'no-useless-call': [2],
|
||||||
|
'no-useless-catch': [2],
|
||||||
|
'no-useless-computed-key': [2],
|
||||||
|
'no-useless-concat': [2],
|
||||||
|
'no-useless-constructor': [2],
|
||||||
|
'no-useless-escape': [2],
|
||||||
|
'no-useless-rename': [2],
|
||||||
|
'no-useless-return': [2],
|
||||||
|
'no-var': [2],
|
||||||
|
'no-void': [2],
|
||||||
|
'no-warning-comments': [0],
|
||||||
|
'no-with': [0], // handled by no-restricted-syntax
|
||||||
|
'object-shorthand': [2, 'always'],
|
||||||
|
'one-var-declaration-per-line': [0],
|
||||||
|
'one-var': [0],
|
||||||
|
'operator-assignment': [2, 'always'],
|
||||||
|
'operator-linebreak': [2, 'after'],
|
||||||
|
'prefer-arrow-callback': [2, {allowNamedFunctions: true, allowUnboundThis: true}],
|
||||||
|
'prefer-const': [2, {destructuring: 'all', ignoreReadBeforeAssign: true}],
|
||||||
|
'prefer-destructuring': [0],
|
||||||
|
'prefer-exponentiation-operator': [2],
|
||||||
|
'prefer-named-capture-group': [0],
|
||||||
|
'prefer-numeric-literals': [2],
|
||||||
|
'prefer-object-has-own': [2],
|
||||||
|
'prefer-object-spread': [2],
|
||||||
|
'prefer-promise-reject-errors': [2, {allowEmptyReject: false}],
|
||||||
|
'prefer-regex-literals': [2],
|
||||||
|
'prefer-rest-params': [2],
|
||||||
|
'prefer-spread': [2],
|
||||||
|
'prefer-template': [2],
|
||||||
|
'radix': [2, 'as-needed'],
|
||||||
|
'regexp/confusing-quantifier': [2],
|
||||||
|
'regexp/control-character-escape': [2],
|
||||||
|
'regexp/hexadecimal-escape': [0],
|
||||||
|
'regexp/letter-case': [0],
|
||||||
|
'regexp/match-any': [2],
|
||||||
|
'regexp/negation': [2],
|
||||||
|
'regexp/no-contradiction-with-assertion': [0],
|
||||||
|
'regexp/no-control-character': [0],
|
||||||
|
'regexp/no-dupe-characters-character-class': [2],
|
||||||
|
'regexp/no-dupe-disjunctions': [2],
|
||||||
|
'regexp/no-empty-alternative': [2],
|
||||||
|
'regexp/no-empty-capturing-group': [2],
|
||||||
|
'regexp/no-empty-character-class': [0],
|
||||||
|
'regexp/no-empty-group': [2],
|
||||||
|
'regexp/no-empty-lookarounds-assertion': [2],
|
||||||
|
'regexp/no-empty-string-literal': [2],
|
||||||
|
'regexp/no-escape-backspace': [2],
|
||||||
|
'regexp/no-extra-lookaround-assertions': [0],
|
||||||
|
'regexp/no-invalid-regexp': [2],
|
||||||
|
'regexp/no-invisible-character': [2],
|
||||||
|
'regexp/no-lazy-ends': [2],
|
||||||
|
'regexp/no-legacy-features': [2],
|
||||||
|
'regexp/no-misleading-capturing-group': [0],
|
||||||
|
'regexp/no-misleading-unicode-character': [0],
|
||||||
|
'regexp/no-missing-g-flag': [2],
|
||||||
|
'regexp/no-non-standard-flag': [2],
|
||||||
|
'regexp/no-obscure-range': [2],
|
||||||
|
'regexp/no-octal': [2],
|
||||||
|
'regexp/no-optional-assertion': [2],
|
||||||
|
'regexp/no-potentially-useless-backreference': [2],
|
||||||
|
'regexp/no-standalone-backslash': [2],
|
||||||
|
'regexp/no-super-linear-backtracking': [0],
|
||||||
|
'regexp/no-super-linear-move': [0],
|
||||||
|
'regexp/no-trivially-nested-assertion': [2],
|
||||||
|
'regexp/no-trivially-nested-quantifier': [2],
|
||||||
|
'regexp/no-unused-capturing-group': [0],
|
||||||
|
'regexp/no-useless-assertions': [2],
|
||||||
|
'regexp/no-useless-backreference': [2],
|
||||||
|
'regexp/no-useless-character-class': [2],
|
||||||
|
'regexp/no-useless-dollar-replacements': [2],
|
||||||
|
'regexp/no-useless-escape': [2],
|
||||||
|
'regexp/no-useless-flag': [2],
|
||||||
|
'regexp/no-useless-lazy': [2],
|
||||||
|
'regexp/no-useless-non-capturing-group': [2],
|
||||||
|
'regexp/no-useless-quantifier': [2],
|
||||||
|
'regexp/no-useless-range': [2],
|
||||||
|
'regexp/no-useless-set-operand': [2],
|
||||||
|
'regexp/no-useless-string-literal': [2],
|
||||||
|
'regexp/no-useless-two-nums-quantifier': [2],
|
||||||
|
'regexp/no-zero-quantifier': [2],
|
||||||
|
'regexp/optimal-lookaround-quantifier': [2],
|
||||||
|
'regexp/optimal-quantifier-concatenation': [0],
|
||||||
|
'regexp/prefer-character-class': [0],
|
||||||
|
'regexp/prefer-d': [0],
|
||||||
|
'regexp/prefer-escape-replacement-dollar-char': [0],
|
||||||
|
'regexp/prefer-lookaround': [0],
|
||||||
|
'regexp/prefer-named-backreference': [0],
|
||||||
|
'regexp/prefer-named-capture-group': [0],
|
||||||
|
'regexp/prefer-named-replacement': [0],
|
||||||
|
'regexp/prefer-plus-quantifier': [2],
|
||||||
|
'regexp/prefer-predefined-assertion': [2],
|
||||||
|
'regexp/prefer-quantifier': [0],
|
||||||
|
'regexp/prefer-question-quantifier': [2],
|
||||||
|
'regexp/prefer-range': [2],
|
||||||
|
'regexp/prefer-regexp-exec': [2],
|
||||||
|
'regexp/prefer-regexp-test': [2],
|
||||||
|
'regexp/prefer-result-array-groups': [0],
|
||||||
|
'regexp/prefer-set-operation': [2],
|
||||||
|
'regexp/prefer-star-quantifier': [2],
|
||||||
|
'regexp/prefer-unicode-codepoint-escapes': [2],
|
||||||
|
'regexp/prefer-w': [0],
|
||||||
|
'regexp/require-unicode-regexp': [0],
|
||||||
|
'regexp/simplify-set-operations': [2],
|
||||||
|
'regexp/sort-alternatives': [0],
|
||||||
|
'regexp/sort-character-class-elements': [0],
|
||||||
|
'regexp/sort-flags': [0],
|
||||||
|
'regexp/strict': [2],
|
||||||
|
'regexp/unicode-escape': [0],
|
||||||
|
'regexp/use-ignore-case': [0],
|
||||||
|
'require-atomic-updates': [0],
|
||||||
|
'require-await': [0], // handled by @typescript-eslint/require-await
|
||||||
|
'require-unicode-regexp': [0],
|
||||||
|
'require-yield': [2],
|
||||||
|
'sonarjs/cognitive-complexity': [0],
|
||||||
|
'sonarjs/elseif-without-else': [0],
|
||||||
|
'sonarjs/max-switch-cases': [0],
|
||||||
|
'sonarjs/no-all-duplicated-branches': [2],
|
||||||
|
'sonarjs/no-collapsible-if': [0],
|
||||||
|
'sonarjs/no-collection-size-mischeck': [2],
|
||||||
|
'sonarjs/no-duplicate-string': [0],
|
||||||
|
'sonarjs/no-duplicated-branches': [0],
|
||||||
|
'sonarjs/no-element-overwrite': [2],
|
||||||
|
'sonarjs/no-empty-collection': [2],
|
||||||
|
'sonarjs/no-extra-arguments': [2],
|
||||||
|
'sonarjs/no-gratuitous-expressions': [2],
|
||||||
|
'sonarjs/no-identical-conditions': [2],
|
||||||
|
'sonarjs/no-identical-expressions': [2],
|
||||||
|
'sonarjs/no-identical-functions': [2, 5],
|
||||||
|
'sonarjs/no-ignored-return': [2],
|
||||||
|
'sonarjs/no-inverted-boolean-check': [2],
|
||||||
|
'sonarjs/no-nested-switch': [0],
|
||||||
|
'sonarjs/no-nested-template-literals': [0],
|
||||||
|
'sonarjs/no-one-iteration-loop': [2],
|
||||||
|
'sonarjs/no-redundant-boolean': [2],
|
||||||
|
'sonarjs/no-redundant-jump': [2],
|
||||||
|
'sonarjs/no-same-line-conditional': [2],
|
||||||
|
'sonarjs/no-small-switch': [0],
|
||||||
|
'sonarjs/no-unused-collection': [2],
|
||||||
|
'sonarjs/no-use-of-empty-return-value': [2],
|
||||||
|
'sonarjs/no-useless-catch': [2],
|
||||||
|
'sonarjs/non-existent-operator': [2],
|
||||||
|
'sonarjs/prefer-immediate-return': [0],
|
||||||
|
'sonarjs/prefer-object-literal': [0],
|
||||||
|
'sonarjs/prefer-single-boolean-return': [0],
|
||||||
|
'sonarjs/prefer-while': [2],
|
||||||
|
'sort-imports': [0],
|
||||||
|
'sort-keys': [0],
|
||||||
|
'sort-vars': [0],
|
||||||
|
'strict': [0],
|
||||||
|
'symbol-description': [2],
|
||||||
|
'unicode-bom': [2, 'never'],
|
||||||
|
'unicorn/better-regex': [0],
|
||||||
|
'unicorn/catch-error-name': [0],
|
||||||
|
'unicorn/consistent-destructuring': [2],
|
||||||
|
'unicorn/consistent-empty-array-spread': [2],
|
||||||
|
'unicorn/consistent-existence-index-check': [0],
|
||||||
|
'unicorn/consistent-function-scoping': [0],
|
||||||
|
'unicorn/custom-error-definition': [0],
|
||||||
|
'unicorn/empty-brace-spaces': [2],
|
||||||
|
'unicorn/error-message': [0],
|
||||||
|
'unicorn/escape-case': [0],
|
||||||
|
'unicorn/expiring-todo-comments': [0],
|
||||||
|
'unicorn/explicit-length-check': [0],
|
||||||
|
'unicorn/filename-case': [0],
|
||||||
|
'unicorn/import-index': [0],
|
||||||
|
'unicorn/import-style': [0],
|
||||||
|
'unicorn/new-for-builtins': [2],
|
||||||
|
'unicorn/no-abusive-eslint-disable': [0],
|
||||||
|
'unicorn/no-anonymous-default-export': [0],
|
||||||
|
'unicorn/no-array-callback-reference': [0],
|
||||||
|
'unicorn/no-array-for-each': [2],
|
||||||
|
'unicorn/no-array-method-this-argument': [2],
|
||||||
|
'unicorn/no-array-push-push': [2],
|
||||||
|
'unicorn/no-array-reduce': [2],
|
||||||
|
'unicorn/no-await-expression-member': [0],
|
||||||
|
'unicorn/no-await-in-promise-methods': [2],
|
||||||
|
'unicorn/no-console-spaces': [0],
|
||||||
|
'unicorn/no-document-cookie': [2],
|
||||||
|
'unicorn/no-empty-file': [2],
|
||||||
|
'unicorn/no-for-loop': [0],
|
||||||
|
'unicorn/no-hex-escape': [0],
|
||||||
|
'unicorn/no-instanceof-array': [0],
|
||||||
|
'unicorn/no-invalid-fetch-options': [2],
|
||||||
|
'unicorn/no-invalid-remove-event-listener': [2],
|
||||||
|
'unicorn/no-keyword-prefix': [0],
|
||||||
|
'unicorn/no-length-as-slice-end': [2],
|
||||||
|
'unicorn/no-lonely-if': [2],
|
||||||
|
'unicorn/no-magic-array-flat-depth': [0],
|
||||||
|
'unicorn/no-negated-condition': [0],
|
||||||
|
'unicorn/no-negation-in-equality-check': [2],
|
||||||
|
'unicorn/no-nested-ternary': [0],
|
||||||
|
'unicorn/no-new-array': [0],
|
||||||
|
'unicorn/no-new-buffer': [0],
|
||||||
|
'unicorn/no-null': [0],
|
||||||
|
'unicorn/no-object-as-default-parameter': [0],
|
||||||
|
'unicorn/no-process-exit': [0],
|
||||||
|
'unicorn/no-single-promise-in-promise-methods': [2],
|
||||||
|
'unicorn/no-static-only-class': [2],
|
||||||
|
'unicorn/no-thenable': [2],
|
||||||
|
'unicorn/no-this-assignment': [2],
|
||||||
|
'unicorn/no-typeof-undefined': [2],
|
||||||
|
'unicorn/no-unnecessary-await': [2],
|
||||||
|
'unicorn/no-unnecessary-polyfills': [2],
|
||||||
|
'unicorn/no-unreadable-array-destructuring': [0],
|
||||||
|
'unicorn/no-unreadable-iife': [2],
|
||||||
|
'unicorn/no-unused-properties': [2],
|
||||||
|
'unicorn/no-useless-fallback-in-spread': [2],
|
||||||
|
'unicorn/no-useless-length-check': [2],
|
||||||
|
'unicorn/no-useless-promise-resolve-reject': [2],
|
||||||
|
'unicorn/no-useless-spread': [2],
|
||||||
|
'unicorn/no-useless-switch-case': [2],
|
||||||
|
'unicorn/no-useless-undefined': [0],
|
||||||
|
'unicorn/no-zero-fractions': [2],
|
||||||
|
'unicorn/number-literal-case': [0],
|
||||||
|
'unicorn/numeric-separators-style': [0],
|
||||||
|
'unicorn/prefer-add-event-listener': [2],
|
||||||
|
'unicorn/prefer-array-find': [2],
|
||||||
|
'unicorn/prefer-array-flat-map': [2],
|
||||||
|
'unicorn/prefer-array-flat': [2],
|
||||||
|
'unicorn/prefer-array-index-of': [2],
|
||||||
|
'unicorn/prefer-array-some': [2],
|
||||||
|
'unicorn/prefer-at': [0],
|
||||||
|
'unicorn/prefer-blob-reading-methods': [2],
|
||||||
|
'unicorn/prefer-code-point': [0],
|
||||||
|
'unicorn/prefer-date-now': [2],
|
||||||
|
'unicorn/prefer-default-parameters': [0],
|
||||||
|
'unicorn/prefer-dom-node-append': [2],
|
||||||
|
'unicorn/prefer-dom-node-dataset': [0],
|
||||||
|
'unicorn/prefer-dom-node-remove': [2],
|
||||||
|
'unicorn/prefer-dom-node-text-content': [2],
|
||||||
|
'unicorn/prefer-event-target': [2],
|
||||||
|
'unicorn/prefer-export-from': [0],
|
||||||
|
'unicorn/prefer-global-this': [0],
|
||||||
|
'unicorn/prefer-includes': [2],
|
||||||
|
'unicorn/prefer-json-parse-buffer': [0],
|
||||||
|
'unicorn/prefer-keyboard-event-key': [2],
|
||||||
|
'unicorn/prefer-logical-operator-over-ternary': [2],
|
||||||
|
'unicorn/prefer-math-min-max': [2],
|
||||||
|
'unicorn/prefer-math-trunc': [2],
|
||||||
|
'unicorn/prefer-modern-dom-apis': [0],
|
||||||
|
'unicorn/prefer-modern-math-apis': [2],
|
||||||
|
'unicorn/prefer-module': [2],
|
||||||
|
'unicorn/prefer-native-coercion-functions': [2],
|
||||||
|
'unicorn/prefer-negative-index': [2],
|
||||||
|
'unicorn/prefer-node-protocol': [2],
|
||||||
|
'unicorn/prefer-number-properties': [0],
|
||||||
|
'unicorn/prefer-object-from-entries': [2],
|
||||||
|
'unicorn/prefer-object-has-own': [0],
|
||||||
|
'unicorn/prefer-optional-catch-binding': [2],
|
||||||
|
'unicorn/prefer-prototype-methods': [0],
|
||||||
|
'unicorn/prefer-query-selector': [2],
|
||||||
|
'unicorn/prefer-reflect-apply': [0],
|
||||||
|
'unicorn/prefer-regexp-test': [2],
|
||||||
|
'unicorn/prefer-set-has': [0],
|
||||||
|
'unicorn/prefer-set-size': [2],
|
||||||
|
'unicorn/prefer-spread': [0],
|
||||||
|
'unicorn/prefer-string-raw': [0],
|
||||||
|
'unicorn/prefer-string-replace-all': [0],
|
||||||
|
'unicorn/prefer-string-slice': [0],
|
||||||
|
'unicorn/prefer-string-starts-ends-with': [2],
|
||||||
|
'unicorn/prefer-string-trim-start-end': [2],
|
||||||
|
'unicorn/prefer-structured-clone': [2],
|
||||||
|
'unicorn/prefer-switch': [0],
|
||||||
|
'unicorn/prefer-ternary': [0],
|
||||||
|
'unicorn/prefer-text-content': [2],
|
||||||
|
'unicorn/prefer-top-level-await': [0],
|
||||||
|
'unicorn/prefer-type-error': [0],
|
||||||
|
'unicorn/prevent-abbreviations': [0],
|
||||||
|
'unicorn/relative-url-style': [2],
|
||||||
|
'unicorn/require-array-join-separator': [2],
|
||||||
|
'unicorn/require-number-to-fixed-digits-argument': [2],
|
||||||
|
'unicorn/require-post-message-target-origin': [0],
|
||||||
|
'unicorn/string-content': [0],
|
||||||
|
'unicorn/switch-case-braces': [0],
|
||||||
|
'unicorn/template-indent': [2],
|
||||||
|
'unicorn/text-encoding-identifier-case': [0],
|
||||||
|
'unicorn/throw-new-error': [2],
|
||||||
|
'use-isnan': [2],
|
||||||
|
'valid-typeof': [2, {requireStringLiterals: true}],
|
||||||
|
'vars-on-top': [0],
|
||||||
|
'wc/attach-shadow-constructor': [2],
|
||||||
|
'wc/define-tag-after-class-definition': [0],
|
||||||
|
'wc/expose-class-on-global': [0],
|
||||||
|
'wc/file-name-matches-element': [2],
|
||||||
|
'wc/guard-define-call': [0],
|
||||||
|
'wc/guard-super-call': [2],
|
||||||
|
'wc/max-elements-per-file': [0],
|
||||||
|
'wc/no-child-traversal-in-attributechangedcallback': [2],
|
||||||
|
'wc/no-child-traversal-in-connectedcallback': [2],
|
||||||
|
'wc/no-closed-shadow-root': [2],
|
||||||
|
'wc/no-constructor-attributes': [2],
|
||||||
|
'wc/no-constructor-params': [2],
|
||||||
|
'wc/no-constructor': [2],
|
||||||
|
'wc/no-customized-built-in-elements': [2],
|
||||||
|
'wc/no-exports-with-element': [0],
|
||||||
|
'wc/no-invalid-element-name': [2],
|
||||||
|
'wc/no-invalid-extends': [2],
|
||||||
|
'wc/no-method-prefixed-with-on': [2],
|
||||||
|
'wc/no-self-class': [2],
|
||||||
|
'wc/no-typos': [2],
|
||||||
|
'wc/require-listener-teardown': [2],
|
||||||
|
'wc/tag-name-matches-class': [2],
|
||||||
|
'yoda': [2, 'never'],
|
||||||
|
},
|
||||||
|
};
|
967
.eslintrc.yaml
967
.eslintrc.yaml
@ -1,967 +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-x/extensions: [".js", ".ts"]
|
|
||||||
import-x/parsers:
|
|
||||||
"@typescript-eslint/parser": [".js", ".ts"]
|
|
||||||
import-x/resolver:
|
|
||||||
typescript: true
|
|
||||||
|
|
||||||
plugins:
|
|
||||||
- "@eslint-community/eslint-plugin-eslint-comments"
|
|
||||||
- "@stylistic/eslint-plugin-js"
|
|
||||||
- "@typescript-eslint/eslint-plugin"
|
|
||||||
- eslint-plugin-array-func
|
|
||||||
- eslint-plugin-github
|
|
||||||
- eslint-plugin-import-x
|
|
||||||
- eslint-plugin-no-jquery
|
|
||||||
- eslint-plugin-no-use-extend-native
|
|
||||||
- eslint-plugin-regexp
|
|
||||||
- eslint-plugin-sonarjs
|
|
||||||
- eslint-plugin-unicorn
|
|
||||||
- eslint-plugin-vitest
|
|
||||||
- eslint-plugin-vitest-globals
|
|
||||||
- eslint-plugin-wc
|
|
||||||
|
|
||||||
env:
|
|
||||||
es2024: true
|
|
||||||
node: true
|
|
||||||
|
|
||||||
overrides:
|
|
||||||
- files: ["web_src/**/*"]
|
|
||||||
globals:
|
|
||||||
__webpack_public_path__: true
|
|
||||||
process: false # https://github.com/webpack/webpack/issues/15833
|
|
||||||
- files: ["web_src/**/*", "docs/**/*"]
|
|
||||||
env:
|
|
||||||
browser: true
|
|
||||||
node: false
|
|
||||||
- files: ["web_src/**/*worker.*"]
|
|
||||||
env:
|
|
||||||
worker: true
|
|
||||||
rules:
|
|
||||||
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
|
|
||||||
- files: ["*.config.*"]
|
|
||||||
rules:
|
|
||||||
import-x/no-unused-modules: [0]
|
|
||||||
- files: ["**/*.d.ts"]
|
|
||||||
rules:
|
|
||||||
import-x/no-unused-modules: [0]
|
|
||||||
"@typescript-eslint/consistent-type-definitions": [0]
|
|
||||||
"@typescript-eslint/consistent-type-imports": [0]
|
|
||||||
- files: ["web_src/js/types.ts"]
|
|
||||||
rules:
|
|
||||||
import-x/no-unused-modules: [0]
|
|
||||||
- files: ["**/*.test.*", "web_src/js/test/setup.ts"]
|
|
||||||
env:
|
|
||||||
vitest-globals/env: true
|
|
||||||
rules:
|
|
||||||
vitest/consistent-test-filename: [0]
|
|
||||||
vitest/consistent-test-it: [0]
|
|
||||||
vitest/expect-expect: [0]
|
|
||||||
vitest/max-expects: [0]
|
|
||||||
vitest/max-nested-describe: [0]
|
|
||||||
vitest/no-alias-methods: [0]
|
|
||||||
vitest/no-commented-out-tests: [0]
|
|
||||||
vitest/no-conditional-expect: [0]
|
|
||||||
vitest/no-conditional-in-test: [0]
|
|
||||||
vitest/no-conditional-tests: [0]
|
|
||||||
vitest/no-disabled-tests: [0]
|
|
||||||
vitest/no-done-callback: [0]
|
|
||||||
vitest/no-duplicate-hooks: [0]
|
|
||||||
vitest/no-focused-tests: [0]
|
|
||||||
vitest/no-hooks: [0]
|
|
||||||
vitest/no-identical-title: [2]
|
|
||||||
vitest/no-interpolation-in-snapshots: [0]
|
|
||||||
vitest/no-large-snapshots: [0]
|
|
||||||
vitest/no-mocks-import: [0]
|
|
||||||
vitest/no-restricted-matchers: [0]
|
|
||||||
vitest/no-restricted-vi-methods: [0]
|
|
||||||
vitest/no-standalone-expect: [0]
|
|
||||||
vitest/no-test-prefixes: [0]
|
|
||||||
vitest/no-test-return-statement: [0]
|
|
||||||
vitest/prefer-called-with: [0]
|
|
||||||
vitest/prefer-comparison-matcher: [0]
|
|
||||||
vitest/prefer-each: [0]
|
|
||||||
vitest/prefer-equality-matcher: [0]
|
|
||||||
vitest/prefer-expect-resolves: [0]
|
|
||||||
vitest/prefer-hooks-in-order: [0]
|
|
||||||
vitest/prefer-hooks-on-top: [2]
|
|
||||||
vitest/prefer-lowercase-title: [0]
|
|
||||||
vitest/prefer-mock-promise-shorthand: [0]
|
|
||||||
vitest/prefer-snapshot-hint: [0]
|
|
||||||
vitest/prefer-spy-on: [0]
|
|
||||||
vitest/prefer-strict-equal: [0]
|
|
||||||
vitest/prefer-to-be: [0]
|
|
||||||
vitest/prefer-to-be-falsy: [0]
|
|
||||||
vitest/prefer-to-be-object: [0]
|
|
||||||
vitest/prefer-to-be-truthy: [0]
|
|
||||||
vitest/prefer-to-contain: [0]
|
|
||||||
vitest/prefer-to-have-length: [0]
|
|
||||||
vitest/prefer-todo: [0]
|
|
||||||
vitest/require-hook: [0]
|
|
||||||
vitest/require-to-throw-message: [0]
|
|
||||||
vitest/require-top-level-describe: [0]
|
|
||||||
vitest/valid-describe-callback: [2]
|
|
||||||
vitest/valid-expect: [2]
|
|
||||||
vitest/valid-title: [2]
|
|
||||||
- files: ["web_src/js/modules/fetch.ts", "web_src/js/standalone/**/*"]
|
|
||||||
rules:
|
|
||||||
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
|
|
||||||
- files: ["**/*.vue"]
|
|
||||||
plugins:
|
|
||||||
- eslint-plugin-vue
|
|
||||||
- eslint-plugin-vue-scoped-css
|
|
||||||
extends:
|
|
||||||
- plugin:vue/vue3-recommended
|
|
||||||
- plugin:vue-scoped-css/vue3-recommended
|
|
||||||
rules:
|
|
||||||
vue/attributes-order: [0]
|
|
||||||
vue/html-closing-bracket-spacing: [2, {startTag: never, endTag: never, selfClosingTag: never}]
|
|
||||||
vue/max-attributes-per-line: [0]
|
|
||||||
vue/singleline-html-element-content-newline: [0]
|
|
||||||
- files: ["tests/e2e/**"]
|
|
||||||
plugins:
|
|
||||||
- eslint-plugin-playwright
|
|
||||||
extends: plugin:playwright/recommended
|
|
||||||
|
|
||||||
rules:
|
|
||||||
"@eslint-community/eslint-comments/disable-enable-pair": [2]
|
|
||||||
"@eslint-community/eslint-comments/no-aggregating-enable": [2]
|
|
||||||
"@eslint-community/eslint-comments/no-duplicate-disable": [2]
|
|
||||||
"@eslint-community/eslint-comments/no-restricted-disable": [0]
|
|
||||||
"@eslint-community/eslint-comments/no-unlimited-disable": [2]
|
|
||||||
"@eslint-community/eslint-comments/no-unused-disable": [2]
|
|
||||||
"@eslint-community/eslint-comments/no-unused-enable": [2]
|
|
||||||
"@eslint-community/eslint-comments/no-use": [0]
|
|
||||||
"@eslint-community/eslint-comments/require-description": [0]
|
|
||||||
"@stylistic/js/array-bracket-newline": [0]
|
|
||||||
"@stylistic/js/array-bracket-spacing": [2, never]
|
|
||||||
"@stylistic/js/array-element-newline": [0]
|
|
||||||
"@stylistic/js/arrow-parens": [2, always]
|
|
||||||
"@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
|
|
||||||
"@stylistic/js/block-spacing": [0]
|
|
||||||
"@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
|
|
||||||
"@stylistic/js/comma-dangle": [2, always-multiline]
|
|
||||||
"@stylistic/js/comma-spacing": [2, {before: false, after: true}]
|
|
||||||
"@stylistic/js/comma-style": [2, last]
|
|
||||||
"@stylistic/js/computed-property-spacing": [2, never]
|
|
||||||
"@stylistic/js/dot-location": [2, property]
|
|
||||||
"@stylistic/js/eol-last": [2]
|
|
||||||
"@stylistic/js/function-call-argument-newline": [0]
|
|
||||||
"@stylistic/js/function-call-spacing": [2, never]
|
|
||||||
"@stylistic/js/function-paren-newline": [0]
|
|
||||||
"@stylistic/js/generator-star-spacing": [0]
|
|
||||||
"@stylistic/js/implicit-arrow-linebreak": [0]
|
|
||||||
"@stylistic/js/indent": [2, 2, {ignoreComments: true, SwitchCase: 1}]
|
|
||||||
"@stylistic/js/key-spacing": [2]
|
|
||||||
"@stylistic/js/keyword-spacing": [2]
|
|
||||||
"@stylistic/js/line-comment-position": [0]
|
|
||||||
"@stylistic/js/linebreak-style": [2, unix]
|
|
||||||
"@stylistic/js/lines-around-comment": [0]
|
|
||||||
"@stylistic/js/lines-between-class-members": [0]
|
|
||||||
"@stylistic/js/max-len": [0]
|
|
||||||
"@stylistic/js/max-statements-per-line": [0]
|
|
||||||
"@stylistic/js/multiline-comment-style": [0]
|
|
||||||
"@stylistic/js/multiline-ternary": [0]
|
|
||||||
"@stylistic/js/new-parens": [2]
|
|
||||||
"@stylistic/js/newline-per-chained-call": [0]
|
|
||||||
"@stylistic/js/no-confusing-arrow": [0]
|
|
||||||
"@stylistic/js/no-extra-parens": [0]
|
|
||||||
"@stylistic/js/no-extra-semi": [2]
|
|
||||||
"@stylistic/js/no-floating-decimal": [0]
|
|
||||||
"@stylistic/js/no-mixed-operators": [0]
|
|
||||||
"@stylistic/js/no-mixed-spaces-and-tabs": [2]
|
|
||||||
"@stylistic/js/no-multi-spaces": [2, {ignoreEOLComments: true, exceptions: {Property: true}}]
|
|
||||||
"@stylistic/js/no-multiple-empty-lines": [2, {max: 1, maxEOF: 0, maxBOF: 0}]
|
|
||||||
"@stylistic/js/no-tabs": [2]
|
|
||||||
"@stylistic/js/no-trailing-spaces": [2]
|
|
||||||
"@stylistic/js/no-whitespace-before-property": [2]
|
|
||||||
"@stylistic/js/nonblock-statement-body-position": [2]
|
|
||||||
"@stylistic/js/object-curly-newline": [0]
|
|
||||||
"@stylistic/js/object-curly-spacing": [2, never]
|
|
||||||
"@stylistic/js/object-property-newline": [0]
|
|
||||||
"@stylistic/js/one-var-declaration-per-line": [0]
|
|
||||||
"@stylistic/js/operator-linebreak": [2, after]
|
|
||||||
"@stylistic/js/padded-blocks": [2, never]
|
|
||||||
"@stylistic/js/padding-line-between-statements": [0]
|
|
||||||
"@stylistic/js/quote-props": [0]
|
|
||||||
"@stylistic/js/quotes": [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
|
|
||||||
"@stylistic/js/rest-spread-spacing": [2, never]
|
|
||||||
"@stylistic/js/semi": [2, always, {omitLastInOneLineBlock: true}]
|
|
||||||
"@stylistic/js/semi-spacing": [2, {before: false, after: true}]
|
|
||||||
"@stylistic/js/semi-style": [2, last]
|
|
||||||
"@stylistic/js/space-before-blocks": [2, always]
|
|
||||||
"@stylistic/js/space-before-function-paren": [2, {anonymous: ignore, named: never, asyncArrow: always}]
|
|
||||||
"@stylistic/js/space-in-parens": [2, never]
|
|
||||||
"@stylistic/js/space-infix-ops": [2]
|
|
||||||
"@stylistic/js/space-unary-ops": [2]
|
|
||||||
"@stylistic/js/spaced-comment": [2, always]
|
|
||||||
"@stylistic/js/switch-colon-spacing": [2]
|
|
||||||
"@stylistic/js/template-curly-spacing": [2, never]
|
|
||||||
"@stylistic/js/template-tag-spacing": [2, never]
|
|
||||||
"@stylistic/js/wrap-iife": [2, inside]
|
|
||||||
"@stylistic/js/wrap-regex": [0]
|
|
||||||
"@stylistic/js/yield-star-spacing": [2, after]
|
|
||||||
"@typescript-eslint/adjacent-overload-signatures": [0]
|
|
||||||
"@typescript-eslint/array-type": [0]
|
|
||||||
"@typescript-eslint/await-thenable": [2]
|
|
||||||
"@typescript-eslint/ban-ts-comment": [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}]
|
|
||||||
"@typescript-eslint/ban-tslint-comment": [0]
|
|
||||||
"@typescript-eslint/class-literal-property-style": [0]
|
|
||||||
"@typescript-eslint/class-methods-use-this": [0]
|
|
||||||
"@typescript-eslint/consistent-generic-constructors": [0]
|
|
||||||
"@typescript-eslint/consistent-indexed-object-style": [0]
|
|
||||||
"@typescript-eslint/consistent-return": [0]
|
|
||||||
"@typescript-eslint/consistent-type-assertions": [2, {assertionStyle: as, objectLiteralTypeAssertions: allow}]
|
|
||||||
"@typescript-eslint/consistent-type-definitions": [2, type]
|
|
||||||
"@typescript-eslint/consistent-type-exports": [2, {fixMixedExportsWithInlineTypeSpecifier: false}]
|
|
||||||
"@typescript-eslint/consistent-type-imports": [2, {prefer: type-imports, fixStyle: separate-type-imports, disallowTypeAnnotations: true}]
|
|
||||||
"@typescript-eslint/default-param-last": [0]
|
|
||||||
"@typescript-eslint/dot-notation": [0]
|
|
||||||
"@typescript-eslint/explicit-function-return-type": [0]
|
|
||||||
"@typescript-eslint/explicit-member-accessibility": [0]
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": [0]
|
|
||||||
"@typescript-eslint/init-declarations": [0]
|
|
||||||
"@typescript-eslint/max-params": [0]
|
|
||||||
"@typescript-eslint/member-ordering": [0]
|
|
||||||
"@typescript-eslint/method-signature-style": [0]
|
|
||||||
"@typescript-eslint/naming-convention": [0]
|
|
||||||
"@typescript-eslint/no-array-constructor": [2]
|
|
||||||
"@typescript-eslint/no-array-delete": [2]
|
|
||||||
"@typescript-eslint/no-base-to-string": [0]
|
|
||||||
"@typescript-eslint/no-confusing-non-null-assertion": [2]
|
|
||||||
"@typescript-eslint/no-confusing-void-expression": [0]
|
|
||||||
"@typescript-eslint/no-deprecated": [2]
|
|
||||||
"@typescript-eslint/no-dupe-class-members": [0]
|
|
||||||
"@typescript-eslint/no-duplicate-enum-values": [2]
|
|
||||||
"@typescript-eslint/no-duplicate-type-constituents": [2, {ignoreUnions: true}]
|
|
||||||
"@typescript-eslint/no-dynamic-delete": [0]
|
|
||||||
"@typescript-eslint/no-empty-function": [0]
|
|
||||||
"@typescript-eslint/no-empty-interface": [0]
|
|
||||||
"@typescript-eslint/no-empty-object-type": [2]
|
|
||||||
"@typescript-eslint/no-explicit-any": [0]
|
|
||||||
"@typescript-eslint/no-extra-non-null-assertion": [2]
|
|
||||||
"@typescript-eslint/no-extraneous-class": [0]
|
|
||||||
"@typescript-eslint/no-floating-promises": [0]
|
|
||||||
"@typescript-eslint/no-for-in-array": [2]
|
|
||||||
"@typescript-eslint/no-implied-eval": [2]
|
|
||||||
"@typescript-eslint/no-import-type-side-effects": [0] # dupe with consistent-type-imports
|
|
||||||
"@typescript-eslint/no-inferrable-types": [0]
|
|
||||||
"@typescript-eslint/no-invalid-this": [0]
|
|
||||||
"@typescript-eslint/no-invalid-void-type": [0]
|
|
||||||
"@typescript-eslint/no-loop-func": [0]
|
|
||||||
"@typescript-eslint/no-loss-of-precision": [0]
|
|
||||||
"@typescript-eslint/no-magic-numbers": [0]
|
|
||||||
"@typescript-eslint/no-meaningless-void-operator": [0]
|
|
||||||
"@typescript-eslint/no-misused-new": [2]
|
|
||||||
"@typescript-eslint/no-misused-promises": [2, {checksVoidReturn: {attributes: false, arguments: false}}]
|
|
||||||
"@typescript-eslint/no-mixed-enums": [0]
|
|
||||||
"@typescript-eslint/no-namespace": [2]
|
|
||||||
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": [0]
|
|
||||||
"@typescript-eslint/no-non-null-asserted-optional-chain": [2]
|
|
||||||
"@typescript-eslint/no-non-null-assertion": [0]
|
|
||||||
"@typescript-eslint/no-redeclare": [0]
|
|
||||||
"@typescript-eslint/no-redundant-type-constituents": [2]
|
|
||||||
"@typescript-eslint/no-require-imports": [2]
|
|
||||||
"@typescript-eslint/no-restricted-imports": [0]
|
|
||||||
"@typescript-eslint/no-restricted-types": [0]
|
|
||||||
"@typescript-eslint/no-shadow": [0]
|
|
||||||
"@typescript-eslint/no-this-alias": [0] # handled by unicorn/no-this-assignment
|
|
||||||
"@typescript-eslint/no-unnecessary-boolean-literal-compare": [0]
|
|
||||||
"@typescript-eslint/no-unnecessary-condition": [0]
|
|
||||||
"@typescript-eslint/no-unnecessary-qualifier": [0]
|
|
||||||
"@typescript-eslint/no-unnecessary-template-expression": [0]
|
|
||||||
"@typescript-eslint/no-unnecessary-type-arguments": [0]
|
|
||||||
"@typescript-eslint/no-unnecessary-type-assertion": [2]
|
|
||||||
"@typescript-eslint/no-unnecessary-type-constraint": [2]
|
|
||||||
"@typescript-eslint/no-unsafe-argument": [0]
|
|
||||||
"@typescript-eslint/no-unsafe-assignment": [0]
|
|
||||||
"@typescript-eslint/no-unsafe-call": [0]
|
|
||||||
"@typescript-eslint/no-unsafe-declaration-merging": [2]
|
|
||||||
"@typescript-eslint/no-unsafe-enum-comparison": [2]
|
|
||||||
"@typescript-eslint/no-unsafe-function-type": [2]
|
|
||||||
"@typescript-eslint/no-unsafe-member-access": [0]
|
|
||||||
"@typescript-eslint/no-unsafe-return": [0]
|
|
||||||
"@typescript-eslint/no-unsafe-unary-minus": [2]
|
|
||||||
"@typescript-eslint/no-unused-expressions": [0]
|
|
||||||
"@typescript-eslint/no-unused-vars": [2, {vars: all, args: all, caughtErrors: all, ignoreRestSiblings: false, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_}]
|
|
||||||
"@typescript-eslint/no-use-before-define": [0]
|
|
||||||
"@typescript-eslint/no-useless-constructor": [0]
|
|
||||||
"@typescript-eslint/no-useless-empty-export": [0]
|
|
||||||
"@typescript-eslint/no-wrapper-object-types": [2]
|
|
||||||
"@typescript-eslint/non-nullable-type-assertion-style": [0]
|
|
||||||
"@typescript-eslint/only-throw-error": [2]
|
|
||||||
"@typescript-eslint/parameter-properties": [0]
|
|
||||||
"@typescript-eslint/prefer-as-const": [2]
|
|
||||||
"@typescript-eslint/prefer-destructuring": [0]
|
|
||||||
"@typescript-eslint/prefer-enum-initializers": [0]
|
|
||||||
"@typescript-eslint/prefer-find": [2]
|
|
||||||
"@typescript-eslint/prefer-for-of": [2]
|
|
||||||
"@typescript-eslint/prefer-function-type": [2]
|
|
||||||
"@typescript-eslint/prefer-includes": [2]
|
|
||||||
"@typescript-eslint/prefer-literal-enum-member": [0]
|
|
||||||
"@typescript-eslint/prefer-namespace-keyword": [0]
|
|
||||||
"@typescript-eslint/prefer-nullish-coalescing": [0]
|
|
||||||
"@typescript-eslint/prefer-optional-chain": [2, {requireNullish: true}]
|
|
||||||
"@typescript-eslint/prefer-promise-reject-errors": [0]
|
|
||||||
"@typescript-eslint/prefer-readonly": [0]
|
|
||||||
"@typescript-eslint/prefer-readonly-parameter-types": [0]
|
|
||||||
"@typescript-eslint/prefer-reduce-type-parameter": [0]
|
|
||||||
"@typescript-eslint/prefer-regexp-exec": [0]
|
|
||||||
"@typescript-eslint/prefer-return-this-type": [0]
|
|
||||||
"@typescript-eslint/prefer-string-starts-ends-with": [2, {allowSingleElementEquality: always}]
|
|
||||||
"@typescript-eslint/promise-function-async": [0]
|
|
||||||
"@typescript-eslint/require-array-sort-compare": [0]
|
|
||||||
"@typescript-eslint/require-await": [0]
|
|
||||||
"@typescript-eslint/restrict-plus-operands": [2]
|
|
||||||
"@typescript-eslint/restrict-template-expressions": [0]
|
|
||||||
"@typescript-eslint/return-await": [0]
|
|
||||||
"@typescript-eslint/strict-boolean-expressions": [0]
|
|
||||||
"@typescript-eslint/switch-exhaustiveness-check": [0]
|
|
||||||
"@typescript-eslint/triple-slash-reference": [2]
|
|
||||||
"@typescript-eslint/typedef": [0]
|
|
||||||
"@typescript-eslint/unbound-method": [0] # too many false-positives
|
|
||||||
"@typescript-eslint/unified-signatures": [2]
|
|
||||||
accessor-pairs: [2]
|
|
||||||
array-callback-return: [2, {checkForEach: true}]
|
|
||||||
array-func/avoid-reverse: [2]
|
|
||||||
array-func/from-map: [2]
|
|
||||||
array-func/no-unnecessary-this-arg: [2]
|
|
||||||
array-func/prefer-array-from: [2]
|
|
||||||
array-func/prefer-flat-map: [0] # handled by unicorn/prefer-array-flat-map
|
|
||||||
array-func/prefer-flat: [0] # handled by unicorn/prefer-array-flat
|
|
||||||
arrow-body-style: [0]
|
|
||||||
block-scoped-var: [2]
|
|
||||||
camelcase: [0]
|
|
||||||
capitalized-comments: [0]
|
|
||||||
class-methods-use-this: [0]
|
|
||||||
complexity: [0]
|
|
||||||
consistent-return: [0]
|
|
||||||
consistent-this: [0]
|
|
||||||
constructor-super: [2]
|
|
||||||
curly: [0]
|
|
||||||
default-case-last: [2]
|
|
||||||
default-case: [0]
|
|
||||||
default-param-last: [0]
|
|
||||||
dot-notation: [0]
|
|
||||||
eqeqeq: [2]
|
|
||||||
for-direction: [2]
|
|
||||||
func-name-matching: [2]
|
|
||||||
func-names: [0]
|
|
||||||
func-style: [0]
|
|
||||||
getter-return: [2]
|
|
||||||
github/a11y-aria-label-is-well-formatted: [0]
|
|
||||||
github/a11y-no-title-attribute: [0]
|
|
||||||
github/a11y-no-visually-hidden-interactive-element: [0]
|
|
||||||
github/a11y-role-supports-aria-props: [0]
|
|
||||||
github/a11y-svg-has-accessible-name: [0]
|
|
||||||
github/array-foreach: [0]
|
|
||||||
github/async-currenttarget: [2]
|
|
||||||
github/async-preventdefault: [2]
|
|
||||||
github/authenticity-token: [0]
|
|
||||||
github/get-attribute: [0]
|
|
||||||
github/js-class-name: [0]
|
|
||||||
github/no-blur: [0]
|
|
||||||
github/no-d-none: [0]
|
|
||||||
github/no-dataset: [2]
|
|
||||||
github/no-dynamic-script-tag: [2]
|
|
||||||
github/no-implicit-buggy-globals: [2]
|
|
||||||
github/no-inner-html: [0]
|
|
||||||
github/no-innerText: [2]
|
|
||||||
github/no-then: [2]
|
|
||||||
github/no-useless-passive: [2]
|
|
||||||
github/prefer-observers: [2]
|
|
||||||
github/require-passive-events: [2]
|
|
||||||
github/unescaped-html-literal: [0]
|
|
||||||
grouped-accessor-pairs: [2]
|
|
||||||
guard-for-in: [0]
|
|
||||||
id-blacklist: [0]
|
|
||||||
id-length: [0]
|
|
||||||
id-match: [0]
|
|
||||||
import-x/consistent-type-specifier-style: [0]
|
|
||||||
import-x/default: [0]
|
|
||||||
import-x/dynamic-import-chunkname: [0]
|
|
||||||
import-x/export: [2]
|
|
||||||
import-x/exports-last: [0]
|
|
||||||
import-x/extensions: [2, always, {ignorePackages: true}]
|
|
||||||
import-x/first: [2]
|
|
||||||
import-x/group-exports: [0]
|
|
||||||
import-x/max-dependencies: [0]
|
|
||||||
import-x/named: [2]
|
|
||||||
import-x/namespace: [0]
|
|
||||||
import-x/newline-after-import: [0]
|
|
||||||
import-x/no-absolute-path: [0]
|
|
||||||
import-x/no-amd: [2]
|
|
||||||
import-x/no-anonymous-default-export: [0]
|
|
||||||
import-x/no-commonjs: [2]
|
|
||||||
import-x/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}]
|
|
||||||
import-x/no-default-export: [0]
|
|
||||||
import-x/no-deprecated: [0]
|
|
||||||
import-x/no-dynamic-require: [0]
|
|
||||||
import-x/no-empty-named-blocks: [2]
|
|
||||||
import-x/no-extraneous-dependencies: [2]
|
|
||||||
import-x/no-import-module-exports: [0]
|
|
||||||
import-x/no-internal-modules: [0]
|
|
||||||
import-x/no-mutable-exports: [0]
|
|
||||||
import-x/no-named-as-default-member: [0]
|
|
||||||
import-x/no-named-as-default: [0]
|
|
||||||
import-x/no-named-default: [0]
|
|
||||||
import-x/no-named-export: [0]
|
|
||||||
import-x/no-namespace: [0]
|
|
||||||
import-x/no-nodejs-modules: [0]
|
|
||||||
import-x/no-relative-packages: [0]
|
|
||||||
import-x/no-relative-parent-imports: [0]
|
|
||||||
import-x/no-restricted-paths: [0]
|
|
||||||
import-x/no-self-import: [2]
|
|
||||||
import-x/no-unassigned-import: [0]
|
|
||||||
import-x/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$"]}]
|
|
||||||
import-x/no-unused-modules: [2, {unusedExports: true}]
|
|
||||||
import-x/no-useless-path-segments: [2, {commonjs: true}]
|
|
||||||
import-x/no-webpack-loader-syntax: [2]
|
|
||||||
import-x/order: [0]
|
|
||||||
import-x/prefer-default-export: [0]
|
|
||||||
import-x/unambiguous: [0]
|
|
||||||
init-declarations: [0]
|
|
||||||
line-comment-position: [0]
|
|
||||||
logical-assignment-operators: [0]
|
|
||||||
max-classes-per-file: [0]
|
|
||||||
max-depth: [0]
|
|
||||||
max-lines-per-function: [0]
|
|
||||||
max-lines: [0]
|
|
||||||
max-nested-callbacks: [0]
|
|
||||||
max-params: [0]
|
|
||||||
max-statements: [0]
|
|
||||||
multiline-comment-style: [2, separate-lines]
|
|
||||||
new-cap: [0]
|
|
||||||
no-alert: [0]
|
|
||||||
no-array-constructor: [0] # handled by @typescript-eslint/no-array-constructor
|
|
||||||
no-async-promise-executor: [0]
|
|
||||||
no-await-in-loop: [0]
|
|
||||||
no-bitwise: [0]
|
|
||||||
no-buffer-constructor: [0]
|
|
||||||
no-caller: [2]
|
|
||||||
no-case-declarations: [2]
|
|
||||||
no-class-assign: [2]
|
|
||||||
no-compare-neg-zero: [2]
|
|
||||||
no-cond-assign: [2, except-parens]
|
|
||||||
no-console: [1, {allow: [debug, info, warn, error]}]
|
|
||||||
no-const-assign: [2]
|
|
||||||
no-constant-binary-expression: [2]
|
|
||||||
no-constant-condition: [0]
|
|
||||||
no-constructor-return: [2]
|
|
||||||
no-continue: [0]
|
|
||||||
no-control-regex: [0]
|
|
||||||
no-debugger: [1]
|
|
||||||
no-delete-var: [2]
|
|
||||||
no-div-regex: [0]
|
|
||||||
no-dupe-args: [2]
|
|
||||||
no-dupe-class-members: [2]
|
|
||||||
no-dupe-else-if: [2]
|
|
||||||
no-dupe-keys: [2]
|
|
||||||
no-duplicate-case: [2]
|
|
||||||
no-duplicate-imports: [0]
|
|
||||||
no-else-return: [2]
|
|
||||||
no-empty-character-class: [2]
|
|
||||||
no-empty-function: [0]
|
|
||||||
no-empty-pattern: [2]
|
|
||||||
no-empty-static-block: [2]
|
|
||||||
no-empty: [2, {allowEmptyCatch: true}]
|
|
||||||
no-eq-null: [2]
|
|
||||||
no-eval: [2]
|
|
||||||
no-ex-assign: [2]
|
|
||||||
no-extend-native: [2]
|
|
||||||
no-extra-bind: [2]
|
|
||||||
no-extra-boolean-cast: [2]
|
|
||||||
no-extra-label: [0]
|
|
||||||
no-fallthrough: [2]
|
|
||||||
no-func-assign: [2]
|
|
||||||
no-global-assign: [2]
|
|
||||||
no-implicit-coercion: [2]
|
|
||||||
no-implicit-globals: [0]
|
|
||||||
no-implied-eval: [0] # handled by @typescript-eslint/no-implied-eval
|
|
||||||
no-import-assign: [2]
|
|
||||||
no-inline-comments: [0]
|
|
||||||
no-inner-declarations: [2]
|
|
||||||
no-invalid-regexp: [2]
|
|
||||||
no-invalid-this: [0]
|
|
||||||
no-irregular-whitespace: [2]
|
|
||||||
no-iterator: [2]
|
|
||||||
no-jquery/no-ajax-events: [2]
|
|
||||||
no-jquery/no-ajax: [2]
|
|
||||||
no-jquery/no-and-self: [2]
|
|
||||||
no-jquery/no-animate-toggle: [2]
|
|
||||||
no-jquery/no-animate: [2]
|
|
||||||
no-jquery/no-append-html: [2]
|
|
||||||
no-jquery/no-attr: [2]
|
|
||||||
no-jquery/no-bind: [2]
|
|
||||||
no-jquery/no-box-model: [2]
|
|
||||||
no-jquery/no-browser: [2]
|
|
||||||
no-jquery/no-camel-case: [2]
|
|
||||||
no-jquery/no-class-state: [2]
|
|
||||||
no-jquery/no-class: [0]
|
|
||||||
no-jquery/no-clone: [2]
|
|
||||||
no-jquery/no-closest: [0]
|
|
||||||
no-jquery/no-constructor-attributes: [2]
|
|
||||||
no-jquery/no-contains: [2]
|
|
||||||
no-jquery/no-context-prop: [2]
|
|
||||||
no-jquery/no-css: [2]
|
|
||||||
no-jquery/no-data: [0]
|
|
||||||
no-jquery/no-deferred: [2]
|
|
||||||
no-jquery/no-delegate: [2]
|
|
||||||
no-jquery/no-done-fail: [2]
|
|
||||||
no-jquery/no-each-collection: [0]
|
|
||||||
no-jquery/no-each-util: [0]
|
|
||||||
no-jquery/no-each: [0]
|
|
||||||
no-jquery/no-error-shorthand: [2]
|
|
||||||
no-jquery/no-error: [2]
|
|
||||||
no-jquery/no-escape-selector: [2]
|
|
||||||
no-jquery/no-event-shorthand: [2]
|
|
||||||
no-jquery/no-extend: [2]
|
|
||||||
no-jquery/no-fade: [2]
|
|
||||||
no-jquery/no-filter: [0]
|
|
||||||
no-jquery/no-find-collection: [0]
|
|
||||||
no-jquery/no-find-util: [2]
|
|
||||||
no-jquery/no-find: [0]
|
|
||||||
no-jquery/no-fx-interval: [2]
|
|
||||||
no-jquery/no-fx: [2]
|
|
||||||
no-jquery/no-global-eval: [2]
|
|
||||||
no-jquery/no-global-selector: [0]
|
|
||||||
no-jquery/no-grep: [2]
|
|
||||||
no-jquery/no-has: [2]
|
|
||||||
no-jquery/no-hold-ready: [2]
|
|
||||||
no-jquery/no-html: [0]
|
|
||||||
no-jquery/no-in-array: [2]
|
|
||||||
no-jquery/no-is-array: [2]
|
|
||||||
no-jquery/no-is-empty-object: [2]
|
|
||||||
no-jquery/no-is-function: [2]
|
|
||||||
no-jquery/no-is-numeric: [2]
|
|
||||||
no-jquery/no-is-plain-object: [2]
|
|
||||||
no-jquery/no-is-window: [2]
|
|
||||||
no-jquery/no-is: [2]
|
|
||||||
no-jquery/no-jquery-constructor: [0]
|
|
||||||
no-jquery/no-live: [2]
|
|
||||||
no-jquery/no-load-shorthand: [2]
|
|
||||||
no-jquery/no-load: [2]
|
|
||||||
no-jquery/no-map-collection: [0]
|
|
||||||
no-jquery/no-map-util: [2]
|
|
||||||
no-jquery/no-map: [2]
|
|
||||||
no-jquery/no-merge: [2]
|
|
||||||
no-jquery/no-node-name: [2]
|
|
||||||
no-jquery/no-noop: [2]
|
|
||||||
no-jquery/no-now: [2]
|
|
||||||
no-jquery/no-on-ready: [2]
|
|
||||||
no-jquery/no-other-methods: [0]
|
|
||||||
no-jquery/no-other-utils: [2]
|
|
||||||
no-jquery/no-param: [2]
|
|
||||||
no-jquery/no-parent: [0]
|
|
||||||
no-jquery/no-parents: [2]
|
|
||||||
no-jquery/no-parse-html-literal: [2]
|
|
||||||
no-jquery/no-parse-html: [2]
|
|
||||||
no-jquery/no-parse-json: [2]
|
|
||||||
no-jquery/no-parse-xml: [2]
|
|
||||||
no-jquery/no-prop: [2]
|
|
||||||
no-jquery/no-proxy: [2]
|
|
||||||
no-jquery/no-ready-shorthand: [2]
|
|
||||||
no-jquery/no-ready: [2]
|
|
||||||
no-jquery/no-selector-prop: [2]
|
|
||||||
no-jquery/no-serialize: [2]
|
|
||||||
no-jquery/no-size: [2]
|
|
||||||
no-jquery/no-sizzle: [2]
|
|
||||||
no-jquery/no-slide: [2]
|
|
||||||
no-jquery/no-sub: [2]
|
|
||||||
no-jquery/no-support: [2]
|
|
||||||
no-jquery/no-text: [2]
|
|
||||||
no-jquery/no-trigger: [0]
|
|
||||||
no-jquery/no-trim: [2]
|
|
||||||
no-jquery/no-type: [2]
|
|
||||||
no-jquery/no-unique: [2]
|
|
||||||
no-jquery/no-unload-shorthand: [2]
|
|
||||||
no-jquery/no-val: [0]
|
|
||||||
no-jquery/no-visibility: [2]
|
|
||||||
no-jquery/no-when: [2]
|
|
||||||
no-jquery/no-wrap: [2]
|
|
||||||
no-jquery/variable-pattern: [2]
|
|
||||||
no-label-var: [2]
|
|
||||||
no-labels: [0] # handled by no-restricted-syntax
|
|
||||||
no-lone-blocks: [2]
|
|
||||||
no-lonely-if: [0]
|
|
||||||
no-loop-func: [0]
|
|
||||||
no-loss-of-precision: [2]
|
|
||||||
no-magic-numbers: [0]
|
|
||||||
no-misleading-character-class: [2]
|
|
||||||
no-multi-assign: [0]
|
|
||||||
no-multi-str: [2]
|
|
||||||
no-negated-condition: [0]
|
|
||||||
no-nested-ternary: [0]
|
|
||||||
no-new-func: [2]
|
|
||||||
no-new-native-nonconstructor: [2]
|
|
||||||
no-new-object: [2]
|
|
||||||
no-new-symbol: [2]
|
|
||||||
no-new-wrappers: [2]
|
|
||||||
no-new: [0]
|
|
||||||
no-nonoctal-decimal-escape: [2]
|
|
||||||
no-obj-calls: [2]
|
|
||||||
no-octal-escape: [2]
|
|
||||||
no-octal: [2]
|
|
||||||
no-param-reassign: [0]
|
|
||||||
no-plusplus: [0]
|
|
||||||
no-promise-executor-return: [0]
|
|
||||||
no-proto: [2]
|
|
||||||
no-prototype-builtins: [2]
|
|
||||||
no-redeclare: [0] # must be disabled for typescript overloads
|
|
||||||
no-regex-spaces: [2]
|
|
||||||
no-restricted-exports: [0]
|
|
||||||
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
|
|
||||||
no-restricted-imports: [0]
|
|
||||||
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.ts instead"}]
|
|
||||||
no-return-assign: [0]
|
|
||||||
no-script-url: [2]
|
|
||||||
no-self-assign: [2, {props: true}]
|
|
||||||
no-self-compare: [2]
|
|
||||||
no-sequences: [2]
|
|
||||||
no-setter-return: [2]
|
|
||||||
no-shadow-restricted-names: [2]
|
|
||||||
no-shadow: [0]
|
|
||||||
no-sparse-arrays: [2]
|
|
||||||
no-template-curly-in-string: [2]
|
|
||||||
no-ternary: [0]
|
|
||||||
no-this-before-super: [2]
|
|
||||||
no-throw-literal: [2]
|
|
||||||
no-undef-init: [2]
|
|
||||||
no-undef: [2, {typeof: true}] # TODO: disable this rule after tsc passes
|
|
||||||
no-undefined: [0]
|
|
||||||
no-underscore-dangle: [0]
|
|
||||||
no-unexpected-multiline: [2]
|
|
||||||
no-unmodified-loop-condition: [2]
|
|
||||||
no-unneeded-ternary: [2]
|
|
||||||
no-unreachable-loop: [2]
|
|
||||||
no-unreachable: [2]
|
|
||||||
no-unsafe-finally: [2]
|
|
||||||
no-unsafe-negation: [2]
|
|
||||||
no-unused-expressions: [2]
|
|
||||||
no-unused-labels: [2]
|
|
||||||
no-unused-private-class-members: [2]
|
|
||||||
no-unused-vars: [0] # handled by @typescript-eslint/no-unused-vars
|
|
||||||
no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
|
|
||||||
no-use-extend-native/no-use-extend-native: [2]
|
|
||||||
no-useless-backreference: [2]
|
|
||||||
no-useless-call: [2]
|
|
||||||
no-useless-catch: [2]
|
|
||||||
no-useless-computed-key: [2]
|
|
||||||
no-useless-concat: [2]
|
|
||||||
no-useless-constructor: [2]
|
|
||||||
no-useless-escape: [2]
|
|
||||||
no-useless-rename: [2]
|
|
||||||
no-useless-return: [2]
|
|
||||||
no-var: [2]
|
|
||||||
no-void: [2]
|
|
||||||
no-warning-comments: [0]
|
|
||||||
no-with: [0] # handled by no-restricted-syntax
|
|
||||||
object-shorthand: [2, always]
|
|
||||||
one-var-declaration-per-line: [0]
|
|
||||||
one-var: [0]
|
|
||||||
operator-assignment: [2, always]
|
|
||||||
operator-linebreak: [2, after]
|
|
||||||
prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
|
|
||||||
prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}]
|
|
||||||
prefer-destructuring: [0]
|
|
||||||
prefer-exponentiation-operator: [2]
|
|
||||||
prefer-named-capture-group: [0]
|
|
||||||
prefer-numeric-literals: [2]
|
|
||||||
prefer-object-has-own: [2]
|
|
||||||
prefer-object-spread: [2]
|
|
||||||
prefer-promise-reject-errors: [2, {allowEmptyReject: false}]
|
|
||||||
prefer-regex-literals: [2]
|
|
||||||
prefer-rest-params: [2]
|
|
||||||
prefer-spread: [2]
|
|
||||||
prefer-template: [2]
|
|
||||||
radix: [2, as-needed]
|
|
||||||
regexp/confusing-quantifier: [2]
|
|
||||||
regexp/control-character-escape: [2]
|
|
||||||
regexp/hexadecimal-escape: [0]
|
|
||||||
regexp/letter-case: [0]
|
|
||||||
regexp/match-any: [2]
|
|
||||||
regexp/negation: [2]
|
|
||||||
regexp/no-contradiction-with-assertion: [0]
|
|
||||||
regexp/no-control-character: [0]
|
|
||||||
regexp/no-dupe-characters-character-class: [2]
|
|
||||||
regexp/no-dupe-disjunctions: [2]
|
|
||||||
regexp/no-empty-alternative: [2]
|
|
||||||
regexp/no-empty-capturing-group: [2]
|
|
||||||
regexp/no-empty-character-class: [0]
|
|
||||||
regexp/no-empty-group: [2]
|
|
||||||
regexp/no-empty-lookarounds-assertion: [2]
|
|
||||||
regexp/no-empty-string-literal: [2]
|
|
||||||
regexp/no-escape-backspace: [2]
|
|
||||||
regexp/no-extra-lookaround-assertions: [0]
|
|
||||||
regexp/no-invalid-regexp: [2]
|
|
||||||
regexp/no-invisible-character: [2]
|
|
||||||
regexp/no-lazy-ends: [2]
|
|
||||||
regexp/no-legacy-features: [2]
|
|
||||||
regexp/no-misleading-capturing-group: [0]
|
|
||||||
regexp/no-misleading-unicode-character: [0]
|
|
||||||
regexp/no-missing-g-flag: [2]
|
|
||||||
regexp/no-non-standard-flag: [2]
|
|
||||||
regexp/no-obscure-range: [2]
|
|
||||||
regexp/no-octal: [2]
|
|
||||||
regexp/no-optional-assertion: [2]
|
|
||||||
regexp/no-potentially-useless-backreference: [2]
|
|
||||||
regexp/no-standalone-backslash: [2]
|
|
||||||
regexp/no-super-linear-backtracking: [0]
|
|
||||||
regexp/no-super-linear-move: [0]
|
|
||||||
regexp/no-trivially-nested-assertion: [2]
|
|
||||||
regexp/no-trivially-nested-quantifier: [2]
|
|
||||||
regexp/no-unused-capturing-group: [0]
|
|
||||||
regexp/no-useless-assertions: [2]
|
|
||||||
regexp/no-useless-backreference: [2]
|
|
||||||
regexp/no-useless-character-class: [2]
|
|
||||||
regexp/no-useless-dollar-replacements: [2]
|
|
||||||
regexp/no-useless-escape: [2]
|
|
||||||
regexp/no-useless-flag: [2]
|
|
||||||
regexp/no-useless-lazy: [2]
|
|
||||||
regexp/no-useless-non-capturing-group: [2]
|
|
||||||
regexp/no-useless-quantifier: [2]
|
|
||||||
regexp/no-useless-range: [2]
|
|
||||||
regexp/no-useless-set-operand: [2]
|
|
||||||
regexp/no-useless-string-literal: [2]
|
|
||||||
regexp/no-useless-two-nums-quantifier: [2]
|
|
||||||
regexp/no-zero-quantifier: [2]
|
|
||||||
regexp/optimal-lookaround-quantifier: [2]
|
|
||||||
regexp/optimal-quantifier-concatenation: [0]
|
|
||||||
regexp/prefer-character-class: [0]
|
|
||||||
regexp/prefer-d: [0]
|
|
||||||
regexp/prefer-escape-replacement-dollar-char: [0]
|
|
||||||
regexp/prefer-lookaround: [0]
|
|
||||||
regexp/prefer-named-backreference: [0]
|
|
||||||
regexp/prefer-named-capture-group: [0]
|
|
||||||
regexp/prefer-named-replacement: [0]
|
|
||||||
regexp/prefer-plus-quantifier: [2]
|
|
||||||
regexp/prefer-predefined-assertion: [2]
|
|
||||||
regexp/prefer-quantifier: [0]
|
|
||||||
regexp/prefer-question-quantifier: [2]
|
|
||||||
regexp/prefer-range: [2]
|
|
||||||
regexp/prefer-regexp-exec: [2]
|
|
||||||
regexp/prefer-regexp-test: [2]
|
|
||||||
regexp/prefer-result-array-groups: [0]
|
|
||||||
regexp/prefer-set-operation: [2]
|
|
||||||
regexp/prefer-star-quantifier: [2]
|
|
||||||
regexp/prefer-unicode-codepoint-escapes: [2]
|
|
||||||
regexp/prefer-w: [0]
|
|
||||||
regexp/require-unicode-regexp: [0]
|
|
||||||
regexp/simplify-set-operations: [2]
|
|
||||||
regexp/sort-alternatives: [0]
|
|
||||||
regexp/sort-character-class-elements: [0]
|
|
||||||
regexp/sort-flags: [0]
|
|
||||||
regexp/strict: [2]
|
|
||||||
regexp/unicode-escape: [0]
|
|
||||||
regexp/use-ignore-case: [0]
|
|
||||||
require-atomic-updates: [0]
|
|
||||||
require-await: [0] # handled by @typescript-eslint/require-await
|
|
||||||
require-unicode-regexp: [0]
|
|
||||||
require-yield: [2]
|
|
||||||
sonarjs/cognitive-complexity: [0]
|
|
||||||
sonarjs/elseif-without-else: [0]
|
|
||||||
sonarjs/max-switch-cases: [0]
|
|
||||||
sonarjs/no-all-duplicated-branches: [2]
|
|
||||||
sonarjs/no-collapsible-if: [0]
|
|
||||||
sonarjs/no-collection-size-mischeck: [2]
|
|
||||||
sonarjs/no-duplicate-string: [0]
|
|
||||||
sonarjs/no-duplicated-branches: [0]
|
|
||||||
sonarjs/no-element-overwrite: [2]
|
|
||||||
sonarjs/no-empty-collection: [2]
|
|
||||||
sonarjs/no-extra-arguments: [2]
|
|
||||||
sonarjs/no-gratuitous-expressions: [2]
|
|
||||||
sonarjs/no-identical-conditions: [2]
|
|
||||||
sonarjs/no-identical-expressions: [2]
|
|
||||||
sonarjs/no-identical-functions: [2, 5]
|
|
||||||
sonarjs/no-ignored-return: [2]
|
|
||||||
sonarjs/no-inverted-boolean-check: [2]
|
|
||||||
sonarjs/no-nested-switch: [0]
|
|
||||||
sonarjs/no-nested-template-literals: [0]
|
|
||||||
sonarjs/no-one-iteration-loop: [2]
|
|
||||||
sonarjs/no-redundant-boolean: [2]
|
|
||||||
sonarjs/no-redundant-jump: [2]
|
|
||||||
sonarjs/no-same-line-conditional: [2]
|
|
||||||
sonarjs/no-small-switch: [0]
|
|
||||||
sonarjs/no-unused-collection: [2]
|
|
||||||
sonarjs/no-use-of-empty-return-value: [2]
|
|
||||||
sonarjs/no-useless-catch: [2]
|
|
||||||
sonarjs/non-existent-operator: [2]
|
|
||||||
sonarjs/prefer-immediate-return: [0]
|
|
||||||
sonarjs/prefer-object-literal: [0]
|
|
||||||
sonarjs/prefer-single-boolean-return: [0]
|
|
||||||
sonarjs/prefer-while: [2]
|
|
||||||
sort-imports: [0]
|
|
||||||
sort-keys: [0]
|
|
||||||
sort-vars: [0]
|
|
||||||
strict: [0]
|
|
||||||
symbol-description: [2]
|
|
||||||
unicode-bom: [2, never]
|
|
||||||
unicorn/better-regex: [0]
|
|
||||||
unicorn/catch-error-name: [0]
|
|
||||||
unicorn/consistent-destructuring: [2]
|
|
||||||
unicorn/consistent-empty-array-spread: [2]
|
|
||||||
unicorn/consistent-existence-index-check: [0]
|
|
||||||
unicorn/consistent-function-scoping: [0]
|
|
||||||
unicorn/custom-error-definition: [0]
|
|
||||||
unicorn/empty-brace-spaces: [2]
|
|
||||||
unicorn/error-message: [0]
|
|
||||||
unicorn/escape-case: [0]
|
|
||||||
unicorn/expiring-todo-comments: [0]
|
|
||||||
unicorn/explicit-length-check: [0]
|
|
||||||
unicorn/filename-case: [0]
|
|
||||||
unicorn/import-index: [0]
|
|
||||||
unicorn/import-style: [0]
|
|
||||||
unicorn/new-for-builtins: [2]
|
|
||||||
unicorn/no-abusive-eslint-disable: [0]
|
|
||||||
unicorn/no-anonymous-default-export: [0]
|
|
||||||
unicorn/no-array-callback-reference: [0]
|
|
||||||
unicorn/no-array-for-each: [2]
|
|
||||||
unicorn/no-array-method-this-argument: [2]
|
|
||||||
unicorn/no-array-push-push: [2]
|
|
||||||
unicorn/no-array-reduce: [2]
|
|
||||||
unicorn/no-await-expression-member: [0]
|
|
||||||
unicorn/no-await-in-promise-methods: [2]
|
|
||||||
unicorn/no-console-spaces: [0]
|
|
||||||
unicorn/no-document-cookie: [2]
|
|
||||||
unicorn/no-empty-file: [2]
|
|
||||||
unicorn/no-for-loop: [0]
|
|
||||||
unicorn/no-hex-escape: [0]
|
|
||||||
unicorn/no-instanceof-array: [0]
|
|
||||||
unicorn/no-invalid-fetch-options: [2]
|
|
||||||
unicorn/no-invalid-remove-event-listener: [2]
|
|
||||||
unicorn/no-keyword-prefix: [0]
|
|
||||||
unicorn/no-length-as-slice-end: [2]
|
|
||||||
unicorn/no-lonely-if: [2]
|
|
||||||
unicorn/no-magic-array-flat-depth: [0]
|
|
||||||
unicorn/no-negated-condition: [0]
|
|
||||||
unicorn/no-negation-in-equality-check: [2]
|
|
||||||
unicorn/no-nested-ternary: [0]
|
|
||||||
unicorn/no-new-array: [0]
|
|
||||||
unicorn/no-new-buffer: [0]
|
|
||||||
unicorn/no-null: [0]
|
|
||||||
unicorn/no-object-as-default-parameter: [0]
|
|
||||||
unicorn/no-process-exit: [0]
|
|
||||||
unicorn/no-single-promise-in-promise-methods: [2]
|
|
||||||
unicorn/no-static-only-class: [2]
|
|
||||||
unicorn/no-thenable: [2]
|
|
||||||
unicorn/no-this-assignment: [2]
|
|
||||||
unicorn/no-typeof-undefined: [2]
|
|
||||||
unicorn/no-unnecessary-await: [2]
|
|
||||||
unicorn/no-unnecessary-polyfills: [2]
|
|
||||||
unicorn/no-unreadable-array-destructuring: [0]
|
|
||||||
unicorn/no-unreadable-iife: [2]
|
|
||||||
unicorn/no-unused-properties: [2]
|
|
||||||
unicorn/no-useless-fallback-in-spread: [2]
|
|
||||||
unicorn/no-useless-length-check: [2]
|
|
||||||
unicorn/no-useless-promise-resolve-reject: [2]
|
|
||||||
unicorn/no-useless-spread: [2]
|
|
||||||
unicorn/no-useless-switch-case: [2]
|
|
||||||
unicorn/no-useless-undefined: [0]
|
|
||||||
unicorn/no-zero-fractions: [2]
|
|
||||||
unicorn/number-literal-case: [0]
|
|
||||||
unicorn/numeric-separators-style: [0]
|
|
||||||
unicorn/prefer-add-event-listener: [2]
|
|
||||||
unicorn/prefer-array-find: [2]
|
|
||||||
unicorn/prefer-array-flat-map: [2]
|
|
||||||
unicorn/prefer-array-flat: [2]
|
|
||||||
unicorn/prefer-array-index-of: [2]
|
|
||||||
unicorn/prefer-array-some: [2]
|
|
||||||
unicorn/prefer-at: [0]
|
|
||||||
unicorn/prefer-blob-reading-methods: [2]
|
|
||||||
unicorn/prefer-code-point: [0]
|
|
||||||
unicorn/prefer-date-now: [2]
|
|
||||||
unicorn/prefer-default-parameters: [0]
|
|
||||||
unicorn/prefer-dom-node-append: [2]
|
|
||||||
unicorn/prefer-dom-node-dataset: [0]
|
|
||||||
unicorn/prefer-dom-node-remove: [2]
|
|
||||||
unicorn/prefer-dom-node-text-content: [2]
|
|
||||||
unicorn/prefer-event-target: [2]
|
|
||||||
unicorn/prefer-export-from: [0]
|
|
||||||
unicorn/prefer-global-this: [0]
|
|
||||||
unicorn/prefer-includes: [2]
|
|
||||||
unicorn/prefer-json-parse-buffer: [0]
|
|
||||||
unicorn/prefer-keyboard-event-key: [2]
|
|
||||||
unicorn/prefer-logical-operator-over-ternary: [2]
|
|
||||||
unicorn/prefer-math-min-max: [2]
|
|
||||||
unicorn/prefer-math-trunc: [2]
|
|
||||||
unicorn/prefer-modern-dom-apis: [0]
|
|
||||||
unicorn/prefer-modern-math-apis: [2]
|
|
||||||
unicorn/prefer-module: [2]
|
|
||||||
unicorn/prefer-native-coercion-functions: [2]
|
|
||||||
unicorn/prefer-negative-index: [2]
|
|
||||||
unicorn/prefer-node-protocol: [2]
|
|
||||||
unicorn/prefer-number-properties: [0]
|
|
||||||
unicorn/prefer-object-from-entries: [2]
|
|
||||||
unicorn/prefer-object-has-own: [0]
|
|
||||||
unicorn/prefer-optional-catch-binding: [2]
|
|
||||||
unicorn/prefer-prototype-methods: [0]
|
|
||||||
unicorn/prefer-query-selector: [2]
|
|
||||||
unicorn/prefer-reflect-apply: [0]
|
|
||||||
unicorn/prefer-regexp-test: [2]
|
|
||||||
unicorn/prefer-set-has: [0]
|
|
||||||
unicorn/prefer-set-size: [2]
|
|
||||||
unicorn/prefer-spread: [0]
|
|
||||||
unicorn/prefer-string-raw: [0]
|
|
||||||
unicorn/prefer-string-replace-all: [0]
|
|
||||||
unicorn/prefer-string-slice: [0]
|
|
||||||
unicorn/prefer-string-starts-ends-with: [2]
|
|
||||||
unicorn/prefer-string-trim-start-end: [2]
|
|
||||||
unicorn/prefer-structured-clone: [2]
|
|
||||||
unicorn/prefer-switch: [0]
|
|
||||||
unicorn/prefer-ternary: [0]
|
|
||||||
unicorn/prefer-text-content: [2]
|
|
||||||
unicorn/prefer-top-level-await: [0]
|
|
||||||
unicorn/prefer-type-error: [0]
|
|
||||||
unicorn/prevent-abbreviations: [0]
|
|
||||||
unicorn/relative-url-style: [2]
|
|
||||||
unicorn/require-array-join-separator: [2]
|
|
||||||
unicorn/require-number-to-fixed-digits-argument: [2]
|
|
||||||
unicorn/require-post-message-target-origin: [0]
|
|
||||||
unicorn/string-content: [0]
|
|
||||||
unicorn/switch-case-braces: [0]
|
|
||||||
unicorn/template-indent: [2]
|
|
||||||
unicorn/text-encoding-identifier-case: [0]
|
|
||||||
unicorn/throw-new-error: [2]
|
|
||||||
use-isnan: [2]
|
|
||||||
valid-typeof: [2, {requireStringLiterals: true}]
|
|
||||||
vars-on-top: [0]
|
|
||||||
wc/attach-shadow-constructor: [2]
|
|
||||||
wc/define-tag-after-class-definition: [0]
|
|
||||||
wc/expose-class-on-global: [0]
|
|
||||||
wc/file-name-matches-element: [2]
|
|
||||||
wc/guard-define-call: [0]
|
|
||||||
wc/guard-super-call: [2]
|
|
||||||
wc/max-elements-per-file: [0]
|
|
||||||
wc/no-child-traversal-in-attributechangedcallback: [2]
|
|
||||||
wc/no-child-traversal-in-connectedcallback: [2]
|
|
||||||
wc/no-closed-shadow-root: [2]
|
|
||||||
wc/no-constructor-attributes: [2]
|
|
||||||
wc/no-constructor-params: [2]
|
|
||||||
wc/no-constructor: [2]
|
|
||||||
wc/no-customized-built-in-elements: [2]
|
|
||||||
wc/no-exports-with-element: [0]
|
|
||||||
wc/no-invalid-element-name: [2]
|
|
||||||
wc/no-invalid-extends: [2]
|
|
||||||
wc/no-method-prefixed-with-on: [2]
|
|
||||||
wc/no-self-class: [2]
|
|
||||||
wc/no-typos: [2]
|
|
||||||
wc/require-listener-teardown: [2]
|
|
||||||
wc/tag-name-matches-class: [2]
|
|
||||||
yoda: [2, never]
|
|
@ -1,5 +1,5 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
|
FROM docker.io/library/golang:1.23-alpine3.21 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-direct}
|
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
|
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
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"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
|
|
||||||
EXPOSE 22 3000
|
EXPOSE 22 3000
|
||||||
@ -78,7 +78,7 @@ ENV GITEA_CUSTOM=/data/gitea
|
|||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
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 /tmp/local /
|
||||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
|
FROM docker.io/library/golang:1.23-alpine3.21 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-direct}
|
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
|
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
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"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
|
|
||||||
EXPOSE 2222 3000
|
EXPOSE 2222 3000
|
||||||
|
@ -46,7 +46,6 @@ Wim <wim@42.be> (@42wim)
|
|||||||
Jason Song <i@wolfogre.com> (@wolfogre)
|
Jason Song <i@wolfogre.com> (@wolfogre)
|
||||||
Yarden Shoham <git@yardenshoham.com> (@yardenshoham)
|
Yarden Shoham <git@yardenshoham.com> (@yardenshoham)
|
||||||
Yu Tian <zettat123@gmail.com> (@Zettat123)
|
Yu Tian <zettat123@gmail.com> (@Zettat123)
|
||||||
Eddie Yang <576951401@qq.com> (@yp05327)
|
|
||||||
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
||||||
Xinyi Gong <hestergong@gmail.com> (@HesterG)
|
Xinyi Gong <hestergong@gmail.com> (@HesterG)
|
||||||
wxiaoguang <wxiaoguang@gmail.com> (@wxiaoguang)
|
wxiaoguang <wxiaoguang@gmail.com> (@wxiaoguang)
|
||||||
|
8
Makefile
8
Makefile
@ -26,17 +26,17 @@ COMMA := ,
|
|||||||
XGO_VERSION := go-1.23.x
|
XGO_VERSION := go-1.23.x
|
||||||
|
|
||||||
AIR_PACKAGE ?= github.com/air-verse/air@v1
|
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.0.3
|
||||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0
|
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0
|
||||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
|
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
|
||||||
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
|
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.12
|
||||||
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1
|
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0
|
||||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0
|
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0
|
||||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
|
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
|
||||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
|
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
|
||||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@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.0
|
||||||
|
|
||||||
DOCKER_IMAGE ?= gitea/gitea
|
DOCKER_IMAGE ?= gitea/gitea
|
||||||
DOCKER_TAG ?= latest
|
DOCKER_TAG ?= latest
|
||||||
|
2
go.mod
2
go.mod
@ -123,7 +123,7 @@ require (
|
|||||||
github.com/yuin/goldmark-meta v1.1.0
|
github.com/yuin/goldmark-meta v1.1.0
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.31.0
|
||||||
golang.org/x/image v0.21.0
|
golang.org/x/image v0.21.0
|
||||||
golang.org/x/net v0.30.0
|
golang.org/x/net v0.33.0
|
||||||
golang.org/x/oauth2 v0.23.0
|
golang.org/x/oauth2 v0.23.0
|
||||||
golang.org/x/sync v0.10.0
|
golang.org/x/sync v0.10.0
|
||||||
golang.org/x/sys v0.28.0
|
golang.org/x/sys v0.28.0
|
||||||
|
4
go.sum
4
go.sum
@ -932,8 +932,8 @@ 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.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -153,28 +153,34 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AggregateJobStatus(jobs []*ActionRunJob) Status {
|
func AggregateJobStatus(jobs []*ActionRunJob) Status {
|
||||||
allDone := true
|
allSuccessOrSkipped := len(jobs) != 0
|
||||||
allWaiting := true
|
allSkipped := len(jobs) != 0
|
||||||
hasFailure := false
|
var hasFailure, hasCancelled, hasWaiting, hasRunning, hasBlocked bool
|
||||||
for _, job := range jobs {
|
for _, job := range jobs {
|
||||||
if !job.Status.IsDone() {
|
allSuccessOrSkipped = allSuccessOrSkipped && (job.Status == StatusSuccess || job.Status == StatusSkipped)
|
||||||
allDone = false
|
allSkipped = allSkipped && job.Status == StatusSkipped
|
||||||
}
|
hasFailure = hasFailure || job.Status == StatusFailure
|
||||||
if job.Status != StatusWaiting && !job.Status.IsDone() {
|
hasCancelled = hasCancelled || job.Status == StatusCancelled
|
||||||
allWaiting = false
|
hasWaiting = hasWaiting || job.Status == StatusWaiting
|
||||||
}
|
hasRunning = hasRunning || job.Status == StatusRunning
|
||||||
if job.Status == StatusFailure || job.Status == StatusCancelled {
|
hasBlocked = hasBlocked || job.Status == StatusBlocked
|
||||||
hasFailure = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if allDone {
|
|
||||||
if hasFailure {
|
|
||||||
return StatusFailure
|
|
||||||
}
|
}
|
||||||
|
switch {
|
||||||
|
case allSkipped:
|
||||||
|
return StatusSkipped
|
||||||
|
case allSuccessOrSkipped:
|
||||||
return StatusSuccess
|
return StatusSuccess
|
||||||
}
|
case hasCancelled:
|
||||||
if allWaiting {
|
return StatusCancelled
|
||||||
return StatusWaiting
|
case hasFailure:
|
||||||
}
|
return StatusFailure
|
||||||
|
case hasRunning:
|
||||||
return StatusRunning
|
return StatusRunning
|
||||||
|
case hasWaiting:
|
||||||
|
return StatusWaiting
|
||||||
|
case hasBlocked:
|
||||||
|
return StatusBlocked
|
||||||
|
default:
|
||||||
|
return StatusUnknown // it shouldn't happen
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
85
models/actions/run_job_status_test.go
Normal file
85
models/actions/run_job_status_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -511,7 +511,7 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.RequestedTeam != nil {
|
if opts.RequestedTeam != nil {
|
||||||
env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam)
|
env := repo_model.AccessibleTeamReposEnv(ctx, organization.OrgFromUser(opts.RequestedUser), opts.RequestedTeam)
|
||||||
teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
|
teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("GetTeamRepositories: %w", err)
|
return nil, fmt.Errorf("GetTeamRepositories: %w", err)
|
||||||
|
@ -217,6 +217,7 @@ func (err ErrGPGKeyAccessDenied) Unwrap() error {
|
|||||||
// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error.
|
// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error.
|
||||||
type ErrKeyAccessDenied struct {
|
type ErrKeyAccessDenied struct {
|
||||||
UserID int64
|
UserID int64
|
||||||
|
RepoID int64
|
||||||
KeyID int64
|
KeyID int64
|
||||||
Note string
|
Note string
|
||||||
}
|
}
|
||||||
@ -228,8 +229,8 @@ func IsErrKeyAccessDenied(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrKeyAccessDenied) Error() string {
|
func (err ErrKeyAccessDenied) Error() string {
|
||||||
return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d, note: %s]",
|
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.KeyID, err.Note)
|
err.UserID, err.RepoID, err.KeyID, err.Note)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrKeyAccessDenied) Unwrap() error {
|
func (err ErrKeyAccessDenied) Unwrap() error {
|
||||||
|
@ -13,6 +13,8 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"xorm.io/xorm"
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,7 +56,8 @@ func TestDumpAuthSource(t *testing.T) {
|
|||||||
|
|
||||||
sb := new(strings.Builder)
|
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"`)
|
assert.Contains(t, sb.String(), `"Provider":"ConvertibleSourceName"`)
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ func CheckCollations(x *xorm.Engine) (*CheckCollationsResult, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) {
|
func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) {
|
||||||
return CheckCollations(x)
|
return CheckCollations(xormEngine)
|
||||||
}
|
}
|
||||||
|
|
||||||
func alterDatabaseCollation(x *xorm.Engine, collation string) error {
|
func alterDatabaseCollation(x *xorm.Engine, collation string) error {
|
||||||
|
@ -94,7 +94,7 @@ func GetEngine(ctx context.Context) Engine {
|
|||||||
if e := getExistingEngine(ctx); e != nil {
|
if e := getExistingEngine(ctx); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
return x.Context(ctx)
|
return xormEngine.Context(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getExistingEngine gets an existing db Engine/Statement from this context or returns nil
|
// getExistingEngine gets an existing db Engine/Statement from this context or returns nil
|
||||||
@ -155,7 +155,7 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) {
|
|||||||
return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil
|
return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := xormEngine.NewSession()
|
||||||
if err := sess.Begin(); err != nil {
|
if err := sess.Begin(); err != nil {
|
||||||
_ = sess.Close()
|
_ = sess.Close()
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -179,7 +179,7 @@ func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error {
|
func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error {
|
||||||
sess := x.NewSession()
|
sess := xormEngine.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
if err := sess.Begin(); err != nil {
|
if err := sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -322,7 +322,7 @@ func CountByBean(ctx context.Context, bean any) (int64, error) {
|
|||||||
|
|
||||||
// TableName returns the table name according a bean object
|
// TableName returns the table name according a bean object
|
||||||
func TableName(bean any) string {
|
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
|
// InTransaction returns true if the engine is in a transaction otherwise return false
|
||||||
|
@ -16,30 +16,30 @@ import (
|
|||||||
|
|
||||||
// ConvertDatabaseTable converts database and tables from utf8 to utf8mb4 if it's mysql and set ROW_FORMAT=dynamic
|
// ConvertDatabaseTable converts database and tables from utf8 to utf8mb4 if it's mysql and set ROW_FORMAT=dynamic
|
||||||
func ConvertDatabaseTable() error {
|
func ConvertDatabaseTable() error {
|
||||||
if x.Dialect().URI().DBType != schemas.MYSQL {
|
if xormEngine.Dialect().URI().DBType != schemas.MYSQL {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := CheckCollations(x)
|
r, err := CheckCollations(xormEngine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tables, err := x.DBMetas()
|
tables, err := xormEngine.DBMetas()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, table := range tables {
|
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
|
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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,11 +49,11 @@ func ConvertDatabaseTable() error {
|
|||||||
|
|
||||||
// ConvertVarcharToNVarchar converts database and tables from varchar to nvarchar if it's mssql
|
// ConvertVarcharToNVarchar converts database and tables from varchar to nvarchar if it's mssql
|
||||||
func ConvertVarcharToNVarchar() error {
|
func ConvertVarcharToNVarchar() error {
|
||||||
if x.Dialect().URI().DBType != schemas.MSSQL {
|
if xormEngine.Dialect().URI().DBType != schemas.MSSQL {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := xormEngine.NewSession()
|
||||||
defer sess.Close()
|
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) + ')'
|
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
|
FROM SYS.columns SC
|
||||||
|
@ -8,17 +8,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
|
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
"xorm.io/xorm/contexts"
|
|
||||||
"xorm.io/xorm/names"
|
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver
|
_ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver
|
||||||
@ -27,9 +20,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
x *xorm.Engine
|
xormEngine *xorm.Engine
|
||||||
tables []any
|
registeredModels []any
|
||||||
initFuncs []func() error
|
registeredInitFuncs []func() error
|
||||||
)
|
)
|
||||||
|
|
||||||
// Engine represents a xorm engine or session.
|
// Engine represents a xorm engine or session.
|
||||||
@ -70,167 +63,38 @@ type Engine interface {
|
|||||||
|
|
||||||
// TableInfo returns table's information via an object
|
// TableInfo returns table's information via an object
|
||||||
func TableInfo(v any) (*schemas.Table, error) {
|
func TableInfo(v any) (*schemas.Table, error) {
|
||||||
return x.TableInfo(v)
|
return xormEngine.TableInfo(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpTables dump tables information
|
// RegisterModel registers model, if initFuncs provided, it will be invoked after data model sync
|
||||||
func DumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
|
|
||||||
return x.DumpTables(tables, w, tp...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterModel registers model, if initfunc provided, it will be invoked after data model sync
|
|
||||||
func RegisterModel(bean any, initFunc ...func() error) {
|
func RegisterModel(bean any, initFunc ...func() error) {
|
||||||
tables = append(tables, bean)
|
registeredModels = append(registeredModels, bean)
|
||||||
if len(initFuncs) > 0 && initFunc[0] != nil {
|
if len(registeredInitFuncs) > 0 && initFunc[0] != nil {
|
||||||
initFuncs = append(initFuncs, initFunc[0])
|
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
|
// SyncAllTables sync the schemas of all tables, is required by unit test code
|
||||||
func SyncAllTables() error {
|
func SyncAllTables() error {
|
||||||
_, err := x.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{
|
_, err := xormEngine.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{
|
||||||
WarnIfDatabaseColumnMissed: true,
|
WarnIfDatabaseColumnMissed: true,
|
||||||
}, tables...)
|
}, registeredModels...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext
|
|
||||||
func InitEngine(ctx context.Context) error {
|
|
||||||
xormEngine, err := newXORMEngine()
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), "SQLite3 support") {
|
|
||||||
return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to connect to database: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
xormEngine.SetMapper(names.GonicMapper{})
|
|
||||||
// WARNING: for serv command, MUST remove the output to os.stdout,
|
|
||||||
// so use log file to instead print to stdout.
|
|
||||||
xormEngine.SetLogger(NewXORMLogger(setting.Database.LogSQL))
|
|
||||||
xormEngine.ShowSQL(setting.Database.LogSQL)
|
|
||||||
xormEngine.SetMaxOpenConns(setting.Database.MaxOpenConns)
|
|
||||||
xormEngine.SetMaxIdleConns(setting.Database.MaxIdleConns)
|
|
||||||
xormEngine.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
|
|
||||||
xormEngine.SetDefaultContext(ctx)
|
|
||||||
|
|
||||||
if setting.Database.SlowQueryThreshold > 0 {
|
|
||||||
xormEngine.AddHook(&SlowQueryHook{
|
|
||||||
Threshold: setting.Database.SlowQueryThreshold,
|
|
||||||
Logger: log.GetLogger("xorm"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
SetDefaultEngine(ctx, xormEngine)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDefaultEngine sets the default engine for db
|
|
||||||
func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) {
|
|
||||||
x = eng
|
|
||||||
DefaultContext = &Context{Context: ctx, engine: x}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnsetDefaultEngine closes and unsets the default engine
|
|
||||||
// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now,
|
|
||||||
// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `x` and DefaultContext without close
|
|
||||||
// Global database engine related functions are all racy and there is no graceful close right now.
|
|
||||||
func UnsetDefaultEngine() {
|
|
||||||
if x != nil {
|
|
||||||
_ = x.Close()
|
|
||||||
x = nil
|
|
||||||
}
|
|
||||||
DefaultContext = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitEngineWithMigration initializes a new xorm.Engine and sets it as the db.DefaultContext
|
|
||||||
// This function must never call .Sync() if the provided migration function fails.
|
|
||||||
// When called from the "doctor" command, the migration function is a version check
|
|
||||||
// that prevents the doctor from fixing anything in the database if the migration level
|
|
||||||
// is different from the expected value.
|
|
||||||
func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) {
|
|
||||||
if err = InitEngine(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = x.Ping(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
preprocessDatabaseCollation(x)
|
|
||||||
|
|
||||||
// We have to run migrateFunc here in case the user is re-running installation on a previously created DB.
|
|
||||||
// If we do not then table schemas will be changed and there will be conflicts when the migrations run properly.
|
|
||||||
//
|
|
||||||
// Installation should only be being re-run if users want to recover an old database.
|
|
||||||
// However, we should think carefully about should we support re-install on an installed instance,
|
|
||||||
// as there may be other problems due to secret reinitialization.
|
|
||||||
if err = migrateFunc(x); err != nil {
|
|
||||||
return fmt.Errorf("migrate: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = SyncAllTables(); err != nil {
|
|
||||||
return fmt.Errorf("sync database struct error: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, initFunc := range initFuncs {
|
|
||||||
if err := initFunc(); err != nil {
|
|
||||||
return fmt.Errorf("initFunc failed: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NamesToBean return a list of beans or an error
|
// NamesToBean return a list of beans or an error
|
||||||
func NamesToBean(names ...string) ([]any, error) {
|
func NamesToBean(names ...string) ([]any, error) {
|
||||||
beans := []any{}
|
beans := []any{}
|
||||||
if len(names) == 0 {
|
if len(names) == 0 {
|
||||||
beans = append(beans, tables...)
|
beans = append(beans, registeredModels...)
|
||||||
return beans, nil
|
return beans, nil
|
||||||
}
|
}
|
||||||
// Need to map provided names to beans...
|
// Need to map provided names to beans...
|
||||||
beanMap := make(map[string]any)
|
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(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean
|
||||||
beanMap[strings.ToLower(x.TableName(bean))] = bean
|
beanMap[strings.ToLower(xormEngine.TableName(bean))] = bean
|
||||||
beanMap[strings.ToLower(x.TableName(bean, true))] = bean
|
beanMap[strings.ToLower(xormEngine.TableName(bean, true))] = bean
|
||||||
}
|
}
|
||||||
|
|
||||||
gotBean := make(map[any]bool)
|
gotBean := make(map[any]bool)
|
||||||
@ -247,36 +111,9 @@ func NamesToBean(names ...string) ([]any, error) {
|
|||||||
return beans, nil
|
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
|
// MaxBatchInsertSize returns the table's max batch insert size
|
||||||
func MaxBatchInsertSize(bean any) int {
|
func MaxBatchInsertSize(bean any) int {
|
||||||
t, err := x.TableInfo(bean)
|
t, err := xormEngine.TableInfo(bean)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 50
|
return 50
|
||||||
}
|
}
|
||||||
@ -285,18 +122,18 @@ func MaxBatchInsertSize(bean any) int {
|
|||||||
|
|
||||||
// IsTableNotEmpty returns true if table has at least one record
|
// IsTableNotEmpty returns true if table has at least one record
|
||||||
func IsTableNotEmpty(beanOrTableName any) (bool, error) {
|
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
|
// DeleteAllRecords will delete all the records of this table
|
||||||
func DeleteAllRecords(tableName string) error {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMaxID will return max id of the table
|
// GetMaxID will return max id of the table
|
||||||
func GetMaxID(beanOrTableName any) (maxID int64, err error) {
|
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
|
return maxID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,24 +145,3 @@ func SetLogSQL(ctx context.Context, on bool) {
|
|||||||
sess.Engine().ShowSQL(on)
|
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
|
|
||||||
}
|
|
||||||
|
33
models/db/engine_dump.go
Normal file
33
models/db/engine_dump.go
Normal file
@ -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)
|
||||||
|
}
|
34
models/db/engine_hook.go
Normal file
34
models/db/engine_hook.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
|
"xorm.io/xorm/contexts"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SlowQueryHook struct {
|
||||||
|
Threshold time.Duration
|
||||||
|
Logger log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ contexts.Hook = (*SlowQueryHook)(nil)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
140
models/db/engine_init.go
Normal file
140
models/db/engine_init.go
Normal file
@ -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(&SlowQueryHook{
|
||||||
|
Threshold: setting.Database.SlowQueryThreshold,
|
||||||
|
Logger: log.GetLogger("xorm"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDefaultEngine(ctx, xe)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultEngine sets the default engine for db
|
||||||
|
func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) {
|
||||||
|
xormEngine = eng
|
||||||
|
DefaultContext = &Context{Context: ctx, engine: xormEngine}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnsetDefaultEngine closes and unsets the default engine
|
||||||
|
// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now,
|
||||||
|
// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `xormEngine` and DefaultContext without close
|
||||||
|
// Global database engine related functions are all racy and there is no graceful close right now.
|
||||||
|
func UnsetDefaultEngine() {
|
||||||
|
if xormEngine != nil {
|
||||||
|
_ = xormEngine.Close()
|
||||||
|
xormEngine = nil
|
||||||
|
}
|
||||||
|
DefaultContext = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitEngineWithMigration initializes a new xorm.Engine and sets it as the db.DefaultContext
|
||||||
|
// This function must never call .Sync() if the provided migration function fails.
|
||||||
|
// When called from the "doctor" command, the migration function is a version check
|
||||||
|
// that prevents the doctor from fixing anything in the database if the migration level
|
||||||
|
// is different from the expected value.
|
||||||
|
func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) {
|
||||||
|
if err = InitEngine(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = xormEngine.Ping(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
preprocessDatabaseCollation(xormEngine)
|
||||||
|
|
||||||
|
// We have to run migrateFunc here in case the user is re-running installation on a previously created DB.
|
||||||
|
// If we do not then table schemas will be changed and there will be conflicts when the migrations run properly.
|
||||||
|
//
|
||||||
|
// Installation should only be being re-run if users want to recover an old database.
|
||||||
|
// However, we should think carefully about should we support re-install on an installed instance,
|
||||||
|
// as there may be other problems due to secret reinitialization.
|
||||||
|
if err = migrateFunc(xormEngine); err != nil {
|
||||||
|
return fmt.Errorf("migrate: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = SyncAllTables(); err != nil {
|
||||||
|
return fmt.Errorf("sync database struct error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, initFunc := range registeredInitFuncs {
|
||||||
|
if err := initFunc(); err != nil {
|
||||||
|
return fmt.Errorf("initFunc failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -16,7 +16,7 @@ var (
|
|||||||
// ErrNameEmpty name is empty error
|
// ErrNameEmpty name is empty error
|
||||||
ErrNameEmpty = util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument}
|
ErrNameEmpty = util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument}
|
||||||
|
|
||||||
// AlphaDashDotPattern characters prohibited in a user name (anything except A-Za-z0-9_.-)
|
// AlphaDashDotPattern characters prohibited in a username (anything except A-Za-z0-9_.-)
|
||||||
AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
|
AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,11 +17,11 @@ func CountBadSequences(_ context.Context) (int64, error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := xormEngine.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
|
|
||||||
var sequences []string
|
var sequences []string
|
||||||
schema := x.Dialect().URI().Schema
|
schema := xormEngine.Dialect().URI().Schema
|
||||||
|
|
||||||
sess.Engine().SetSchema("")
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := xormEngine.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
if err := sess.Begin(); err != nil {
|
if err := sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
552
models/error.go
552
models/error.go
@ -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)
|
|
||||||
}
|
|
@ -13,9 +13,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/modules/testlogger"
|
"code.gitea.io/gitea/modules/testlogger"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -92,10 +92,7 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu
|
|||||||
func MainTest(m *testing.M) {
|
func MainTest(m *testing.M) {
|
||||||
testlogger.Init()
|
testlogger.Init()
|
||||||
|
|
||||||
giteaRoot := base.SetupGiteaRoot()
|
giteaRoot := test.SetupGiteaRoot()
|
||||||
if giteaRoot == "" {
|
|
||||||
testlogger.Fatalf("Environment variable $GITEA_ROOT not set\n")
|
|
||||||
}
|
|
||||||
giteaBinary := "gitea"
|
giteaBinary := "gitea"
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
giteaBinary += ".exe"
|
giteaBinary += ".exe"
|
||||||
|
@ -9,11 +9,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
actions_model "code.gitea.io/gitea/models/actions"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"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"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
@ -407,33 +404,6 @@ func GetOrgByName(ctx context.Context, name string) (*Organization, error) {
|
|||||||
return u, nil
|
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
|
// GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization
|
||||||
func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) {
|
func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) {
|
||||||
var authorize perm.AccessMode
|
var authorize perm.AccessMode
|
||||||
@ -604,7 +574,9 @@ func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error {
|
|||||||
return err
|
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)
|
teams := make([]*Team, 0, org.NumTeams)
|
||||||
return teams, db.GetEngine(ctx).
|
return teams, db.GetEngine(ctx).
|
||||||
Where("`team_user`.org_id = ?", org.ID).
|
Where("`team_user`.org_id = ?", org.ID).
|
||||||
@ -616,7 +588,8 @@ func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ..
|
|||||||
Find(&teams)
|
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)
|
teamIDs := make([]int64, 0, org.NumTeams)
|
||||||
return teamIDs, db.GetEngine(ctx).
|
return teamIDs, db.GetEngine(ctx).
|
||||||
Table("team").
|
Table("team").
|
||||||
@ -640,175 +613,3 @@ func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder {
|
|||||||
func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) {
|
func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) {
|
||||||
return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode)
|
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
|
|
||||||
}
|
|
||||||
|
@ -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)
|
|
||||||
}
|
|
@ -318,7 +318,7 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
||||||
testSuccess := func(userID, expectedCount int64) {
|
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)
|
assert.NoError(t, err)
|
||||||
count, err := env.CountRepos()
|
count, err := env.CountRepos()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -332,7 +332,7 @@ func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
||||||
testSuccess := func(userID int64, expectedRepoIDs []int64) {
|
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)
|
assert.NoError(t, err)
|
||||||
repoIDs, err := env.RepoIDs(1, 100)
|
repoIDs, err := env.RepoIDs(1, 100)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -346,7 +346,7 @@ func TestAccessibleReposEnv_Repos(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
||||||
testSuccess := func(userID int64, expectedRepoIDs []int64) {
|
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)
|
assert.NoError(t, err)
|
||||||
repos, err := env.Repos(1, 100)
|
repos, err := env.Repos(1, 100)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -365,7 +365,7 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
||||||
testSuccess := func(userID int64, expectedRepoIDs []int64) {
|
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)
|
assert.NoError(t, err)
|
||||||
repos, err := env.MirrorRepos()
|
repos, err := env.MirrorRepos()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -36,6 +36,21 @@ func init() {
|
|||||||
db.RegisterModel(new(OrgUser))
|
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.
|
// GetOrganizationCount returns count of membership of organization of the user.
|
||||||
func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) {
|
func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) {
|
||||||
return db.GetEngine(ctx).
|
return db.GetEngine(ctx).
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
@ -79,7 +78,6 @@ type Team struct {
|
|||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
AccessMode perm.AccessMode `xorm:"'authorize'"`
|
AccessMode perm.AccessMode `xorm:"'authorize'"`
|
||||||
Repos []*repo_model.Repository `xorm:"-"`
|
|
||||||
Members []*user_model.User `xorm:"-"`
|
Members []*user_model.User `xorm:"-"`
|
||||||
NumRepos int
|
NumRepos int
|
||||||
NumMembers int
|
NumMembers int
|
||||||
@ -155,17 +153,6 @@ func (t *Team) IsMember(ctx context.Context, userID int64) bool {
|
|||||||
return isMember
|
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.
|
// LoadMembers returns paginated members in team of organization.
|
||||||
func (t *Team) LoadMembers(ctx context.Context) (err error) {
|
func (t *Team) LoadMembers(ctx context.Context) (err error) {
|
||||||
t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
|
t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"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
|
// 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).
|
return teams, db.GetEngine(ctx).
|
||||||
Join("INNER", "team_repo", "team_repo.team_id = team.id").
|
Join("INNER", "team_repo", "team_repo.team_id = team.id").
|
||||||
Where("team.org_id = ?", repo.OwnerID).
|
Where("team.org_id = ?", orgID).
|
||||||
And("team_repo.repo_id=?", repo.ID).
|
And("team_repo.repo_id=?", repoID).
|
||||||
OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
|
OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
|
||||||
Find(&teams)
|
Find(&teams)
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,7 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
|
||||||
"xorm.io/builder"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TeamRepo represents an team-repository relation.
|
// TeamRepo represents an team-repository relation.
|
||||||
@ -32,29 +29,6 @@ func HasTeamRepo(ctx context.Context, orgID, teamID, repoID int64) bool {
|
|||||||
return has
|
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
|
// AddTeamRepo adds a repo for an organization's team
|
||||||
func AddTeamRepo(ctx context.Context, orgID, teamID, repoID int64) error {
|
func AddTeamRepo(ctx context.Context, orgID, teamID, repoID int64) error {
|
||||||
_, err := db.GetEngine(ctx).Insert(&TeamRepo{
|
_, err := db.GetEngine(ctx).Insert(&TeamRepo{
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -42,9 +43,12 @@ func TestTeam_GetRepositories(t *testing.T) {
|
|||||||
|
|
||||||
test := func(teamID int64) {
|
test := func(teamID int64) {
|
||||||
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
||||||
assert.NoError(t, team.LoadRepositories(db.DefaultContext))
|
repos, err := repo_model.GetTeamRepositories(db.DefaultContext, &repo_model.SearchTeamRepoOptions{
|
||||||
assert.Len(t, team.Repos, team.NumRepos)
|
TeamID: team.ID,
|
||||||
for _, repo := range team.Repos {
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, repos, team.NumRepos)
|
||||||
|
for _, repo := range repos {
|
||||||
unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID})
|
unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,6 +301,21 @@ func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
|
|||||||
Find(&ps)
|
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
|
// HasOwnerPackages tests if a user/org has accessible packages
|
||||||
func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {
|
func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {
|
||||||
return db.GetEngine(ctx).
|
return db.GetEngine(ctx).
|
||||||
|
@ -6,15 +6,12 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
_ "image/jpeg" // Needed for jpeg support
|
_ "image/jpeg" // Needed for jpeg support
|
||||||
|
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
@ -315,48 +312,3 @@ func DoctorUserStarNum(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteDeployKey delete deploy keys
|
|
||||||
func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error {
|
|
||||||
key, err := asymkey_model.GetDeployKeyByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
if asymkey_model.IsErrDeployKeyNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("GetDeployKeyByID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user has access to delete this key.
|
|
||||||
if !doer.IsAdmin {
|
|
||||||
repo, err := repo_model.GetRepositoryByID(ctx, key.RepoID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("GetRepositoryByID: %w", err)
|
|
||||||
}
|
|
||||||
has, err := access_model.IsUserRepoAdmin(ctx, repo, doer)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("GetUserRepoPermission: %w", err)
|
|
||||||
} else if !has {
|
|
||||||
return asymkey_model.ErrKeyAccessDenied{
|
|
||||||
UserID: doer.ID,
|
|
||||||
KeyID: key.ID,
|
|
||||||
Note: "deploy",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := db.DeleteByID[asymkey_model.DeployKey](ctx, key.ID); err != nil {
|
|
||||||
return fmt.Errorf("delete deploy key [%d]: %w", key.ID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is the last reference to same key content.
|
|
||||||
has, err := asymkey_model.IsDeployKeyExistByKeyID(ctx, key.KeyID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if !has {
|
|
||||||
if _, err = db.DeleteByID[asymkey_model.PublicKey](ctx, key.KeyID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
206
models/repo/org_repo.go
Normal file
206
models/repo/org_repo.go
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
org_model "code.gitea.io/gitea/models/organization"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetOrgRepositories get repos belonging to the given organization
|
||||||
|
func GetOrgRepositories(ctx context.Context, orgID int64) (RepositoryList, error) {
|
||||||
|
var orgRepos []*Repository
|
||||||
|
return orgRepos, db.GetEngine(ctx).Where("owner_id = ?", orgID).Find(&orgRepos)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchTeamRepoOptions struct {
|
||||||
|
db.ListOptions
|
||||||
|
TeamID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepositories returns paginated repositories in team of organization.
|
||||||
|
func GetTeamRepositories(ctx context.Context, opts *SearchTeamRepoOptions) (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 []*Repository
|
||||||
|
return repos, sess.OrderBy("repository.name").
|
||||||
|
Find(&repos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) (RepositoryList, error)
|
||||||
|
MirrorRepos() (RepositoryList, error)
|
||||||
|
AddKeyword(keyword string)
|
||||||
|
SetSort(db.SearchOrderBy)
|
||||||
|
}
|
||||||
|
|
||||||
|
type accessibleReposEnv struct {
|
||||||
|
org *org_model.Organization
|
||||||
|
user *user_model.User
|
||||||
|
team *org_model.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 *org_model.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 AccessibleTeamReposEnv(ctx context.Context, org *org_model.Organization, team *org_model.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(&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) (RepositoryList, error) {
|
||||||
|
repoIDs, err := env.RepoIDs(page, pageSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("GetUserRepositoryIDs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repos := make([]*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() (RepositoryList, error) {
|
||||||
|
repoIDs, err := env.MirrorRepoIDs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("MirrorRepoIDs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repos := make([]*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
|
||||||
|
}
|
@ -37,7 +37,7 @@ type ErrUserDoesNotHaveAccessToRepo struct {
|
|||||||
RepoName string
|
RepoName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrRepoFileAlreadyExists.
|
// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrUserDoesNotHaveAccessToRepo.
|
||||||
func IsErrUserDoesNotHaveAccessToRepo(err error) bool {
|
func IsErrUserDoesNotHaveAccessToRepo(err error) bool {
|
||||||
_, ok := err.(ErrUserDoesNotHaveAccessToRepo)
|
_, ok := err.(ErrUserDoesNotHaveAccessToRepo)
|
||||||
return ok
|
return ok
|
||||||
@ -866,6 +866,21 @@ func (repo *Repository) TemplateRepo(ctx context.Context) *Repository {
|
|||||||
return repo
|
return repo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
type CountRepositoryOptions struct {
|
type CountRepositoryOptions struct {
|
||||||
OwnerID int64
|
OwnerID int64
|
||||||
Private optional.Option[bool]
|
Private optional.Option[bool]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package models
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -10,16 +10,58 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
// RepoTransfer is used to manage repository transfers
|
// RepoTransfer is used to manage repository transfers
|
||||||
type RepoTransfer struct {
|
type RepoTransfer struct { //nolint
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
DoerID int64
|
DoerID int64
|
||||||
Doer *user_model.User `xorm:"-"`
|
Doer *user_model.User `xorm:"-"`
|
||||||
@ -126,7 +168,7 @@ func GetPendingRepositoryTransfers(ctx context.Context, opts *PendingRepositoryT
|
|||||||
|
|
||||||
// GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
|
// GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
|
||||||
// process for the repository
|
// process for the repository
|
||||||
func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) (*RepoTransfer, error) {
|
func GetPendingRepositoryTransfer(ctx context.Context, repo *Repository) (*RepoTransfer, error) {
|
||||||
transfers, err := GetPendingRepositoryTransfers(ctx, &PendingRepositoryTransferOptions{RepoID: repo.ID})
|
transfers, err := GetPendingRepositoryTransfers(ctx, &PendingRepositoryTransferOptions{RepoID: repo.ID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -145,11 +187,11 @@ func DeleteRepositoryTransfer(ctx context.Context, repoID int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TestRepositoryReadyForTransfer make sure repo is ready to transfer
|
// TestRepositoryReadyForTransfer make sure repo is ready to transfer
|
||||||
func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
|
func TestRepositoryReadyForTransfer(status RepositoryStatus) error {
|
||||||
switch status {
|
switch status {
|
||||||
case repo_model.RepositoryBeingMigrated:
|
case RepositoryBeingMigrated:
|
||||||
return errors.New("repo is not ready, currently migrating")
|
return errors.New("repo is not ready, currently migrating")
|
||||||
case repo_model.RepositoryPendingTransfer:
|
case RepositoryPendingTransfer:
|
||||||
return ErrRepoTransferInProgress{}
|
return ErrRepoTransferInProgress{}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -159,7 +201,7 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
|
|||||||
// it marks the repository transfer as "pending"
|
// it marks the repository transfer as "pending"
|
||||||
func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
|
func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
repo, err := repo_model.GetRepositoryByID(ctx, repoID)
|
repo, err := GetRepositoryByID(ctx, repoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -169,16 +211,16 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.Status = repo_model.RepositoryPendingTransfer
|
repo.Status = RepositoryPendingTransfer
|
||||||
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
|
if err := UpdateRepositoryCols(ctx, repo, "status"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if new owner has repository with same name.
|
// Check if new owner has repository with same name.
|
||||||
if has, err := repo_model.IsRepositoryModelExist(ctx, newOwner, repo.Name); err != nil {
|
if has, err := IsRepositoryModelExist(ctx, newOwner, repo.Name); err != nil {
|
||||||
return fmt.Errorf("IsRepositoryExist: %w", err)
|
return fmt.Errorf("IsRepositoryExist: %w", err)
|
||||||
} else if has {
|
} else if has {
|
||||||
return repo_model.ErrRepoAlreadyExist{
|
return ErrRepoAlreadyExist{
|
||||||
Uname: newOwner.LowerName,
|
Uname: newOwner.LowerName,
|
||||||
Name: repo.Name,
|
Name: repo.Name,
|
||||||
}
|
}
|
@ -14,13 +14,13 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/system"
|
"code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/auth/password/hash"
|
"code.gitea.io/gitea/modules/auth/password/hash"
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/setting/config"
|
"code.gitea.io/gitea/modules/setting/config"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -235,5 +235,5 @@ func PrepareTestEnv(t testing.TB) {
|
|||||||
assert.NoError(t, PrepareTestDatabase())
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
metaPath := filepath.Join(giteaRoot, "tests", "gitea-repositories-meta")
|
metaPath := filepath.Join(giteaRoot, "tests", "gitea-repositories-meta")
|
||||||
assert.NoError(t, SyncDirs(metaPath, setting.RepoRootPath))
|
assert.NoError(t, SyncDirs(metaPath, setting.RepoRootPath))
|
||||||
base.SetupGiteaRoot() // Makes sure GITEA_ROOT is set
|
test.SetupGiteaRoot() // Makes sure GITEA_ROOT is set
|
||||||
}
|
}
|
||||||
|
@ -788,6 +788,21 @@ func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, o
|
|||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
// IsLastAdminUser check whether user is the last admin
|
// IsLastAdminUser check whether user is the last admin
|
||||||
func IsLastAdminUser(ctx context.Context, user *User) bool {
|
func IsLastAdminUser(ctx context.Context, user *User) bool {
|
||||||
if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: optional.Some(true)}) <= 1 {
|
if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: optional.Some(true)}) <= 1 {
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package base
|
|
||||||
|
|
||||||
type (
|
|
||||||
// TplName template relative path type
|
|
||||||
TplName string
|
|
||||||
)
|
|
@ -13,9 +13,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -189,49 +186,3 @@ func EntryIcon(entry *git.TreeEntry) string {
|
|||||||
|
|
||||||
return "file"
|
return "file"
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupGiteaRoot Sets GITEA_ROOT if it is not already set and returns the value
|
|
||||||
func SetupGiteaRoot() string {
|
|
||||||
giteaRoot := os.Getenv("GITEA_ROOT")
|
|
||||||
if giteaRoot == "" {
|
|
||||||
_, filename, _, _ := runtime.Caller(0)
|
|
||||||
giteaRoot = strings.TrimSuffix(filename, "modules/base/tool.go")
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
rel, err := filepath.Rel(giteaRoot, wd)
|
|
||||||
if err != nil && strings.HasPrefix(filepath.ToSlash(rel), "../") {
|
|
||||||
giteaRoot = wd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(filepath.Join(giteaRoot, "gitea")); os.IsNotExist(err) {
|
|
||||||
giteaRoot = ""
|
|
||||||
} else if err := os.Setenv("GITEA_ROOT", giteaRoot); err != nil {
|
|
||||||
giteaRoot = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return giteaRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatNumberSI format a number
|
|
||||||
func FormatNumberSI(data any) string {
|
|
||||||
var num int64
|
|
||||||
if num1, ok := data.(int64); ok {
|
|
||||||
num = num1
|
|
||||||
} else if num1, ok := data.(int); ok {
|
|
||||||
num = int64(num1)
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if num < 1000 {
|
|
||||||
return fmt.Sprintf("%d", num)
|
|
||||||
} else if num < 1000000 {
|
|
||||||
num2 := float32(num) / float32(1000.0)
|
|
||||||
return fmt.Sprintf("%.1fk", num2)
|
|
||||||
} else if num < 1000000000 {
|
|
||||||
num2 := float32(num) / float32(1000000.0)
|
|
||||||
return fmt.Sprintf("%.1fM", num2)
|
|
||||||
}
|
|
||||||
num2 := float32(num) / float32(1000000000.0)
|
|
||||||
return fmt.Sprintf("%.1fG", num2)
|
|
||||||
}
|
|
||||||
|
@ -169,18 +169,3 @@ func TestInt64sToStrings(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test EntryIcon
|
// TODO: Test EntryIcon
|
||||||
|
|
||||||
func TestSetupGiteaRoot(t *testing.T) {
|
|
||||||
t.Setenv("GITEA_ROOT", "test")
|
|
||||||
assert.Equal(t, "test", SetupGiteaRoot())
|
|
||||||
t.Setenv("GITEA_ROOT", "")
|
|
||||||
assert.NotEqual(t, "test", SetupGiteaRoot())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatNumberSI(t *testing.T) {
|
|
||||||
assert.Equal(t, "125", FormatNumberSI(int(125)))
|
|
||||||
assert.Equal(t, "1.3k", FormatNumberSI(int64(1317)))
|
|
||||||
assert.Equal(t, "21.3M", FormatNumberSI(21317675))
|
|
||||||
assert.Equal(t, "45.7G", FormatNumberSI(45721317675))
|
|
||||||
assert.Equal(t, "", FormatNumberSI("test"))
|
|
||||||
}
|
|
||||||
|
@ -7,10 +7,8 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -32,7 +30,6 @@ type WriteCloserError interface {
|
|||||||
func ensureValidGitRepository(ctx context.Context, repoPath string) error {
|
func ensureValidGitRepository(ctx context.Context, repoPath string) error {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand(ctx, "rev-parse").
|
err := NewCommand(ctx, "rev-parse").
|
||||||
SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)).
|
|
||||||
Run(&RunOpts{
|
Run(&RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
@ -62,13 +59,9 @@ func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
|
|||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, filename, line, _ := runtime.Caller(2)
|
|
||||||
filename = strings.TrimPrefix(filename, callerPrefix)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand(ctx, "cat-file", "--batch-check").
|
err := NewCommand(ctx, "cat-file", "--batch-check").
|
||||||
SetDescription(fmt.Sprintf("%s cat-file --batch-check [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
|
|
||||||
Run(&RunOpts{
|
Run(&RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdin: batchStdinReader,
|
Stdin: batchStdinReader,
|
||||||
@ -114,13 +107,9 @@ func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
|
|||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, filename, line, _ := runtime.Caller(2)
|
|
||||||
filename = strings.TrimPrefix(filename, callerPrefix)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand(ctx, "cat-file", "--batch").
|
err := NewCommand(ctx, "cat-file", "--batch").
|
||||||
SetDescription(fmt.Sprintf("%s cat-file --batch [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
|
|
||||||
Run(&RunOpts{
|
Run(&RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdin: batchStdinReader,
|
Stdin: batchStdinReader,
|
||||||
@ -320,13 +309,6 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu
|
|||||||
return mode, fname, sha, n, err
|
return mode, fname, sha, n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var callerPrefix string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
_, filename, _, _ := runtime.Caller(0)
|
|
||||||
callerPrefix = strings.TrimSuffix(filename, "modules/git/batch_reader.go")
|
|
||||||
}
|
|
||||||
|
|
||||||
func DiscardFull(rd *bufio.Reader, discard int64) error {
|
func DiscardFull(rd *bufio.Reader, discard int64) error {
|
||||||
if discard > math.MaxInt32 {
|
if discard > math.MaxInt32 {
|
||||||
n, err := rd.Discard(math.MaxInt32)
|
n, err := rd.Discard(math.MaxInt32)
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -142,9 +141,7 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
|
|||||||
// There is no equivalent on Windows. May be implemented if Gitea uses an external git backend.
|
// There is no equivalent on Windows. May be implemented if Gitea uses an external git backend.
|
||||||
cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile)
|
cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile)
|
||||||
}
|
}
|
||||||
cmd.AddDynamicArguments(commit.ID.String()).
|
cmd.AddDynamicArguments(commit.ID.String()).AddDashesAndList(file)
|
||||||
AddDashesAndList(file).
|
|
||||||
SetDescription(fmt.Sprintf("GetBlame [repo_path: %s]", repoPath))
|
|
||||||
reader, stdout, err := os.Pipe()
|
reader, stdout, err := os.Pipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ignoreRevsFile != nil {
|
if ignoreRevsFile != nil {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -43,18 +44,24 @@ type Command struct {
|
|||||||
prog string
|
prog string
|
||||||
args []string
|
args []string
|
||||||
parentContext context.Context
|
parentContext context.Context
|
||||||
desc string
|
|
||||||
globalArgsLength int
|
globalArgsLength int
|
||||||
brokenArgs []string
|
brokenArgs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) String() string {
|
func logArgSanitize(arg string) string {
|
||||||
return c.toString(false)
|
if strings.Contains(arg, "://") && strings.Contains(arg, "@") {
|
||||||
|
return util.SanitizeCredentialURLs(arg)
|
||||||
|
} else if filepath.IsAbs(arg) {
|
||||||
|
base := filepath.Base(arg)
|
||||||
|
dir := filepath.Dir(arg)
|
||||||
|
return filepath.Join(filepath.Base(dir), base)
|
||||||
|
}
|
||||||
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) toString(sanitizing bool) string {
|
func (c *Command) LogString() string {
|
||||||
// WARNING: this function is for debugging purposes only. It's much better than old code (which only joins args with space),
|
// WARNING: this function is for debugging purposes only. It's much better than old code (which only joins args with space),
|
||||||
// It's impossible to make a simple and 100% correct implementation of argument quoting for different platforms.
|
// It's impossible to make a simple and 100% correct implementation of argument quoting for different platforms here.
|
||||||
debugQuote := func(s string) string {
|
debugQuote := func(s string) string {
|
||||||
if strings.ContainsAny(s, " `'\"\t\r\n") {
|
if strings.ContainsAny(s, " `'\"\t\r\n") {
|
||||||
return fmt.Sprintf("%q", s)
|
return fmt.Sprintf("%q", s)
|
||||||
@ -63,12 +70,11 @@ func (c *Command) toString(sanitizing bool) string {
|
|||||||
}
|
}
|
||||||
a := make([]string, 0, len(c.args)+1)
|
a := make([]string, 0, len(c.args)+1)
|
||||||
a = append(a, debugQuote(c.prog))
|
a = append(a, debugQuote(c.prog))
|
||||||
for _, arg := range c.args {
|
if c.globalArgsLength > 0 {
|
||||||
if sanitizing && (strings.Contains(arg, "://") && strings.Contains(arg, "@")) {
|
a = append(a, "...global...")
|
||||||
a = append(a, debugQuote(util.SanitizeCredentialURLs(arg)))
|
|
||||||
} else {
|
|
||||||
a = append(a, debugQuote(arg))
|
|
||||||
}
|
}
|
||||||
|
for i := c.globalArgsLength; i < len(c.args); i++ {
|
||||||
|
a = append(a, debugQuote(logArgSanitize(c.args[i])))
|
||||||
}
|
}
|
||||||
return strings.Join(a, " ")
|
return strings.Join(a, " ")
|
||||||
}
|
}
|
||||||
@ -112,12 +118,6 @@ func (c *Command) SetParentContext(ctx context.Context) *Command {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDescription sets the description for this command which be returned on c.String()
|
|
||||||
func (c *Command) SetDescription(desc string) *Command {
|
|
||||||
c.desc = desc
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// isSafeArgumentValue checks if the argument is safe to be used as a value (not an option)
|
// isSafeArgumentValue checks if the argument is safe to be used as a value (not an option)
|
||||||
func isSafeArgumentValue(s string) bool {
|
func isSafeArgumentValue(s string) bool {
|
||||||
return s == "" || s[0] != '-'
|
return s == "" || s[0] != '-'
|
||||||
@ -271,8 +271,12 @@ var ErrBrokenCommand = errors.New("git command is broken")
|
|||||||
|
|
||||||
// Run runs the command with the RunOpts
|
// Run runs the command with the RunOpts
|
||||||
func (c *Command) Run(opts *RunOpts) error {
|
func (c *Command) Run(opts *RunOpts) error {
|
||||||
|
return c.run(1, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) run(skip int, opts *RunOpts) error {
|
||||||
if len(c.brokenArgs) != 0 {
|
if len(c.brokenArgs) != 0 {
|
||||||
log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " "))
|
log.Error("git command is broken: %s, broken args: %s", c.LogString(), strings.Join(c.brokenArgs, " "))
|
||||||
return ErrBrokenCommand
|
return ErrBrokenCommand
|
||||||
}
|
}
|
||||||
if opts == nil {
|
if opts == nil {
|
||||||
@ -285,20 +289,14 @@ func (c *Command) Run(opts *RunOpts) error {
|
|||||||
timeout = defaultCommandExecutionTimeout
|
timeout = defaultCommandExecutionTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.Dir) == 0 {
|
var desc string
|
||||||
log.Debug("git.Command.Run: %s", c)
|
callerInfo := util.CallerFuncName(1 /* util */ + 1 /* this */ + skip /* parent */)
|
||||||
} else {
|
if pos := strings.LastIndex(callerInfo, "/"); pos >= 0 {
|
||||||
log.Debug("git.Command.RunDir(%s): %s", opts.Dir, c)
|
callerInfo = callerInfo[pos+1:]
|
||||||
}
|
|
||||||
|
|
||||||
desc := c.desc
|
|
||||||
if desc == "" {
|
|
||||||
if opts.Dir == "" {
|
|
||||||
desc = fmt.Sprintf("git: %s", c.toString(true))
|
|
||||||
} else {
|
|
||||||
desc = fmt.Sprintf("git(dir:%s): %s", opts.Dir, c.toString(true))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// these logs are for debugging purposes only, so no guarantee of correctness or stability
|
||||||
|
desc = fmt.Sprintf("git.Run(by:%s, repo:%s): %s", callerInfo, logArgSanitize(opts.Dir), c.LogString())
|
||||||
|
log.Debug("git.Command: %s", desc)
|
||||||
|
|
||||||
var ctx context.Context
|
var ctx context.Context
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
@ -401,7 +399,7 @@ func IsErrorExitCode(err error, code int) bool {
|
|||||||
|
|
||||||
// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
|
// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
|
||||||
func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
|
func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
|
||||||
stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
|
stdoutBytes, stderrBytes, err := c.runStdBytes(opts)
|
||||||
stdout = util.UnsafeBytesToString(stdoutBytes)
|
stdout = util.UnsafeBytesToString(stdoutBytes)
|
||||||
stderr = util.UnsafeBytesToString(stderrBytes)
|
stderr = util.UnsafeBytesToString(stderrBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -413,6 +411,10 @@ func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr Run
|
|||||||
|
|
||||||
// RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
|
// RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
|
||||||
func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
|
func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
|
||||||
|
return c.runStdBytes(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) runStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
|
||||||
if opts == nil {
|
if opts == nil {
|
||||||
opts = &RunOpts{}
|
opts = &RunOpts{}
|
||||||
}
|
}
|
||||||
@ -435,7 +437,7 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
|
|||||||
PipelineFunc: opts.PipelineFunc,
|
PipelineFunc: opts.PipelineFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := c.Run(newOpts)
|
err := c.run(2, newOpts)
|
||||||
stderr = stderrBuf.Bytes()
|
stderr = stderrBuf.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)}
|
return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)}
|
||||||
|
@ -55,8 +55,8 @@ func TestGitArgument(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommandString(t *testing.T) {
|
func TestCommandString(t *testing.T) {
|
||||||
cmd := NewCommandContextNoGlobals(context.Background(), "a", "-m msg", "it's a test", `say "hello"`)
|
cmd := NewCommandContextNoGlobals(context.Background(), "a", "-m msg", "it's a test", `say "hello"`)
|
||||||
assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.String())
|
assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.LogString())
|
||||||
|
|
||||||
cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/")
|
cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/", "/root/dir-a/dir-b")
|
||||||
assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/"`, cmd.toString(true))
|
assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/" dir-a/dir-b`, cmd.LogString())
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,12 @@ package git
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
giturl "code.gitea.io/gitea/modules/git/url"
|
giturl "code.gitea.io/gitea/modules/git/url"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
|
// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
|
||||||
@ -37,3 +41,61 @@ func GetRemoteURL(ctx context.Context, repoPath, remoteName string) (*giturl.Git
|
|||||||
}
|
}
|
||||||
return giturl.Parse(addr)
|
return giturl.Parse(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseRemoteAddr checks if given remote address is valid,
|
||||||
|
// and returns composed URL with needed username and password.
|
||||||
|
func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) {
|
||||||
|
remoteAddr = strings.TrimSpace(remoteAddr)
|
||||||
|
// Remote address can be HTTP/HTTPS/Git URL or local path.
|
||||||
|
if strings.HasPrefix(remoteAddr, "http://") ||
|
||||||
|
strings.HasPrefix(remoteAddr, "https://") ||
|
||||||
|
strings.HasPrefix(remoteAddr, "git://") {
|
||||||
|
u, err := url.Parse(remoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
return "", &ErrInvalidCloneAddr{IsURLError: true, Host: remoteAddr}
|
||||||
|
}
|
||||||
|
if len(authUsername)+len(authPassword) > 0 {
|
||||||
|
u.User = url.UserPassword(authUsername, authPassword)
|
||||||
|
}
|
||||||
|
remoteAddr = u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return remoteAddr, nil
|
||||||
|
}
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/proxy"
|
"code.gitea.io/gitea/modules/proxy"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GPGSettings represents the default GPG settings for this repository
|
// GPGSettings represents the default GPG settings for this repository
|
||||||
@ -160,12 +159,6 @@ func CloneWithArgs(ctx context.Context, args TrustedCmdArgs, from, to string, op
|
|||||||
}
|
}
|
||||||
cmd.AddDashesAndList(from, to)
|
cmd.AddDashesAndList(from, to)
|
||||||
|
|
||||||
if strings.Contains(from, "://") && strings.Contains(from, "@") {
|
|
||||||
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.SanitizeCredentialURLs(from), to, opts.Shared, opts.Mirror, opts.Depth))
|
|
||||||
} else {
|
|
||||||
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, from, to, opts.Shared, opts.Mirror, opts.Depth))
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Timeout <= 0 {
|
if opts.Timeout <= 0 {
|
||||||
opts.Timeout = -1
|
opts.Timeout = -1
|
||||||
}
|
}
|
||||||
@ -213,12 +206,6 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
|||||||
}
|
}
|
||||||
cmd.AddDashesAndList(remoteBranchArgs...)
|
cmd.AddDashesAndList(remoteBranchArgs...)
|
||||||
|
|
||||||
if strings.Contains(opts.Remote, "://") && strings.Contains(opts.Remote, "@") {
|
|
||||||
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, util.SanitizeCredentialURLs(opts.Remote), opts.Force, opts.Mirror))
|
|
||||||
} else {
|
|
||||||
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror))
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, stderr, err := cmd.RunStdString(&RunOpts{Env: opts.Env, Timeout: opts.Timeout, Dir: repoPath})
|
stdout, stderr, err := cmd.RunStdString(&RunOpts{Env: opts.Env, Timeout: opts.Timeout, Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(stderr, "non-fast-forward") {
|
if strings.Contains(stderr, "non-fast-forward") {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/gtprof"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@ -136,7 +137,7 @@ func (g *Manager) doShutdown() {
|
|||||||
}
|
}
|
||||||
g.lock.Lock()
|
g.lock.Lock()
|
||||||
g.shutdownCtxCancel()
|
g.shutdownCtxCancel()
|
||||||
atShutdownCtx := pprof.WithLabels(g.hammerCtx, pprof.Labels("graceful-lifecycle", "post-shutdown"))
|
atShutdownCtx := pprof.WithLabels(g.hammerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-shutdown"))
|
||||||
pprof.SetGoroutineLabels(atShutdownCtx)
|
pprof.SetGoroutineLabels(atShutdownCtx)
|
||||||
for _, fn := range g.toRunAtShutdown {
|
for _, fn := range g.toRunAtShutdown {
|
||||||
go fn()
|
go fn()
|
||||||
@ -167,7 +168,7 @@ func (g *Manager) doHammerTime(d time.Duration) {
|
|||||||
default:
|
default:
|
||||||
log.Warn("Setting Hammer condition")
|
log.Warn("Setting Hammer condition")
|
||||||
g.hammerCtxCancel()
|
g.hammerCtxCancel()
|
||||||
atHammerCtx := pprof.WithLabels(g.terminateCtx, pprof.Labels("graceful-lifecycle", "post-hammer"))
|
atHammerCtx := pprof.WithLabels(g.terminateCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-hammer"))
|
||||||
pprof.SetGoroutineLabels(atHammerCtx)
|
pprof.SetGoroutineLabels(atHammerCtx)
|
||||||
}
|
}
|
||||||
g.lock.Unlock()
|
g.lock.Unlock()
|
||||||
@ -183,7 +184,7 @@ func (g *Manager) doTerminate() {
|
|||||||
default:
|
default:
|
||||||
log.Warn("Terminating")
|
log.Warn("Terminating")
|
||||||
g.terminateCtxCancel()
|
g.terminateCtxCancel()
|
||||||
atTerminateCtx := pprof.WithLabels(g.managerCtx, pprof.Labels("graceful-lifecycle", "post-terminate"))
|
atTerminateCtx := pprof.WithLabels(g.managerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-terminate"))
|
||||||
pprof.SetGoroutineLabels(atTerminateCtx)
|
pprof.SetGoroutineLabels(atTerminateCtx)
|
||||||
|
|
||||||
for _, fn := range g.toRunAtTerminate {
|
for _, fn := range g.toRunAtTerminate {
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/gtprof"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FIXME: it seems that there is a bug when using systemd Type=notify: the "Install Page" (INSTALL_LOCK=false) doesn't notify properly.
|
// FIXME: it seems that there is a bug when using systemd Type=notify: the "Install Page" (INSTALL_LOCK=false) doesn't notify properly.
|
||||||
@ -65,10 +67,10 @@ func (g *Manager) prepare(ctx context.Context) {
|
|||||||
g.hammerCtx, g.hammerCtxCancel = context.WithCancel(ctx)
|
g.hammerCtx, g.hammerCtxCancel = context.WithCancel(ctx)
|
||||||
g.managerCtx, g.managerCtxCancel = context.WithCancel(ctx)
|
g.managerCtx, g.managerCtxCancel = context.WithCancel(ctx)
|
||||||
|
|
||||||
g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels("graceful-lifecycle", "with-terminate"))
|
g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-terminate"))
|
||||||
g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels("graceful-lifecycle", "with-shutdown"))
|
g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-shutdown"))
|
||||||
g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels("graceful-lifecycle", "with-hammer"))
|
g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-hammer"))
|
||||||
g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels("graceful-lifecycle", "with-manager"))
|
g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-manager"))
|
||||||
|
|
||||||
if !g.setStateTransition(stateInit, stateRunning) {
|
if !g.setStateTransition(stateInit, stateRunning) {
|
||||||
panic("invalid graceful manager state: transition from init to running failed")
|
panic("invalid graceful manager state: transition from init to running failed")
|
||||||
|
25
modules/gtprof/gtprof.go
Normal file
25
modules/gtprof/gtprof.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package gtprof
|
||||||
|
|
||||||
|
// This is a Gitea-specific profiling package,
|
||||||
|
// the name is chosen to distinguish it from the standard pprof tool and "GNU gprof"
|
||||||
|
|
||||||
|
// LabelGracefulLifecycle is a label marking manager lifecycle phase
|
||||||
|
// Making it compliant with prometheus key regex https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
|
||||||
|
// would enable someone interested to be able to continuously gather profiles into pyroscope.
|
||||||
|
// Other labels for pprof should also follow this rule.
|
||||||
|
const LabelGracefulLifecycle = "graceful_lifecycle"
|
||||||
|
|
||||||
|
// LabelPid is a label set on goroutines that have a process attached
|
||||||
|
const LabelPid = "pid"
|
||||||
|
|
||||||
|
// LabelPpid is a label set on goroutines that have a process attached
|
||||||
|
const LabelPpid = "ppid"
|
||||||
|
|
||||||
|
// LabelProcessType is a label set on goroutines that have a process attached
|
||||||
|
const LabelProcessType = "process_type"
|
||||||
|
|
||||||
|
// LabelProcessDescription is a label set on goroutines that have a process attached
|
||||||
|
const LabelProcessDescription = "process_description"
|
@ -13,7 +13,6 @@ import (
|
|||||||
type Event struct {
|
type Event struct {
|
||||||
Time time.Time
|
Time time.Time
|
||||||
|
|
||||||
GoroutinePid string
|
|
||||||
Caller string
|
Caller string
|
||||||
Filename string
|
Filename string
|
||||||
Line int
|
Line int
|
||||||
@ -218,18 +217,17 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms
|
|||||||
}
|
}
|
||||||
|
|
||||||
if flags&Lgopid == Lgopid {
|
if flags&Lgopid == Lgopid {
|
||||||
if event.GoroutinePid != "" {
|
deprecatedGoroutinePid := "no-gopid" // use a dummy value to avoid breaking the log format
|
||||||
buf = append(buf, '[')
|
buf = append(buf, '[')
|
||||||
if mode.Colorize {
|
if mode.Colorize {
|
||||||
buf = append(buf, ColorBytes(FgHiYellow)...)
|
buf = append(buf, ColorBytes(FgHiYellow)...)
|
||||||
}
|
}
|
||||||
buf = append(buf, event.GoroutinePid...)
|
buf = append(buf, deprecatedGoroutinePid...)
|
||||||
if mode.Colorize {
|
if mode.Colorize {
|
||||||
buf = append(buf, resetBytes...)
|
buf = append(buf, resetBytes...)
|
||||||
}
|
}
|
||||||
buf = append(buf, ']', ' ')
|
buf = append(buf, ']', ' ')
|
||||||
}
|
}
|
||||||
}
|
|
||||||
buf = append(buf, msg...)
|
buf = append(buf, msg...)
|
||||||
|
|
||||||
if event.Stacktrace != "" && mode.StacktraceLevel <= event.Level {
|
if event.Stacktrace != "" && mode.StacktraceLevel <= event.Level {
|
||||||
|
@ -28,14 +28,13 @@ func TestEventFormatTextMessage(t *testing.T) {
|
|||||||
Caller: "caller",
|
Caller: "caller",
|
||||||
Filename: "filename",
|
Filename: "filename",
|
||||||
Line: 123,
|
Line: 123,
|
||||||
GoroutinePid: "pid",
|
|
||||||
Level: ERROR,
|
Level: ERROR,
|
||||||
Stacktrace: "stacktrace",
|
Stacktrace: "stacktrace",
|
||||||
},
|
},
|
||||||
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
|
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [pid] msg format: arg0 arg1
|
assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [no-gopid] msg format: arg0 arg1
|
||||||
stacktrace
|
stacktrace
|
||||||
|
|
||||||
`, string(res))
|
`, string(res))
|
||||||
@ -46,12 +45,11 @@ func TestEventFormatTextMessage(t *testing.T) {
|
|||||||
Caller: "caller",
|
Caller: "caller",
|
||||||
Filename: "filename",
|
Filename: "filename",
|
||||||
Line: 123,
|
Line: 123,
|
||||||
GoroutinePid: "pid",
|
|
||||||
Level: ERROR,
|
Level: ERROR,
|
||||||
Stacktrace: "stacktrace",
|
Stacktrace: "stacktrace",
|
||||||
},
|
},
|
||||||
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
|
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mpid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res))
|
assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mno-gopid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res))
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ const (
|
|||||||
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
|
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
|
||||||
Llevelinitial // Initial character of the provided level in brackets, eg. [I] for info
|
Llevelinitial // Initial character of the provided level in brackets, eg. [I] for info
|
||||||
Llevel // Provided level in brackets [INFO]
|
Llevel // Provided level in brackets [INFO]
|
||||||
Lgopid // the Goroutine-PID of the context
|
Lgopid // the Goroutine-PID of the context, deprecated and it is always a const value
|
||||||
|
|
||||||
Lmedfile = Lshortfile | Llongfile // last 20 characters of the filename
|
Lmedfile = Lshortfile | Llongfile // last 20 characters of the filename
|
||||||
LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial // default
|
LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial // default
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package log
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel
|
|
||||||
func runtime_getProfLabel() unsafe.Pointer //nolint
|
|
||||||
|
|
||||||
type labelMap map[string]string
|
|
||||||
|
|
||||||
func getGoroutineLabels() map[string]string {
|
|
||||||
l := (*labelMap)(runtime_getProfLabel())
|
|
||||||
if l == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return *l
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"runtime/pprof"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_getGoroutineLabels(t *testing.T) {
|
|
||||||
pprof.Do(context.Background(), pprof.Labels(), func(ctx context.Context) {
|
|
||||||
currentLabels := getGoroutineLabels()
|
|
||||||
pprof.ForLabels(ctx, func(key, value string) bool {
|
|
||||||
assert.EqualValues(t, value, currentLabels[key])
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
pprof.Do(ctx, pprof.Labels("Test_getGoroutineLabels", "Test_getGoroutineLabels_child1"), func(ctx context.Context) {
|
|
||||||
currentLabels := getGoroutineLabels()
|
|
||||||
pprof.ForLabels(ctx, func(key, value string) bool {
|
|
||||||
assert.EqualValues(t, value, currentLabels[key])
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
if assert.NotNil(t, currentLabels) {
|
|
||||||
assert.EqualValues(t, "Test_getGoroutineLabels_child1", currentLabels["Test_getGoroutineLabels"])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
@ -200,11 +200,6 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) {
|
|||||||
event.Stacktrace = Stack(skip + 1)
|
event.Stacktrace = Stack(skip + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := getGoroutineLabels()
|
|
||||||
if labels != nil {
|
|
||||||
event.GoroutinePid = labels["pid"]
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a simple text message without color
|
// get a simple text message without color
|
||||||
msgArgs := make([]any, len(logArgs))
|
msgArgs := make([]any, len(logArgs))
|
||||||
copy(msgArgs, logArgs)
|
copy(msgArgs, logArgs)
|
||||||
|
@ -24,7 +24,7 @@ type GlobalVarsType struct {
|
|||||||
LinkRegex *regexp.Regexp // fast matching a URL link, no any extra validation.
|
LinkRegex *regexp.Regexp // fast matching a URL link, no any extra validation.
|
||||||
}
|
}
|
||||||
|
|
||||||
var GlobalVars = sync.OnceValue[*GlobalVarsType](func() *GlobalVarsType {
|
var GlobalVars = sync.OnceValue(func() *GlobalVarsType {
|
||||||
v := &GlobalVarsType{}
|
v := &GlobalVarsType{}
|
||||||
v.wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}((?:/|[#?])[-a-zA-Z0-9@:%_\+.~#!?&//=\(\);,'">\^{}\[\]` + "`" + `]*)?`)
|
v.wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}((?:/|[#?])[-a-zA-Z0-9@:%_\+.~#!?&//=\(\);,'">\^{}\[\]` + "`" + `]*)?`)
|
||||||
v.LinkRegex, _ = xurls.StrictMatchingScheme("https?://")
|
v.LinkRegex, _ = xurls.StrictMatchingScheme("https?://")
|
||||||
|
@ -42,7 +42,7 @@ type globalVarsType struct {
|
|||||||
nulCleaner *strings.Replacer
|
nulCleaner *strings.Replacer
|
||||||
}
|
}
|
||||||
|
|
||||||
var globalVars = sync.OnceValue[*globalVarsType](func() *globalVarsType {
|
var globalVars = sync.OnceValue(func() *globalVarsType {
|
||||||
v := &globalVarsType{}
|
v := &globalVarsType{}
|
||||||
// NOTE: All below regex matching do not perform any extra validation.
|
// NOTE: All below regex matching do not perform any extra validation.
|
||||||
// Thus a link is produced even if the linked entity does not exist.
|
// Thus a link is produced even if the linked entity does not exist.
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
var reAttrClass = sync.OnceValue[*regexp.Regexp](func() *regexp.Regexp {
|
var reAttrClass = sync.OnceValue(func() *regexp.Regexp {
|
||||||
// TODO: it isn't a problem at the moment because our HTML contents are always well constructed
|
// TODO: it isn't a problem at the moment because our HTML contents are always well constructed
|
||||||
return regexp.MustCompile(`(<[^>]+)\s+class="([^"]+)"([^>]*>)`)
|
return regexp.MustCompile(`(<[^>]+)\s+class="([^"]+)"([^>]*>)`)
|
||||||
})
|
})
|
||||||
|
@ -112,7 +112,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// it is copied from old code, which is quite doubtful whether it is correct
|
// it is copied from old code, which is quite doubtful whether it is correct
|
||||||
var reValidIconName = sync.OnceValue[*regexp.Regexp](func() *regexp.Regexp {
|
var reValidIconName = sync.OnceValue(func() *regexp.Regexp {
|
||||||
return regexp.MustCompile(`^[-\w]+$`) // old: regexp.MustCompile("^[a-z ]+$")
|
return regexp.MustCompile(`^[-\w]+$`) // old: regexp.MustCompile("^[a-z ]+$")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -129,7 +129,8 @@ func SpecializedMarkdown(ctx *markup.RenderContext) *GlodmarkRender {
|
|||||||
Enabled: setting.Markdown.EnableMath,
|
Enabled: setting.Markdown.EnableMath,
|
||||||
ParseDollarInline: true,
|
ParseDollarInline: true,
|
||||||
ParseDollarBlock: true,
|
ParseDollarBlock: true,
|
||||||
ParseSquareBlock: true, // TODO: this is a bad syntax, it should be deprecated in the future (by some config options)
|
ParseSquareBlock: true, // TODO: this is a bad syntax "\[ ... \]", it conflicts with normal markdown escaping, it should be deprecated in the future (by some config options)
|
||||||
|
// ParseBracketInline: true, // TODO: this is also a bad syntax "\( ... \)", it also conflicts, it should be deprecated in the future
|
||||||
}),
|
}),
|
||||||
meta.Meta,
|
meta.Meta,
|
||||||
),
|
),
|
||||||
|
@ -44,7 +44,8 @@ var (
|
|||||||
|
|
||||||
// https://man.archlinux.org/man/PKGBUILD.5
|
// https://man.archlinux.org/man/PKGBUILD.5
|
||||||
namePattern = regexp.MustCompile(`\A[a-zA-Z0-9@._+-]+\z`)
|
namePattern = regexp.MustCompile(`\A[a-zA-Z0-9@._+-]+\z`)
|
||||||
versionPattern = regexp.MustCompile(`\A(?:[0-9]:)?[a-zA-Z0-9.+~]+(?:-[a-zA-Z0-9.+-~]+)?\z`)
|
// (epoch:pkgver-pkgrel)
|
||||||
|
versionPattern = regexp.MustCompile(`\A(?:\d:)?[\w.+~]+(?:-[-\w.+~]+)?\z`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
@ -69,10 +70,12 @@ type FileMetadata struct {
|
|||||||
Packager string `json:"packager,omitempty"`
|
Packager string `json:"packager,omitempty"`
|
||||||
Groups []string `json:"groups,omitempty"`
|
Groups []string `json:"groups,omitempty"`
|
||||||
Provides []string `json:"provides,omitempty"`
|
Provides []string `json:"provides,omitempty"`
|
||||||
|
Replaces []string `json:"replaces,omitempty"`
|
||||||
Depends []string `json:"depends,omitempty"`
|
Depends []string `json:"depends,omitempty"`
|
||||||
OptDepends []string `json:"opt_depends,omitempty"`
|
OptDepends []string `json:"opt_depends,omitempty"`
|
||||||
MakeDepends []string `json:"make_depends,omitempty"`
|
MakeDepends []string `json:"make_depends,omitempty"`
|
||||||
CheckDepends []string `json:"check_depends,omitempty"`
|
CheckDepends []string `json:"check_depends,omitempty"`
|
||||||
|
Conflicts []string `json:"conflicts,omitempty"`
|
||||||
XData []string `json:"xdata,omitempty"`
|
XData []string `json:"xdata,omitempty"`
|
||||||
Backup []string `json:"backup,omitempty"`
|
Backup []string `json:"backup,omitempty"`
|
||||||
Files []string `json:"files,omitempty"`
|
Files []string `json:"files,omitempty"`
|
||||||
@ -201,12 +204,16 @@ func ParsePackageInfo(r io.Reader) (*Package, error) {
|
|||||||
p.FileMetadata.Provides = append(p.FileMetadata.Provides, value)
|
p.FileMetadata.Provides = append(p.FileMetadata.Provides, value)
|
||||||
case "depend":
|
case "depend":
|
||||||
p.FileMetadata.Depends = append(p.FileMetadata.Depends, value)
|
p.FileMetadata.Depends = append(p.FileMetadata.Depends, value)
|
||||||
|
case "replaces":
|
||||||
|
p.FileMetadata.Replaces = append(p.FileMetadata.Replaces, value)
|
||||||
case "optdepend":
|
case "optdepend":
|
||||||
p.FileMetadata.OptDepends = append(p.FileMetadata.OptDepends, value)
|
p.FileMetadata.OptDepends = append(p.FileMetadata.OptDepends, value)
|
||||||
case "makedepend":
|
case "makedepend":
|
||||||
p.FileMetadata.MakeDepends = append(p.FileMetadata.MakeDepends, value)
|
p.FileMetadata.MakeDepends = append(p.FileMetadata.MakeDepends, value)
|
||||||
case "checkdepend":
|
case "checkdepend":
|
||||||
p.FileMetadata.CheckDepends = append(p.FileMetadata.CheckDepends, value)
|
p.FileMetadata.CheckDepends = append(p.FileMetadata.CheckDepends, value)
|
||||||
|
case "conflict":
|
||||||
|
p.FileMetadata.Conflicts = append(p.FileMetadata.Conflicts, value)
|
||||||
case "backup":
|
case "backup":
|
||||||
p.FileMetadata.Backup = append(p.FileMetadata.Backup, value)
|
p.FileMetadata.Backup = append(p.FileMetadata.Backup, value)
|
||||||
case "group":
|
case "group":
|
||||||
|
@ -42,8 +42,10 @@ depend = gitea
|
|||||||
provides = common
|
provides = common
|
||||||
provides = gitea
|
provides = gitea
|
||||||
optdepend = hex
|
optdepend = hex
|
||||||
|
replaces = gogs
|
||||||
checkdepend = common
|
checkdepend = common
|
||||||
makedepend = cmake
|
makedepend = cmake
|
||||||
|
conflict = ninja
|
||||||
backup = usr/bin/paket1`)
|
backup = usr/bin/paket1`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +122,14 @@ func TestParsePackageInfo(t *testing.T) {
|
|||||||
assert.ErrorIs(t, err, ErrInvalidName)
|
assert.ErrorIs(t, err, ErrInvalidName)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Regexp", func(t *testing.T) {
|
||||||
|
assert.Regexp(t, versionPattern, "1.2_3~4+5")
|
||||||
|
assert.Regexp(t, versionPattern, "1:2_3~4+5")
|
||||||
|
assert.NotRegexp(t, versionPattern, "a:1.0.0-1")
|
||||||
|
assert.NotRegexp(t, versionPattern, "0.0.1/1-1")
|
||||||
|
assert.NotRegexp(t, versionPattern, "1.0.0 -1")
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("InvalidVersion", func(t *testing.T) {
|
t.Run("InvalidVersion", func(t *testing.T) {
|
||||||
data := createPKGINFOContent(packageName, "")
|
data := createPKGINFOContent(packageName, "")
|
||||||
|
|
||||||
@ -149,8 +159,10 @@ func TestParsePackageInfo(t *testing.T) {
|
|||||||
assert.ElementsMatch(t, []string{"group"}, p.FileMetadata.Groups)
|
assert.ElementsMatch(t, []string{"group"}, p.FileMetadata.Groups)
|
||||||
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Provides)
|
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Provides)
|
||||||
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Depends)
|
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Depends)
|
||||||
|
assert.ElementsMatch(t, []string{"gogs"}, p.FileMetadata.Replaces)
|
||||||
assert.ElementsMatch(t, []string{"hex"}, p.FileMetadata.OptDepends)
|
assert.ElementsMatch(t, []string{"hex"}, p.FileMetadata.OptDepends)
|
||||||
assert.ElementsMatch(t, []string{"common"}, p.FileMetadata.CheckDepends)
|
assert.ElementsMatch(t, []string{"common"}, p.FileMetadata.CheckDepends)
|
||||||
|
assert.ElementsMatch(t, []string{"ninja"}, p.FileMetadata.Conflicts)
|
||||||
assert.ElementsMatch(t, []string{"cmake"}, p.FileMetadata.MakeDepends)
|
assert.ElementsMatch(t, []string{"cmake"}, p.FileMetadata.MakeDepends)
|
||||||
assert.ElementsMatch(t, []string{"usr/bin/paket1"}, p.FileMetadata.Backup)
|
assert.ElementsMatch(t, []string{"usr/bin/paket1"}, p.FileMetadata.Backup)
|
||||||
})
|
})
|
||||||
|
@ -32,7 +32,7 @@ func (c *Context) Value(key any) any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ProcessContextKey is the key under which process contexts are stored
|
// ProcessContextKey is the key under which process contexts are stored
|
||||||
var ProcessContextKey any = "process-context"
|
var ProcessContextKey any = "process_context"
|
||||||
|
|
||||||
// GetContext will return a process context if one exists
|
// GetContext will return a process context if one exists
|
||||||
func GetContext(ctx context.Context) *Context {
|
func GetContext(ctx context.Context) *Context {
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/gtprof"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: This packages still uses a singleton for the Manager.
|
// TODO: This packages still uses a singleton for the Manager.
|
||||||
@ -25,18 +27,6 @@ var (
|
|||||||
DefaultContext = context.Background()
|
DefaultContext = context.Background()
|
||||||
)
|
)
|
||||||
|
|
||||||
// DescriptionPProfLabel is a label set on goroutines that have a process attached
|
|
||||||
const DescriptionPProfLabel = "process-description"
|
|
||||||
|
|
||||||
// PIDPProfLabel is a label set on goroutines that have a process attached
|
|
||||||
const PIDPProfLabel = "pid"
|
|
||||||
|
|
||||||
// PPIDPProfLabel is a label set on goroutines that have a process attached
|
|
||||||
const PPIDPProfLabel = "ppid"
|
|
||||||
|
|
||||||
// ProcessTypePProfLabel is a label set on goroutines that have a process attached
|
|
||||||
const ProcessTypePProfLabel = "process-type"
|
|
||||||
|
|
||||||
// IDType is a pid type
|
// IDType is a pid type
|
||||||
type IDType string
|
type IDType string
|
||||||
|
|
||||||
@ -187,7 +177,12 @@ func (pm *Manager) Add(ctx context.Context, description string, cancel context.C
|
|||||||
|
|
||||||
Trace(true, pid, description, parentPID, processType)
|
Trace(true, pid, description, parentPID, processType)
|
||||||
|
|
||||||
pprofCtx := pprof.WithLabels(ctx, pprof.Labels(DescriptionPProfLabel, description, PPIDPProfLabel, string(parentPID), PIDPProfLabel, string(pid), ProcessTypePProfLabel, processType))
|
pprofCtx := pprof.WithLabels(ctx, pprof.Labels(
|
||||||
|
gtprof.LabelProcessDescription, description,
|
||||||
|
gtprof.LabelPpid, string(parentPID),
|
||||||
|
gtprof.LabelPid, string(pid),
|
||||||
|
gtprof.LabelProcessType, processType,
|
||||||
|
))
|
||||||
if currentlyRunning {
|
if currentlyRunning {
|
||||||
pprof.SetGoroutineLabels(pprofCtx)
|
pprof.SetGoroutineLabels(pprofCtx)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/gtprof"
|
||||||
|
|
||||||
"github.com/google/pprof/profile"
|
"github.com/google/pprof/profile"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -202,7 +204,7 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int
|
|||||||
|
|
||||||
// Add the non-process associated labels from the goroutine sample to the Stack
|
// Add the non-process associated labels from the goroutine sample to the Stack
|
||||||
for name, value := range sample.Label {
|
for name, value := range sample.Label {
|
||||||
if name == DescriptionPProfLabel || name == PIDPProfLabel || (!flat && name == PPIDPProfLabel) || name == ProcessTypePProfLabel {
|
if name == gtprof.LabelProcessDescription || name == gtprof.LabelPid || (!flat && name == gtprof.LabelPpid) || name == gtprof.LabelProcessType {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +226,7 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int
|
|||||||
var process *Process
|
var process *Process
|
||||||
|
|
||||||
// Try to get the PID from the goroutine labels
|
// Try to get the PID from the goroutine labels
|
||||||
if pidvalue, ok := sample.Label[PIDPProfLabel]; ok && len(pidvalue) == 1 {
|
if pidvalue, ok := sample.Label[gtprof.LabelPid]; ok && len(pidvalue) == 1 {
|
||||||
pid := IDType(pidvalue[0])
|
pid := IDType(pidvalue[0])
|
||||||
|
|
||||||
// Now try to get the process from our map
|
// Now try to get the process from our map
|
||||||
@ -238,20 +240,20 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int
|
|||||||
|
|
||||||
// get the parent PID
|
// get the parent PID
|
||||||
ppid := IDType("")
|
ppid := IDType("")
|
||||||
if value, ok := sample.Label[PPIDPProfLabel]; ok && len(value) == 1 {
|
if value, ok := sample.Label[gtprof.LabelPpid]; ok && len(value) == 1 {
|
||||||
ppid = IDType(value[0])
|
ppid = IDType(value[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// format the description
|
// format the description
|
||||||
description := "(dead process)"
|
description := "(dead process)"
|
||||||
if value, ok := sample.Label[DescriptionPProfLabel]; ok && len(value) == 1 {
|
if value, ok := sample.Label[gtprof.LabelProcessDescription]; ok && len(value) == 1 {
|
||||||
description = value[0] + " " + description
|
description = value[0] + " " + description
|
||||||
}
|
}
|
||||||
|
|
||||||
// override the type of the process to "code" but add the old type as a label on the first stack
|
// override the type of the process to "code" but add the old type as a label on the first stack
|
||||||
ptype := NoneProcessType
|
ptype := NoneProcessType
|
||||||
if value, ok := sample.Label[ProcessTypePProfLabel]; ok && len(value) == 1 {
|
if value, ok := sample.Label[gtprof.LabelProcessType]; ok && len(value) == 1 {
|
||||||
stack.Labels = append(stack.Labels, &Label{Name: ProcessTypePProfLabel, Value: value[0]})
|
stack.Labels = append(stack.Labels, &Label{Name: gtprof.LabelProcessType, Value: value[0]})
|
||||||
}
|
}
|
||||||
process = &Process{
|
process = &Process{
|
||||||
PID: pid,
|
PID: pid,
|
||||||
|
@ -6,6 +6,7 @@ package queue
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime/pprof"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -241,6 +242,9 @@ func NewWorkerPoolQueueWithContext[T any](ctx context.Context, name string, queu
|
|||||||
w.origHandler = handler
|
w.origHandler = handler
|
||||||
w.safeHandler = func(t ...T) (unhandled []T) {
|
w.safeHandler = func(t ...T) (unhandled []T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
// FIXME: there is no ctx support in the handler, so process manager is unable to restore the labels
|
||||||
|
// so here we explicitly set the "queue ctx" labels again after the handler is done
|
||||||
|
pprof.SetGoroutineLabels(w.ctxRun)
|
||||||
err := recover()
|
err := recover()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Recovered from panic in queue %q handler: %v\n%s", name, err, log.Stack(2))
|
log.Error("Recovered from panic in queue %q handler: %v\n%s", name, err, log.Stack(2))
|
||||||
|
@ -32,7 +32,7 @@ var (
|
|||||||
// issueNumericPattern matches string that references to a numeric issue, e.g. #1287
|
// issueNumericPattern matches string that references to a numeric issue, e.g. #1287
|
||||||
issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`)
|
issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`)
|
||||||
// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234
|
// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234
|
||||||
issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\')`)
|
issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\'|,)`)
|
||||||
// crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository
|
// crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository
|
||||||
// e.g. org/repo#12345
|
// e.g. org/repo#12345
|
||||||
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
|
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
|
||||||
|
@ -463,6 +463,7 @@ func TestRegExp_issueAlphanumericPattern(t *testing.T) {
|
|||||||
"ABC-123:",
|
"ABC-123:",
|
||||||
"\"ABC-123\"",
|
"\"ABC-123\"",
|
||||||
"'ABC-123'",
|
"'ABC-123'",
|
||||||
|
"ABC-123, unknown PR",
|
||||||
}
|
}
|
||||||
falseTestCases := []string{
|
falseTestCases := []string{
|
||||||
"RC-08",
|
"RC-08",
|
||||||
|
@ -12,6 +12,9 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CanUserForkBetweenOwners returns true if user can fork between owners.
|
||||||
|
// By default, a user can fork a repository from another owner, but not from themselves.
|
||||||
|
// Many users really like to fork their own repositories, so add an experimental setting to allow this.
|
||||||
func CanUserForkBetweenOwners(id1, id2 int64) bool {
|
func CanUserForkBetweenOwners(id1, id2 int64) bool {
|
||||||
if id1 != id2 {
|
if id1 != id2 {
|
||||||
return true
|
return true
|
||||||
|
@ -31,12 +31,7 @@ func Test_getLicense(t *testing.T) {
|
|||||||
|
|
||||||
Copyright (c) 2023 Gitea
|
Copyright (c) 2023 Gitea
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted`,
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
`,
|
|
||||||
wantErr: assert.NoError,
|
wantErr: assert.NoError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -53,7 +48,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) {
|
if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert.Equalf(t, tt.want, string(got), "GetLicense(%v, %v)", tt.args.name, tt.args.values)
|
assert.Contains(t, string(got), tt.want, "GetLicense(%v, %v)", tt.args.name, tt.args.values)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ var defaultI18nLangNames = []string{
|
|||||||
"zh-TW", "繁體中文(台灣)",
|
"zh-TW", "繁體中文(台灣)",
|
||||||
"de-DE", "Deutsch",
|
"de-DE", "Deutsch",
|
||||||
"fr-FR", "Français",
|
"fr-FR", "Français",
|
||||||
|
"ga-IE", "Gaeilge",
|
||||||
"nl-NL", "Nederlands",
|
"nl-NL", "Nederlands",
|
||||||
"lv-LV", "Latviešu",
|
"lv-LV", "Latviešu",
|
||||||
"ru-RU", "Русский",
|
"ru-RU", "Русский",
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ func NewFuncMap() template.FuncMap {
|
|||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// time / number / format
|
// time / number / format
|
||||||
"FileSize": base.FileSize,
|
"FileSize": base.FileSize,
|
||||||
"CountFmt": base.FormatNumberSI,
|
"CountFmt": countFmt,
|
||||||
"Sec2Time": util.SecToTime,
|
"Sec2Time": util.SecToTime,
|
||||||
|
|
||||||
"TimeEstimateString": timeEstimateString,
|
"TimeEstimateString": timeEstimateString,
|
||||||
@ -239,29 +238,8 @@ func iif(condition any, vals ...any) any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isTemplateTruthy(v any) bool {
|
func isTemplateTruthy(v any) bool {
|
||||||
if v == nil {
|
truth, _ := template.IsTrue(v)
|
||||||
return false
|
return truth
|
||||||
}
|
|
||||||
|
|
||||||
rv := reflect.ValueOf(v)
|
|
||||||
switch rv.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return rv.Bool()
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return rv.Int() != 0
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
||||||
return rv.Uint() != 0
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return rv.Float() != 0
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
return rv.Complex() != 0
|
|
||||||
case reflect.String, reflect.Slice, reflect.Array, reflect.Map:
|
|
||||||
return rv.Len() > 0
|
|
||||||
case reflect.Struct:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return !rv.IsNil()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// evalTokens evaluates the expression by tokens and returns the result, see the comment of eval.Expr for details.
|
// evalTokens evaluates the expression by tokens and returns the result, see the comment of eval.Expr for details.
|
||||||
@ -286,14 +264,6 @@ func userThemeName(user *user_model.User) string {
|
|||||||
return setting.UI.DefaultTheme
|
return setting.UI.DefaultTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
func timeEstimateString(timeSec any) string {
|
|
||||||
v, _ := util.ToInt64(timeSec)
|
|
||||||
if v == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return util.TimeEstimateString(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryBuild builds a query string from a list of key-value pairs.
|
// QueryBuild builds a query string from a list of key-value pairs.
|
||||||
// It omits the nil and empty strings, but it doesn't omit other zero values,
|
// It omits the nil and empty strings, but it doesn't omit other zero values,
|
||||||
// because the zero value of number types may have a meaning.
|
// because the zero value of number types may have a meaning.
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/htmlutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -65,31 +66,12 @@ func TestSanitizeHTML(t *testing.T) {
|
|||||||
assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), SanitizeHTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`))
|
assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), SanitizeHTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTemplateTruthy(t *testing.T) {
|
func TestTemplateIif(t *testing.T) {
|
||||||
tmpl := template.New("test")
|
tmpl := template.New("test")
|
||||||
tmpl.Funcs(template.FuncMap{"Iif": iif})
|
tmpl.Funcs(template.FuncMap{"Iif": iif})
|
||||||
template.Must(tmpl.Parse(`{{if .Value}}true{{else}}false{{end}}:{{Iif .Value "true" "false"}}`))
|
template.Must(tmpl.Parse(`{{if .Value}}true{{else}}false{{end}}:{{Iif .Value "true" "false"}}`))
|
||||||
|
|
||||||
cases := []any{
|
cases := []any{nil, false, true, "", "string", 0, 1}
|
||||||
nil, false, true, "", "string", 0, 1,
|
|
||||||
byte(0), byte(1), int64(0), int64(1), float64(0), float64(1),
|
|
||||||
complex(0, 0), complex(1, 0),
|
|
||||||
(chan int)(nil), make(chan int),
|
|
||||||
(func())(nil), func() {},
|
|
||||||
util.ToPointer(0), util.ToPointer(util.ToPointer(0)),
|
|
||||||
util.ToPointer(1), util.ToPointer(util.ToPointer(1)),
|
|
||||||
[0]int{},
|
|
||||||
[1]int{0},
|
|
||||||
[]int(nil),
|
|
||||||
[]int{},
|
|
||||||
[]int{0},
|
|
||||||
map[any]any(nil),
|
|
||||||
map[any]any{},
|
|
||||||
map[any]any{"k": "v"},
|
|
||||||
(*struct{})(nil),
|
|
||||||
struct{}{},
|
|
||||||
util.ToPointer(struct{}{}),
|
|
||||||
}
|
|
||||||
w := &strings.Builder{}
|
w := &strings.Builder{}
|
||||||
truthyCount := 0
|
truthyCount := 0
|
||||||
for i, v := range cases {
|
for i, v := range cases {
|
||||||
@ -102,3 +84,37 @@ func TestTemplateTruthy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.True(t, truthyCount != 0 && truthyCount != len(cases))
|
assert.True(t, truthyCount != 0 && truthyCount != len(cases))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTemplateEscape(t *testing.T) {
|
||||||
|
execTmpl := func(code string) string {
|
||||||
|
tmpl := template.New("test")
|
||||||
|
tmpl.Funcs(template.FuncMap{"QueryBuild": QueryBuild, "HTMLFormat": htmlutil.HTMLFormat})
|
||||||
|
template.Must(tmpl.Parse(code))
|
||||||
|
w := &strings.Builder{}
|
||||||
|
assert.NoError(t, tmpl.Execute(w, nil))
|
||||||
|
return w.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Golang URL Escape", func(t *testing.T) {
|
||||||
|
// Golang template considers "href", "*src*", "*uri*", "*url*" (and more) ... attributes as contentTypeURL and does auto-escaping
|
||||||
|
actual := execTmpl(`<a href="?a={{"%"}}"></a>`)
|
||||||
|
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
|
||||||
|
actual = execTmpl(`<a data-xxx-url="?a={{"%"}}"></a>`)
|
||||||
|
assert.Equal(t, `<a data-xxx-url="?a=%25"></a>`, actual)
|
||||||
|
})
|
||||||
|
t.Run("Golang URL No-escape", func(t *testing.T) {
|
||||||
|
// non-URL content isn't auto-escaped
|
||||||
|
actual := execTmpl(`<a data-link="?a={{"%"}}"></a>`)
|
||||||
|
assert.Equal(t, `<a data-link="?a=%"></a>`, actual)
|
||||||
|
})
|
||||||
|
t.Run("QueryBuild", func(t *testing.T) {
|
||||||
|
actual := execTmpl(`<a href="{{QueryBuild "?" "a" "%"}}"></a>`)
|
||||||
|
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
|
||||||
|
actual = execTmpl(`<a href="?{{QueryBuild "a" "%"}}"></a>`)
|
||||||
|
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
|
||||||
|
})
|
||||||
|
t.Run("HTMLFormat", func(t *testing.T) {
|
||||||
|
actual := execTmpl("{{HTMLFormat `<a k=\"%s\">%s</a>` `\"` `<>`}}")
|
||||||
|
assert.Equal(t, `<a k="""><></a>`, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -29,6 +29,8 @@ import (
|
|||||||
|
|
||||||
type TemplateExecutor scopedtmpl.TemplateExecutor
|
type TemplateExecutor scopedtmpl.TemplateExecutor
|
||||||
|
|
||||||
|
type TplName string
|
||||||
|
|
||||||
type HTMLRender struct {
|
type HTMLRender struct {
|
||||||
templates atomic.Pointer[scopedtmpl.ScopedTemplate]
|
templates atomic.Pointer[scopedtmpl.ScopedTemplate]
|
||||||
}
|
}
|
||||||
@ -40,7 +42,8 @@ var (
|
|||||||
|
|
||||||
var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors")
|
var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors")
|
||||||
|
|
||||||
func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any, ctx context.Context) error { //nolint:revive
|
func (h *HTMLRender) HTML(w io.Writer, status int, tplName TplName, data any, ctx context.Context) error { //nolint:revive
|
||||||
|
name := string(tplName)
|
||||||
if respWriter, ok := w.(http.ResponseWriter); ok {
|
if respWriter, ok := w.(http.ResponseWriter); ok {
|
||||||
if respWriter.Header().Get("Content-Type") == "" {
|
if respWriter.Header().Get("Content-Type") == "" {
|
||||||
respWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
|
respWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
37
modules/templates/util_format.go
Normal file
37
modules/templates/util_format.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package templates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func timeEstimateString(timeSec any) string {
|
||||||
|
v, _ := util.ToInt64(timeSec)
|
||||||
|
if v == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return util.TimeEstimateString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func countFmt(data any) string {
|
||||||
|
// legacy code, not ideal, still used in some places
|
||||||
|
num, err := util.ToInt64(data)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if num < 1000 {
|
||||||
|
return fmt.Sprintf("%d", num)
|
||||||
|
} else if num < 1_000_000 {
|
||||||
|
num2 := float32(num) / 1000.0
|
||||||
|
return fmt.Sprintf("%.1fk", num2)
|
||||||
|
} else if num < 1_000_000_000 {
|
||||||
|
num2 := float32(num) / 1_000_000.0
|
||||||
|
return fmt.Sprintf("%.1fM", num2)
|
||||||
|
}
|
||||||
|
num2 := float32(num) / 1_000_000_000.0
|
||||||
|
return fmt.Sprintf("%.1fG", num2)
|
||||||
|
}
|
18
modules/templates/util_format_test.go
Normal file
18
modules/templates/util_format_test.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package templates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCountFmt(t *testing.T) {
|
||||||
|
assert.Equal(t, "125", countFmt(125))
|
||||||
|
assert.Equal(t, "1.3k", countFmt(int64(1317)))
|
||||||
|
assert.Equal(t, "21.3M", countFmt(21317675))
|
||||||
|
assert.Equal(t, "45.7G", countFmt(45721317675))
|
||||||
|
assert.Equal(t, "", countFmt("test"))
|
||||||
|
}
|
@ -60,3 +60,7 @@ func (su *StringUtils) EllipsisString(s string, maxLength int) string {
|
|||||||
func (su *StringUtils) ToUpper(s string) string {
|
func (su *StringUtils) ToUpper(s string) string {
|
||||||
return strings.ToUpper(s)
|
return strings.ToUpper(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (su *StringUtils) TrimPrefix(s, prefix string) string {
|
||||||
|
return strings.TrimPrefix(s, prefix)
|
||||||
|
}
|
||||||
|
@ -4,11 +4,16 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RedirectURL returns the redirect URL of a http response.
|
// RedirectURL returns the redirect URL of a http response.
|
||||||
@ -41,3 +46,19 @@ func MockVariableValue[T any](p *T, v ...T) (reset func()) {
|
|||||||
}
|
}
|
||||||
return func() { *p = old }
|
return func() { *p = old }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetupGiteaRoot Sets GITEA_ROOT if it is not already set and returns the value
|
||||||
|
func SetupGiteaRoot() string {
|
||||||
|
giteaRoot := os.Getenv("GITEA_ROOT")
|
||||||
|
if giteaRoot != "" {
|
||||||
|
return giteaRoot
|
||||||
|
}
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
giteaRoot = filepath.Dir(filepath.Dir(filepath.Dir(filename)))
|
||||||
|
fixturesDir := filepath.Join(giteaRoot, "models", "fixtures")
|
||||||
|
if exist, _ := util.IsDir(fixturesDir); !exist {
|
||||||
|
panic(fmt.Sprintf("fixtures directory not found: %s", fixturesDir))
|
||||||
|
}
|
||||||
|
_ = os.Setenv("GITEA_ROOT", giteaRoot)
|
||||||
|
return giteaRoot
|
||||||
|
}
|
||||||
|
17
modules/test/utils_test.go
Normal file
17
modules/test/utils_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetupGiteaRoot(t *testing.T) {
|
||||||
|
t.Setenv("GITEA_ROOT", "test")
|
||||||
|
assert.Equal(t, "test", SetupGiteaRoot())
|
||||||
|
t.Setenv("GITEA_ROOT", "")
|
||||||
|
assert.NotEqual(t, "test", SetupGiteaRoot())
|
||||||
|
}
|
13
modules/util/runtime.go
Normal file
13
modules/util/runtime.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
func CallerFuncName(skip int) string {
|
||||||
|
pc := make([]uintptr, 1)
|
||||||
|
runtime.Callers(skip+1, pc)
|
||||||
|
funcName := runtime.FuncForPC(pc[0]).Name()
|
||||||
|
return funcName
|
||||||
|
}
|
32
modules/util/runtime_test.go
Normal file
32
modules/util/runtime_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCallerFuncName(t *testing.T) {
|
||||||
|
s := CallerFuncName(1)
|
||||||
|
assert.Equal(t, "code.gitea.io/gitea/modules/util.TestCallerFuncName", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCallerFuncName(b *testing.B) {
|
||||||
|
// BenchmarkCaller/sprintf-12 12744829 95.49 ns/op
|
||||||
|
b.Run("sprintf", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = fmt.Sprintf("aaaaaaaaaaaaaaaa %s %s %s", "bbbbbbbbbbbbbbbbbbb", b.Name(), "ccccccccccccccccccccc")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// BenchmarkCaller/caller-12 10625133 113.6 ns/op
|
||||||
|
// It is almost as fast as fmt.Sprintf
|
||||||
|
b.Run("caller", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
CallerFuncName(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -25,7 +25,7 @@ type timeStrGlobalVarsType struct {
|
|||||||
// In the future, it could be some configurable options to help users
|
// In the future, it could be some configurable options to help users
|
||||||
// to convert the working time to different units.
|
// to convert the working time to different units.
|
||||||
|
|
||||||
var timeStrGlobalVars = sync.OnceValue[*timeStrGlobalVarsType](func() *timeStrGlobalVarsType {
|
var timeStrGlobalVars = sync.OnceValue(func() *timeStrGlobalVarsType {
|
||||||
v := &timeStrGlobalVarsType{}
|
v := &timeStrGlobalVarsType{}
|
||||||
v.re = regexp.MustCompile(`(?i)(\d+)\s*([hms])`)
|
v.re = regexp.MustCompile(`(?i)(\d+)\s*([hms])`)
|
||||||
v.units = []struct {
|
v.units = []struct {
|
||||||
|
@ -242,10 +242,10 @@ func TestReserveLineBreakForTextarea(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionalArg(t *testing.T) {
|
func TestOptionalArg(t *testing.T) {
|
||||||
foo := func(other any, optArg ...int) int {
|
foo := func(_ any, optArg ...int) int {
|
||||||
return OptionalArg(optArg)
|
return OptionalArg(optArg)
|
||||||
}
|
}
|
||||||
bar := func(other any, optArg ...int) int {
|
bar := func(_ any, optArg ...int) int {
|
||||||
return OptionalArg(optArg, 42)
|
return OptionalArg(optArg, 42)
|
||||||
}
|
}
|
||||||
assert.Equal(t, 0, foo(nil))
|
assert.Equal(t, 0, foo(nil))
|
||||||
|
31
options/gitignore/AutomationStudio
Normal file
31
options/gitignore/AutomationStudio
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# gitignore template for B&R Automation Studio (AS) 4
|
||||||
|
# website: https://www.br-automation.com/en-us/products/software/automation-software/automation-studio/
|
||||||
|
|
||||||
|
# AS temporary directories
|
||||||
|
Binaries/
|
||||||
|
Diagnosis/
|
||||||
|
Temp/
|
||||||
|
TempObjects/
|
||||||
|
|
||||||
|
# AS transfer files
|
||||||
|
*artransfer.br
|
||||||
|
*arTrsfmode.nv
|
||||||
|
|
||||||
|
# 'ignored' directory
|
||||||
|
ignored/
|
||||||
|
|
||||||
|
# ARNC0ext
|
||||||
|
*arnc0ext.br
|
||||||
|
|
||||||
|
# AS File types
|
||||||
|
*.bak
|
||||||
|
*.isopen
|
||||||
|
*.orig
|
||||||
|
*.log
|
||||||
|
*.asar
|
||||||
|
*.csvlog*
|
||||||
|
*.set
|
||||||
|
!**/Physical/**/*.set
|
||||||
|
|
||||||
|
# RevInfo variables
|
||||||
|
*RevInfo.var
|
28
options/gitignore/Firebase
Normal file
28
options/gitignore/Firebase
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Firebase build and deployment files
|
||||||
|
/firebase-debug.log
|
||||||
|
/firebase-debug.*.log
|
||||||
|
.firebaserc
|
||||||
|
|
||||||
|
# Firebase Hosting
|
||||||
|
/firebase.json
|
||||||
|
*.cache
|
||||||
|
hosting/.cache
|
||||||
|
|
||||||
|
# Firebase Functions
|
||||||
|
/functions/node_modules/
|
||||||
|
/functions/.env
|
||||||
|
/functions/package-lock.json
|
||||||
|
|
||||||
|
# Firebase Emulators
|
||||||
|
/firebase-*.zip
|
||||||
|
/.firebase/
|
||||||
|
/emulator-ui/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Environment files (local configs)
|
||||||
|
/.env.*
|
42
options/gitignore/Modelica
Normal file
42
options/gitignore/Modelica
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Modelica - an object-oriented language for modeling of cyber-physical systems
|
||||||
|
# https://modelica.org/
|
||||||
|
# Ignore temporary files, build results, simulation files
|
||||||
|
|
||||||
|
## Modelica-specific files
|
||||||
|
*~
|
||||||
|
*.bak
|
||||||
|
*.bak-mo
|
||||||
|
*.mof
|
||||||
|
\#*\#
|
||||||
|
*.moe
|
||||||
|
*.mol
|
||||||
|
|
||||||
|
## Build artefacts
|
||||||
|
*.exe
|
||||||
|
*.exp
|
||||||
|
*.o
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
## Simulation files
|
||||||
|
*.mat
|
||||||
|
|
||||||
|
## Package files
|
||||||
|
*.gz
|
||||||
|
*.rar
|
||||||
|
*.tar
|
||||||
|
*.zip
|
||||||
|
|
||||||
|
## Dymola-specific files
|
||||||
|
buildlog.txt
|
||||||
|
dsfinal.txt
|
||||||
|
dsin.txt
|
||||||
|
dslog.txt
|
||||||
|
dsmodel*
|
||||||
|
dsres.txt
|
||||||
|
dymosim*
|
||||||
|
request
|
||||||
|
stat
|
||||||
|
status
|
||||||
|
stop
|
||||||
|
success
|
||||||
|
*.
|
@ -166,3 +166,6 @@ cython_debug/
|
|||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||||
*.bbl
|
*.bbl
|
||||||
|
*.bbl-SAVE-ERROR
|
||||||
*.bcf
|
*.bcf
|
||||||
*.blg
|
*.blg
|
||||||
*-blx.aux
|
*-blx.aux
|
||||||
|
@ -2,18 +2,18 @@ Elastic License 2.0
|
|||||||
|
|
||||||
URL: https://www.elastic.co/licensing/elastic-license
|
URL: https://www.elastic.co/licensing/elastic-license
|
||||||
|
|
||||||
## Acceptance
|
Acceptance
|
||||||
|
|
||||||
By using the software, you agree to all of the terms and conditions below.
|
By using the software, you agree to all of the terms and conditions below.
|
||||||
|
|
||||||
## Copyright License
|
Copyright License
|
||||||
|
|
||||||
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
||||||
non-sublicensable, non-transferable license to use, copy, distribute, make
|
non-sublicensable, non-transferable license to use, copy, distribute, make
|
||||||
available, and prepare derivative works of the software, in each case subject to
|
available, and prepare derivative works of the software, in each case subject to
|
||||||
the limitations and conditions below.
|
the limitations and conditions below.
|
||||||
|
|
||||||
## Limitations
|
Limitations
|
||||||
|
|
||||||
You may not provide the software to third parties as a hosted or managed
|
You may not provide the software to third parties as a hosted or managed
|
||||||
service, where the service provides users with access to any substantial set of
|
service, where the service provides users with access to any substantial set of
|
||||||
@ -27,7 +27,7 @@ You may not alter, remove, or obscure any licensing, copyright, or other notices
|
|||||||
of the licensor in the software. Any use of the licensor’s trademarks is subject
|
of the licensor in the software. Any use of the licensor’s trademarks is subject
|
||||||
to applicable law.
|
to applicable law.
|
||||||
|
|
||||||
## Patents
|
Patents
|
||||||
|
|
||||||
The licensor grants you a license, under any patent claims the licensor can
|
The licensor grants you a license, under any patent claims the licensor can
|
||||||
license, or becomes able to license, to make, have made, use, sell, offer for
|
license, or becomes able to license, to make, have made, use, sell, offer for
|
||||||
@ -40,7 +40,7 @@ the software granted under these terms ends immediately. If your company makes
|
|||||||
such a claim, your patent license ends immediately for work on behalf of your
|
such a claim, your patent license ends immediately for work on behalf of your
|
||||||
company.
|
company.
|
||||||
|
|
||||||
## Notices
|
Notices
|
||||||
|
|
||||||
You must ensure that anyone who gets a copy of any part of the software from you
|
You must ensure that anyone who gets a copy of any part of the software from you
|
||||||
also gets a copy of these terms.
|
also gets a copy of these terms.
|
||||||
@ -53,7 +53,7 @@ software prominent notices stating that you have modified the software.
|
|||||||
These terms do not imply any licenses other than those expressly granted in
|
These terms do not imply any licenses other than those expressly granted in
|
||||||
these terms.
|
these terms.
|
||||||
|
|
||||||
## Termination
|
Termination
|
||||||
|
|
||||||
If you use the software in violation of these terms, such use is not licensed,
|
If you use the software in violation of these terms, such use is not licensed,
|
||||||
and your licenses will automatically terminate. If the licensor provides you
|
and your licenses will automatically terminate. If the licensor provides you
|
||||||
@ -63,31 +63,31 @@ reinstated retroactively. However, if you violate these terms after such
|
|||||||
reinstatement, any additional violation of these terms will cause your licenses
|
reinstatement, any additional violation of these terms will cause your licenses
|
||||||
to terminate automatically and permanently.
|
to terminate automatically and permanently.
|
||||||
|
|
||||||
## No Liability
|
No Liability
|
||||||
|
|
||||||
*As far as the law allows, the software comes as is, without any warranty or
|
As far as the law allows, the software comes as is, without any warranty or
|
||||||
condition, and the licensor will not be liable to you for any damages arising
|
condition, and the licensor will not be liable to you for any damages arising
|
||||||
out of these terms or the use or nature of the software, under any kind of
|
out of these terms or the use or nature of the software, under any kind of
|
||||||
legal claim.*
|
legal claim.
|
||||||
|
|
||||||
## Definitions
|
Definitions
|
||||||
|
|
||||||
The **licensor** is the entity offering these terms, and the **software** is the
|
The licensor is the entity offering these terms, and the software is the
|
||||||
software the licensor makes available under these terms, including any portion
|
software the licensor makes available under these terms, including any portion
|
||||||
of it.
|
of it.
|
||||||
|
|
||||||
**you** refers to the individual or entity agreeing to these terms.
|
you refers to the individual or entity agreeing to these terms.
|
||||||
|
|
||||||
**your company** is any legal entity, sole proprietorship, or other kind of
|
your company is any legal entity, sole proprietorship, or other kind of
|
||||||
organization that you work for, plus all organizations that have control over,
|
organization that you work for, plus all organizations that have control over,
|
||||||
are under the control of, or are under common control with that
|
are under the control of, or are under common control with that
|
||||||
organization. **control** means ownership of substantially all the assets of an
|
organization. control means ownership of substantially all the assets of an
|
||||||
entity, or the power to direct its management and policies by vote, contract, or
|
entity, or the power to direct its management and policies by vote, contract, or
|
||||||
otherwise. Control can be direct or indirect.
|
otherwise. Control can be direct or indirect.
|
||||||
|
|
||||||
**your licenses** are all the licenses granted to you for the software under
|
your licenses are all the licenses granted to you for the software under
|
||||||
these terms.
|
these terms.
|
||||||
|
|
||||||
**use** means anything you do with the software requiring one of your licenses.
|
use means anything you do with the software requiring one of your licenses.
|
||||||
|
|
||||||
**trademark** means trademarks, service marks, and similar rights.
|
trademark means trademarks, service marks, and similar rights.
|
||||||
|
4
options/license/MIPS
Normal file
4
options/license/MIPS
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.
|
||||||
|
MIPS Computer Systems, Inc. grants reproduction and use
|
||||||
|
rights to all parties, PROVIDED that this comment is
|
||||||
|
maintained in the copy.
|
@ -2,8 +2,17 @@ MIT License
|
|||||||
|
|
||||||
Copyright (c) <year> <copyright holders>
|
Copyright (c) <year> <copyright holders>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||||
|
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||||
|
following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||||
|
portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||||
|
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||||
|
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
7
options/license/ThirdEye
Normal file
7
options/license/ThirdEye
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
(C) Copyright 1984 by Third Eye Software, Inc.
|
||||||
|
|
||||||
|
Third Eye Software, Inc. grants reproduction and use rights to
|
||||||
|
all parties, PROVIDED that this comment is maintained in the copy.
|
||||||
|
|
||||||
|
Third Eye makes no claims about the applicability of this
|
||||||
|
symbol table to a particular use.
|
@ -1946,8 +1946,8 @@ pulls.delete.title = Delete this pull request?
|
|||||||
pulls.delete.text = Do you really want to delete this pull request? (This will permanently remove all content. Consider closing it instead, if you intend to keep it archived)
|
pulls.delete.text = Do you really want to delete this pull request? (This will permanently remove all content. Consider closing it instead, if you intend to keep it archived)
|
||||||
|
|
||||||
pulls.recently_pushed_new_branches = You pushed on branch <strong>%[1]s</strong> %[2]s
|
pulls.recently_pushed_new_branches = You pushed on branch <strong>%[1]s</strong> %[2]s
|
||||||
pulls.upstream_diverging_prompt_behind_1 = This branch is %d commit behind %s
|
pulls.upstream_diverging_prompt_behind_1 = This branch is %[1]d commit behind %[2]s
|
||||||
pulls.upstream_diverging_prompt_behind_n = This branch is %d commits behind %s
|
pulls.upstream_diverging_prompt_behind_n = This branch is %[1]d commits behind %[2]s
|
||||||
pulls.upstream_diverging_prompt_base_newer = The base branch %s has new changes
|
pulls.upstream_diverging_prompt_base_newer = The base branch %s has new changes
|
||||||
pulls.upstream_diverging_merge = Sync fork
|
pulls.upstream_diverging_merge = Sync fork
|
||||||
|
|
||||||
@ -3773,6 +3773,9 @@ variables.creation.success = The variable "%s" has been added.
|
|||||||
variables.update.failed = Failed to edit variable.
|
variables.update.failed = Failed to edit variable.
|
||||||
variables.update.success = The variable has been edited.
|
variables.update.success = The variable has been edited.
|
||||||
|
|
||||||
|
logs.always_auto_scroll = Always auto scroll logs
|
||||||
|
logs.always_expand_running = Always expand running logs
|
||||||
|
|
||||||
[projects]
|
[projects]
|
||||||
deleted.display_name = Deleted Project
|
deleted.display_name = Deleted Project
|
||||||
type-1.display_name = Individual Project
|
type-1.display_name = Individual Project
|
||||||
|
@ -1109,6 +1109,7 @@ delete_preexisting_success=Fichiers dépossédés supprimés dans %s.
|
|||||||
blame_prior=Voir le blame avant cette modification
|
blame_prior=Voir le blame avant cette modification
|
||||||
blame.ignore_revs=Les révisions dans <a href="%s">.git-blame-ignore-revs</a> sont ignorées. Vous pouvez quand même <a href="%s">voir ces blâmes</a>.
|
blame.ignore_revs=Les révisions dans <a href="%s">.git-blame-ignore-revs</a> sont ignorées. Vous pouvez quand même <a href="%s">voir ces blâmes</a>.
|
||||||
blame.ignore_revs.failed=Impossible d'ignorer les révisions dans <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Impossible d'ignorer les révisions dans <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
|
user_search_tooltip=Affiche un maximum de 30 utilisateurs
|
||||||
|
|
||||||
tree_path_not_found_commit=Le chemin %[1]s n’existe pas dans la révision %[2]s.
|
tree_path_not_found_commit=Le chemin %[1]s n’existe pas dans la révision %[2]s.
|
||||||
tree_path_not_found_branch=Le chemin %[1]s n’existe pas dans la branche %[2]s.
|
tree_path_not_found_branch=Le chemin %[1]s n’existe pas dans la branche %[2]s.
|
||||||
@ -1527,6 +1528,8 @@ issues.filter_assignee=Assigné
|
|||||||
issues.filter_assginee_no_select=Tous les assignés
|
issues.filter_assginee_no_select=Tous les assignés
|
||||||
issues.filter_assginee_no_assignee=Aucun assigné
|
issues.filter_assginee_no_assignee=Aucun assigné
|
||||||
issues.filter_poster=Auteur
|
issues.filter_poster=Auteur
|
||||||
|
issues.filter_user_placeholder=Rechercher des utilisateurs
|
||||||
|
issues.filter_user_no_select=Tous les utilisateurs
|
||||||
issues.filter_type=Type
|
issues.filter_type=Type
|
||||||
issues.filter_type.all_issues=Tous les tickets
|
issues.filter_type.all_issues=Tous les tickets
|
||||||
issues.filter_type.assigned_to_you=Qui vous sont assignés
|
issues.filter_type.assigned_to_you=Qui vous sont assignés
|
||||||
@ -1676,7 +1679,6 @@ issues.timetracker_timer_stop=Arrêter le minuteur
|
|||||||
issues.timetracker_timer_discard=Annuler le minuteur
|
issues.timetracker_timer_discard=Annuler le minuteur
|
||||||
issues.timetracker_timer_manually_add=Pointer du temps
|
issues.timetracker_timer_manually_add=Pointer du temps
|
||||||
|
|
||||||
issues.time_estimate_placeholder=1h 2m
|
|
||||||
issues.time_estimate_set=Définir le temps estimé
|
issues.time_estimate_set=Définir le temps estimé
|
||||||
issues.time_estimate_display=Estimation : %s
|
issues.time_estimate_display=Estimation : %s
|
||||||
issues.change_time_estimate_at=a changé le temps estimé à <b>%s</b> %s
|
issues.change_time_estimate_at=a changé le temps estimé à <b>%s</b> %s
|
||||||
@ -1943,8 +1945,6 @@ pulls.delete.title=Supprimer cette demande d'ajout ?
|
|||||||
pulls.delete.text=Voulez-vous vraiment supprimer cet demande d'ajout ? (Cela supprimera définitivement tout le contenu. Envisagez de le fermer à la place, si vous avez l'intention de le garder archivé)
|
pulls.delete.text=Voulez-vous vraiment supprimer cet demande d'ajout ? (Cela supprimera définitivement tout le contenu. Envisagez de le fermer à la place, si vous avez l'intention de le garder archivé)
|
||||||
|
|
||||||
pulls.recently_pushed_new_branches=Vous avez soumis sur la branche <strong>%[1]s</strong> %[2]s
|
pulls.recently_pushed_new_branches=Vous avez soumis sur la branche <strong>%[1]s</strong> %[2]s
|
||||||
pulls.upstream_diverging_prompt_behind_1=Cette branche est en retard de %d révision sur %s
|
|
||||||
pulls.upstream_diverging_prompt_behind_n=Cette branche est en retard de %d révisions sur %s
|
|
||||||
pulls.upstream_diverging_prompt_base_newer=La branche de base %s a de nouveaux changements
|
pulls.upstream_diverging_prompt_base_newer=La branche de base %s a de nouveaux changements
|
||||||
pulls.upstream_diverging_merge=Synchroniser la bifurcation
|
pulls.upstream_diverging_merge=Synchroniser la bifurcation
|
||||||
|
|
||||||
@ -2629,6 +2629,7 @@ release.new_release=Nouvelle publication
|
|||||||
release.draft=Brouillon
|
release.draft=Brouillon
|
||||||
release.prerelease=Pré-publication
|
release.prerelease=Pré-publication
|
||||||
release.stable=Stable
|
release.stable=Stable
|
||||||
|
release.latest=Dernière
|
||||||
release.compare=Comparer
|
release.compare=Comparer
|
||||||
release.edit=Éditer
|
release.edit=Éditer
|
||||||
release.ahead.commits=<strong>%d</strong> révisions
|
release.ahead.commits=<strong>%d</strong> révisions
|
||||||
|
@ -1109,6 +1109,7 @@ delete_preexisting_success=Scriosta comhaid neamhghlactha i %s
|
|||||||
blame_prior=Féach ar an milleán roimh an athrú seo
|
blame_prior=Féach ar an milleán roimh an athrú seo
|
||||||
blame.ignore_revs=Ag déanamh neamhairde de leasuithe i <a href="%s">.git-blame-ignore-revs</a>. Cliceáil <a href="%s">anseo chun seachaint</a> agus an gnáth-amharc milleán a fheiceáil.
|
blame.ignore_revs=Ag déanamh neamhairde de leasuithe i <a href="%s">.git-blame-ignore-revs</a>. Cliceáil <a href="%s">anseo chun seachaint</a> agus an gnáth-amharc milleán a fheiceáil.
|
||||||
blame.ignore_revs.failed=Theip ar neamhaird a dhéanamh ar leasuithe i <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Theip ar neamhaird a dhéanamh ar leasuithe i <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
|
user_search_tooltip=Taispeáint uasmhéid de 30 úsáideoir
|
||||||
|
|
||||||
tree_path_not_found_commit=Níl cosán %[1]s ann i dtiomantas %[2]s
|
tree_path_not_found_commit=Níl cosán %[1]s ann i dtiomantas %[2]s
|
||||||
tree_path_not_found_branch=Níl cosán %[1]s ann i mbrainse %[2]s
|
tree_path_not_found_branch=Níl cosán %[1]s ann i mbrainse %[2]s
|
||||||
@ -1527,6 +1528,8 @@ issues.filter_assignee=Sannaitheoir
|
|||||||
issues.filter_assginee_no_select=Gach sannaithe
|
issues.filter_assginee_no_select=Gach sannaithe
|
||||||
issues.filter_assginee_no_assignee=Gan sannaitheoir
|
issues.filter_assginee_no_assignee=Gan sannaitheoir
|
||||||
issues.filter_poster=Údar
|
issues.filter_poster=Údar
|
||||||
|
issues.filter_user_placeholder=Cuardaigh úsáideoirí
|
||||||
|
issues.filter_user_no_select=Gach úsáideoir
|
||||||
issues.filter_type=Cineál
|
issues.filter_type=Cineál
|
||||||
issues.filter_type.all_issues=Gach saincheist
|
issues.filter_type.all_issues=Gach saincheist
|
||||||
issues.filter_type.assigned_to_you=Sannta duit
|
issues.filter_type.assigned_to_you=Sannta duit
|
||||||
@ -1676,7 +1679,6 @@ issues.timetracker_timer_stop=Stop an t-amadóir
|
|||||||
issues.timetracker_timer_discard=Déan an t-amadóir a scriosadh
|
issues.timetracker_timer_discard=Déan an t-amadóir a scriosadh
|
||||||
issues.timetracker_timer_manually_add=Cuir Am leis
|
issues.timetracker_timer_manually_add=Cuir Am leis
|
||||||
|
|
||||||
issues.time_estimate_placeholder=1u 2n
|
|
||||||
issues.time_estimate_set=Socraigh am measta
|
issues.time_estimate_set=Socraigh am measta
|
||||||
issues.time_estimate_display=Meastachán: %s
|
issues.time_estimate_display=Meastachán: %s
|
||||||
issues.change_time_estimate_at=d'athraigh an meastachán ama go <b>%s</b> %s
|
issues.change_time_estimate_at=d'athraigh an meastachán ama go <b>%s</b> %s
|
||||||
@ -1943,8 +1945,6 @@ pulls.delete.title=Scrios an t-iarratas tarraingthe seo?
|
|||||||
pulls.delete.text=An bhfuil tú cinnte gur mhaith leat an t-iarratas tarraingthe seo a scriosadh? (Bainfidh sé seo an t-inneachar go léir go buan. Smaoinigh ar é a dhúnadh ina ionad sin, má tá sé i gceist agat é a choinneáil i gcartlann)
|
pulls.delete.text=An bhfuil tú cinnte gur mhaith leat an t-iarratas tarraingthe seo a scriosadh? (Bainfidh sé seo an t-inneachar go léir go buan. Smaoinigh ar é a dhúnadh ina ionad sin, má tá sé i gceist agat é a choinneáil i gcartlann)
|
||||||
|
|
||||||
pulls.recently_pushed_new_branches=Bhrúigh tú ar bhrainse <strong>%[1]s</strong> %[2]s
|
pulls.recently_pushed_new_branches=Bhrúigh tú ar bhrainse <strong>%[1]s</strong> %[2]s
|
||||||
pulls.upstream_diverging_prompt_behind_1=Tá an brainse seo %d tiomantas taobh thiar de %s
|
|
||||||
pulls.upstream_diverging_prompt_behind_n=Tá an brainse seo %d geallta taobh thiar de %s
|
|
||||||
pulls.upstream_diverging_prompt_base_newer=Tá athruithe nua ar an mbunbhrainse %s
|
pulls.upstream_diverging_prompt_base_newer=Tá athruithe nua ar an mbunbhrainse %s
|
||||||
pulls.upstream_diverging_merge=Forc sionc
|
pulls.upstream_diverging_merge=Forc sionc
|
||||||
|
|
||||||
@ -2629,6 +2629,7 @@ release.new_release=Scaoileadh Nua
|
|||||||
release.draft=Dréacht
|
release.draft=Dréacht
|
||||||
release.prerelease=Réamh-eisiúint
|
release.prerelease=Réamh-eisiúint
|
||||||
release.stable=Cobhsaí
|
release.stable=Cobhsaí
|
||||||
|
release.latest=Is déanaí
|
||||||
release.compare=Déan comparáid
|
release.compare=Déan comparáid
|
||||||
release.edit=cuir in eagar
|
release.edit=cuir in eagar
|
||||||
release.ahead.commits=Geallann <strong>%d</strong>
|
release.ahead.commits=Geallann <strong>%d</strong>
|
||||||
|
@ -22,11 +22,25 @@ toc=Daftar Isi
|
|||||||
username=Nama Pengguna
|
username=Nama Pengguna
|
||||||
email=Alamat Email
|
email=Alamat Email
|
||||||
password=Kata Sandi
|
password=Kata Sandi
|
||||||
|
re_type=Konfirmasi Kata Sandi
|
||||||
captcha=CAPTCHA
|
captcha=CAPTCHA
|
||||||
twofa=Otentikasi Dua Faktor
|
twofa=Otentikasi Dua Faktor
|
||||||
twofa_scratch=Kode Awal Dua Faktor
|
twofa_scratch=Kode Awal Dua Faktor
|
||||||
passcode=Kode Akses
|
passcode=Kode Akses
|
||||||
|
|
||||||
|
webauthn_insert_key=Masukkan kunci keamanan anda
|
||||||
|
webauthn_sign_in=Tekan tombol pada kunci keamanan Anda. Jika kunci keamanan Anda tidak memiliki tombol, masukkan kembali.
|
||||||
|
webauthn_press_button=Silakan tekan tombol pada kunci keamanan Anda…
|
||||||
|
webauthn_use_twofa=Gunakan kode dua faktor dari telepon Anda
|
||||||
|
webauthn_error=Tidak dapat membaca kunci keamanan Anda.
|
||||||
|
webauthn_unsupported_browser=Browser Anda saat ini tidak mendukung WebAuthn.
|
||||||
|
webauthn_error_unknown=Terdapat kesalahan yang tidak diketahui. Mohon coba lagi.
|
||||||
|
webauthn_error_insecure=`WebAuthn hanya mendukung koneksi aman. Untuk pengujian melalui HTTP, Anda dapat menggunakan "localhost" atau "127.0.0.1"`
|
||||||
|
webauthn_error_unable_to_process=Server tidak dapat memproses permintaan Anda.
|
||||||
|
webauthn_error_duplicated=Kunci keamanan tidak diperbolehkan untuk permintaan ini. Pastikan bahwa kunci ini belum terdaftar sebelumnya.
|
||||||
|
webauthn_error_empty=Anda harus menetapkan nama untuk kunci ini.
|
||||||
|
webauthn_error_timeout=Waktu habis sebelum kunci Anda dapat dibaca. Mohon muat ulang halaman ini dan coba lagi.
|
||||||
|
webauthn_reload=Muat ulang
|
||||||
|
|
||||||
repository=Repositori
|
repository=Repositori
|
||||||
organization=Organisasi
|
organization=Organisasi
|
||||||
@ -36,6 +50,8 @@ new_migrate=Migrasi Baru
|
|||||||
new_mirror=Duplikat Baru
|
new_mirror=Duplikat Baru
|
||||||
new_fork=Fork Repositori Baru
|
new_fork=Fork Repositori Baru
|
||||||
new_org=Organisasi Baru
|
new_org=Organisasi Baru
|
||||||
|
new_project=Proyek Baru
|
||||||
|
new_project_column=Kolom Baru
|
||||||
manage_org=Mengelola Organisasi
|
manage_org=Mengelola Organisasi
|
||||||
admin_panel=Administrasi Situs
|
admin_panel=Administrasi Situs
|
||||||
account_settings=Pengaturan Akun
|
account_settings=Pengaturan Akun
|
||||||
@ -55,29 +71,58 @@ pull_requests=Tarik Permintaan
|
|||||||
issues=Masalah
|
issues=Masalah
|
||||||
milestones=Tonggak
|
milestones=Tonggak
|
||||||
|
|
||||||
|
ok=Oke
|
||||||
cancel=Batal
|
cancel=Batal
|
||||||
|
retry=Coba lagi
|
||||||
|
rerun=Jalankan ulang
|
||||||
|
rerun_all=Jalankan ulang semua job
|
||||||
save=Simpan
|
save=Simpan
|
||||||
add=Tambah
|
add=Tambah
|
||||||
add_all=Tambah Semua
|
add_all=Tambah Semua
|
||||||
remove=Buang
|
remove=Buang
|
||||||
remove_all=Buang Semua
|
remove_all=Buang Semua
|
||||||
|
remove_label_str=`Hapus item "%s"`
|
||||||
edit=Edit
|
edit=Edit
|
||||||
|
view=Tampilan
|
||||||
|
test=Pengujian
|
||||||
|
|
||||||
enabled=Aktif
|
enabled=Aktif
|
||||||
disabled=Nonaktif
|
disabled=Nonaktif
|
||||||
|
locked=Terkunci
|
||||||
|
|
||||||
|
copy=Salin
|
||||||
|
copy_url=Salin URL
|
||||||
|
copy_hash=Salin hash
|
||||||
|
copy_content=Salin konten
|
||||||
|
copy_branch=Salin nama branch
|
||||||
|
copy_success=Tersalin!
|
||||||
|
copy_error=Gagal menyalin
|
||||||
|
copy_type_unsupported=Tipe berkas ini tidak dapat disalin
|
||||||
|
|
||||||
write=Tulis
|
write=Tulis
|
||||||
preview=Pratinjau
|
preview=Pratinjau
|
||||||
loading=Memuat…
|
loading=Memuat…
|
||||||
|
|
||||||
|
error=Gangguan
|
||||||
|
error404=Halaman yang akan kamu akses <strong>tidak dapat ditemukan</strong> atau <strong>kamu tidak memiliki akses </strong> untuk melihatnya.
|
||||||
|
go_back=Kembali
|
||||||
|
invalid_data=Data invalid: %v
|
||||||
|
|
||||||
|
never=Tidak Pernah
|
||||||
|
unknown=Tidak diketahui
|
||||||
|
|
||||||
|
rss_feed=Umpan Berita
|
||||||
|
|
||||||
|
pin=Sematkan
|
||||||
|
unpin=Lepas sematan
|
||||||
|
|
||||||
|
artifacts=Artefak
|
||||||
|
confirm_delete_artifact=Apakah Anda yakin ingin menghapus artefak '%s' ?
|
||||||
|
|
||||||
archived=Diarsipkan
|
archived=Diarsipkan
|
||||||
|
|
||||||
|
concept_system_global=Global
|
||||||
|
concept_user_individual=Perorangan
|
||||||
concept_code_repository=Repositori
|
concept_code_repository=Repositori
|
||||||
|
|
||||||
show_full_screen=Tampilkan layar penuh
|
show_full_screen=Tampilkan layar penuh
|
||||||
@ -682,13 +727,16 @@ commits.newer=Terbaru
|
|||||||
commits.signed_by=Ditandai oleh
|
commits.signed_by=Ditandai oleh
|
||||||
|
|
||||||
|
|
||||||
|
commitstatus.error=Gangguan
|
||||||
|
|
||||||
|
|
||||||
projects.description_placeholder=Deskripsi
|
projects.description_placeholder=Deskripsi
|
||||||
projects.title=Judul
|
projects.title=Judul
|
||||||
|
projects.new=Proyek Baru
|
||||||
projects.template.desc=Contoh
|
projects.template.desc=Contoh
|
||||||
projects.column.edit_title=Nama
|
projects.column.edit_title=Nama
|
||||||
projects.column.new_title=Nama
|
projects.column.new_title=Nama
|
||||||
|
projects.column.new=Kolom Baru
|
||||||
|
|
||||||
issues.new=Masalah Baru
|
issues.new=Masalah Baru
|
||||||
issues.new.labels=Label
|
issues.new.labels=Label
|
||||||
|
@ -145,6 +145,7 @@ confirm_delete_selected=選択したすべてのアイテムを削除してよ
|
|||||||
|
|
||||||
name=名称
|
name=名称
|
||||||
value=値
|
value=値
|
||||||
|
readme=Readme
|
||||||
|
|
||||||
filter=フィルター
|
filter=フィルター
|
||||||
filter.clear=フィルターをクリア
|
filter.clear=フィルターをクリア
|
||||||
@ -1043,6 +1044,8 @@ generate_repo=リポジトリの生成
|
|||||||
generate_from=他からの生成
|
generate_from=他からの生成
|
||||||
repo_desc=説明
|
repo_desc=説明
|
||||||
repo_desc_helper=簡単な説明を入力してください (オプション)
|
repo_desc_helper=簡単な説明を入力してください (オプション)
|
||||||
|
repo_no_desc=説明が提供されていません
|
||||||
|
repo_lang=言語
|
||||||
repo_gitignore_helper=.gitignoreテンプレートを選択してください。
|
repo_gitignore_helper=.gitignoreテンプレートを選択してください。
|
||||||
repo_gitignore_helper_desc=一般的な言語のテンプレートリストから、追跡しないファイルの設定を選択します。 各言語のビルドツールが生成する典型的なファイルが、デフォルトで.gitignoreに含まれます。
|
repo_gitignore_helper_desc=一般的な言語のテンプレートリストから、追跡しないファイルの設定を選択します。 各言語のビルドツールが生成する典型的なファイルが、デフォルトで.gitignoreに含まれます。
|
||||||
issue_labels=イシューラベル
|
issue_labels=イシューラベル
|
||||||
@ -1666,12 +1669,25 @@ issues.delete.title=このイシューを削除しますか?
|
|||||||
issues.delete.text=本当にこのイシューを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください)
|
issues.delete.text=本当にこのイシューを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください)
|
||||||
|
|
||||||
issues.tracker=タイムトラッカー
|
issues.tracker=タイムトラッカー
|
||||||
|
issues.timetracker_timer_start=タイマー開始
|
||||||
|
issues.timetracker_timer_stop=タイマー終了
|
||||||
|
issues.timetracker_timer_discard=タイマー破棄
|
||||||
|
issues.timetracker_timer_manually_add=時間を追加
|
||||||
|
|
||||||
|
issues.time_estimate_set=見積時間を設定
|
||||||
|
issues.time_estimate_display=見積時間: %s
|
||||||
|
issues.change_time_estimate_at=が見積時間を <b>%s</b> に変更 %s
|
||||||
|
issues.remove_time_estimate_at=が見積時間を削除 %s
|
||||||
|
issues.time_estimate_invalid=見積時間のフォーマットが不正です
|
||||||
|
issues.start_tracking_history=が作業を開始 %s
|
||||||
issues.tracker_auto_close=タイマーは、このイシューがクローズされると自動的に終了します
|
issues.tracker_auto_close=タイマーは、このイシューがクローズされると自動的に終了します
|
||||||
issues.tracking_already_started=`<a href="%s">別のイシュー</a>で既にタイムトラッキングを開始しています!`
|
issues.tracking_already_started=`<a href="%s">別のイシュー</a>で既にタイムトラッキングを開始しています!`
|
||||||
|
issues.stop_tracking_history=が <b>%s</b> の作業を終了 %s
|
||||||
issues.cancel_tracking_history=`がタイムトラッキングを中止 %s`
|
issues.cancel_tracking_history=`がタイムトラッキングを中止 %s`
|
||||||
issues.del_time=このタイムログを削除
|
issues.del_time=このタイムログを削除
|
||||||
|
issues.add_time_history=が作業時間 <b>%s</b> を追加 %s
|
||||||
issues.del_time_history=`が作業時間を削除 %s`
|
issues.del_time_history=`が作業時間を削除 %s`
|
||||||
|
issues.add_time_manually=時間の手入力
|
||||||
issues.add_time_hours=時間
|
issues.add_time_hours=時間
|
||||||
issues.add_time_minutes=分
|
issues.add_time_minutes=分
|
||||||
issues.add_time_sum_to_small=時間が入力されていません。
|
issues.add_time_sum_to_small=時間が入力されていません。
|
||||||
@ -1691,15 +1707,15 @@ issues.due_date_form_add=期日の追加
|
|||||||
issues.due_date_form_edit=変更
|
issues.due_date_form_edit=変更
|
||||||
issues.due_date_form_remove=削除
|
issues.due_date_form_remove=削除
|
||||||
issues.due_date_not_writer=イシューの期日を変更するには、リポジトリへの書き込み権限が必要です。
|
issues.due_date_not_writer=イシューの期日を変更するには、リポジトリへの書き込み権限が必要です。
|
||||||
issues.due_date_not_set=期日は未設定です。
|
issues.due_date_not_set=期日は設定されていません。
|
||||||
issues.due_date_added=が期日 %s を追加 %s
|
issues.due_date_added=が期日 %s を追加 %s
|
||||||
issues.due_date_modified=が期日を %[2]s から %[1]s に変更 %[3]s
|
issues.due_date_modified=が期日を %[2]s から %[1]s に変更 %[3]s
|
||||||
issues.due_date_remove=が期日 %s を削除 %s
|
issues.due_date_remove=が期日 %s を削除 %s
|
||||||
issues.due_date_overdue=期日は過ぎています
|
issues.due_date_overdue=期日は過ぎています
|
||||||
issues.due_date_invalid=期日が正しくないか範囲を超えています。 'yyyy-mm-dd' の形式で入力してください。
|
issues.due_date_invalid=期日が正しくないか範囲を超えています。 'yyyy-mm-dd' の形式で入力してください。
|
||||||
issues.dependency.title=依存関係
|
issues.dependency.title=依存関係
|
||||||
issues.dependency.issue_no_dependencies=依存関係が設定されていません。
|
issues.dependency.issue_no_dependencies=依存関係は設定されていません。
|
||||||
issues.dependency.pr_no_dependencies=依存関係が設定されていません。
|
issues.dependency.pr_no_dependencies=依存関係は設定されていません。
|
||||||
issues.dependency.no_permission_1=%d 個の依存関係への読み取り権限がありません
|
issues.dependency.no_permission_1=%d 個の依存関係への読み取り権限がありません
|
||||||
issues.dependency.no_permission_n=%d 個の依存関係への読み取り権限がありません
|
issues.dependency.no_permission_n=%d 個の依存関係への読み取り権限がありません
|
||||||
issues.dependency.no_permission.can_remove=この依存関係への読み取り権限はありませんが、この依存関係は削除できます
|
issues.dependency.no_permission.can_remove=この依存関係への読み取り権限はありませんが、この依存関係は削除できます
|
||||||
@ -1924,6 +1940,8 @@ pulls.delete.title=このプルリクエストを削除しますか?
|
|||||||
pulls.delete.text=本当にこのプルリクエストを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください)
|
pulls.delete.text=本当にこのプルリクエストを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください)
|
||||||
|
|
||||||
pulls.recently_pushed_new_branches=%[2]s 、あなたはブランチ <strong>%[1]s</strong> にプッシュしました
|
pulls.recently_pushed_new_branches=%[2]s 、あなたはブランチ <strong>%[1]s</strong> にプッシュしました
|
||||||
|
pulls.upstream_diverging_prompt_base_newer=ベースブランチ %s に新しい変更があります
|
||||||
|
pulls.upstream_diverging_merge=フォークを同期
|
||||||
|
|
||||||
pull.deleted_branch=(削除済み):%s
|
pull.deleted_branch=(削除済み):%s
|
||||||
pull.agit_documentation=AGitに関するドキュメントを確認する
|
pull.agit_documentation=AGitに関するドキュメントを確認する
|
||||||
|
@ -1679,7 +1679,6 @@ issues.timetracker_timer_stop=Parar cronómetro
|
|||||||
issues.timetracker_timer_discard=Descartar cronómetro
|
issues.timetracker_timer_discard=Descartar cronómetro
|
||||||
issues.timetracker_timer_manually_add=Adicionar tempo
|
issues.timetracker_timer_manually_add=Adicionar tempo
|
||||||
|
|
||||||
issues.time_estimate_placeholder=1h 2m
|
|
||||||
issues.time_estimate_set=Definir tempo estimado
|
issues.time_estimate_set=Definir tempo estimado
|
||||||
issues.time_estimate_display=Estimativa: %s
|
issues.time_estimate_display=Estimativa: %s
|
||||||
issues.change_time_estimate_at=alterou a estimativa de tempo para <b>%s</b> %s
|
issues.change_time_estimate_at=alterou a estimativa de tempo para <b>%s</b> %s
|
||||||
@ -1946,8 +1945,6 @@ pulls.delete.title=Eliminar este pedido de integração?
|
|||||||
pulls.delete.text=Tem a certeza que quer eliminar este pedido de integração? Isso irá remover todo o conteúdo permanentemente. Como alternativa considere fechá-lo, se pretender mantê-lo em arquivo.
|
pulls.delete.text=Tem a certeza que quer eliminar este pedido de integração? Isso irá remover todo o conteúdo permanentemente. Como alternativa considere fechá-lo, se pretender mantê-lo em arquivo.
|
||||||
|
|
||||||
pulls.recently_pushed_new_branches=Enviou para o ramo <strong>%[1]s</strong> %[2]s
|
pulls.recently_pushed_new_branches=Enviou para o ramo <strong>%[1]s</strong> %[2]s
|
||||||
pulls.upstream_diverging_prompt_behind_1=Este ramo está %d cometimento atrás de %s
|
|
||||||
pulls.upstream_diverging_prompt_behind_n=Este ramo está %d cometimentos atrás de %s
|
|
||||||
pulls.upstream_diverging_prompt_base_newer=O ramo base %s tem novas modificações
|
pulls.upstream_diverging_prompt_base_newer=O ramo base %s tem novas modificações
|
||||||
pulls.upstream_diverging_merge=Sincronizar derivação
|
pulls.upstream_diverging_merge=Sincronizar derivação
|
||||||
|
|
||||||
@ -2632,6 +2629,7 @@ release.new_release=Novo lançamento
|
|||||||
release.draft=Rascunho
|
release.draft=Rascunho
|
||||||
release.prerelease=Pré-lançamento
|
release.prerelease=Pré-lançamento
|
||||||
release.stable=Estável
|
release.stable=Estável
|
||||||
|
release.latest=Mais recente
|
||||||
release.compare=Comparar
|
release.compare=Comparar
|
||||||
release.edit=editar
|
release.edit=editar
|
||||||
release.ahead.commits=<strong>%d</strong> cometimentos
|
release.ahead.commits=<strong>%d</strong> cometimentos
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user