diff --git a/.bundler-audit.yml b/.bundler-audit.yml deleted file mode 100644 index 0671df390f..0000000000 --- a/.bundler-audit.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -ignore: - # devise-two-factor advisory about brute-forcing TOTP - # We have rate-limits on authentication endpoints in place (including second - # factor verification) since Mastodon v3.2.0 - - CVE-2024-0227 diff --git a/.eslintrc.js b/.eslintrc.js index 8fe3a98b4a..b75168b612 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -366,6 +366,9 @@ module.exports = defineConfig({ // Disable formatting rules that have been enabled in the base config 'indent': 'off', + // This is not needed as we use noImplicitReturns, which handles this in addition to understanding types + 'consistent-return': 'off', + 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'], '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'], diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml index bbc31598c7..e3e2da0c78 100644 --- a/.github/workflows/bundler-audit.yml +++ b/.github/workflows/bundler-audit.yml @@ -6,14 +6,12 @@ on: paths: - 'Gemfile*' - '.ruby-version' - - '.bundler-audit.yml' - '.github/workflows/bundler-audit.yml' pull_request: paths: - 'Gemfile*' - '.ruby-version' - - '.bundler-audit.yml' - '.github/workflows/bundler-audit.yml' schedule: @@ -23,12 +21,17 @@ jobs: security: runs-on: ubuntu-latest + env: + BUNDLE_ONLY: development + steps: - name: Clone repository uses: actions/checkout@v4 - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true - name: Run bundler-audit - run: bundle exec bundler-audit + run: bundle exec bundler-audit check --update diff --git a/.github/workflows/lint-haml.yml b/.github/workflows/lint-haml.yml index 25615b720d..ca4b0c80bf 100644 --- a/.github/workflows/lint-haml.yml +++ b/.github/workflows/lint-haml.yml @@ -26,12 +26,18 @@ on: jobs: lint: runs-on: ubuntu-latest + + env: + BUNDLE_ONLY: development + steps: - name: Clone repository uses: actions/checkout@v4 - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true - name: Run haml-lint run: | diff --git a/.github/workflows/lint-ruby.yml b/.github/workflows/lint-ruby.yml index 411b323486..f4e81d508b 100644 --- a/.github/workflows/lint-ruby.yml +++ b/.github/workflows/lint-ruby.yml @@ -27,18 +27,23 @@ jobs: lint: runs-on: ubuntu-latest + env: + BUNDLE_ONLY: development + steps: - name: Clone repository uses: actions/checkout@v4 - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true - name: Set-up RuboCop Problem Matcher uses: r7kamura/rubocop-problem-matchers-action@v1 - name: Run rubocop - run: bundle exec rubocop + run: bin/rubocop - name: Run brakeman if: always() # Run both checks, even if the first failed diff --git a/.github/workflows/test-migrations-two-step.yml b/.github/workflows/test-migrations-two-step.yml deleted file mode 100644 index 6698847315..0000000000 --- a/.github/workflows/test-migrations-two-step.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: Test two step migrations -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - pull_request: - -jobs: - pre_job: - runs-on: ubuntu-latest - - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-two-step.yml", "lib/tasks/tests.rake"]' - - test: - runs-on: ubuntu-latest - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' - - strategy: - fail-fast: false - - matrix: - postgres: - - 14-alpine - - 15-alpine - - services: - postgres: - image: postgres:${{ matrix.postgres}} - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - env: - CONTINUOUS_INTEGRATION: true - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - DISABLE_SIMPLECOV: true - RAILS_ENV: test - BUNDLE_CLEAN: true - BUNDLE_FROZEN: true - BUNDLE_WITHOUT: 'development production' - BUNDLE_JOBS: 3 - BUNDLE_RETRY: 3 - - steps: - - uses: actions/checkout@v4 - - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - - - name: Create database - run: './bin/rails db:create' - - - name: Run historical migrations with data population - run: './bin/rails tests:migrations:prepare_database' - env: - SKIP_POST_DEPLOYMENT_MIGRATIONS: true - - - name: Run all remaining pre-deployment migrations - run: './bin/rails db:migrate' - env: - SKIP_POST_DEPLOYMENT_MIGRATIONS: true - - - name: Run all post-deployment migrations - run: './bin/rails db:migrate' - - - name: Check migration result - run: './bin/rails tests:migrations:check_database' diff --git a/.github/workflows/test-migrations-one-step.yml b/.github/workflows/test-migrations.yml similarity index 66% rename from .github/workflows/test-migrations-one-step.yml rename to .github/workflows/test-migrations.yml index 1ff5cc06b9..f057efc11a 100644 --- a/.github/workflows/test-migrations-one-step.yml +++ b/.github/workflows/test-migrations.yml @@ -1,4 +1,5 @@ -name: Test one step migrations +name: Historical data migration test + on: push: branches-ignore: @@ -17,7 +18,7 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-one-step.yml", "lib/tasks/tests.rake"]' + paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations.yml", "lib/tasks/tests.rake"]' test: runs-on: ubuntu-latest @@ -57,7 +58,6 @@ jobs: - 6379:6379 env: - CONTINUOUS_INTEGRATION: true DB_HOST: localhost DB_USER: postgres DB_PASS: postgres @@ -65,7 +65,7 @@ jobs: RAILS_ENV: test BUNDLE_CLEAN: true BUNDLE_FROZEN: true - BUNDLE_WITHOUT: 'development production' + BUNDLE_WITHOUT: 'development:production' BUNDLE_JOBS: 3 BUNDLE_RETRY: 3 @@ -75,14 +75,19 @@ jobs: - name: Set up Ruby environment uses: ./.github/actions/setup-ruby - - name: Create database - run: './bin/rails db:create' + - name: Test "one step migration" flow + run: | + bin/rails db:drop + bin/rails db:create + bin/rails tests:migrations:prepare_database + bin/rails db:migrate + bin/rails tests:migrations:check_database - - name: Run historical migrations with data population - run: './bin/rails tests:migrations:prepare_database' - - - name: Run all remaining migrations - run: './bin/rails db:migrate' - - - name: Check migration result - run: './bin/rails tests:migrations:check_database' + - name: Test "two step migration" flow + run: | + bin/rails db:drop + bin/rails db:create + SKIP_POST_DEPLOYMENT_MIGRATIONS=true bin/rails tests:migrations:prepare_database + SKIP_POST_DEPLOYMENT_MIGRATIONS=true bin/rails db:migrate + bin/rails db:migrate + bin/rails tests:migrations:check_database diff --git a/.rubocop.yml b/.rubocop.yml index cbc0afd281..cf4ee565e0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,34 @@ -# Can be removed once all rules are addressed or moved to this file as documented overrides -inherit_from: .rubocop_todo.yml +--- +AllCops: + CacheRootDirectory: tmp + DisplayCopNames: true + DisplayStyleGuide: true + Exclude: + - db/schema.rb + - bin/* + - node_modules/**/* + - Vagrantfile + - vendor/**/* + - config/initializers/json_ld* + - lib/mastodon/migration_helpers.rb + - lib/templates/**/* + ExtraDetails: true + NewCops: enable + TargetRubyVersion: 3.1 # Oldest supported ruby version + UseCache: true + +inherit_from: + - .rubocop/layout.yml + - .rubocop/metrics.yml + - .rubocop/naming.yml + - .rubocop/rails.yml + - .rubocop/rspec_rails.yml + - .rubocop/rspec.yml + - .rubocop/style.yml + - .rubocop/custom.yml + - .rubocop_todo.yml + - .rubocop/strict.yml -# Used for merging with exclude lists with .rubocop_todo.yml inherit_mode: merge: - Exclude @@ -12,229 +39,3 @@ require: - rubocop-rspec_rails - rubocop-performance - rubocop-capybara - - ./lib/linter/rubocop_middle_dot - -AllCops: - TargetRubyVersion: 3.1 # Set to minimum supported version of CI - DisplayCopNames: true - DisplayStyleGuide: true - ExtraDetails: true - UseCache: true - CacheRootDirectory: tmp - NewCops: enable # Opt-in to newly added rules - Exclude: - - db/schema.rb - - 'bin/*' - - 'node_modules/**/*' - - 'Vagrantfile' - - 'vendor/**/*' - - 'config/initializers/json_ld*' # Generated files - - 'lib/mastodon/migration_helpers.rb' # Vendored from GitLab - - 'lib/templates/**/*' - -# Reason: Prefer Hashes without extreme indentation -# https://docs.rubocop.org/rubocop/cops_layout.html#layoutfirsthashelementindentation -Layout/FirstHashElementIndentation: - EnforcedStyle: consistent - -# Reason: Currently disabled in .rubocop_todo.yml -# https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength -Layout/LineLength: - Max: 300 # Default of 120 causes a duplicate entry in generated todo file - -## Disable most Metrics/*Length cops -# Reason: those are often triggered and force significant refactors when this happend -# but the team feel they are not really improving the code quality. - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsblocklength -Metrics/BlockLength: - Enabled: false - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsclasslength -Metrics/ClassLength: - Enabled: false - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmethodlength -Metrics/MethodLength: - Enabled: false - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmodulelength -Metrics/ModuleLength: - Enabled: false - -## End Disable Metrics/*Length cops - -# Reason: Currently disabled in .rubocop_todo.yml -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsabcsize -Metrics/AbcSize: - Exclude: - - 'lib/mastodon/cli/*.rb' - -# Reason: Currently disabled in .rubocop_todo.yml -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricscyclomaticcomplexity -Metrics/CyclomaticComplexity: - Exclude: - - lib/mastodon/cli/*.rb - -# Reason: -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsparameterlists -Metrics/ParameterLists: - CountKeywordArgs: false - -# Reason: Prefer seeing a variable name -# https://docs.rubocop.org/rubocop/cops_naming.html#namingblockforwarding -Naming/BlockForwarding: - EnforcedStyle: explicit - -# Reason: Prevailing style is argument file paths -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsfilepath -Rails/FilePath: - EnforcedStyle: arguments - -# Reason: Prevailing style uses numeric status codes, matches RSpec/Rails/HttpStatus -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railshttpstatus -Rails/HttpStatus: - EnforcedStyle: numeric - -# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter -Rails/LexicallyScopedActionFilter: - Exclude: - - 'app/controllers/auth/*' - -# Reason: These tasks are doing local work which do not need full env loaded -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsrakeenvironment -Rails/RakeEnvironment: - Exclude: - - 'lib/tasks/auto_annotate_models.rake' - - 'lib/tasks/emojis.rake' - - 'lib/tasks/mastodon.rake' - - 'lib/tasks/repo.rake' - - 'lib/tasks/statistics.rake' - -# Reason: There are appropriate times to use these features -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsskipsmodelvalidations -Rails/SkipsModelValidations: - Enabled: false - -# Reason: We want to preserve the ability to migrate from arbitrary old versions, -# and cannot guarantee that every installation has run every migration as they upgrade. -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsunusedignoredcolumns -Rails/UnusedIgnoredColumns: - Enabled: false - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsnegateinclude -Rails/NegateInclude: - Enabled: false - -# Reason: Enforce default limit, but allow some elements to span lines -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecexamplelength -RSpec/ExampleLength: - CountAsOne: ['array', 'heredoc', 'method_call'] - -# Reason: Deprecated cop, will be removed in 3.0, replaced by SpecFilePathFormat -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecfilepath -RSpec/FilePath: - Enabled: false - -# Reason: -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnamedsubject -RSpec/NamedSubject: - EnforcedStyle: named_only - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnottonot -RSpec/NotToNot: - EnforcedStyle: to_not - -# Reason: Match overrides from Rspec/FilePath rule above -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecspecfilepathformat -RSpec/SpecFilePathFormat: - CustomTransform: - ActivityPub: activitypub - DeepL: deepl - FetchOEmbedService: fetch_oembed_service - OEmbedController: oembed_controller - OStatus: ostatus - -# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus -# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus -RSpecRails/HttpStatus: - EnforcedStyle: numeric - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#styleclassandmodulechildren -Style/ClassAndModuleChildren: - Enabled: false - -# Reason: Classes mostly self-document with their names -# https://docs.rubocop.org/rubocop/cops_style.html#styledocumentation -Style/Documentation: - Enabled: false - -# Reason: Route redirects are not token-formatted and must be skipped -# https://docs.rubocop.org/rubocop/cops_style.html#styleformatstringtoken -Style/FormatStringToken: - inherit_mode: - merge: - - AllowedMethods # The rubocop-rails config adds `redirect` - AllowedMethods: - - redirect_with_vary - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop/cops_style.html#stylehashaslastarrayitem -Style/HashAsLastArrayItem: - Enabled: false - -# Reason: Enforce modern Ruby style -# https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax -Style/HashSyntax: - EnforcedStyle: ruby19_no_mixed_keys - EnforcedShorthandSyntax: either - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#stylenumericliterals -Style/NumericLiterals: - AllowedPatterns: - - \d{4}_\d{2}_\d{2}_\d{6} # For DB migration date version number readability - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#stylepercentliteraldelimiters -Style/PercentLiteralDelimiters: - PreferredDelimiters: - '%i': '()' - '%w': '()' - -# Reason: Prefer less indentation in conditional assignments -# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantbegin -Style/RedundantBegin: - Enabled: false - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantfetchblock -Style/RedundantFetchBlock: - Enabled: false - -# Reason: Overridden to reduce implicit StandardError rescues -# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror -Style/RescueStandardError: - EnforcedStyle: implicit - -# Reason: Originally disabled for CodeClimate, and no config consensus has been found -# https://docs.rubocop.org/rubocop/cops_style.html#stylesymbolarray -Style/SymbolArray: - Enabled: false - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#styletrailingcommainarrayliteral -Style/TrailingCommaInArrayLiteral: - EnforcedStyleForMultiline: 'comma' - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#styletrailingcommainhashliteral -Style/TrailingCommaInHashLiteral: - EnforcedStyleForMultiline: 'comma' - -Style/MiddleDot: - Enabled: true diff --git a/.rubocop/custom.yml b/.rubocop/custom.yml new file mode 100644 index 0000000000..63035837f8 --- /dev/null +++ b/.rubocop/custom.yml @@ -0,0 +1,6 @@ +--- +require: + - ../lib/linter/rubocop_middle_dot + +Style/MiddleDot: + Enabled: true diff --git a/.rubocop/layout.yml b/.rubocop/layout.yml new file mode 100644 index 0000000000..487879ca2c --- /dev/null +++ b/.rubocop/layout.yml @@ -0,0 +1,6 @@ +--- +Layout/FirstHashElementIndentation: + EnforcedStyle: consistent + +Layout/LineLength: + Max: 300 # Default of 120 causes a duplicate entry in generated todo file diff --git a/.rubocop/metrics.yml b/.rubocop/metrics.yml new file mode 100644 index 0000000000..89532af42a --- /dev/null +++ b/.rubocop/metrics.yml @@ -0,0 +1,23 @@ +--- +Metrics/AbcSize: + Exclude: + - lib/mastodon/cli/*.rb + +Metrics/BlockLength: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Exclude: + - lib/mastodon/cli/*.rb + +Metrics/MethodLength: + Enabled: false + +Metrics/ModuleLength: + Enabled: false + +Metrics/ParameterLists: + CountKeywordArgs: false diff --git a/.rubocop/naming.yml b/.rubocop/naming.yml new file mode 100644 index 0000000000..da6ad4ac57 --- /dev/null +++ b/.rubocop/naming.yml @@ -0,0 +1,3 @@ +--- +Naming/BlockForwarding: + EnforcedStyle: explicit diff --git a/.rubocop/rails.yml b/.rubocop/rails.yml new file mode 100644 index 0000000000..b83928dee6 --- /dev/null +++ b/.rubocop/rails.yml @@ -0,0 +1,27 @@ +--- +Rails/FilePath: + EnforcedStyle: arguments + +Rails/HttpStatus: + EnforcedStyle: numeric + +Rails/LexicallyScopedActionFilter: + Exclude: + - app/controllers/auth/* # Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions + +Rails/NegateInclude: + Enabled: false + +Rails/RakeEnvironment: + Exclude: # Tasks are doing local work which do not need full env loaded + - lib/tasks/auto_annotate_models.rake + - lib/tasks/emojis.rake + - lib/tasks/mastodon.rake + - lib/tasks/repo.rake + - lib/tasks/statistics.rake + +Rails/SkipsModelValidations: + Enabled: false + +Rails/UnusedIgnoredColumns: + Enabled: false # Preserve ability to migrate from arbitrary old versions diff --git a/.rubocop/rspec.yml b/.rubocop/rspec.yml new file mode 100644 index 0000000000..a6f8a7aee0 --- /dev/null +++ b/.rubocop/rspec.yml @@ -0,0 +1,17 @@ +--- +RSpec/ExampleLength: + CountAsOne: ['array', 'heredoc', 'method_call'] + +RSpec/NamedSubject: + EnforcedStyle: named_only + +RSpec/NotToNot: + EnforcedStyle: to_not + +RSpec/SpecFilePathFormat: + CustomTransform: + ActivityPub: activitypub + DeepL: deepl + FetchOEmbedService: fetch_oembed_service + OEmbedController: oembed_controller + OStatus: ostatus diff --git a/.rubocop/rspec_rails.yml b/.rubocop/rspec_rails.yml new file mode 100644 index 0000000000..993a5689ad --- /dev/null +++ b/.rubocop/rspec_rails.yml @@ -0,0 +1,3 @@ +--- +RSpecRails/HttpStatus: + EnforcedStyle: numeric diff --git a/.rubocop/strict.yml b/.rubocop/strict.yml new file mode 100644 index 0000000000..2222c6d8b9 --- /dev/null +++ b/.rubocop/strict.yml @@ -0,0 +1,19 @@ +Lint/Debugger: # Remove any `binding.pry` + Enabled: true + Exclude: [] + +RSpec/Focus: # Require full spec run on CI + Enabled: true + Exclude: [] + +Rails/Output: # Remove any `puts` debugging + Enabled: true + Exclude: [] + +Rails/FindEach: # Using `each` could impact performance, use `find_each` + Enabled: true + Exclude: [] + +Rails/UniqBeforePluck: # Require `uniq.pluck` and not `pluck.uniq` + Enabled: true + Exclude: [] diff --git a/.rubocop/style.yml b/.rubocop/style.yml new file mode 100644 index 0000000000..03e35a70ac --- /dev/null +++ b/.rubocop/style.yml @@ -0,0 +1,47 @@ +--- +Style/ClassAndModuleChildren: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/FormatStringToken: + AllowedMethods: + - redirect_with_vary # Route redirects are not token-formatted + inherit_mode: + merge: + - AllowedMethods + +Style/HashAsLastArrayItem: + Enabled: false + +Style/HashSyntax: + EnforcedShorthandSyntax: either + EnforcedStyle: ruby19_no_mixed_keys + +Style/NumericLiterals: + AllowedPatterns: + - \d{4}_\d{2}_\d{2}_\d{6} + +Style/PercentLiteralDelimiters: + PreferredDelimiters: + '%i': () + '%w': () + +Style/RedundantBegin: + Enabled: false + +Style/RedundantFetchBlock: + Enabled: false + +Style/RescueStandardError: + EnforcedStyle: implicit + +Style/SymbolArray: + Enabled: false + +Style/TrailingCommaInArrayLiteral: + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma diff --git a/.ruby-version b/.ruby-version index 4772543317..619b537668 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.2 +3.3.3 diff --git a/Dockerfile b/Dockerfile index 2dc7602b2d..e29377829c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ ARG BUILDPLATFORM=${BUILDPLATFORM} # Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] # renovate: datasource=docker depName=docker.io/ruby -ARG RUBY_VERSION="3.3.2" +ARG RUBY_VERSION="3.3.3" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] # renovate: datasource=node-version depName=node ARG NODE_MAJOR_VERSION="20" diff --git a/Gemfile b/Gemfile index be02a65626..b00eaecbcf 100644 --- a/Gemfile +++ b/Gemfile @@ -171,6 +171,7 @@ group :development do gem 'rubocop-performance', require: false gem 'rubocop-rails', require: false gem 'rubocop-rspec', require: false + gem 'rubocop-rspec_rails', require: false # Annotates modules with schema gem 'annotate', '~> 3.2' diff --git a/Gemfile.lock b/Gemfile.lock index c2253fe19c..172b7cbdd4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,7 +109,7 @@ GEM aws-sdk-kms (1.83.0) aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.152.1) + aws-sdk-s3 (1.152.2) aws-sdk-core (~> 3, >= 3.197.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) @@ -584,7 +584,7 @@ GEM orm_adapter (0.5.0) ox (2.14.18) parallel (1.25.1) - parser (3.3.2.0) + parser (3.3.3.0) ast (~> 2.4.1) racc parslet (2.0.0) @@ -698,8 +698,8 @@ GEM responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.2.8) - strscan (>= 3.0.9) + rexml (3.3.0) + strscan rotp (6.3.0) rouge (4.2.1) rpam2 (4.0.2) @@ -746,8 +746,6 @@ GEM parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) - rubocop-factory_bot (2.25.1) - rubocop (~> 1.41) rubocop-performance (1.21.0) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) @@ -756,13 +754,11 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (2.31.0) - rubocop (~> 1.40) - rubocop-capybara (~> 2.17) - rubocop-factory_bot (~> 2.22) - rubocop-rspec_rails (~> 2.28) - rubocop-rspec_rails (2.28.3) - rubocop (~> 1.40) + rubocop-rspec (3.0.1) + rubocop (~> 1.61) + rubocop-rspec_rails (2.30.0) + rubocop (~> 1.61) + rubocop-rspec (~> 3, >= 3.0.1) ruby-prof (1.7.0) ruby-progressbar (1.13.0) ruby-saml (1.16.0) @@ -776,7 +772,7 @@ GEM fugit (~> 1.1, >= 1.1.6) safety_net_attestation (0.4.0) jwt (~> 2.0) - sanitize (6.1.0) + sanitize (6.1.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) scenic (1.8.0) @@ -1028,6 +1024,7 @@ DEPENDENCIES rubocop-performance rubocop-rails rubocop-rspec + rubocop-rspec_rails ruby-prof ruby-progressbar (~> 1.13) ruby-vips (~> 2.2) diff --git a/README.md b/README.md index c2f80374af..0fdc8d378c 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre ### Tech stack - **Ruby on Rails** powers the REST API and other web pages -- **React.js** and Redux are used for the dynamic parts of the interface +- **React.js** and **Redux** are used for the dynamic parts of the interface - **Node.js** powers the streaming API ### Requirements diff --git a/app/javascript/mastodon/actions/importer/index.js b/app/javascript/mastodon/actions/importer/index.js index 16f191b584..d906bdfb14 100644 --- a/app/javascript/mastodon/actions/importer/index.js +++ b/app/javascript/mastodon/actions/importer/index.js @@ -68,13 +68,17 @@ export function importFetchedStatuses(statuses) { status.filtered.forEach(result => pushUnique(filters, result.filter)); } - if (status.reblog && status.reblog.id) { + if (status.reblog?.id) { processStatus(status.reblog); } - if (status.poll && status.poll.id) { + if (status.poll?.id) { pushUnique(polls, normalizePoll(status.poll, getState().getIn(['polls', status.poll.id]))); } + + if (status.card?.author_account) { + pushUnique(accounts, status.card.author_account); + } } statuses.forEach(processStatus); diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js index b5a30343e4..be76b0f391 100644 --- a/app/javascript/mastodon/actions/importer/normalizer.js +++ b/app/javascript/mastodon/actions/importer/normalizer.js @@ -36,6 +36,10 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.poll = status.poll.id; } + if (status.card?.author_account) { + normalStatus.card = { ...status.card, author_account: status.card.author_account.id }; + } + if (status.filtered) { normalStatus.filtered = status.filtered.map(normalizeFilterResult); } diff --git a/app/javascript/mastodon/actions/trends.js b/app/javascript/mastodon/actions/trends.js index 0b840b41ce..01089fccbb 100644 --- a/app/javascript/mastodon/actions/trends.js +++ b/app/javascript/mastodon/actions/trends.js @@ -1,6 +1,6 @@ import api, { getLinks } from '../api'; -import { importFetchedStatuses } from './importer'; +import { importFetchedStatuses, importFetchedAccounts } from './importer'; export const TRENDS_TAGS_FETCH_REQUEST = 'TRENDS_TAGS_FETCH_REQUEST'; export const TRENDS_TAGS_FETCH_SUCCESS = 'TRENDS_TAGS_FETCH_SUCCESS'; @@ -49,8 +49,11 @@ export const fetchTrendingLinks = () => (dispatch) => { dispatch(fetchTrendingLinksRequest()); api() - .get('/api/v1/trends/links') - .then(({ data }) => dispatch(fetchTrendingLinksSuccess(data))) + .get('/api/v1/trends/links', { params: { limit: 20 } }) + .then(({ data }) => { + dispatch(importFetchedAccounts(data.map(link => link.author_account).filter(account => !!account))); + dispatch(fetchTrendingLinksSuccess(data)); + }) .catch(err => dispatch(fetchTrendingLinksFail(err))); }; diff --git a/app/javascript/mastodon/components/more_from_author.jsx b/app/javascript/mastodon/components/more_from_author.jsx new file mode 100644 index 0000000000..c20e76ac45 --- /dev/null +++ b/app/javascript/mastodon/components/more_from_author.jsx @@ -0,0 +1,19 @@ +import PropTypes from 'prop-types'; + +import { FormattedMessage } from 'react-intl'; + +import { AuthorLink } from 'mastodon/features/explore/components/author_link'; + +export const MoreFromAuthor = ({ accountId }) => ( +