├── .discourse-compatibility ├── .github └── workflows │ └── discourse-plugin.yml ├── .gitignore ├── .npmrc ├── .prettierrc.cjs ├── .rubocop.yml ├── .streerc ├── .template-lintrc.cjs ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── app ├── controllers │ └── discourse_code_review │ │ ├── admin_code_review_controller.rb │ │ ├── code_review_controller.rb │ │ ├── organizations_controller.rb │ │ └── repos_controller.rb ├── jobs │ ├── regular │ │ ├── code_review_sync_commit_comments.rb │ │ ├── code_review_sync_commits.rb │ │ └── code_review_sync_pull_request.rb │ └── scheduled │ │ └── code_review_sync_repos.rb └── models │ ├── commit_topic.rb │ ├── github_repo_category.rb │ └── skipped_code_review.rb ├── assets ├── javascripts │ └── discourse │ │ ├── activity-route-map.js │ │ ├── code-review-route-map.js │ │ ├── connectors │ │ ├── user-activity-bottom │ │ │ ├── approval-given-button.gjs │ │ │ └── approval-pending-button.gjs │ │ └── user-preferences-notifications │ │ │ └── notify-code-review.gjs │ │ ├── controllers │ │ └── admin-plugins-code-review.js │ │ ├── initializers │ │ └── init-code-review.js │ │ ├── routes │ │ ├── admin-plugins-code-review.js │ │ ├── user-activity-approval-given.js │ │ └── user-activity-approval-pending.js │ │ └── templates │ │ └── admin │ │ └── plugins-code-review.gjs └── stylesheets │ └── code_review.scss ├── config ├── locales │ ├── client.ar.yml │ ├── client.be.yml │ ├── client.bg.yml │ ├── client.bs_BA.yml │ ├── client.ca.yml │ ├── client.cs.yml │ ├── client.da.yml │ ├── client.de.yml │ ├── client.el.yml │ ├── client.en.yml │ ├── client.en_GB.yml │ ├── client.es.yml │ ├── client.et.yml │ ├── client.fa_IR.yml │ ├── client.fi.yml │ ├── client.fr.yml │ ├── client.gl.yml │ ├── client.he.yml │ ├── client.hr.yml │ ├── client.hu.yml │ ├── client.hy.yml │ ├── client.id.yml │ ├── client.it.yml │ ├── client.ja.yml │ ├── client.ko.yml │ ├── client.lt.yml │ ├── client.lv.yml │ ├── client.nb_NO.yml │ ├── client.nl.yml │ ├── client.pl_PL.yml │ ├── client.pt.yml │ ├── client.pt_BR.yml │ ├── client.ro.yml │ ├── client.ru.yml │ ├── client.sk.yml │ ├── client.sl.yml │ ├── client.sq.yml │ ├── client.sr.yml │ ├── client.sv.yml │ ├── client.sw.yml │ ├── client.te.yml │ ├── client.th.yml │ ├── client.tr_TR.yml │ ├── client.ug.yml │ ├── client.uk.yml │ ├── client.ur.yml │ ├── client.vi.yml │ ├── client.zh_CN.yml │ ├── client.zh_TW.yml │ ├── server.ar.yml │ ├── server.be.yml │ ├── server.bg.yml │ ├── server.bs_BA.yml │ ├── server.ca.yml │ ├── server.cs.yml │ ├── server.da.yml │ ├── server.de.yml │ ├── server.el.yml │ ├── server.en.yml │ ├── server.en_GB.yml │ ├── server.es.yml │ ├── server.et.yml │ ├── server.fa_IR.yml │ ├── server.fi.yml │ ├── server.fr.yml │ ├── server.gl.yml │ ├── server.he.yml │ ├── server.hr.yml │ ├── server.hu.yml │ ├── server.hy.yml │ ├── server.id.yml │ ├── server.it.yml │ ├── server.ja.yml │ ├── server.ko.yml │ ├── server.lt.yml │ ├── server.lv.yml │ ├── server.nb_NO.yml │ ├── server.nl.yml │ ├── server.pl_PL.yml │ ├── server.pt.yml │ ├── server.pt_BR.yml │ ├── server.ro.yml │ ├── server.ru.yml │ ├── server.sk.yml │ ├── server.sl.yml │ ├── server.sq.yml │ ├── server.sr.yml │ ├── server.sv.yml │ ├── server.sw.yml │ ├── server.te.yml │ ├── server.th.yml │ ├── server.tr_TR.yml │ ├── server.ug.yml │ ├── server.uk.yml │ ├── server.ur.yml │ ├── server.vi.yml │ ├── server.zh_CN.yml │ └── server.zh_TW.yml └── settings.yml ├── db └── migrate │ ├── 20181213080000_create_custom_field_indexes.rb │ ├── 20200920080000_add_skipped_code_reviews.rb │ ├── 20220111185133_create_code_review_github_repos.rb │ └── 20220111185242_create_code_review_commit_topics.rb ├── eslint.config.mjs ├── lib ├── discourse_code_review │ ├── category_extension.rb │ ├── github_pr_poster.rb │ ├── github_pr_syncer.rb │ ├── github_repo.rb │ ├── github_user_syncer.rb │ ├── importer.rb │ ├── list_controller_extension.rb │ ├── rake_tasks.rb │ ├── source.rb │ ├── source │ │ ├── commit_querier.rb │ │ ├── git_repo.rb │ │ ├── github_pr_querier.rb │ │ ├── github_pr_service.rb │ │ └── github_user_querier.rb │ ├── state.rb │ ├── state │ │ ├── commit_approval.rb │ │ ├── commit_topics.rb │ │ ├── github_repo_categories.rb │ │ └── helpers.rb │ └── topic_extension.rb ├── enumerators.rb ├── graphql_client.rb ├── octokit_rate_limit_retry_mixin.rb ├── typed_data.rb └── validators │ └── parent_category_validator.rb ├── package.json ├── plugin.rb ├── pnpm-lock.yaml ├── spec ├── discourse_code_review │ └── lib │ │ ├── github_pr_querier_spec.rb │ │ ├── github_pr_service_spec.rb │ │ ├── github_pr_syncer_spec.rb │ │ ├── github_repo_spec.rb │ │ ├── github_user_syncer_spec.rb │ │ ├── importer_spec.rb │ │ └── state │ │ ├── commit_approval_spec.rb │ │ ├── commit_topics_spec.rb │ │ └── github_repo_categories_spec.rb ├── helpers │ ├── github_rest_api_mock.rb │ ├── graphql_client_mock.rb │ ├── integration.rb │ ├── remote_mocks.rb │ └── rugged_interceptor.rb ├── jobs │ ├── code_review_sync_commits_spec.rb │ └── code_review_sync_repos_spec.rb ├── lib │ ├── enumerators_spec.rb │ ├── github_pr_syncer_spec.rb │ └── octokit_rate_limit_retry_mixin_spec.rb ├── plugin_spec.rb ├── requests │ └── discourse_code_review │ │ ├── code_review_controller_spec.rb │ │ ├── list_controller_spec.rb │ │ └── repos_controller_spec.rb ├── system │ ├── core_features_spec.rb │ └── keyboard_shortcuts_spec.rb └── tasks │ └── code_review_sha_backfill_spec.rb ├── stylelint.config.mjs ├── test └── javascripts │ └── acceptance │ ├── admin-webhook-configuration-test.js │ ├── commit-approved-notifications-test.js │ ├── self-approve-desktop-test.js │ ├── self-approve-mobile-test.js │ ├── user-activity-approval-given-test.js │ └── user-activity-approval-pending-test.js └── translator.yml /.discourse-compatibility: -------------------------------------------------------------------------------- 1 | < 3.5.0.beta5-dev: 4252aceb38564cbad8dbbda78db83b2a8de09d24 2 | < 3.5.0.beta1-dev: 24d6c72422f9e4336d5f1fba9ce12b24d0e007ad 3 | < 3.4.0.beta3-dev: 203b047e5bfdcb038fafa97cf03c00fa2d89ec05 4 | < 3.4.0.beta2-dev: a6faed4b36a2519c56792cea967d0629db3194fc 5 | < 3.4.0.beta1-dev: a36e36e38619f1b239c1c5d891469e8b089459e4 6 | < 3.3.0.beta1-dev: de63793ad493f30904f1e45ea38daa027bb4e3f5 7 | 3.1.999: 735d5171bf12516d93ef1d2993807f364687adea 8 | 2.8.0.beta9: 006a9bec2fe227382ae61a5e25e28dcb0a1a0ab0 9 | -------------------------------------------------------------------------------- /.github/workflows/discourse-plugin.yml: -------------------------------------------------------------------------------- 1 | name: Discourse Plugin 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | ci: 11 | uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /gems 3 | /auto_generated 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict = true 2 | auto-install-peers = false 3 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = require("@discourse/lint-configs/prettier"); 2 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_gem: 2 | rubocop-discourse: stree-compat.yml 3 | -------------------------------------------------------------------------------- /.streerc: -------------------------------------------------------------------------------- 1 | --print-width=100 2 | --plugins=plugin/trailing_comma 3 | -------------------------------------------------------------------------------- /.template-lintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = require("@discourse/lint-configs/template-lint"); 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | group :development do 6 | gem "rubocop-discourse" 7 | gem "syntax_tree" 8 | end 9 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (8.0.2) 5 | base64 6 | benchmark (>= 0.3) 7 | bigdecimal 8 | concurrent-ruby (~> 1.0, >= 1.3.1) 9 | connection_pool (>= 2.2.5) 10 | drb 11 | i18n (>= 1.6, < 2) 12 | logger (>= 1.4.2) 13 | minitest (>= 5.1) 14 | securerandom (>= 0.3) 15 | tzinfo (~> 2.0, >= 2.0.5) 16 | uri (>= 0.13.1) 17 | ast (2.4.3) 18 | base64 (0.3.0) 19 | benchmark (0.4.1) 20 | bigdecimal (3.2.0) 21 | concurrent-ruby (1.3.5) 22 | connection_pool (2.5.3) 23 | drb (2.2.3) 24 | i18n (1.14.7) 25 | concurrent-ruby (~> 1.0) 26 | json (2.12.2) 27 | language_server-protocol (3.17.0.5) 28 | lint_roller (1.1.0) 29 | logger (1.7.0) 30 | minitest (5.25.5) 31 | parallel (1.27.0) 32 | parser (3.3.8.0) 33 | ast (~> 2.4.1) 34 | racc 35 | prettier_print (1.2.1) 36 | prism (1.4.0) 37 | racc (1.8.1) 38 | rack (3.1.15) 39 | rainbow (3.1.1) 40 | regexp_parser (2.10.0) 41 | rubocop (1.75.8) 42 | json (~> 2.3) 43 | language_server-protocol (~> 3.17.0.2) 44 | lint_roller (~> 1.1.0) 45 | parallel (~> 1.10) 46 | parser (>= 3.3.0.2) 47 | rainbow (>= 2.2.2, < 4.0) 48 | regexp_parser (>= 2.9.3, < 3.0) 49 | rubocop-ast (>= 1.44.0, < 2.0) 50 | ruby-progressbar (~> 1.7) 51 | unicode-display_width (>= 2.4.0, < 4.0) 52 | rubocop-ast (1.44.1) 53 | parser (>= 3.3.7.2) 54 | prism (~> 1.4) 55 | rubocop-capybara (2.22.1) 56 | lint_roller (~> 1.1) 57 | rubocop (~> 1.72, >= 1.72.1) 58 | rubocop-discourse (3.12.1) 59 | activesupport (>= 6.1) 60 | lint_roller (>= 1.1.0) 61 | rubocop (>= 1.73.2) 62 | rubocop-capybara (>= 2.22.0) 63 | rubocop-factory_bot (>= 2.27.0) 64 | rubocop-rails (>= 2.30.3) 65 | rubocop-rspec (>= 3.0.1) 66 | rubocop-rspec_rails (>= 2.31.0) 67 | rubocop-factory_bot (2.27.1) 68 | lint_roller (~> 1.1) 69 | rubocop (~> 1.72, >= 1.72.1) 70 | rubocop-rails (2.32.0) 71 | activesupport (>= 4.2.0) 72 | lint_roller (~> 1.1) 73 | rack (>= 1.1) 74 | rubocop (>= 1.75.0, < 2.0) 75 | rubocop-ast (>= 1.44.0, < 2.0) 76 | rubocop-rspec (3.6.0) 77 | lint_roller (~> 1.1) 78 | rubocop (~> 1.72, >= 1.72.1) 79 | rubocop-rspec_rails (2.31.0) 80 | lint_roller (~> 1.1) 81 | rubocop (~> 1.72, >= 1.72.1) 82 | rubocop-rspec (~> 3.5) 83 | ruby-progressbar (1.13.0) 84 | securerandom (0.4.1) 85 | syntax_tree (6.2.0) 86 | prettier_print (>= 1.2.0) 87 | tzinfo (2.0.6) 88 | concurrent-ruby (~> 1.0) 89 | unicode-display_width (3.1.4) 90 | unicode-emoji (~> 4.0, >= 4.0.4) 91 | unicode-emoji (4.0.4) 92 | uri (1.0.3) 93 | 94 | PLATFORMS 95 | ruby 96 | 97 | DEPENDENCIES 98 | rubocop-discourse 99 | syntax_tree 100 | 101 | BUNDLED WITH 102 | 2.6.9 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Civilized Discourse Construction Kit, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discourse Code Review Plugin 2 | 3 | Review GitHub commits on Discourse 4 | 5 | For more information, please see: https://meta.discourse.org/t/discourse-code-review/103142 6 | -------------------------------------------------------------------------------- /app/controllers/discourse_code_review/admin_code_review_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | class AdminCodeReviewController < ::ApplicationController 5 | requires_plugin DiscourseCodeReview::PLUGIN_NAME 6 | 7 | def index 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/controllers/discourse_code_review/organizations_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | class OrganizationsController < ::ApplicationController 5 | requires_plugin DiscourseCodeReview::PLUGIN_NAME 6 | 7 | def index 8 | render_json_dump(DiscourseCodeReview.github_organizations) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/discourse_code_review/repos_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | class ReposController < ::ApplicationController 5 | requires_plugin DiscourseCodeReview::PLUGIN_NAME 6 | 7 | before_action :set_organization 8 | before_action :set_repo, only: %i[has_configured_webhook configure_webhook] 9 | 10 | def index 11 | repository_names = client.organization_repositories(organization).map(&:name) 12 | render_json_dump(repository_names) 13 | rescue DiscourseCodeReview::APIUserError, Octokit::Unauthorized 14 | render json: 15 | failed_json.merge( 16 | error: I18n.t("discourse_code_review.bad_github_credentials_error"), 17 | ), 18 | status: 401 19 | end 20 | 21 | def has_configured_webhook 22 | hook = get_hook 23 | 24 | has_configured_webhook = hook.present? 25 | has_configured_webhook &&= hook[:events].to_set == webhook_events.to_set 26 | has_configured_webhook &&= hook[:config][:url] == webhook_config[:url] 27 | has_configured_webhook &&= hook[:config][:content_type] == webhook_config[:content_type] 28 | render_json_dump(has_configured_webhook: has_configured_webhook) 29 | rescue Octokit::NotFound 30 | render json: 31 | failed_json.merge( 32 | error: I18n.t("discourse_code_review.bad_github_permissions_error"), 33 | ), 34 | status: 400 35 | end 36 | 37 | def configure_webhook 38 | hook = get_hook 39 | 40 | if hook.present? 41 | client.edit_hook( 42 | full_repo_name, 43 | hook[:id], 44 | "web", 45 | webhook_config, 46 | events: webhook_events, 47 | active: true, 48 | ) 49 | else 50 | client.create_hook( 51 | full_repo_name, 52 | "web", 53 | webhook_config, 54 | events: webhook_events, 55 | active: true, 56 | ) 57 | end 58 | 59 | render_json_dump(has_configured_webhook: true) 60 | end 61 | 62 | private 63 | 64 | attr_reader :organization 65 | attr_reader :repo 66 | 67 | def full_repo_name 68 | "#{organization}/#{repo}" 69 | end 70 | 71 | def set_organization 72 | @organization = params[:organization_id] 73 | end 74 | 75 | def set_repo 76 | @repo = params[:id] 77 | end 78 | 79 | def client 80 | DiscourseCodeReview.octokit_bot_client 81 | end 82 | 83 | def get_hook 84 | client 85 | .hooks(full_repo_name) 86 | .select do |hook| 87 | config = hook[:config] 88 | url = URI.parse(config[:url]) 89 | 90 | url.hostname == Discourse.current_hostname && url.path == "/code-review/webhook" 91 | end 92 | .first 93 | end 94 | 95 | def webhook_config 96 | { 97 | url: "https://#{Discourse.current_hostname}/code-review/webhook", 98 | content_type: "json", 99 | secret: SiteSetting.code_review_github_webhook_secret, 100 | } 101 | end 102 | 103 | def webhook_events 104 | %w[ 105 | commit_comment 106 | issue_comment 107 | pull_request 108 | pull_request_review 109 | pull_request_review_comment 110 | push 111 | ] 112 | end 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /app/jobs/regular/code_review_sync_commit_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jobs 4 | class CodeReviewSyncCommitComments < ::Jobs::Base 5 | include OctokitRateLimitRetryMixin 6 | 7 | sidekiq_options queue: "low" 8 | 9 | def execute(args) 10 | repo_name, commit_sha, repo_id = args.values_at(:repo_name, :commit_sha, :repo_id) 11 | 12 | raise Discourse::InvalidParameters.new(:repo_name) unless repo_name.kind_of?(String) 13 | 14 | raise Discourse::InvalidParameters.new(:commit_sha) unless commit_sha.kind_of?(String) 15 | 16 | client = DiscourseCodeReview.octokit_client 17 | github_commit_querier = DiscourseCodeReview.github_commit_querier 18 | repo = 19 | DiscourseCodeReview::GithubRepo.new( 20 | repo_name, 21 | client, 22 | github_commit_querier, 23 | repo_id: repo_id, 24 | ) 25 | 26 | importer = DiscourseCodeReview::Importer.new(repo) 27 | importer.sync_commit_sha(commit_sha) 28 | 29 | syncer = DiscourseCodeReview.github_pr_syncer 30 | syncer.sync_associated_pull_requests(repo_name, commit_sha, repo_id: repo_id) 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/jobs/regular/code_review_sync_commits.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jobs 4 | class CodeReviewSyncCommits < ::Jobs::Base 5 | include OctokitRateLimitRetryMixin 6 | 7 | sidekiq_options queue: "low" 8 | 9 | def execute(args) 10 | raise Discourse::InvalidParameters.new(:repo_name) unless args[:repo_name].kind_of?(String) 11 | 12 | repo_name, repo_id = args.values_at(:repo_name, :repo_id) 13 | 14 | octokit_client = DiscourseCodeReview.octokit_client 15 | github_commit_querier = DiscourseCodeReview.github_commit_querier 16 | 17 | repo = 18 | DiscourseCodeReview::GithubRepo.new( 19 | repo_name, 20 | octokit_client, 21 | github_commit_querier, 22 | repo_id: repo_id, 23 | ) 24 | 25 | if args[:skip_if_up_to_date] 26 | begin 27 | owner, name = repo_name.split("/") 28 | last_remote_commit = github_commit_querier.last_commit(owner, name) 29 | rescue GraphQLClient::GraphQLError => e 30 | end 31 | 32 | return if !last_remote_commit || repo.last_local_commit == last_remote_commit 33 | end 34 | 35 | importer = DiscourseCodeReview::Importer.new(repo) 36 | 37 | importer.sync_merged_commits do |commit_hash| 38 | if SiteSetting.code_review_approve_approved_prs 39 | DiscourseCodeReview.github_pr_syncer.apply_github_approves(repo_name, commit_hash) 40 | end 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /app/jobs/regular/code_review_sync_pull_request.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jobs 4 | class CodeReviewSyncPullRequest < ::Jobs::Base 5 | include OctokitRateLimitRetryMixin 6 | 7 | sidekiq_options queue: "low" 8 | 9 | def execute(args) 10 | repo_name, issue_number, repo_id = args.values_at(:repo_name, :issue_number, :repo_id) 11 | 12 | raise Discourse::InvalidParameters.new(:repo_name) unless repo_name.kind_of?(String) 13 | 14 | syncer = DiscourseCodeReview.github_pr_syncer 15 | syncer.sync_pull_request(repo_name, issue_number, repo_id: repo_id) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/jobs/scheduled/code_review_sync_repos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jobs 4 | class CodeReviewSyncRepos < ::Jobs::Scheduled 5 | every 1.hour 6 | 7 | def execute(args = {}) 8 | DiscourseCodeReview::GithubRepoCategory 9 | .not_moved 10 | .pluck(:name, :repo_id) 11 | .each do |repo_name, repo_id| 12 | ::Jobs.enqueue( 13 | :code_review_sync_commits, 14 | repo_name: repo_name, 15 | repo_id: repo_id, 16 | skip_if_up_to_date: true, 17 | ) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/models/commit_topic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DiscourseCodeReview::CommitTopic < ActiveRecord::Base 4 | self.table_name = "code_review_commit_topics" 5 | belongs_to :topic 6 | end 7 | -------------------------------------------------------------------------------- /app/models/github_repo_category.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DiscourseCodeReview::GithubRepoCategory < ActiveRecord::Base 4 | self.table_name = "code_review_github_repos" 5 | belongs_to :category 6 | 7 | # "Moved" indicates that the repo has either been transferred or renamed. 8 | # 9 | scope :not_moved, -> { where.not(repo_id: nil) } 10 | end 11 | -------------------------------------------------------------------------------- /app/models/skipped_code_review.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DiscourseCodeReview::SkippedCodeReview < ActiveRecord::Base 4 | self.table_name = "skipped_code_reviews" 5 | belongs_to :user 6 | belongs_to :topic 7 | end 8 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/activity-route-map.js: -------------------------------------------------------------------------------- 1 | export default { 2 | resource: "user.userActivity", 3 | 4 | map() { 5 | this.route("approval-given"); 6 | this.route("approval-pending"); 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/code-review-route-map.js: -------------------------------------------------------------------------------- 1 | export default { 2 | resource: "admin.adminPlugins", 3 | path: "/plugins", 4 | map() { 5 | this.route("code-review"); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/user-activity-bottom/approval-given-button.gjs: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { LinkTo } from "@ember/routing"; 3 | import { classNames, tagName } from "@ember-decorators/component"; 4 | import { i18n } from "discourse-i18n"; 5 | 6 | @tagName("") 7 | @classNames("user-activity-bottom-outlet", "approval-given-button") 8 | export default class ApprovalGivenButton extends Component { 9 | 14 | } 15 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/user-activity-bottom/approval-pending-button.gjs: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { LinkTo } from "@ember/routing"; 3 | import { classNames, tagName } from "@ember-decorators/component"; 4 | import { i18n } from "discourse-i18n"; 5 | 6 | @tagName("") 7 | @classNames("user-activity-bottom-outlet", "approval-pending-button") 8 | export default class ApprovalPendingButton extends Component { 9 | 14 | } 15 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/user-preferences-notifications/notify-code-review.gjs: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { classNames, tagName } from "@ember-decorators/component"; 3 | import PreferenceCheckbox from "discourse/components/preference-checkbox"; 4 | import { i18n } from "discourse-i18n"; 5 | 6 | @tagName("div") 7 | @classNames("user-preferences-notifications-outlet", "notify-code-review") 8 | export default class NotifyCodeReview extends Component { 9 | static shouldRender(args, context) { 10 | return context.currentUser && context.currentUser.admin; 11 | } 12 | 13 | init() { 14 | super.init(...arguments); 15 | const user = this.model; 16 | this.set( 17 | "notifyOnCodeReviews", 18 | user.custom_fields.notify_on_code_reviews !== false 19 | ); 20 | this.addObserver("notifyOnCodeReviews", () => { 21 | user.set( 22 | "custom_fields.notify_on_code_reviews", 23 | this.get("notifyOnCodeReviews") 24 | ); 25 | }); 26 | } 27 | 28 | 39 | } 40 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/routes/admin-plugins-code-review.js: -------------------------------------------------------------------------------- 1 | import DiscourseRoute from "discourse/routes/discourse"; 2 | 3 | export default class AdminPluginsCodeReview extends DiscourseRoute { 4 | controllerName = "admin-plugins-code-review"; 5 | 6 | activate() { 7 | this.controllerFor(this.controllerName).loadOrganizations(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/routes/user-activity-approval-given.js: -------------------------------------------------------------------------------- 1 | import UserTopicListRoute from "discourse/routes/user-topic-list"; 2 | import { i18n } from "discourse-i18n"; 3 | 4 | export default class UserActivityApprovalGiven extends UserTopicListRoute { 5 | model() { 6 | const username = this.modelFor("user").username_lower; 7 | return this.store 8 | .findFiltered("topicList", { 9 | filter: `topics/approval-given/${username}`, 10 | }) 11 | .then((model) => { 12 | // andrei: we agreed that this is an anti pattern, 13 | // it's better to avoid mutating a rest model like this 14 | // this place we'll be refactored later 15 | // see https://github.com/discourse/discourse/pull/14313#discussion_r708784704 16 | model.set("emptyState", this.emptyState()); 17 | return model; 18 | }); 19 | } 20 | 21 | emptyState() { 22 | const user = this.modelFor("user"); 23 | let title; 24 | 25 | if (this.isCurrentUser(user)) { 26 | title = i18n("code_review.approval_given_empty_state_title"); 27 | } else { 28 | title = i18n("code_review.approval_given_empty_state_title_others", { 29 | username: user.username, 30 | }); 31 | } 32 | const body = ""; 33 | return { title, body }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/routes/user-activity-approval-pending.js: -------------------------------------------------------------------------------- 1 | import UserTopicListRoute from "discourse/routes/user-topic-list"; 2 | import { i18n } from "discourse-i18n"; 3 | 4 | export default class UserActivityApprovalPending extends UserTopicListRoute { 5 | model() { 6 | const username = this.modelFor("user").username_lower; 7 | return this.store 8 | .findFiltered("topicList", { 9 | filter: `topics/approval-pending/${username}`, 10 | }) 11 | .then((model) => { 12 | // andrei: we agreed that this is an anti pattern, 13 | // it's better to avoid mutating a rest model like this 14 | // this place we'll be refactored later 15 | // see https://github.com/discourse/discourse/pull/14313#discussion_r708784704 16 | model.set("emptyState", this.emptyState()); 17 | return model; 18 | }); 19 | } 20 | 21 | emptyState() { 22 | const user = this.modelFor("user"); 23 | let title; 24 | 25 | if (this.isCurrentUser(user)) { 26 | title = i18n("code_review.approval_pending_empty_state_title"); 27 | } else { 28 | title = i18n("code_review.approval_pending_empty_state_title_others", { 29 | username: user.username, 30 | }); 31 | } 32 | const body = ""; 33 | return { title, body }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/templates/admin/plugins-code-review.gjs: -------------------------------------------------------------------------------- 1 | import { fn } from "@ember/helper"; 2 | import RouteTemplate from "ember-route-template"; 3 | import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner"; 4 | import DButton from "discourse/components/d-button"; 5 | import icon from "discourse/helpers/d-icon"; 6 | import htmlSafe from "discourse/helpers/html-safe"; 7 | import { i18n } from "discourse-i18n"; 8 | 9 | export default RouteTemplate( 10 | 65 | ); 66 | -------------------------------------------------------------------------------- /assets/stylesheets/code_review.scss: -------------------------------------------------------------------------------- 1 | .code-review-webhook-repo, 2 | .code-review-webhook-configured, 3 | .code-review-webhook-not-configured { 4 | margin-left: 2em; 5 | } 6 | 7 | thead, 8 | tbody { 9 | &.code-review { 10 | .topic-list-item { 11 | .link-bottom-line { 12 | align-items: baseline; 13 | 14 | .committer { 15 | color: var(--primary-high); 16 | font-size: $font-down-1; 17 | font-weight: bold; 18 | margin-right: 12px; 19 | } 20 | 21 | .commit-state { 22 | font-size: $font-down-1; 23 | margin-left: 12px; 24 | } 25 | 26 | .approved { 27 | color: var(--success); 28 | } 29 | 30 | .followup { 31 | color: var(--danger); 32 | } 33 | 34 | .pending { 35 | color: #dbab09; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | .code-review-webhook-tree { 43 | h2 { 44 | margin-top: 1rem; 45 | } 46 | } 47 | 48 | .notification[class*="code-review-"] { 49 | .item-label { 50 | display: block; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /config/locales/client.ar.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ar: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse Code Review" 13 | js: 14 | action_codes: 15 | approved: "تمت الموافقة" 16 | followup: "المتابعة" 17 | followed_up: "تمت المتابعة" 18 | merged: "تم الدمج" 19 | renamed: "تمت إعادة التسمية" 20 | pr_merge_info: "معلومات دمج PR" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: 'تمت الموافقة على "%{topicTitle}"' 25 | multiple: 26 | zero: "%{count} التزام تمت الموافقة عليه" 27 | one: "التزام واحد (%{count}) تمت الموافقة عليه" 28 | two: "التزامان (%{count}) تمت الموافقة عليهما" 29 | few: "%{count} التزامات تمت الموافقة عليها" 30 | many: "%{count} التزامًا تمت الموافقة عليه" 31 | other: "%{count} التزام تمت الموافقة عليه" 32 | title: "تمت الموافقة على الإرسال" 33 | code_review: 34 | title: "مراجعة الرمز" 35 | approve: 36 | title: "الموافقة على الإرسال" 37 | label: "الموافقة" 38 | followup: 39 | title: "المتابعة بشأن الإرسال" 40 | label: "المتابعة" 41 | followed_up: 42 | title: "تمت المتابعة بشأن الإرسال" 43 | label: "تمت المتابعة" 44 | skip: 45 | title: "تخطي الإرسال" 46 | label: "تخطي" 47 | approval_given: "تم منح الموافقة" 48 | approval_given_empty_state_title: "ليس لديك أي التزامات تمت الموافقة عليها حتى الآن" 49 | approval_given_empty_state_title_others: "ليس لدى المستخدم %{username} أي إرسالات تمت الموافقة عليها حتى الآن" 50 | approval_pending: "الموافقة قيد الانتظار" 51 | approval_pending_empty_state_title: "ليس لديك التزامات تنتظر الموافقة" 52 | approval_pending_empty_state_title_others: "ليس لدى المستخدم %{username} أي إرسالات تنتظر الموافقة" 53 | github_webhooks: "خطافات ويب Github" 54 | no_organizations_configured: "أنت بحاجة إلى إعداد مؤسسة واحدة على الأقل باستخدام إعداد الموقع code review github organizations قبل أن تتمكن من إعداد خطافات الويب." 55 | webhooks_load_error: "حدث خطأ في تحميل بيانات خطاف الويب، ولا يمكن إعداد خطافات الويب حتى يتم تصحيح هذا الخطأ." 56 | configure_webhooks: "إعداد خطافات الويب" 57 | configure_webhook: "إعداد خطاف الويب" 58 | notify_on_approval: "إرسال إشعار بالموافقات على مراجعة الرمز" 59 | configure_webhooks_warning: "سيؤدي النقر على \"إعداد خطافات الويب\" إلى استخدام واجهة برمجة تطبيقات GitHub لإنشاء خطافات الويب لكل مستودع في كل مؤسسة أعددتها. سيتم إنشاء مشغِّلات الأحداث push، وcommit_comment، وissue_comment، وpull_request، وpull_request_review، وpull_request_comment. يُرجى العلم بأنك يجب أن تكون قد أعددت أيضًا إعداد الموقع code review github webhook secret لتسير الأمور بشكلٍ صحيح. راجع وثائق خطافات ويب GitHub لمزيدٍ من المعلومات." 60 | -------------------------------------------------------------------------------- /config/locales/client.be.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | be: 8 | js: 9 | action_codes: 10 | approved: "Адобрана" 11 | code_review: 12 | approve: 13 | label: "ўхваляць" 14 | -------------------------------------------------------------------------------- /config/locales/client.bg.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bg: 8 | js: 9 | action_codes: 10 | approved: "Одобрена" 11 | code_review: 12 | approve: 13 | label: "Одобри" 14 | -------------------------------------------------------------------------------- /config/locales/client.bs_BA.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bs_BA: 8 | js: 9 | action_codes: 10 | approved: "Dozvojeno" 11 | code_review: 12 | approve: 13 | label: "Odobri" 14 | -------------------------------------------------------------------------------- /config/locales/client.ca.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ca: 8 | js: 9 | action_codes: 10 | approved: "Aprovat" 11 | code_review: 12 | approve: 13 | label: "Aprova" 14 | -------------------------------------------------------------------------------- /config/locales/client.cs.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | cs: 8 | js: 9 | action_codes: 10 | approved: "Schválen" 11 | code_review: 12 | approve: 13 | label: "Schválit" 14 | -------------------------------------------------------------------------------- /config/locales/client.da.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | da: 8 | js: 9 | action_codes: 10 | approved: "Godkendt" 11 | code_review: 12 | approve: 13 | label: "Godkend" 14 | -------------------------------------------------------------------------------- /config/locales/client.de.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | de: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse – Code-Review" 13 | js: 14 | action_codes: 15 | approved: "Genehmigt" 16 | followup: "Nachbereiten" 17 | followed_up: "Nachbereitet" 18 | merged: "Zusammengeführt" 19 | renamed: "Umbenannt" 20 | pr_merge_info: "Informationen zur PR-Zusammenführung" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '„%{topicTitle}“ genehmigt' 25 | multiple: 26 | one: "%{count} Commit wurde genehmigt" 27 | other: "%{count} Commits wurden genehmigt" 28 | title: "Commit genehmigt" 29 | code_review: 30 | title: "Code-Review" 31 | approve: 32 | title: "Commit genehmigen" 33 | label: "Genehmigen" 34 | followup: 35 | title: "Commit nachbereiten" 36 | label: "Nachbereiten" 37 | followed_up: 38 | title: "Commit nachbereitet" 39 | label: "Nachbereitet" 40 | skip: 41 | title: "Commit überspringen" 42 | label: "Überspringen" 43 | approval_given: "Genehmigung erteilt" 44 | approval_given_empty_state_title: "Du hast noch keine genehmigten Commits" 45 | approval_given_empty_state_title_others: "%{username} hat noch keine genehmigten Commits" 46 | approval_pending: "Genehmigung ausstehend" 47 | approval_pending_empty_state_title: "Du hast keine Commits, die auf Genehmigung warten" 48 | approval_pending_empty_state_title_others: "%{username} hat keine Commits, die auf Genehmigung warten" 49 | github_webhooks: "Github-Webhooks" 50 | no_organizations_configured: "Du musst mindestens eine Organisation mit der Website-Einstellung code review github organizations konfigurieren, bevor Webhooks konfiguriert werden können." 51 | webhooks_load_error: "Es gab einen Fehler beim Laden von Webhook-Daten. Webhooks können nicht konfiguriert werden, bis dieser Fehler behoben ist." 52 | configure_webhooks: "Webhooks konfigurieren" 53 | configure_webhook: "Webhook konfigurieren" 54 | notify_on_approval: "Bei Code-Review-Genehmigungen benachrichtigen" 55 | configure_webhooks_warning: "Wenn du auf „Webhooks konfigurieren“ klickst, wird die GitHub-API verwendet, um Webhooks für jedes Repository in jeder von dir konfigurierten Organisation zu erstellen. Die Ereignisauslöser push, commit_comment, issue_comment, pull_request, pull_request_review und pull_request_comment werden erstellt. Bitte beachte, dass du auch die Website-Einstellung code review github webhook secret konfiguriert haben musst, damit dies funktioniert. Weitere Informationen findest du in der GitHub-Webhook-Dokumentation." 56 | -------------------------------------------------------------------------------- /config/locales/client.el.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | el: 8 | js: 9 | action_codes: 10 | approved: "Εγκρίθηκε " 11 | code_review: 12 | approve: 13 | label: "Έγκριση" 14 | -------------------------------------------------------------------------------- /config/locales/client.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | admin_js: 3 | admin: 4 | site_settings: 5 | categories: 6 | discourse_code_review: "Discourse Code Review" 7 | js: 8 | action_codes: 9 | approved: "Approved" 10 | followup: "Follow Up" 11 | followed_up: "Followed Up" 12 | merged: "Merged" 13 | renamed: "Renamed" 14 | pr_merge_info: "PR Merge Info" 15 | notifications: 16 | code_review: 17 | commit_approved: 18 | single: '"%{topicTitle}" approved' 19 | multiple: 20 | one: "%{count} commit was approved" 21 | other: "%{count} commits were approved" 22 | title: "commit approved" 23 | code_review: 24 | title: "Code Review" 25 | approve: 26 | title: "Approve commit" 27 | label: "Approve" 28 | followup: 29 | title: "Follow up commit" 30 | label: "Follow Up" 31 | followed_up: 32 | title: "Followed up commit" 33 | label: "Followed Up" 34 | skip: 35 | title: "Skip commit" 36 | label: "Skip" 37 | approval_given: "Approval Given" 38 | approval_given_empty_state_title: "You don't have approved commits yet" 39 | approval_given_empty_state_title_others: "%{username} doesn't have approved commits yet" 40 | approval_pending: "Approval Pending" 41 | approval_pending_empty_state_title: "You don't have commits waiting for approval" 42 | approval_pending_empty_state_title_others: "%{username} doesn't have commits waiting for approval" 43 | github_webhooks: "Github Webhooks" 44 | no_organizations_configured: "You need to configure at least one organization with the code review github organizations site setting before webhooks can be configured." 45 | webhooks_load_error: "There was an error loading webhook data, webhooks cannot be configured until this is resolved." 46 | configure_webhooks: "Configure Webhooks" 47 | configure_webhook: "Configure Webhook" 48 | notify_on_approval: "Notify on code review approvals" 49 | configure_webhooks_warning: "Clicking 'Configure Webhooks' will use the GitHub API to create webhooks for every repository in every organization you have configured. The push, commit_comment, issue_comment, pull_request, pull_request_review, and pull_request_comment event triggers will be created. Please note you must also have the code review github webhook secret site setting configured for this to work. See the GitHub webhook documentation for more information." 50 | -------------------------------------------------------------------------------- /config/locales/client.en_GB.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | en_GB: 8 | -------------------------------------------------------------------------------- /config/locales/client.es.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | es: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Revisión del código de Discourse" 13 | js: 14 | action_codes: 15 | approved: "Aprobado" 16 | followup: "Seguimiento" 17 | followed_up: "Seguido" 18 | merged: "Fusionado" 19 | renamed: "Renombrado" 20 | pr_merge_info: "Información de fusión de PR" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '«%{topicTitle}» aprobado' 25 | multiple: 26 | one: "Se aprobó %{count} commit" 27 | other: "Se aprobaron %{count} commits" 28 | title: "commit aprobada" 29 | code_review: 30 | title: "Revisión de código" 31 | approve: 32 | title: "Aprobar commit" 33 | label: "Aprobar" 34 | followup: 35 | title: "Commit de seguimiento" 36 | label: "Seguimiento" 37 | followed_up: 38 | title: "Commit seguido" 39 | label: "Seguido" 40 | skip: 41 | title: "Omitir commit" 42 | label: "Omitir" 43 | approval_given: "Aprobación concedida" 44 | approval_given_empty_state_title: "Todavía no tienes commits aprobados" 45 | approval_given_empty_state_title_others: "%{username} todavía no tiene commits aprobados" 46 | approval_pending: "Aprobación pendiente" 47 | approval_pending_empty_state_title: "No tienes commits esperando la aprobación" 48 | approval_pending_empty_state_title_others: "%{username} no tiene commits en espera de aprobación" 49 | github_webhooks: "Webhooks de Github" 50 | no_organizations_configured: "Tienes que configurar al menos una organización con la configuración del sitio organizaciones de revisión de código de github antes de poder configurar los webhooks." 51 | webhooks_load_error: "Se ha producido un error al cargar los datos del webhook, los webhooks no pueden configurarse hasta que se resuelva." 52 | configure_webhooks: "Configurar webhooks" 53 | configure_webhook: "Configurar webhook" 54 | notify_on_approval: "Notificar sobre aprobaciones de revisión de código" 55 | configure_webhooks_warning: "Al hacer clic en «Configurar Webhooks» se utilizará la API de GitHub para crear webhooks para cada repositorio de cada organización que hayas configurado. Se crearán los activadores de eventos push, commit_comment, issue_comment, pull_request, pull_request_review y pull_request_comment. Ten en cuenta que también debes tener configurado el secreto del webhook de github para que esto funcione. Consulta la documentación sobre webhooks de GitHub para obtener más información." 56 | -------------------------------------------------------------------------------- /config/locales/client.et.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | et: 8 | js: 9 | action_codes: 10 | approved: "Heakskiidetud" 11 | code_review: 12 | approve: 13 | label: "Kinnita" 14 | -------------------------------------------------------------------------------- /config/locales/client.fa_IR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fa_IR: 8 | js: 9 | action_codes: 10 | approved: "پذیرفته شده" 11 | merged: "ادغام شد" 12 | renamed: "تغییر نام داد" 13 | notifications: 14 | code_review: 15 | commit_approved: 16 | single: '«%{topicTitle}» تایید شد' 17 | code_review: 18 | title: "بررسی کد" 19 | approve: 20 | label: "تایید" 21 | skip: 22 | label: "رد کردن" 23 | github_webhooks: "گیت‌هاب وب‌هوک" 24 | -------------------------------------------------------------------------------- /config/locales/client.fi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fi: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discoursen Koodin tarkistus" 13 | js: 14 | action_codes: 15 | approved: "Hyväksytty" 16 | followup: "Seuranta" 17 | followed_up: "Seurattu" 18 | merged: "Yhdistetty" 19 | renamed: "Nimetty uudelleen" 20 | pr_merge_info: "Vetopyynnön yhdistämistiedot" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '"%{topicTitle}" hyväksytty' 25 | multiple: 26 | one: "%{count} solmu hyväksyttiin" 27 | other: "%{count} solmua hyväksyttiin" 28 | title: "solmu hyväksytty" 29 | code_review: 30 | title: "Koodin tarkistus" 31 | approve: 32 | title: "Hyväksy solmu" 33 | label: "Hyväksy" 34 | followup: 35 | title: "Seurantasolmu" 36 | label: "Seuranta" 37 | followed_up: 38 | title: "Seurattu solmu" 39 | label: "Seurattu" 40 | skip: 41 | title: "Ohita solmu" 42 | label: "Ohita" 43 | approval_given: "Hyväksyntä annettu" 44 | approval_given_empty_state_title: "Sinulla ei ole vielä hyväksyttyjä solmuja" 45 | approval_given_empty_state_title_others: "Käyttäjällä %{username} ei ole vielä hyväksyttyjä solmuja" 46 | approval_pending: "Odottaa hyväksyntää" 47 | approval_pending_empty_state_title: "Sinulla ei ole hyväksyntää odottavia solmuja" 48 | approval_pending_empty_state_title_others: "Käyttäjällä %{username} ei ole hyväksyntää odottavia solmuja" 49 | github_webhooks: "Githubin webhookit" 50 | no_organizations_configured: "Sinun täytyy määrittää vähintään yksi organisaatio, jolla on code review github organizations -sivustoasetus, ennen kuin webhookeja voi määrittää." 51 | webhooks_load_error: "Webhook-tietojen lataamisessa tapahtui virhe. Webhookeja ei voi määrittää ennen kuin ongelma on ratkaistu." 52 | configure_webhooks: "Määritä webhookeja" 53 | configure_webhook: "Määritä webhook" 54 | notify_on_approval: "Ilmoita koodin tarkistuksen hyväksynnöistä" 55 | configure_webhooks_warning: "Määritä webhookeja -valinnan napsauttaminen käyttää GitHubin APIa webhookien luomiseen jokaiselle tietosäilölle jokaisessa määrittämässäsi organisaatiossa. Push-, commit_comment-, issue_comment-, pull_request, pull_request_review ja pull_request_comment- tapahtumatriggerit luodaan. Huomaa, että sinulla täytyy olla myös code review github webhook secret -sivustoasetus määritettynä, jotta tämä toimii. Katso lisätietoja GitHubin webhook-ohjeista." 56 | -------------------------------------------------------------------------------- /config/locales/client.fr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fr: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Révision du code de Discourse" 13 | js: 14 | action_codes: 15 | approved: "Approuvé" 16 | followup: "Suivre" 17 | followed_up: "Suivi" 18 | merged: "Fusionné" 19 | renamed: "Renommé" 20 | pr_merge_info: "Informations sur la fusion des requêtes « pull »" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '« %{topicTitle} » approuvé' 25 | multiple: 26 | one: "%{count} commit a été approuvé" 27 | other: "%{count} commits ont été approuvés" 28 | title: "commit approuvé" 29 | code_review: 30 | title: "Examen du code" 31 | approve: 32 | title: "Approuver le commit" 33 | label: "Approuver" 34 | followup: 35 | title: "Suivre le commit" 36 | label: "Suivi" 37 | followed_up: 38 | title: "Commit suivi" 39 | label: "Suivi" 40 | skip: 41 | title: "Ignorer le commit" 42 | label: "Ignorer" 43 | approval_given: "Approbation donnée" 44 | approval_given_empty_state_title: "Vous n'avez pas encore de commits approuvés" 45 | approval_given_empty_state_title_others: "%{username} n'a pas encore de commits approuvés" 46 | approval_pending: "Approbation en attente" 47 | approval_pending_empty_state_title: "Vous n'avez pas de commits en attente d'approbation" 48 | approval_pending_empty_state_title_others: "%{username} n'a pas de commits en attente d'approbation" 49 | github_webhooks: "Webhooks Github" 50 | no_organizations_configured: "Vous devez configurer au moins une organisation avec code review github organizations avant de pouvoir configurer les webhooks." 51 | webhooks_load_error: "Une erreur s'est produite lors du chargement des données du webhook, les webhooks ne peuvent pas être configurés tant que ce problème n'est pas résolu." 52 | configure_webhooks: "Configurer les Webhooks" 53 | configure_webhook: "Configurer le Webhook" 54 | notify_on_approval: "Notifier les approbations de révision de code" 55 | configure_webhooks_warning: "En cliquant sur « Configurer les Webhooks », vous utiliserez l'API de GitHub pour créer des webhooks pour chaque référentiel dans chaque organisation que vous avez configurée. Les déclencheurs d'événement push, commit_comment, issue_comment, pull_request, pull_request_reviewet pull_request_comment seront créés. Veuillez noter que vous devez également configurer le paramètre de site code review github webhook secret pour que cela fonctionne. Consultez la documentation du webhook GitHub pour en savoir plus." 56 | -------------------------------------------------------------------------------- /config/locales/client.gl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | gl: 8 | js: 9 | action_codes: 10 | approved: "Aprobado" 11 | code_review: 12 | approve: 13 | label: "Aprobar" 14 | -------------------------------------------------------------------------------- /config/locales/client.he.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | he: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse סקירת קוד" 13 | js: 14 | action_codes: 15 | approved: "אושר" 16 | followup: "לעקוב" 17 | followed_up: "במעקב" 18 | merged: "מוזג" 19 | renamed: "השם השתנה" 20 | pr_merge_info: "פרטי מיזוג בקשת הדחיפה" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '„%{topicTitle}” קיבל אישור' 25 | multiple: 26 | one: "הגשה %{count} קיבלה אישור" 27 | two: "%{count} הגשות קיבלו אישור" 28 | many: "%{count} הגשות קיבלו אישור" 29 | other: "%{count} הגשות קיבלו אישור" 30 | title: "ההגשה אושרה" 31 | code_review: 32 | title: "סקירת קוד" 33 | approve: 34 | title: "אישור הגשה" 35 | label: "אישור" 36 | followup: 37 | title: "מעקב אחר הגשה" 38 | label: "מעקב" 39 | followed_up: 40 | title: "הגשה במעקב" 41 | label: "במעקב" 42 | skip: 43 | title: "דילוג על הגשה" 44 | label: "דילוג" 45 | approval_given: "ניתן אישור" 46 | approval_given_empty_state_title: "אין לך הגשות מאושרות עדיין" 47 | approval_given_empty_state_title_others: "למשתמש %{username} אין עדיין הגשות מאושרות" 48 | approval_pending: "אישור ממתין" 49 | approval_pending_empty_state_title: "אין לך הגשות שמחכות לאישור" 50 | approval_pending_empty_state_title_others: "למשתמש %{username} אין הגשות שממתינות לאישור" 51 | github_webhooks: "התליות מקוונות של GitHub" 52 | no_organizations_configured: "עליך להגדיר לפחות ארגון אחד עם הגדרת האתר סקירת קוד בארגוני GitHub בטרם יתאפשר לך להגדיר התליות." 53 | webhooks_load_error: "אירעה שגיאה בטעינת נתוני ההתלייה, לא ניתן להגדיר התליות עד לפתרון התקלה." 54 | configure_webhooks: "הגדרת התליות רשת" 55 | configure_webhook: "הגדרת התליית רשת" 56 | notify_on_approval: "להודיע על אישורי סקירת קוד" 57 | configure_webhooks_warning: "לחיצה על ‚הגדרת התליות’ תשתמש ב־API של GitHub כדי ליצור התליות לכל אחד מהמאגרים בכל אחד מהארגונים שהגדרת. מקפיצי האירועים push,‏ commit_comment,‏ issue_comment,‏ pull_request,‏ pull_request_review ו־pull_request_comment. נא לשים לב שחובה גם להגדיר את הגדרת האתר סוד סקירת קוד בהתלייה של GitHub כדי שזה יעבוד. אפשר גם לעיין בתיעוד ההתליות של GitHub" 58 | -------------------------------------------------------------------------------- /config/locales/client.hr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hr: 8 | js: 9 | action_codes: 10 | approved: "Odobrio" 11 | code_review: 12 | approve: 13 | label: "Odobri" 14 | -------------------------------------------------------------------------------- /config/locales/client.hu.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hu: 8 | js: 9 | action_codes: 10 | approved: "Jóváhagyott" 11 | code_review: 12 | approve: 13 | label: "Jóváhagyás" 14 | -------------------------------------------------------------------------------- /config/locales/client.hy.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hy: 8 | js: 9 | action_codes: 10 | approved: "Հաստատված է" 11 | code_review: 12 | approve: 13 | label: "Հաստատել" 14 | -------------------------------------------------------------------------------- /config/locales/client.id.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | id: 8 | js: 9 | action_codes: 10 | approved: "Disetujui" 11 | code_review: 12 | approve: 13 | label: "Terima" 14 | -------------------------------------------------------------------------------- /config/locales/client.it.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | it: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Revisione codice Discourse" 13 | js: 14 | action_codes: 15 | approved: "Approvato" 16 | followup: "Completamento" 17 | followed_up: "Completato" 18 | merged: "Unito" 19 | renamed: "Rinominato" 20 | pr_merge_info: "Informazioni unione PR" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '"%{topicTitle}" approvato' 25 | multiple: 26 | one: "%{count} commit è stato approvato" 27 | other: "%{count} commit sono stati approvati" 28 | title: "commit approvato" 29 | code_review: 30 | title: "Revisione del codice" 31 | approve: 32 | title: "Approva commit" 33 | label: "Approva" 34 | followup: 35 | title: "Completa commit" 36 | label: "Completamento" 37 | followed_up: 38 | title: "Commit completato" 39 | label: "Completato" 40 | skip: 41 | title: "Ignora commit" 42 | label: "Ignora" 43 | approval_given: "Approvazione data" 44 | approval_given_empty_state_title: "Non hai ancora commit approvati" 45 | approval_given_empty_state_title_others: "%{username} non ha ancora commit approvati" 46 | approval_pending: "In attesa di approvazione" 47 | approval_pending_empty_state_title: "Non hai commit in attesa di approvazione" 48 | approval_pending_empty_state_title_others: "%{username} non ha commit in attesa di approvazione" 49 | github_webhooks: "Webhook Github" 50 | no_organizations_configured: "Devi configurare almeno un'organizzazione con il sito di organizzazioni github di revisione codice prima di poter configurare i webhook." 51 | webhooks_load_error: "Si è verificato un errore durante il caricamento dei dati del webhook, i webhook non possono essere configurati fino a quando il problema non viene risolto." 52 | configure_webhooks: "Configura i Webhook" 53 | configure_webhook: "Configura Webhook" 54 | notify_on_approval: "Notifica in caso di approvazione di revisioni codice" 55 | configure_webhooks_warning: "Facendo clic su \"Configura i Webhook\" il sistema utilizzerà l'API GitHub per creare i webhook per ogni archivio di ogni organizzazione configurata. Saranno creati i criteri di attivazione degli eventi push, commit_comment, issue_comment, pull_request, pull_request_review e pull_request_comment. Nota: perché questa operazione funzioni, è necessario aver configurato anche l'impostazione del sito code review github webhook secret. Per ulteriori informazioni, consultare la documentazione dei webhook GitHub." 56 | -------------------------------------------------------------------------------- /config/locales/client.ja.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ja: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse コードレビュー" 13 | js: 14 | action_codes: 15 | approved: "承認済み" 16 | followup: "フォローアップ" 17 | followed_up: "フォローアップ済み" 18 | merged: "マージ済み" 19 | renamed: "名前変更済み" 20 | pr_merge_info: "PR マージ情報" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '「%{topicTitle}」が承認されました' 25 | multiple: 26 | other: "%{count} 件のコミットが承認されました" 27 | title: "コミットが承認されました" 28 | code_review: 29 | title: "コードレビュー" 30 | approve: 31 | title: "コミットの承認" 32 | label: "承認" 33 | followup: 34 | title: "コミットのフォローアップ" 35 | label: "フォローアップ" 36 | followed_up: 37 | title: "フォローアップ済みのコミット" 38 | label: "フォローアップ済み" 39 | skip: 40 | title: "コミットをスキップ" 41 | label: "スキップ" 42 | approval_given: "承認済み" 43 | approval_given_empty_state_title: "まだ承認されたコミットはありません" 44 | approval_given_empty_state_title_others: "%{username}には承認されたコミットがまだありません" 45 | approval_pending: "承認待ち" 46 | approval_pending_empty_state_title: "承認待ちのコミットはありません" 47 | approval_pending_empty_state_title_others: "%{username}には承認待ちのコミットはありません" 48 | github_webhooks: "Github Webhook" 49 | no_organizations_configured: "Webhook を構成する前に、少なくとも 1 つの組織の code review github organizations サイト設定を構成する必要があります。" 50 | webhooks_load_error: "Webhook データの読み込み中にエラーが発生しました。Webhook はこれが解決されるまで構成できません。" 51 | configure_webhooks: "Webhook を構成" 52 | configure_webhook: "Webhook を構成" 53 | notify_on_approval: "コードレビューの承認を通知する" 54 | configure_webhooks_warning: "「Webhook を構成」をクリックすると、GitHub API を使用して、構成済みのすべての組織の各リポジトリに Webhook が作成されます。 pushcommit_commentissue_commentpull_requestpull_request_review、および pull_request_comment イベントトリガーが作成されます。これが機能するには、code review github webhook secret サイト設定が構成されていることも必要であることに注意してください。詳細は、GitHub の Webhook に関するドキュメントをご覧ください。" 55 | -------------------------------------------------------------------------------- /config/locales/client.ko.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ko: 8 | js: 9 | action_codes: 10 | approved: "승인" 11 | code_review: 12 | approve: 13 | label: "승인" 14 | -------------------------------------------------------------------------------- /config/locales/client.lt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lt: 8 | js: 9 | action_codes: 10 | approved: "Patvirtinta" 11 | code_review: 12 | approve: 13 | label: "Patvirtinti" 14 | -------------------------------------------------------------------------------- /config/locales/client.lv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lv: 8 | js: 9 | action_codes: 10 | approved: "Apstiprināt" 11 | code_review: 12 | approve: 13 | label: "Apstiprināt" 14 | -------------------------------------------------------------------------------- /config/locales/client.nb_NO.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nb_NO: 8 | js: 9 | action_codes: 10 | approved: "Godkjent" 11 | code_review: 12 | approve: 13 | label: "Godkjenn" 14 | -------------------------------------------------------------------------------- /config/locales/client.nl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nl: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse-codereview" 13 | js: 14 | action_codes: 15 | approved: "Goedgekeurd" 16 | followup: "Opvolgen" 17 | followed_up: "Opgevolgd" 18 | merged: "Samengevoegd" 19 | renamed: "Hernoemd" 20 | pr_merge_info: "Samenvoegingsinfo pullverzoeken" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '"%{topicTitle}" goedgekeurd' 25 | multiple: 26 | one: "%{count} commit is goedgekeurd" 27 | other: "%{count} commits zijn goedgekeurd" 28 | title: "commit goedgekeurd" 29 | code_review: 30 | title: "Codebeoordeling" 31 | approve: 32 | title: "Commit goedkeuren" 33 | label: "Goedkeuren" 34 | followup: 35 | title: "Commit opvolgen" 36 | label: "Opvolgen" 37 | followed_up: 38 | title: "Commit opgevolgd" 39 | label: "Opgevolgd" 40 | skip: 41 | title: "Commit overslaan" 42 | label: "Overslaan" 43 | approval_given: "Goedkeuring gegeven" 44 | approval_given_empty_state_title: "Je hebt nog geen goedgekeurde commits" 45 | approval_given_empty_state_title_others: "%{username} heeft nog geen goedgekeurde commits" 46 | approval_pending: "In afwachting van goedkeuring" 47 | approval_pending_empty_state_title: "Je hebt geen commits die wachten op goedkeuring" 48 | approval_pending_empty_state_title_others: "%{username} heeft geen commits die wachten op goedkeuring" 49 | github_webhooks: "Github-webhooks" 50 | no_organizations_configured: "Je moet minimaal één organisatie configureren in de site-instelling code review github organizations voordat webhooks kunnen worden geconfigureerd." 51 | webhooks_load_error: "Er is een fout opgetreden bij het laden van webhookgegevens. Webhooks kunnen pas worden geconfigureerd als dit is opgelost." 52 | configure_webhooks: "Webhooks configureren" 53 | configure_webhook: "Webhook configureren" 54 | notify_on_approval: "Melden bij goedkeuring van codereviews" 55 | configure_webhooks_warning: "Door op 'Webhooks configureren' te klikken, wordt de GitHub-API gebruikt om webhooks te maken voor elke repository in elke organisatie die je hebt geconfigureerd. De gebeurtenistriggers push, commit_comment, issue_comment, pull_request, pull_request_reviewen pull_request_comment worden gemaakt. Houd er rekening mee dat je ook de site-instelling code review github webhook secret moet hebben geconfigureerd om dit te laten werken. Zie de GitHub-webhookdocumentatie voor meer informatie." 56 | -------------------------------------------------------------------------------- /config/locales/client.pl_PL.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pl_PL: 8 | js: 9 | action_codes: 10 | approved: "Zaakceptowany" 11 | followup: "Śledź" 12 | followed_up: "Śledzony" 13 | merged: "Połączony" 14 | renamed: "Przemianowany" 15 | pr_merge_info: "Informacje o połączeniu PR" 16 | notifications: 17 | code_review: 18 | commit_approved: 19 | single: '"%{topicTitle}" zatwierdzony' 20 | multiple: 21 | one: "%{count} commit został zatwierdzony" 22 | few: "%{count} commity zostały zatwierdzone" 23 | many: "%{count} commitów zostało zatwierdzonych" 24 | other: "%{count} commitów zostało zatwierdzonych" 25 | title: "commit zatwierdzony" 26 | code_review: 27 | title: "Przegląd kodu" 28 | approve: 29 | title: "Zatwierdź commit" 30 | label: "Zatwierdź" 31 | followup: 32 | title: "Śledź commit" 33 | label: "Śledź" 34 | followed_up: 35 | title: "Rozpoczęto śledzenie commita" 36 | label: "Śledzony" 37 | skip: 38 | title: "Pomiń commit" 39 | label: "Pomiń" 40 | approval_given: "Zgoda udzielona" 41 | approval_given_empty_state_title: "Nie masz jeszcze zatwierdzonych commitów" 42 | approval_pending: "Oczekiwanie na zatwierdzenie" 43 | approval_pending_empty_state_title: "Nie masz commitów oczekujących na zatwierdzenie" 44 | github_webhooks: "Webhooki Githuba" 45 | no_organizations_configured: "Zanim będzie można skonfigurować webhooki, musisz skonfigurować co najmniej jedną organizację z ustawieniem code review github organizations." 46 | webhooks_load_error: "Podczas ładowania danych webhooka wystąpił błąd. Nie można konfigurować webhooków, dopóki ten problem nie zostanie rozwiązany." 47 | configure_webhooks: "Skonfiguruj webhooki" 48 | configure_webhook: "Skonfiguruj webhook" 49 | notify_on_approval: "Powiadamiaj o zatwierdzeniach przeglądu kodu" 50 | configure_webhooks_warning: "Kliknięcie \"Skonfiguruj webhooki\" spowoduje użycie interfejsu API GitHub do utworzenia webhooków dla każdego repozytorium w każdej organizacji, którą skonfigurowałeś. Zostaną utworzone wyzwalacze zdarzeń push, commit_comment, issue_comment, pull_request, pull_request_revieworaz pull_request_comment. Pamiętaj, że aby to zadziałało, musisz mieć również skonfigurowane ustawienie code review github webhook secret. Aby uzyskać więcej informacji, zapoznaj się z dokumentacją GitHub webhook ." 51 | -------------------------------------------------------------------------------- /config/locales/client.pt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt: 8 | js: 9 | action_codes: 10 | approved: "Aprovado" 11 | code_review: 12 | approve: 13 | label: "Aprovar" 14 | -------------------------------------------------------------------------------- /config/locales/client.pt_BR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt_BR: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse Code Review" 13 | js: 14 | action_codes: 15 | approved: "Aprovou" 16 | followup: "Acompanhar" 17 | followed_up: "Acompanhou" 18 | merged: "Mesclou" 19 | renamed: "Renomeou" 20 | pr_merge_info: "Informações de mesclagem de RP" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: 'Aprovou "%{topicTitle}"' 25 | multiple: 26 | one: "%{count} confirmação foi aprovada" 27 | other: "%{count} confirmações foram aprovadas" 28 | title: "confirmação aprovada" 29 | code_review: 30 | title: "Revisão de código" 31 | approve: 32 | title: "Aprovar confirmação" 33 | label: "Aprovar" 34 | followup: 35 | title: "Acompanhar confirmação" 36 | label: "Acompanhar" 37 | followed_up: 38 | title: "Confirmação acompanhada" 39 | label: "Acompanhou" 40 | skip: 41 | title: "Pular confirmação" 42 | label: "Pular" 43 | approval_given: "Aprovação concedida" 44 | approval_given_empty_state_title: "Você ainda não tem confirmações aprovadas" 45 | approval_given_empty_state_title_others: "%{username} ainda não aprovou nenhuma confirmação" 46 | approval_pending: "Aprovação pendente" 47 | approval_pending_empty_state_title: "Você não tem confirmações aguardando aprovação" 48 | approval_pending_empty_state_title_others: "%{username} não tem confirmações aguardando aprovação" 49 | github_webhooks: "Webhooks do Github" 50 | no_organizations_configured: "Você precisa configurar pelo menos uma organização com a configuração do site de organizações do github para revisão de código antes de configurar webhooks." 51 | webhooks_load_error: "Houve um erro ao carregar dados do webhook, os webhooks não podem ser configurados até resolver isso." 52 | configure_webhooks: "Configurar webhooks" 53 | configure_webhook: "Configurar webhooks" 54 | notify_on_approval: "Notificar sobre aprovações de revisão no código" 55 | configure_webhooks_warning: "Clicar em \"Configurar webhooks\" usará a API do GitHub para criar webhooks para todos os repositórios das organizações configuradas. Serão criados gatilhos dos eventos push, commit_comment, issue_comment, pull_request, pull_request_review e pull_request_comment. Observe que você também precisa ter a configuração do site segredo do webhook do github para revisão de código para isso funcionar. Acesse GitHub webhook documentation para obter mais informações." 56 | -------------------------------------------------------------------------------- /config/locales/client.ro.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ro: 8 | js: 9 | action_codes: 10 | approved: "Aprobat" 11 | code_review: 12 | approve: 13 | label: "Aprobare" 14 | -------------------------------------------------------------------------------- /config/locales/client.ru.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ru: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Плагин Discourse «Проверка кода»" 13 | js: 14 | action_codes: 15 | approved: "Одобрено" 16 | followup: "Отслеживать" 17 | followed_up: "В отслеживаемых" 18 | merged: "Слито" 19 | renamed: "Переименовано" 20 | pr_merge_info: "Информация о запросе на слияние" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: 'Коммит «%{topicTitle}» одобрен' 25 | multiple: 26 | one: "%{count} коммит был одобрен" 27 | few: "%{count} коммита были одобрены" 28 | many: "%{count} коммитов были одобрены" 29 | other: "%{count} коммита были одобрены" 30 | title: "Коммит одобрен" 31 | code_review: 32 | title: "Проверка кода" 33 | approve: 34 | title: "Одобрить коммит" 35 | label: "Одобрить" 36 | followup: 37 | title: "Отслеживать коммит" 38 | label: "Отслеживать" 39 | followed_up: 40 | title: "Коммит в отслеживаемых" 41 | label: "В отслеживаемых" 42 | skip: 43 | title: "Пропустить коммит" 44 | label: "Пропустить" 45 | approval_given: "Выдано одобрение" 46 | approval_given_empty_state_title: "У вас ещё нет одобренных коммитов" 47 | approval_given_empty_state_title_others: "У пользователя %{username} еще нет одобренных коммитов" 48 | approval_pending: "Ожидает одобрения" 49 | approval_pending_empty_state_title: "У вас нет коммитов, ожидающих одобрения" 50 | approval_pending_empty_state_title_others: "У пользователя %{username} еще нет коммитов, ожидающих одобрения" 51 | github_webhooks: "Вебхуки Github" 52 | no_organizations_configured: "Перед настройкой вебхуков необходимо настроить хотя бы одну организацию в параметре code review github organizations." 53 | webhooks_load_error: "Произошла ошибка при загрузке данных вебхуков, вебхуки не могут быть настроены, пока эта проблема не будет решена." 54 | configure_webhooks: "Настройка вебхуков" 55 | configure_webhook: "Настройка вебхука" 56 | notify_on_approval: "Уведомление об одобрении кода" 57 | configure_webhooks_warning: "Нажав «Настройка вебхуков», вы будете использовать GitHub API для создания вебхуков для каждого репозитория в каждой настроенной вами организации. Будут созданы триггеры событий push, commit_comment, issue_comment, pull_request, pull_request_review и pull_request_comment. У вас также должен быть настроен параметр сайта code review github webhook secret. Дополнительную информацию см. в документации по вебхукам GitHub." 58 | -------------------------------------------------------------------------------- /config/locales/client.sk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sk: 8 | js: 9 | action_codes: 10 | approved: "Schválený" 11 | code_review: 12 | approve: 13 | label: "Schváliť" 14 | -------------------------------------------------------------------------------- /config/locales/client.sl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sl: 8 | js: 9 | action_codes: 10 | approved: "Potrjeno" 11 | code_review: 12 | approve: 13 | label: "Odobri" 14 | -------------------------------------------------------------------------------- /config/locales/client.sq.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sq: 8 | js: 9 | action_codes: 10 | approved: "Aprovuar" 11 | code_review: 12 | approve: 13 | label: "Aprovo" 14 | -------------------------------------------------------------------------------- /config/locales/client.sr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sr: 8 | js: 9 | action_codes: 10 | approved: "Potvrđenji" 11 | code_review: 12 | approve: 13 | label: "Odobri" 14 | -------------------------------------------------------------------------------- /config/locales/client.sv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sv: 8 | js: 9 | action_codes: 10 | approved: "Godkända" 11 | followup: "Uppföljning" 12 | followed_up: "Uppföljda" 13 | merged: "Sammanslagna" 14 | renamed: "Bytt namn" 15 | pr_merge_info: "Information om PR-sammanslagning" 16 | notifications: 17 | code_review: 18 | commit_approved: 19 | single: '"%{topicTitle}" har godkänts' 20 | title: "åtagande godkänt" 21 | code_review: 22 | title: "Kodgranskning" 23 | approve: 24 | title: "Godkänn åtagande" 25 | label: "Godkänn" 26 | followup: 27 | title: "Följ upp åtagande" 28 | label: "Följ upp" 29 | followed_up: 30 | title: "Följde upp åtagande" 31 | label: "Uppföljda" 32 | skip: 33 | title: "Hoppa över åtagande" 34 | label: "Hoppa över" 35 | approval_given: "Godkännande givet" 36 | approval_given_empty_state_title: "Du har inte godkända åtaganden än" 37 | approval_pending: "Väntar på godkännande" 38 | approval_pending_empty_state_title: "Du har inga åtaganden som väntar på godkännande" 39 | github_webhooks: "Github Webhooks" 40 | no_organizations_configured: "Du måste konfigurera minst en organisation med webbplatsinställningar för kodgransknings-github-organisationerna innan webhooks kan konfigureras." 41 | webhooks_load_error: "Det uppstod ett fel vid inläsning av webhook-data och webhooks kan inte konfigureras förrän detta har lösts." 42 | configure_webhooks: "Konfigurera Webhooks" 43 | configure_webhook: "Konfigurera Webhook" 44 | notify_on_approval: "Avisera vid godkännande av kodgranskning" 45 | configure_webhooks_warning: "Genom att klicka på 'Konfigurera Webhooks' används GitHub API för att skapa webhooks för varje lagringsplats i varje organisation som du har konfigurerat. Händelseutlösarna push, commit_comment, issue_comment, pull_request, pull_request_review och pull_request_comment skapas. Observera att du också måste ha konfigurerat webbplatsinställningen code review github webhook secret för att detta ska fungera. Se GitHub-webhook-dokumentationen för mer information." 46 | -------------------------------------------------------------------------------- /config/locales/client.sw.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sw: 8 | js: 9 | action_codes: 10 | approved: "Wamekubaliwa" 11 | code_review: 12 | approve: 13 | label: "Imethibitishwa" 14 | -------------------------------------------------------------------------------- /config/locales/client.te.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | te: 8 | js: 9 | action_codes: 10 | approved: "ఆమోదించబడింది" 11 | code_review: 12 | approve: 13 | label: "అంగీకరించు" 14 | -------------------------------------------------------------------------------- /config/locales/client.th.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | th: 8 | js: 9 | action_codes: 10 | approved: "อนุมัติ" 11 | code_review: 12 | approve: 13 | label: "อนุมัติ" 14 | -------------------------------------------------------------------------------- /config/locales/client.tr_TR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | tr_TR: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse Kod İncelemesi" 13 | js: 14 | action_codes: 15 | approved: "Onaylandı" 16 | followup: "Takip et" 17 | followed_up: "Takip Edildi" 18 | merged: "Birleştirildi" 19 | renamed: "Yeniden adlandırıldı" 20 | pr_merge_info: "PR Birleştirme Bilgileri" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '"%{topicTitle}" onaylandı' 25 | multiple: 26 | one: "%{count} taahhüt onaylandı" 27 | other: "%{count} taahhüt onaylandı" 28 | title: "taahhüt onaylandı" 29 | code_review: 30 | title: "Kod İncelemesi" 31 | approve: 32 | title: "Taahhüdü onayla" 33 | label: "Onayla" 34 | followup: 35 | title: "Taahhüdü takip et" 36 | label: "Takip et" 37 | followed_up: 38 | title: "Taahhüt takip edildi" 39 | label: "Takip Edildi" 40 | skip: 41 | title: "Taahhüdü atla" 42 | label: "Atla" 43 | approval_given: "Onay Verildi" 44 | approval_given_empty_state_title: "Henüz onaylanmış taahhüdünüz yok" 45 | approval_given_empty_state_title_others: "%{username} henüz onaylanmış taahhütlere sahip değil" 46 | approval_pending: "Onay Bekliyor" 47 | approval_pending_empty_state_title: "Onay bekleyen taahhüdünüz yok" 48 | approval_pending_empty_state_title_others: "%{username} onay bekleyen taahhütlere sahip değil" 49 | github_webhooks: "Github Web Kancaları" 50 | no_organizations_configured: "Web kancalarının yapılandırılabilmesi için code review github organizations site ayarı ile en az bir kuruluşu yapılandırmanız gerekir." 51 | webhooks_load_error: "Web kancası verileri yüklenirken bir hata oluştu, bu sorun çözülene kadar web kancaları yapılandırılamıyor." 52 | configure_webhooks: "Web kancalarını yapılandırın" 53 | configure_webhook: "Web kancasını yapılandırın" 54 | notify_on_approval: "Kod inceleme onaylarını bildirin" 55 | configure_webhooks_warning: "\"Web Kancalarını Yapılandır\" seçeneğine tıkladığınızda GitHub API'si kullanılarakyapılandırdığınız her kuruluştaki her depo için web kancaları oluşturulur. push, commit_comment, issue_comment, pull_request, pull_request_reviewve pull_request_comment olay tetikleyicileri oluşturulur. Bunun çalışması için code review github webhook secret site ayarının da yapılandırılmış olması gerektiğini lütfen unutmayın. Daha fazla bilgi için GitHub webhook belgelerine göz atın." 56 | -------------------------------------------------------------------------------- /config/locales/client.ug.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ug: 8 | js: 9 | action_codes: 10 | approved: "تەستىقلاندى" 11 | code_review: 12 | approve: 13 | label: "تەستىقلا" 14 | -------------------------------------------------------------------------------- /config/locales/client.uk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | uk: 8 | js: 9 | action_codes: 10 | approved: "Схвалено" 11 | code_review: 12 | approve: 13 | label: "Схвалити" 14 | -------------------------------------------------------------------------------- /config/locales/client.ur.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ur: 8 | js: 9 | action_codes: 10 | approved: "منظورشدہ" 11 | code_review: 12 | approve: 13 | label: "منظور" 14 | -------------------------------------------------------------------------------- /config/locales/client.vi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | vi: 8 | js: 9 | action_codes: 10 | approved: "Đã phê duyệt" 11 | code_review: 12 | approve: 13 | label: "Duyệt" 14 | -------------------------------------------------------------------------------- /config/locales/client.zh_CN.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_CN: 8 | admin_js: 9 | admin: 10 | site_settings: 11 | categories: 12 | discourse_code_review: "Discourse Code Review" 13 | js: 14 | action_codes: 15 | approved: "已批准" 16 | followup: "跟进" 17 | followed_up: "已跟进" 18 | merged: "已合并" 19 | renamed: "已重命名" 20 | pr_merge_info: "PR 合并信息" 21 | notifications: 22 | code_review: 23 | commit_approved: 24 | single: '“%{topicTitle}”已被批准' 25 | multiple: 26 | other: "%{count} 项提交已被批准" 27 | title: "提交已被批准" 28 | code_review: 29 | title: "代码审查" 30 | approve: 31 | title: "批准提交" 32 | label: "批准" 33 | followup: 34 | title: "跟进提交" 35 | label: "跟进" 36 | followed_up: 37 | title: "已跟进提交" 38 | label: "已跟进" 39 | skip: 40 | title: "跳过提交" 41 | label: "跳过" 42 | approval_given: "批准已授予" 43 | approval_given_empty_state_title: "您还没有获得批准的提交" 44 | approval_given_empty_state_title_others: "%{username} 还没有获得批准的提交" 45 | approval_pending: "批准待处理" 46 | approval_pending_empty_state_title: "您没有等待审批的提交" 47 | approval_pending_empty_state_title_others: "%{username} 没有等待审批的提交" 48 | github_webhooks: "Github 网络钩子" 49 | no_organizations_configured: "在配置网络钩子之前,您需要至少配置一个具有 code review github organizations 站点设置的组织。" 50 | webhooks_load_error: "加载网络钩子数据时出错,在此问题解决之前无法配置网络钩子。" 51 | configure_webhooks: "配置网络钩子" 52 | configure_webhook: "配置网络钩子" 53 | notify_on_approval: "通知代码审查批准" 54 | configure_webhooks_warning: "点击“配置网络钩子”将使用 GitHub API 为您配置的每个组织中的每个仓库创建网络钩子。pushcommit_commentissue_commentpull_requestpull_request_reviewpull_request_comment 事件触发器将被创建。请注意,您还必须配置 code review github webhook secret 站点设置才能使其正常工作。请参阅 GitHub 网络钩子文档,了解更多信息。" 55 | -------------------------------------------------------------------------------- /config/locales/client.zh_TW.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_TW: 8 | js: 9 | action_codes: 10 | approved: "已同意" 11 | code_review: 12 | approve: 13 | label: "批准" 14 | -------------------------------------------------------------------------------- /config/locales/server.ar.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ar: 8 | site_settings: 9 | code_review_enabled: "تفعيل مراجعة رمز Discourse" 10 | code_review_allowed_groups: "المجموعات المسموح لها بمراجعة الرموز البرمجية" 11 | code_review_github_token: "الرمز المميَّز لاستخدامه في واجهة برمجة تطبيقات github، يمكن إنشاء ذلك عن طريق https://github.com/settings/tokens/new. إذن 'repo' مطلوب إذا كان sync_to_github أو code_review_allow_private_clone مفعلًا" 12 | code_review_sync_to_github: "يتطلب: code_review_github_token، هل يجب إرسال التعليقات الموجودة هنا إلى github؟" 13 | code_review_catch_up_commits: "إنشاء هذا العدد من الموضوعات للإرسالات القديمة عند إنشاء مستودع جديد" 14 | code_review_allow_private_clone: "يتطلب: سيستنسخ code_review_github_token المستودعات كالمستخدم المرتبط، هذه الحماية مصمَّمة لإيقاف نسخ المستودعات الخاصة على المواقع العامة." 15 | code_review_allow_manual_followup: "السماح بزر المتابعة على الإرسالات" 16 | code_review_pending_tag: "الوسم الذي سيتم تطبيقه على الإرسالات قيد الانتظار" 17 | code_review_followup_tag: "الوسم الذي سيتم تطبيقه على إرسالات المتابعة" 18 | code_review_approved_tag: "الوسم الذي سيتم تطبيقه على الإرسالات التي تمت الموافقة عليها" 19 | code_review_unmerged_tag: "الوسم الذي سيتم تطبيقه على الإرسالات غير المدمجة" 20 | code_review_commit_tag: "الوسم الذي سيتم تطبيقه لإرسال الموضوعات" 21 | code_review_pull_request_tag: "الوسم الذي سيتم تطبيقه لسحب موضوعات الطلب" 22 | code_review_github_webhook_secret: "سلسلة خطاف الويب السرية لاستخدامها في https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "السماح بالموافقة التلقائية على الإرسالات" 24 | code_review_skip_duration_minutes: "سيؤدي استخدام زر التخطي إلى تخطي الإرسال لهذا العدد من الدقائق" 25 | code_review_auto_assign_on_followup: "تخصيص الموضوع إلى المؤلف تلقائيًا عند المتابعة" 26 | code_review_auto_unassign_on_approve: "إلغاء تخصيص الموضوع تلقائيًا عند الموافقة" 27 | code_review_auto_approve_followed_up_commits: "الموافقة تلقائيًا على الإرسالات المرجعية من الإرسال الحالي" 28 | code_review_github_organizations: "مؤسسات Github (مفصولة بفاصلة) التي تحتوي على مستودعات يجب مزامنتها هنا" 29 | code_review_approve_approved_prs: "الموافقة التلقائية على الإرسالات الموجودة في طلبات السحب التي تمت الموافقة عليها" 30 | code_review_default_mute_new_categories: "كتم جميع فئات المستخدمين التي أنشأها المكوِّن الإضافي" 31 | code_review_default_parent_category: "الفئة الرئيسية الافتراضية للفئات التي أنشأها المكوِّن الإضافي" 32 | discourse_code_review: 33 | category_description: | 34 | تم إنشاء هذه الفئة لتحتوي على مراجعات لرمز المستودع %{repo_name}. يتم إنشاء الموضوعات لكل طلب إرسال أو سحب. 35 | bad_github_permissions_error: "حدثت مشكلة في أثناء جلب بيانات خطاف الويب من GitHub. يُرجى التحقُّق من تفعيل نطاق \"المستودع\" في الرمز المميَّز الذي تم إعداده في إعداد الموقع code_review_github_token. راجع https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps لمزيدٍ من التفاصيل." 36 | bad_github_credentials_error: "حدثت مشكلة في بيانات اعتماد GitHub الخاصة بك. يُرجى التحقُّق من إعداد الموقع code_review_github_token الخاص بك وإعادة المحاولة." 37 | approval_list: 38 | user_not_found: "تعذَّر العثور على مستخدم باسم المستخدم %{username}" 39 | -------------------------------------------------------------------------------- /config/locales/server.be.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | be: 8 | -------------------------------------------------------------------------------- /config/locales/server.bg.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bg: 8 | -------------------------------------------------------------------------------- /config/locales/server.bs_BA.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bs_BA: 8 | -------------------------------------------------------------------------------- /config/locales/server.ca.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ca: 8 | -------------------------------------------------------------------------------- /config/locales/server.cs.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | cs: 8 | -------------------------------------------------------------------------------- /config/locales/server.da.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | da: 8 | -------------------------------------------------------------------------------- /config/locales/server.de.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | de: 8 | site_settings: 9 | code_review_enabled: "Discourse-Code-Review aktivieren" 10 | code_review_allowed_groups: "Gruppen, die Code überprüfen dürfen" 11 | code_review_github_token: "Das Token für die Github-API. Kann unter https://github.com/settings/tokens/new generiert werden. Die Berechtigung „repo“ ist erforderlich, wenn sync_to_github oder code_review_allow_private_clone aktiviert ist" 12 | code_review_sync_to_github: "ERFORDERT: code_review_github_token. Sollen Kommentare hier an github gesendet werden?" 13 | code_review_catch_up_commits: "Wenn ein neues Repo hinzugefügt wird, wird diese Anzahl von Themen für alte Commits erstellt" 14 | code_review_allow_private_clone: "ERFORDERT: code_review_github_token. Klont die Repos als zugehöriger Benutzer. Diese Sicherung dient dazu, das Klonen privater Repos auf öffentlichen Websites zu verhindern." 15 | code_review_allow_manual_followup: "Schaltfläche „Nachbereiten“ bei Commits erlauben" 16 | code_review_pending_tag: "Auf ausstehende Commits anzuwendendes Schlagwort" 17 | code_review_followup_tag: "Auf Nachbereitungs-Commits anzuwendendes Schlagwort" 18 | code_review_approved_tag: "Auf genehmigte Commits anzuwendendes Schlagwort" 19 | code_review_unmerged_tag: "Auf nicht zusammengeführte Commits anzuwendendes Schlagwort" 20 | code_review_commit_tag: "Auf Commit-Themen anzuwendendes Schlagwort" 21 | code_review_pull_request_tag: "Auf PR-Themen anzuwendendes Schlagwort" 22 | code_review_github_webhook_secret: "Webhook-Geheimstring zur Verwendung für https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "Selbstgenehmigung von Commits zulassen" 24 | code_review_skip_duration_minutes: "Die Schaltfläche „Überspringen“ überspringt Commit für so viele Minuten" 25 | code_review_auto_assign_on_followup: "Autor bei Nachbereitung automatisch Thema zuweisen" 26 | code_review_auto_unassign_on_approve: "Zuweisung des Themas bei Genehmigung automatisch aufheben" 27 | code_review_auto_approve_followed_up_commits: "Commits, die vom aktuellen Commit referenziert werden, automatisch genehmigen" 28 | code_review_github_organizations: "Github-Organisationen (getrennt durch Komma) mit Repos, die hier synchronisiert werden sollen" 29 | code_review_approve_approved_prs: "Commits automatisch genehmigen, die in genehmigten PRs existieren" 30 | code_review_default_mute_new_categories: "Für alle vom Plug-in erstellten Benutzerkategorien stummschalten" 31 | code_review_default_parent_category: "Standardmäßige übergeordnete Kategorie für Kategorien, die vom Plug-in erstellt wurden" 32 | discourse_code_review: 33 | category_description: | 34 | Diese Kategorie wurde für Code-Reviews für %{repo_name} erstellt. Themen werden für jeden Commit oder jedes PR erstellt. 35 | bad_github_permissions_error: "Es gab ein Problem beim Abrufen von Webhook-Daten von GitHub. Bitte überprüfe, ob für dein Token, das in der Website-Einstellung code_review_github_token konfiguriert ist, der Bereich „repo“ aktiviert ist. Siehe https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps für weitere Details." 36 | bad_github_credentials_error: "Es gab ein Problem mit deinen GitHub-Anmeldedaten. Bitte überprüfe deine Website-Einstellung code_review_github_token und versuche es erneut." 37 | approval_list: 38 | user_not_found: "Benutzer mit dem Benutzernamen %{username} konnte nicht gefunden werden" 39 | -------------------------------------------------------------------------------- /config/locales/server.el.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | el: 8 | -------------------------------------------------------------------------------- /config/locales/server.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | site_settings: 3 | code_review_enabled: "enable Discourse code review" 4 | code_review_allowed_groups: "Groups allowed to review code" 5 | code_review_github_token: "Token to use for github API, this can be generated via https://github.com/settings/tokens/new . 'repo' permission is required if sync_to_github or code_review_allow_private_clone is enabled" 6 | code_review_sync_to_github: "REQUIRES: code_review_github_token, should comments here be sent to github?" 7 | code_review_catch_up_commits: "When a new repo is added create this number of topics for old commits" 8 | code_review_allow_private_clone: "REQUIRES: code_review_github_token, will clone the repos as the associated user, this safeguard is in place to disable cloning of private repos on public sites." 9 | code_review_allow_manual_followup: "Allow follow up button on commits" 10 | code_review_pending_tag: "Tag to apply to pending commits" 11 | code_review_followup_tag: "Tag to apply to follow up commits" 12 | code_review_approved_tag: "Tag to apply to approved commits" 13 | code_review_unmerged_tag: "Tag to apply to unmerged commits" 14 | code_review_commit_tag: "Tag to apply to commit topics" 15 | code_review_pull_request_tag: "Tag to apply to pull request topics" 16 | code_review_github_webhook_secret: "web hook secret string to use use for https://sitename/code-review/webhook" 17 | code_review_allow_self_approval: "Allow self approval of commits" 18 | code_review_skip_duration_minutes: "Skip button will skip commit for this many minutes" 19 | code_review_auto_assign_on_followup: "Automatically assign topic to author on followup" 20 | code_review_auto_unassign_on_approve: "Automatically unassign topic on approve" 21 | code_review_auto_approve_followed_up_commits: "Automatically approve commits referenced from current commit" 22 | code_review_github_organizations: "Github organizations (comma separated) containing repos that should be synced here" 23 | code_review_approve_approved_prs: "Auto approve commits that exist in approved pull requests" 24 | code_review_default_mute_new_categories: "Mute for all users categories created by the plugin" 25 | code_review_default_parent_category: "Default parent category for categories created by the plugin" 26 | discourse_code_review: 27 | category_description: | 28 | This category was created to contain code reviews for %{repo_name}. Topics are created for each commit or pull request. 29 | bad_github_permissions_error: "There was an issue when fetching webhook data from GitHub. Please check your token configured in the code_review_github_token site setting has the 'repo' scope enabled. See https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps for more details." 30 | bad_github_credentials_error: "There was an issue with your GitHub credentials. Please check your code_review_github_token site setting and try again." 31 | approval_list: 32 | user_not_found: "Couldn't find user with username %{username}" 33 | 34 | -------------------------------------------------------------------------------- /config/locales/server.en_GB.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | en_GB: 8 | -------------------------------------------------------------------------------- /config/locales/server.es.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | es: 8 | site_settings: 9 | code_review_enabled: "habilitar la revisión del código de Discourse" 10 | code_review_allowed_groups: "Grupos autorizados a revisar el código" 11 | code_review_github_token: "Token que se utilizará para la API de github, se puede generar a través de https://github.com/settings/tokens/new . El permiso 'repo' es necesario si se activa sync_to_github o code_review_allow_private_clone" 12 | code_review_sync_to_github: "REQUIERE: code_review_github_token, ¿se deben enviar los comentarios aquí a github?" 13 | code_review_catch_up_commits: "Cuando se añade un nuevo repositorio se crea este número de temas para los commits antiguos" 14 | code_review_allow_private_clone: "REQUIERE: code_review_github_token, clonará los repositorios como el usuario asociado, esta medida de seguridad es para desactivar la clonación de repositorios privados en sitios públicos." 15 | code_review_allow_manual_followup: "Permitir botón de seguimiento en commits" 16 | code_review_pending_tag: "Etiqueta a aplicar a los commits pendientes" 17 | code_review_followup_tag: "Etiqueta a aplicar a los commits de seguimiento" 18 | code_review_approved_tag: "Etiqueta a aplicar a los commits aprobados" 19 | code_review_unmerged_tag: "Etiqueta a aplicar a los commits no fusionados" 20 | code_review_commit_tag: "Etiqueta a aplicar a los temas de commit" 21 | code_review_pull_request_tag: "Etiqueta a aplicar a los temas de solicitud de extracción" 22 | code_review_github_webhook_secret: "cadena secreta del web hook a utilizar para https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "Permitir la autoaprobación de commits" 24 | code_review_skip_duration_minutes: "El botón Omitir omitirá el commit durante esta cantidad de minutos" 25 | code_review_auto_assign_on_followup: "Asignar automáticamente el tema al autor en el seguimiento" 26 | code_review_auto_unassign_on_approve: "Anular la asignación automática del tema al aprobar" 27 | code_review_auto_approve_followed_up_commits: "Aprobar automáticamente commits referenciados desde el commit actual" 28 | code_review_github_organizations: "Organizaciones de Github (separadas por comas) que contienen repositorios que deben sincronizarse aquí" 29 | code_review_approve_approved_prs: "Aprobar automáticamente los commits que existen en las solicitudes de extracción aprobadas" 30 | code_review_default_mute_new_categories: "Silenciar todas las categorías de usuarios creadas por el plugin" 31 | code_review_default_parent_category: "Categoría principal predeterminada para las categorías creadas por el plugin" 32 | discourse_code_review: 33 | category_description: | 34 | Esta categoría se creó para contener revisiones de código para %{repo_name}. Los temas se crean para cada commit o solicitud de extracción. 35 | bad_github_permissions_error: "Se produjo un problema al obtener datos de webhook de GitHub. Comprueba que tu token configurado en la configuración del sitio code_review_github_token tiene habilitado el ámbito de «repositorio». Consulta https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps para obtener más información." 36 | bad_github_credentials_error: "Hubo un problema con tus credenciales de GitHub. Comprueba la configuración de tu sitio code_review_github_token e inténtalo de nuevo." 37 | approval_list: 38 | user_not_found: "No se ha podido encontrar al usuario con nombre de usuario %{username}" 39 | -------------------------------------------------------------------------------- /config/locales/server.et.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | et: 8 | -------------------------------------------------------------------------------- /config/locales/server.fa_IR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fa_IR: 8 | site_settings: 9 | code_review_allowed_groups: "گروه‌های که مجاز به بررسی کد هستند" 10 | -------------------------------------------------------------------------------- /config/locales/server.fi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fi: 8 | site_settings: 9 | code_review_enabled: "ota Discoursen koodin tarkistus käyttöön" 10 | code_review_allowed_groups: "Ryhmät, jotka saavat tarkistaa koodia" 11 | code_review_github_token: "Githubin APIssa käytettävä tunnus, sen voi luoda osoitteessa https://github.com/settings/tokens/new. \"Repo\"-oikeus vaaditaan, jos sync_to_github tai code_review_allow_private_clone on käytössä." 12 | code_review_sync_to_github: "EDELLYTYS: code_review_github_token, pitäisikö nämä kommentit lähettää githubille?" 13 | code_review_catch_up_commits: "Kun uusi tietosäilö lisätään, luo tämä määrä ketjuja vanhoille solmuille" 14 | code_review_allow_private_clone: "EDELLYTYS: code_review_github_token, kloonaa tietosäilöt yhdistettynä käyttäjänä, tämä varotoimi on käytössä yksityisten tietosäilöjen kloonauksen estämiseksi julkisilla sivustoilla." 15 | code_review_allow_manual_followup: "Salli seurantapainike solmuissa" 16 | code_review_pending_tag: "Odottavissa solmuissa käytettävä tunniste" 17 | code_review_followup_tag: "Seurantasolmuissa käytettävä tunniste" 18 | code_review_approved_tag: "Hyväksytyissä solmuissa käytettävä tunniste" 19 | code_review_unmerged_tag: "Yhdistämättömissä solmuissa käytettävä tunniste" 20 | code_review_commit_tag: "Solmuketjuissa käytettävä tunniste" 21 | code_review_pull_request_tag: "Vetopyyntöketjuissa käytettävä tunniste" 22 | code_review_github_webhook_secret: "webhookin salainen merkkijono käytettäväksi kohteessa https://sivustonnimi/code-review/webhook" 23 | code_review_allow_self_approval: "Salli solmujen itsenäinen hyväksyntä" 24 | code_review_skip_duration_minutes: "Ohita-painike ohittaa solmun näin monen minuutin ajaksi" 25 | code_review_auto_assign_on_followup: "Määritä ketju automaattisesti tekijälle seurannan yhteydessä" 26 | code_review_auto_unassign_on_approve: "Poista ketjun määritys automaattisesti hyväksymisen yhteydessä" 27 | code_review_auto_approve_followed_up_commits: "Hyväksy automaattisesti solmut, joihin on viitattu nykyisestä solmusta" 28 | code_review_github_organizations: "Github-organisaatiot (erotettuna pilkulla), jotka sisältävät tietosäilöjä, jotka tulisi synkronoida täällä" 29 | code_review_approve_approved_prs: "Hyväksy automaattisesti solmut, jotka ovat hyväksytyissä vetopyynnöissä" 30 | code_review_default_mute_new_categories: "Mykistä kaikille lisäosan luomille käyttäjäluokille" 31 | code_review_default_parent_category: "Oletusarvoinen ylätason alue lisäosan luomille alueille" 32 | discourse_code_review: 33 | category_description: | 34 | Tämä alue luotiin sisältämään tietosäilön %{repo_name} kooditarkistuksia. Ketjuja luodaan jokaiselle solmulle tai vetopyynnölle. 35 | bad_github_permissions_error: "Webhook-tietojen hakemisessa GitHubista tapahtui virhe. Tarkista, että code_review_github_token-sivustoasetuksissa määritetyssä tunnuksessa on repo-alue käytössä. Katso lisätietoja osoitteesta https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps." 36 | bad_github_credentials_error: "GitHub-tunnistetiedoissasi oli ongelma. Tarkista code_review_github_token-sivustoasetus ja yritä uudelleen." 37 | approval_list: 38 | user_not_found: "Käyttäjää käyttäjänimellä %{username} ei löydy" 39 | -------------------------------------------------------------------------------- /config/locales/server.gl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | gl: 8 | -------------------------------------------------------------------------------- /config/locales/server.he.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | he: 8 | site_settings: 9 | code_review_enabled: "לאפשר סקירת קוד עם Discourse" 10 | code_review_allowed_groups: "קבוצות שמורשות לסקור קוד" 11 | code_review_github_token: "אסימון לשימוש ב־API של GitHub, אפשר לייצר אותו דרך https://github.com/settings/tokens/new. הרשאות ‚repo’ נחוצות אם sync_to_github (סנכרון לגיטהאב) ו־code_review_allow_private_clone (לאפשר שכפול פרטי לסקירת קוד) פעילים" 12 | code_review_sync_to_github: "דורש: code_review_github_token (אסימון GitHub לסקירת קוד), האם הערות מכאן אמורות להישלח ל־GitHub?" 13 | code_review_catch_up_commits: "כאשר מאגר חדש נוסף יש ליצור מספר כזה של נושאים להגשות ישנות" 14 | code_review_allow_private_clone: "דורש: code_review_github_token (אסימון GitHub לסקירת קוד), ישכפל את המאגרים בתור המשתמש המוקצה, הגנה זו נועדה להשבית שכפול של מאגרים פרטיים באתרים ציבוריים." 15 | code_review_allow_manual_followup: "לאפשר כפתור להמשך טיפול על הגשות" 16 | code_review_pending_tag: "תגית להחלה על הגשות בהמתנה" 17 | code_review_followup_tag: "תגית להחלה על הגשות לטיפול" 18 | code_review_approved_tag: "תגית להחלה על הגשות מאושרות" 19 | code_review_unmerged_tag: "תגית להחלה על הגשות שטרם מוזגו" 20 | code_review_commit_tag: "תגית להחלה על נושאי הגשה" 21 | code_review_pull_request_tag: "תגית להחלה על נושאי בקשות משיכה (PR)" 22 | code_review_github_webhook_secret: "מחרוזת התליה סודית לשימוש עבור https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "לאפשר אישור עצמי של הגשות" 24 | code_review_skip_duration_minutes: "כפתור הדילוג ידלג על הגשות למשך כמות כזאת של דקות" 25 | code_review_auto_assign_on_followup: "להקצות את הנושא ליוצרו אוטומטית עם המשך טיפול" 26 | code_review_auto_unassign_on_approve: "לבטל את הקצאת הנושאים אוטומטית עם אישורם" 27 | code_review_auto_approve_followed_up_commits: "לאשר אוטומטית הגשות שהופנו מההגשה הנוכחית" 28 | code_review_github_organizations: "ארגוני Github (מופרדים בפסיקים) המכילים מאגרים שיש לסנכרן כאן" 29 | code_review_approve_approved_prs: "לאשר אוטומטית הגשות שקיימות בבקשות משיכה (PRs) שאושרו" 30 | code_review_default_mute_new_categories: "להשתיק לכל קטגוריות המשתמשים שנוצרו על ידי התוסף" 31 | code_review_default_parent_category: "קטגוריות הורה לקטגוריות שנוצרו על ידי התוסף כברירת מחדל" 32 | discourse_code_review: 33 | category_description: | 34 | קטגוריה זו נוצרה כדי להכיל סקירות קוד עבור %{repo_name}. נושאים נוצרו עבור כל הגשה או בקשת משיכה (PR). 35 | bad_github_permissions_error: "אירעה תקלה בשליפת נתוני התליות מ־GitHub. נא לבדוק שלאסימון שמוגדר בהגדרת האתר code_review_github_token מופעל התחום ‚repo’ (מאגר). כדאי לפנות אל https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps לפרטים נוספים." 36 | bad_github_credentials_error: "הייתה תקלה עם פרטי הגישה שלך ל־GitHub. נא לבדוק את הגדרת האתר שלך code_review_github_token (אסימון GitHub לסקירת קוד) ולנסות שוב." 37 | approval_list: 38 | user_not_found: "לא ניתן למצוא משתמש עם שם המשתמש %{username}" 39 | -------------------------------------------------------------------------------- /config/locales/server.hr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hr: 8 | -------------------------------------------------------------------------------- /config/locales/server.hu.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hu: 8 | -------------------------------------------------------------------------------- /config/locales/server.hy.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hy: 8 | -------------------------------------------------------------------------------- /config/locales/server.id.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | id: 8 | -------------------------------------------------------------------------------- /config/locales/server.it.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | it: 8 | site_settings: 9 | code_review_enabled: "abilita la revisione codice di Discourse" 10 | code_review_allowed_groups: "Gruppi autorizzati a rivedere il codice" 11 | code_review_github_token: "Token da utilizzare per l'API github, che può essere generato tramite la pagina https://github.com/settings/tokens/new. L'autorizzazione 'repo' è richiesta se le opzioni sync_to_github o code_review_allow_private_clone sono abilitate" 12 | code_review_sync_to_github: "RICHIEDE: code_review_github_token, i commenti qui devono essere inviati a github?" 13 | code_review_catch_up_commits: "Quando viene aggiunto un nuovo archivio, crea il numero di argomenti indicato per i vecchi commit" 14 | code_review_allow_private_clone: "RICHIEDE: code_review_github_token, clonerà gli archivi dell'utente associato, questa protezione è in atto per disabilitare la clonazione di archivi privati su siti pubblici." 15 | code_review_allow_manual_followup: "Consenti il pulsante di completamento sui commit" 16 | code_review_pending_tag: "Etichetta da applicare ai commit in sospeso" 17 | code_review_followup_tag: "Etichetta da applicare ai commit da completare" 18 | code_review_approved_tag: "Etichetta da applicare ai commit approvati" 19 | code_review_unmerged_tag: "Etichetta da applicare ai commit non uniti" 20 | code_review_commit_tag: "Etichetta da applicare al commit di argomenti" 21 | code_review_pull_request_tag: "Etichetta da applicare agli argomenti di richieste pull" 22 | code_review_github_webhook_secret: "stringa segreta web hook da utilizzare per https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "Consenti approvazione automatica dei commit" 24 | code_review_skip_duration_minutes: "Il pulsante Ignora salterà il commit per i minuti indicati" 25 | code_review_auto_assign_on_followup: "Assegna automaticamente l'argomento all'autore in fase di completamento" 26 | code_review_auto_unassign_on_approve: "Annulla automaticamente l'assegnazione dell'argomento all'approvazione" 27 | code_review_auto_approve_followed_up_commits: "Approva automaticamente i commit a cui fa riferimento il commit corrente" 28 | code_review_github_organizations: "Organizzazioni Github (separate da virgola) contenenti archivi da sincronizzare qui" 29 | code_review_approve_approved_prs: "Approva automaticamente i commit che esistono nelle richieste pull approvate" 30 | code_review_default_mute_new_categories: "Silenzia per tutte le categorie di utenti create dal plugin" 31 | code_review_default_parent_category: "Categoria superiore predefinita per le categorie create dal plug-in" 32 | discourse_code_review: 33 | category_description: | 34 | Questa categoria è stata creata per contenere le revisioni del codice per %{repo_name}. Gli argomenti vengono creati per ogni commit o richiesta pull. 35 | bad_github_permissions_error: "Si è verificato un problema durante il recupero dei dati webhook da GitHub. Verifica che il tuo token configurato nell'impostazione del sito code_review_github_token abbia l'ambito \"repo\" abilitato. Per maggiori dettagli, consultare la pagina https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps." 36 | bad_github_credentials_error: "Si è verificato un problema con le tue credenziali GitHub. Controlla l'impostazione code_review_github_token del tuo sito e riprova." 37 | approval_list: 38 | user_not_found: "Impossibile trovare un utente con nome utente %{username}" 39 | -------------------------------------------------------------------------------- /config/locales/server.ja.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ja: 8 | site_settings: 9 | code_review_enabled: "Discourse コードレビューを有効にする" 10 | code_review_allowed_groups: "コードのレビューを許可されたグループ" 11 | code_review_github_token: "GitHub API に使用するトークン。これは、https://github.com/settings/tokens/new で生成できます。sync_to_github or code_review_allow_private_clone が有効である場合は、「repo」権限が必要です。" 12 | code_review_sync_to_github: "必須: code_review_github_token。ここのコメントを GitHub に送信する必要がありますか?" 13 | code_review_catch_up_commits: "新しいリポジトリが追加されると、古いコミットにこの数のトピックを作成する" 14 | code_review_allow_private_clone: "必須: code_review_github_token。関連付けられたユーザーとしてレポジトリのクローンを作成します。このセーフガードは、公開サイトでの非公開リポジトリのクローン作成を無効にするために用意されています。" 15 | code_review_allow_manual_followup: "コミットにフォローアップボタンを許可する" 16 | code_review_pending_tag: "保留中のコミットに適用するタグ" 17 | code_review_followup_tag: "フォローアップコミットに適用するタグ" 18 | code_review_approved_tag: "承認済みコミットに適用するタグ" 19 | code_review_unmerged_tag: "マージされていないコミットに適用するタグ" 20 | code_review_commit_tag: "コミットトピックに適用するタグ" 21 | code_review_pull_request_tag: "プルリクエストのトピックに適用するタグ" 22 | code_review_github_webhook_secret: "https://sitename/code-review/webhook に使用する Webhook シークレット文字列" 23 | code_review_allow_self_approval: "コミットの自己承認を許可する" 24 | code_review_skip_duration_minutes: "スキップボタンはこの時間(分数)コミットをスキップする" 25 | code_review_auto_assign_on_followup: "フォローアップ時にトピックを作成者に自動的に割り当てる" 26 | code_review_auto_unassign_on_approve: "承認時にトピックの割り当てを自動的に解除する" 27 | code_review_auto_approve_followed_up_commits: "現在のコミットから参照されているコミットを自動的に承認する" 28 | code_review_github_organizations: "ここで同期する必要のあるリポジトリを含む GitHub 組織(コンマ区切り)" 29 | code_review_approve_approved_prs: "承認済みのプルリクエストに存在するコミットを自動承認する" 30 | code_review_default_mute_new_categories: "プラグインによって作成されたすべてのユーザーカテゴリをミュートする" 31 | code_review_default_parent_category: "プラグインによって作成されたカテゴリのデフォルトの親カテゴリ" 32 | discourse_code_review: 33 | category_description: | 34 | このカテゴリは、%{repo_name} のコードレビューを含むために作成されました。トピックは、コミットまたはプルリクエストごとに作成されます。 35 | bad_github_permissions_error: "GitHub から Webhook データを取得する際に問題が発生しました。code_review_github_token サイト設定で構成されているトークンで「repo」スコープが有効になっていることを確認してください。詳細は、https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps をご覧ください。" 36 | bad_github_credentials_error: "GitHub 資格情報に問題がありました。code_review_github_token サイト設定を確認して、もう一度お試しください。" 37 | approval_list: 38 | user_not_found: "%{username} というユーザー名のユーザーは見つかりませんでした" 39 | -------------------------------------------------------------------------------- /config/locales/server.ko.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ko: 8 | -------------------------------------------------------------------------------- /config/locales/server.lt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lt: 8 | -------------------------------------------------------------------------------- /config/locales/server.lv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lv: 8 | -------------------------------------------------------------------------------- /config/locales/server.nb_NO.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nb_NO: 8 | -------------------------------------------------------------------------------- /config/locales/server.nl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nl: 8 | site_settings: 9 | code_review_enabled: "Discourse-codereview inschakelen" 10 | code_review_allowed_groups: "Groepen die code mogen beoordelen" 11 | code_review_github_token: "Te gebruiken token voor Github-API. Deze kan worden gegenereerd via https://github.com/settings/tokens/new. Repositorytoestemming is vereist als sync_to_github of code_review_allow_private_clone is ingeschakeld" 12 | code_review_sync_to_github: "VEREIST: code_review_github_token, moeten opmerkingen hier naar Github worden gestuurd?" 13 | code_review_catch_up_commits: "Wanneer een nieuwe repository wordt toegevoegd, dit aantal topics maken voor oude commits" 14 | code_review_allow_private_clone: "VEREIST: code_review_github_token, kloont de repisotory's als de bijbehorende gebruiker. Deze beveiliging is aanwezig om het klonen van privéreopsitory's op openbare sites uit te schakelen." 15 | code_review_allow_manual_followup: "Opvolgknop bij commits toestaan" 16 | code_review_pending_tag: "Tag om toe te passen op wachtende commits" 17 | code_review_followup_tag: "Tag om toe te passen op opvolgcommits" 18 | code_review_approved_tag: "Tag om toe te passen op goedgekeurde commits" 19 | code_review_unmerged_tag: "Tag om toe te passen op niet-samengevoegde commits" 20 | code_review_commit_tag: "Tag om toe te passen op committopics" 21 | code_review_pull_request_tag: "Tag om toe te passen op pullverzoektopics" 22 | code_review_github_webhook_secret: "geheime webhooktekenreeks om te gebruiken voor https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "Zelfgoedkeuring van commits toestaan" 24 | code_review_skip_duration_minutes: "Overslaanknop slaat commit over voor dit aantal minuten" 25 | code_review_auto_assign_on_followup: "Topic automatisch toewijzen aan auteur bij opvolging" 26 | code_review_auto_unassign_on_approve: "Toewijzing van topic automatisch ongedaan maken bij goedkeuring" 27 | code_review_auto_approve_followed_up_commits: "Committs waarnaar wordt verwezen vanuit de huidige commit automatisch goedkeuren" 28 | code_review_github_organizations: "Github-organisaties (gescheiden door komma's) die repository's bevatten die hier gesynchroniseerd moeten worden" 29 | code_review_approve_approved_prs: "Commits in goedgekeurde pullverzoeken automatisch goedkeuren" 30 | code_review_default_mute_new_categories: "Dempen voor alle gebruikerscategorieën die door de plug-in zijn gemaakt" 31 | code_review_default_parent_category: "Standaard bovenliggende categorie voor categorieën die door de plug-in zijn gemaakt" 32 | discourse_code_review: 33 | category_description: | 34 | Deze categorie is gemaakt om codereviews voor %{repo_name}te bevatten. Voor elke commit of elk pullverzoek worden topics gemaakt. 35 | bad_github_permissions_error: "Er is een probleem opgetreden bij het ophalen van webhookgegevens van GitHub. Controleer of je token geconfigureerd in de site-instelling code_review_github_token het bereik 'repo' heeft ingeschakeld. Zie https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps voor meer informatie." 36 | bad_github_credentials_error: "Er was een probleem met je GitHub-aanmeldgegevens. Controleer je site-instelling code_review_github_token en probeer het opnieuw." 37 | approval_list: 38 | user_not_found: "Kan gebruiker met gebruikersnaam %{username} niet vinden" 39 | -------------------------------------------------------------------------------- /config/locales/server.pl_PL.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pl_PL: 8 | site_settings: 9 | code_review_enabled: "włącz przegląd kodu Discourse" 10 | code_review_allowed_groups: "Grupy dopuszczone do przeglądania kodu" 11 | code_review_allow_manual_followup: "Zezwalaj na przycisk śledzenia przy commitach" 12 | code_review_pending_tag: "Tag do zastosowania do oczekujących commitów" 13 | code_review_followup_tag: "Tag do zastosowania do śledzonych commitów" 14 | code_review_approved_tag: "Tag do zastosowania do zatwierdzonych commitów" 15 | code_review_unmerged_tag: "Znacznik do zastosowania do niezłączonych commitów" 16 | code_review_commit_tag: "Tag do zastosowania do tematów commitów" 17 | code_review_pull_request_tag: "Tag do zastosowania do tematów pull request" 18 | code_review_github_organizations: "Organizacje Github (oddzielone przecinkami) zawierające repozytoria, które należy tutaj zsynchronizować" 19 | code_review_approve_approved_prs: "Automatycznie zatwierdzaj commity, które istnieją w zatwierdzonych pull requestach." 20 | code_review_default_mute_new_categories: "Wycisz dla wszystkich kategorii użytkowników utworzonych przez wtyczkę" 21 | discourse_code_review: 22 | bad_github_credentials_error: "Wystąpił problem z Twoimi danymi logowania GitHub. Sprawdź ustawienia witryny code_review_github_token i spróbuj ponownie." 23 | -------------------------------------------------------------------------------- /config/locales/server.pt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt: 8 | -------------------------------------------------------------------------------- /config/locales/server.pt_BR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt_BR: 8 | site_settings: 9 | code_review_enabled: "ativar revisão de código do Discourse" 10 | code_review_allowed_groups: "Grupos autorizados a revisar o código" 11 | code_review_github_token: "Token para usar a API do github, pode ser gerada em https://github.com/settings/tokens/new . 'repo' permission é necessário se sync_to_github or code_review_allow_private_clone estiver ativado" 12 | code_review_sync_to_github: "REQUER: code_review_github_token, enviar comentários para o github?" 13 | code_review_catch_up_commits: "Ao adicionar um novo repositório, criar esta quantidade de tópicos para confirmações antigas" 14 | code_review_allow_private_clone: "REQUER: code_review_github_token, clonará os repositórios como usuário(a) associado(a), essa proteção foi aplicada para destivar a clonagem de repositórios privados em sites públicos." 15 | code_review_allow_manual_followup: "Permitir botão de acompanhamento em confirmações" 16 | code_review_pending_tag: "Etiqueta para aplicar confirmações pendentes" 17 | code_review_followup_tag: "Etiqueta para aplicar confirmações acompanhadas" 18 | code_review_approved_tag: "Etiqueta para aplicar confirmações aprovadas" 19 | code_review_unmerged_tag: "Etiqueta para aplicar confirmações não mescladas" 20 | code_review_commit_tag: "Etiqueta para aplicar para confirmar tópicos" 21 | code_review_pull_request_tag: "Etiqueta para aplicar para receber tópicos solicitados" 22 | code_review_github_webhook_secret: "string secreta do webhook para uso. Use para https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "Permitir autoaprovação de confirmações" 24 | code_review_skip_duration_minutes: "O botão de pular irá pular a confirmação por estes minutos" 25 | code_review_auto_assign_on_followup: "Atribuir tópico automaticamente ao(à) autor(a) ao acompanhar" 26 | code_review_auto_unassign_on_approve: "Remover atribuição de tópico automaticamente ao aprovar" 27 | code_review_auto_approve_followed_up_commits: "Aprovar automaticamente confirmações indicadas na confirmação atual" 28 | code_review_github_organizations: "Organizações do Github (separadas por vírgula) contendo repositórios que devem ser sincronizados aqui" 29 | code_review_approve_approved_prs: "Aprovar automaticamente confirmações existentes em solicitações de recepção aprovadas" 30 | code_review_default_mute_new_categories: "Silenciar todas as categorias de usuário(a) criadas pelo plugin" 31 | code_review_default_parent_category: "Categoria pai padrão para categorias criadas pelo plugin" 32 | discourse_code_review: 33 | category_description: | 34 | Esta categoria foi criada para conter revisões de código para %{repo_name}. Tópicos são criados para cada confirmação ou solicitação de recepção. 35 | bad_github_permissions_error: "Ocorreu um problema ao buscar dados do webhook no GitHub. Verifique se o token configurado na configuração do site code_review_github_token tem o escopo \"repositório\" ativado. Acesse https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps para obter mais informações." 36 | bad_github_credentials_error: "Ocorreu um problema com as suas credenciais do GitHub. Verifique sua configuração do site code_review_github_token e tente novamente." 37 | approval_list: 38 | user_not_found: "Não foi possível encontrar usuário(a) com nome de usuário(a) %{username}" 39 | -------------------------------------------------------------------------------- /config/locales/server.ro.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ro: 8 | -------------------------------------------------------------------------------- /config/locales/server.ru.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ru: 8 | site_settings: 9 | code_review_enabled: "Включить проверку кода" 10 | code_review_allowed_groups: "Группы, которым разрешено проверять код" 11 | code_review_github_token: "Токен для использования в github API, его можно сгенерировать по ссылке https://github.com/settings/tokens/new. Разрешение «repo» требуется, если включён sync_to_github или code_review_allow_private_clone" 12 | code_review_sync_to_github: "ТРЕБУЕТСЯ: code_review_github_token, следует ли отправлять комментарии на github?" 13 | code_review_catch_up_commits: "При добавлении нового репозитория создавать указанное здесь количество тем для старых коммитов" 14 | code_review_allow_private_clone: "ТРЕБУЕТСЯ: code_review_github_token, клонировать репозитории в качестве связанного пользователя, эта защита предназначена для отключения клонирования частных репозиториев на общедоступных сайтах." 15 | code_review_allow_manual_followup: "Отображать кнопку 'Отслеживать' в коммите" 16 | code_review_pending_tag: "Тег для применения к ожидающим коммитам" 17 | code_review_followup_tag: "Тег для применения к отслеживаемым коммитам" 18 | code_review_approved_tag: "Тег для применения к одобренным коммитам" 19 | code_review_unmerged_tag: "Тег для применения к неслитым коммитам" 20 | code_review_commit_tag: "Тег для применения к темам коммита" 21 | code_review_pull_request_tag: "Тег для применения к темам запросов на слияние" 22 | code_review_github_webhook_secret: "Секретная строка веб-хука для использования на https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "Разрешить автоматическое одобрение коммитов" 24 | code_review_skip_duration_minutes: "Кнопка 'Пропустить' отложит проверку кода на указанное здесь количество минут" 25 | code_review_auto_assign_on_followup: "Автоматически назначать тему автору при отслеживании" 26 | code_review_auto_unassign_on_approve: "Автоматически отменять назначение темы при одобрении" 27 | code_review_auto_approve_followed_up_commits: "Автоматически одобрять коммиты, на которые ссылается текущий коммит" 28 | code_review_github_organizations: "Организации Github (указываются через запятую), содержащие репозитории, которые должны быть синхронизированы с текущим сайтом" 29 | code_review_approve_approved_prs: "Автоматически одобрять коммиты, существующие в одобренных запросах на слияние" 30 | code_review_default_mute_new_categories: "Отключить уведомления для всех разделов, создаваемых плагином" 31 | code_review_default_parent_category: "Родительский раздел по умолчанию для разделов, создаваемых плагином" 32 | discourse_code_review: 33 | category_description: | 34 | Эта раздел был создан для проверки кода репозитория %{repo_name}. Для каждого коммита или запроса на слияние создаются отдельные темы. 35 | bad_github_permissions_error: "Возникла проблема при получении данных вебхуком с сайта GitHub. Убедитесь, что для вашего токена, указанного в настройке code_review_github_token, включена область видимости 'repo'. Подробнее см. https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps." 36 | bad_github_credentials_error: "Возникла проблема с вашими учётными данными GitHub. Пожалуйста, проверьте настройку code_review_github_token и повторите попытку." 37 | approval_list: 38 | user_not_found: "Не удалось найти пользователя с именем %{username}" 39 | -------------------------------------------------------------------------------- /config/locales/server.sk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sk: 8 | -------------------------------------------------------------------------------- /config/locales/server.sl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sl: 8 | -------------------------------------------------------------------------------- /config/locales/server.sq.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sq: 8 | -------------------------------------------------------------------------------- /config/locales/server.sr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sr: 8 | -------------------------------------------------------------------------------- /config/locales/server.sv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sv: 8 | site_settings: 9 | code_review_enabled: "aktivera granskning av Discourse-kod" 10 | code_review_allowed_groups: "Grupper tillåtna att granska kod" 11 | code_review_github_token: "Token som ska användas för github-API och kan genereras via https://github.com/settings/tokens/new. 'repo'-tillstånd krävs om sync_to_github eller code_review_allow_private_clone har aktiverats" 12 | code_review_sync_to_github: "KRÄVER: code_review_github_token, ska kommentarer här skickas till github?" 13 | code_review_catch_up_commits: "När en ny lagringsplats läggs till ska detta antal ämnen skapas för gamla åtaganden" 14 | code_review_allow_private_clone: "KRÄVER: code_review_github_token, kommer att klona lagringsplatserna som kopplad användare, denna skyddsåtgärd finns för att inaktivera kloning av privata lagringsplatser på offentliga webbplatser." 15 | code_review_allow_manual_followup: "Tillåt uppföljningsknapp vid åtaganden" 16 | code_review_pending_tag: "Tagg som ska tillämpas på väntande åtaganden" 17 | code_review_followup_tag: "Tagg som ska tillämpas på uppföljningsåtaganden" 18 | code_review_approved_tag: "Tagg som ska tillämpas på godkända åtaganden" 19 | code_review_unmerged_tag: "Tagg som ska tillämpas på icke-sammanslagna åtaganden" 20 | code_review_commit_tag: "Tagg som ska tillämpas på åtagandeämnen" 21 | code_review_pull_request_tag: "Tagg som ska tillämpas på dragförfrågningsämnen" 22 | code_review_github_webhook_secret: "webhook hemlig sträng som ska användas för https://sitename/code-review/webhook" 23 | code_review_allow_self_approval: "Tillåt självgodkännande av åtaganden" 24 | code_review_skip_duration_minutes: "Hoppa över-knappen hoppar över åtagandet under detta antal minuter" 25 | code_review_auto_assign_on_followup: "Tilldela automatiskt ämne till författaren vid uppföljning" 26 | code_review_auto_unassign_on_approve: "Ta automatiskt bort tilldelningen av ämnet vid godkännande" 27 | code_review_auto_approve_followed_up_commits: "Godkänn automatiskt åtaganden som aktuella åtaganden hänvisar till" 28 | code_review_github_organizations: "Github-organisationer (kommaseparerade) som innehåller lagringsplatser som ska synkroniseras här" 29 | code_review_approve_approved_prs: "Godkänn automatiskt åtaganden som finns i godkända dragförfrågningar" 30 | code_review_default_mute_new_categories: "Tysta för alla användarkategorier som skapats av tillägget" 31 | code_review_default_parent_category: "Förvald överordnad kategori för kategorier som skapats av tillägget" 32 | discourse_code_review: 33 | category_description: | 34 | Denna kategori skapades för att innehålla kodgranskningar för %{repo_name}. Ämnen skapas för varje åtagande eller dragförfrågning. 35 | bad_github_permissions_error: "Det uppstod ett problem vid hämtning av webhook-data från GitHub. Kontrollera att din token som konfigurerats i webbplatsinställningen code_review_github_token har 'repo'-omfånget aktiverat. Se mer information på https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps." 36 | bad_github_credentials_error: "Det uppstod ett problem med dina GitHub-autentiseringsuppgifter. Kontrollera din webbplatsinställning för code_review_github_token och försök igen." 37 | -------------------------------------------------------------------------------- /config/locales/server.sw.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sw: 8 | -------------------------------------------------------------------------------- /config/locales/server.te.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | te: 8 | -------------------------------------------------------------------------------- /config/locales/server.th.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | th: 8 | -------------------------------------------------------------------------------- /config/locales/server.tr_TR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | tr_TR: 8 | site_settings: 9 | code_review_enabled: "Discourse kod incelemesini etkinleştirin" 10 | code_review_allowed_groups: "Kodu incelemesine izin verilen gruplar" 11 | code_review_github_token: "Github API için kullanılacak token, https://github.com/settings/tokens/new adresinden oluşturulabilir. sync_to_github veya code_review_allow_private_clone etkinleştirilmişse \"repo\" izni gereklidir" 12 | code_review_sync_to_github: "GEREKLİ: code_review_github_token, buradaki yorumlar github'a gönderilmeli mi?" 13 | code_review_catch_up_commits: "Yeni bir repo eklendiğinde eski taahhütler için bu sayıda konu oluşturun" 14 | code_review_allow_private_clone: "GEREKLİ: code_review_github_token, repoları ilişkili kullanıcı olarak klonlayacak, bu koruma, özel repoların halka açık sitelerde klonlanmasını devre dışı bırakmak için mevcuttur." 15 | code_review_allow_manual_followup: "Taahhütler üzerinde takip düğmesine izin ver" 16 | code_review_pending_tag: "Bekleyen taahhütlere uygulanacak etiket" 17 | code_review_followup_tag: "Taahhütleri takip etmek için uygulanacak etiket" 18 | code_review_approved_tag: "Onaylanan taahhütlere uygulanacak etiket" 19 | code_review_unmerged_tag: "Birleştirilmemiş taahhütlere uygulanacak etiket" 20 | code_review_commit_tag: "Taahhüt konularına uygulanacak etiket" 21 | code_review_pull_request_tag: "Çekme talebi konularına uygulanacak etiket" 22 | code_review_github_webhook_secret: "https://sitename/code-review/webhook için kullanılacak web kancası gizli dizesi" 23 | code_review_allow_self_approval: "Taahhütlerin kendi kendine onaylanmasına izin verin" 24 | code_review_skip_duration_minutes: "Atla düğmesi şu kadar dakika boyunca işlemeyi atlayacak" 25 | code_review_auto_assign_on_followup: "Takipte konuyu yazara otomatik olarak ata" 26 | code_review_auto_unassign_on_approve: "Onaylandığında otomatik olarak konu atamasını kaldır" 27 | code_review_auto_approve_followed_up_commits: "Geçerli taahhütten referans alınan taahhütleri otomatik olarak onayla" 28 | code_review_github_organizations: "Burada senkronize edilmesi gereken repoları içeren Github organizasyonları (virgülle ayrılır)" 29 | code_review_approve_approved_prs: "Onaylanan çekme isteklerinde bulunan taahhütleri otomatik olarak onaylayın" 30 | code_review_default_mute_new_categories: "Eklenti tarafından oluşturulan tüm kullanıcı kategorileri için sessize al" 31 | code_review_default_parent_category: "Eklenti tarafından oluşturulan kategoriler için varsayılan üst kategori" 32 | discourse_code_review: 33 | category_description: | 34 | Bu kategori %{repo_name} için kod incelemelerini içermek üzere oluşturuldu. Başlıklar her taahhüt veya çekme talebi için oluşturulur. 35 | bad_github_permissions_error: "GitHub'dan web kancası verileri alınırken bir sorun oluştu. Lütfen code_review_github_token site ayarında yapılandırılan belirtecinizin \"repo\" kapsamının etkin olup olmadığını kontrol edin. Daha fazla bilgi için https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps adresini ziyaret edin." 36 | bad_github_credentials_error: "GitHub kimlik bilgilerinizle ilgili bir sorun oluştu. Lütfen code_review_github_token site ayarınızı kontrol edin ve tekrar deneyin." 37 | approval_list: 38 | user_not_found: "Kullanıcı adı %{username} olan kullanıcı bulunamadı" 39 | -------------------------------------------------------------------------------- /config/locales/server.ug.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ug: 8 | -------------------------------------------------------------------------------- /config/locales/server.uk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | uk: 8 | -------------------------------------------------------------------------------- /config/locales/server.ur.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ur: 8 | -------------------------------------------------------------------------------- /config/locales/server.vi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | vi: 8 | -------------------------------------------------------------------------------- /config/locales/server.zh_CN.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_CN: 8 | site_settings: 9 | code_review_enabled: "启用 Discourse Code Review" 10 | code_review_allowed_groups: "允许审查代码的群组" 11 | code_review_github_token: "用于 github API 的令牌,可以通过 https://github.com/settings/tokens/new 生成。如果启用了 sync_to_github 或 code_review_allow_private_clone,则需要“repo”权限" 12 | code_review_sync_to_github: "要求:code_review_github_token,这里的评论要发到 github 吗?" 13 | code_review_catch_up_commits: "添加新仓库时,为旧提交创建此数量的话题" 14 | code_review_allow_private_clone: "要求:code_review_github_token,将作为关联用户克隆仓库,此保护措施可禁止在公共站点上克隆私有仓库。" 15 | code_review_allow_manual_followup: "允许提交的跟进按钮" 16 | code_review_pending_tag: "应用于待处理提交的标签" 17 | code_review_followup_tag: "应用于跟进提交的标签" 18 | code_review_approved_tag: "应用于已批准提交的标签" 19 | code_review_unmerged_tag: "应用于未合并提交的标签" 20 | code_review_commit_tag: "应用于提交话题的标签" 21 | code_review_pull_request_tag: "应用于拉取请求话题的标签" 22 | code_review_github_webhook_secret: "用于 https://sitename/code-review/webhook 的网络钩子密钥字符串" 23 | code_review_allow_self_approval: "允许自我批准提交" 24 | code_review_skip_duration_minutes: "跳过按钮将在此数值的分钟内跳过提交" 25 | code_review_auto_assign_on_followup: "跟进时自动将话题分配给作者" 26 | code_review_auto_unassign_on_approve: "批准时自动取消分配话题" 27 | code_review_auto_approve_followed_up_commits: "自动批准从当前提交引用的提交" 28 | code_review_github_organizations: "应在此处同步的仓库所属的 Github 组织(逗号分隔)" 29 | code_review_approve_approved_prs: "自动批准已批准的拉取请求中存在的提交" 30 | code_review_default_mute_new_categories: "为插件创建的所有用户类别设置免打扰" 31 | code_review_default_parent_category: "插件创建的类别的默认上级类别" 32 | discourse_code_review: 33 | category_description: | 34 | 此类别的创建目的是包含 %{repo_name} 的代码审查。会为每个提交或拉取请求创建话题。 35 | bad_github_permissions_error: "从 GitHub 获取网络钩子数据时出现问题。请检查您在 code_review_github_token 站点设置中配置的令牌是否启用了“repo”范围。请参阅 https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps,了解详细信息。" 36 | bad_github_credentials_error: "您的 GitHub 凭据存在问题。请检查您的 code_review_github_token 站点设置,然后重试。" 37 | approval_list: 38 | user_not_found: "找不到用户名为 %{username} 的用户" 39 | -------------------------------------------------------------------------------- /config/locales/server.zh_TW.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_TW: 8 | -------------------------------------------------------------------------------- /config/settings.yml: -------------------------------------------------------------------------------- 1 | discourse_code_review: 2 | code_review_enabled: false 3 | code_review_allowed_groups: 4 | default: "" 5 | type: group_list 6 | list_type: compact 7 | code_review_github_token: "" 8 | code_review_sync_to_github: false 9 | code_review_catch_up_commits: 10 10 | code_review_allow_private_clone: false 11 | code_review_allow_manual_followup: 12 | client: true 13 | default: true 14 | code_review_pending_tag: 15 | client: true 16 | default: "pending" 17 | code_review_approved_tag: 18 | client: true 19 | default: "approved" 20 | code_review_followup_tag: 21 | client: true 22 | default: "follow-up" 23 | code_review_unmerged_tag: "unmerged" 24 | code_review_commit_tag: "commit" 25 | code_review_pull_request_tag: "pull-request" 26 | code_review_github_webhook_secret: 27 | default: "" 28 | secret: true 29 | code_review_allow_self_approval: 30 | client: true 31 | default: false 32 | code_review_skip_duration_minutes: 2880 33 | code_review_auto_assign_on_followup: true 34 | code_review_auto_unassign_on_approve: true 35 | code_review_auto_approve_followed_up_commits: true 36 | code_review_github_organizations: "" 37 | code_review_approve_approved_prs: false 38 | code_review_default_mute_new_categories: false 39 | code_review_default_parent_category: 40 | type: category 41 | default: "" 42 | validator: "ParentCategoryValidator" 43 | -------------------------------------------------------------------------------- /db/migrate/20181213080000_create_custom_field_indexes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateCustomFieldIndexes < ActiveRecord::Migration[5.2] 4 | def change 5 | add_index :topic_custom_fields, [:value], unique: true, where: "name = 'commit hash'" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20200920080000_add_skipped_code_reviews.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSkippedCodeReviews < ActiveRecord::Migration[6.0] 4 | def change 5 | create_table :skipped_code_reviews do |t| 6 | t.integer :topic_id, null: false 7 | t.integer :user_id, null: false 8 | t.datetime :expires_at, null: false 9 | 10 | t.timestamps null: false 11 | end 12 | 13 | add_index :skipped_code_reviews, %i[topic_id user_id], unique: true 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20220111185133_create_code_review_github_repos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateCodeReviewGithubRepos < ActiveRecord::Migration[6.1] 4 | def change 5 | create_table :code_review_github_repos, id: false do |t| 6 | t.integer :category_id, null: false, primary_key: true 7 | t.text :name 8 | t.text :repo_id 9 | t.timestamps 10 | end 11 | 12 | add_index :code_review_github_repos, :repo_id, unique: true 13 | add_index :code_review_github_repos, :name, unique: true 14 | 15 | reversible { |dir| dir.up { execute <<~SQL } } 16 | INSERT INTO code_review_github_repos (category_id, repo_id, name, created_at, updated_at) 17 | SELECT 18 | categories.id, 19 | repo_ids.value, 20 | names.value, 21 | least(repo_ids.created_at, names.created_at), 22 | greatest(repo_ids.updated_at, names.updated_at) 23 | FROM categories 24 | LEFT OUTER JOIN 25 | ( 26 | SELECT * 27 | FROM category_custom_fields 28 | WHERE name = 'GitHub Repo Name' 29 | ) names 30 | ON names.category_id = categories.id 31 | LEFT OUTER JOIN 32 | ( 33 | SELECT * 34 | FROM category_custom_fields 35 | WHERE name = 'GitHub Repo ID' 36 | ) repo_ids 37 | ON repo_ids.category_id = categories.id 38 | WHERE repo_ids.value IS NOT NULL 39 | OR names.value IS NOT NULL 40 | SQL 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /db/migrate/20220111185242_create_code_review_commit_topics.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateCodeReviewCommitTopics < ActiveRecord::Migration[6.1] 4 | def change 5 | create_table :code_review_commit_topics, id: false do |t| 6 | t.integer :topic_id, null: false, primary_key: true 7 | t.text :sha, null: false 8 | t.timestamps 9 | end 10 | 11 | add_index :code_review_commit_topics, :sha, unique: true 12 | 13 | reversible { |dir| dir.up { execute <<~SQL } } 14 | INSERT INTO code_review_commit_topics (topic_id, sha, created_at, updated_at) 15 | SELECT 16 | topics.id, 17 | github_hashes.value, 18 | github_hashes.created_at, 19 | github_hashes.updated_at 20 | FROM 21 | ( 22 | SELECT * 23 | FROM topic_custom_fields 24 | WHERE name = 'commit hash' 25 | ) github_hashes 26 | INNER JOIN topics 27 | ON github_hashes.topic_id = topics.id 28 | SQL 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import DiscourseRecommended from "@discourse/lint-configs/eslint"; 2 | 3 | export default [...DiscourseRecommended]; 4 | -------------------------------------------------------------------------------- /lib/discourse_code_review/category_extension.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | module CategoryExtension 5 | extend ActiveSupport::Concern 6 | 7 | prepended do 8 | has_one :github_repo_category, 9 | class_name: "DiscourseCodeReview::GithubRepoCategory", 10 | dependent: :destroy 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/discourse_code_review/github_user_syncer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | class GithubUserSyncer 5 | def initialize(user_querier) 6 | @user_querier = user_querier 7 | end 8 | 9 | def ensure_user(name:, email: nil, github_login: nil, github_id: nil) 10 | user = nil 11 | 12 | user ||= 13 | if github_id 14 | User.find_by( 15 | id: UserCustomField.select(:user_id).where(name: GITHUB_ID, value: github_id).limit(1), 16 | ) 17 | end 18 | 19 | user ||= 20 | if github_login 21 | user = 22 | User.find_by( 23 | id: 24 | UserCustomField 25 | .select(:user_id) 26 | .where(name: GITHUB_LOGIN, value: github_login) 27 | .limit(1), 28 | ) 29 | end 30 | 31 | user ||= 32 | begin 33 | email ||= email_for(github_login) 34 | 35 | User.find_by_email(email) 36 | end 37 | 38 | user ||= 39 | begin 40 | User.create!( 41 | email: email, 42 | username: resolve_username(github_login, name, email), 43 | name: name.presence || User.suggest_name(email), 44 | staged: true, 45 | ) 46 | end 47 | 48 | if github_login 49 | rel = UserCustomField.where(name: GITHUB_LOGIN, value: github_login) 50 | existing = rel.pluck(:user_id) 51 | 52 | if existing != [user.id] 53 | rel.destroy_all 54 | UserCustomField.create!(name: GITHUB_LOGIN, value: github_login, user_id: user.id) 55 | end 56 | end 57 | 58 | if github_id 59 | rel = UserCustomField.where(name: GITHUB_ID, value: github_id) 60 | existing = rel.pluck(:user_id) 61 | 62 | if existing != [user.id] 63 | rel.destroy_all 64 | UserCustomField.create!(name: GITHUB_ID, value: github_id, user_id: user.id) 65 | end 66 | end 67 | user 68 | end 69 | 70 | private 71 | 72 | attr_reader :user_querier 73 | 74 | def email_for(github_login) 75 | email = 76 | begin 77 | user_querier.get_user_email(github_login) 78 | rescue Octokit::NotFound 79 | nil 80 | end 81 | email || "#{github_login}@fake.github.com" 82 | end 83 | 84 | def resolve_username(github_login, name, email) 85 | suggester_input = [github_login, name] 86 | suggester_input << email if SiteSetting.use_email_for_username_and_name_suggestions 87 | 88 | UserNameSuggester.suggest(*suggester_input) 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /lib/discourse_code_review/importer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | class Importer 5 | attr_reader :github_repo 6 | 7 | def initialize(github_repo) 8 | @github_repo = github_repo 9 | end 10 | 11 | def self.sync_commit(sha) 12 | client = DiscourseCodeReview.octokit_client 13 | github_commit_querier = DiscourseCodeReview.github_commit_querier 14 | 15 | State::GithubRepoCategories.each_repo_name do |repo_name| 16 | repo = GithubRepo.new(repo_name, client, github_commit_querier) 17 | importer = Importer.new(repo) 18 | 19 | if commit = repo.commit(sha) 20 | importer.sync_commit(commit) 21 | return repo_name 22 | end 23 | end 24 | 25 | nil 26 | end 27 | 28 | def self.sync_commit_from_repo(repo_name, sha) 29 | client = DiscourseCodeReview.octokit_client 30 | github_commit_querier = DiscourseCodeReview.github_commit_querier 31 | repo = GithubRepo.new(repo_name, client, github_commit_querier) 32 | importer = Importer.new(repo) 33 | importer.sync_commit_sha(sha) 34 | end 35 | 36 | def category_id 37 | @category_id ||= 38 | State::GithubRepoCategories.ensure_category( 39 | repo_name: github_repo.name, 40 | repo_id: github_repo.repo_id, 41 | ).id 42 | end 43 | 44 | def sync_merged_commits 45 | last_commit = nil 46 | github_repo.commits_since.each do |commit| 47 | sync_commit(commit) 48 | 49 | yield commit[:hash] if block_given? 50 | 51 | github_repo.last_commit = commit[:hash] 52 | end 53 | end 54 | 55 | def sync_commit_sha(commit_sha) 56 | commit = github_repo.commit(commit_sha) 57 | return if commit.nil? 58 | sync_commit(commit) 59 | end 60 | 61 | def sync_commit(commit) 62 | topic_id = import_commit(commit) 63 | import_comments(topic_id, commit[:hash]) 64 | topic_id 65 | end 66 | 67 | def import_commit(commit) 68 | merged = github_repo.default_branch_contains?(commit[:hash]) 69 | followees = github_repo.followees(commit[:hash]) 70 | 71 | user = 72 | DiscourseCodeReview.github_user_syncer.ensure_user( 73 | email: commit[:email], 74 | name: commit[:name], 75 | github_login: commit[:author_login], 76 | github_id: commit[:author_id], 77 | ) 78 | 79 | State::CommitTopics.ensure_commit( 80 | category_id: category_id, 81 | commit: commit, 82 | merged: merged, 83 | repo_name: github_repo.name, 84 | user: user, 85 | followees: followees, 86 | ) 87 | end 88 | 89 | def import_comments(topic_id, commit_sha) 90 | github_repo 91 | .commit_comments(commit_sha) 92 | .each do |comment| 93 | login = comment[:login] || "unknown" 94 | user = 95 | DiscourseCodeReview.github_user_syncer.ensure_user(name: login, github_login: login) 96 | 97 | State::CommitTopics.ensure_commit_comment( 98 | user: user, 99 | topic_id: topic_id, 100 | comment: comment, 101 | ) 102 | end 103 | end 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /lib/discourse_code_review/list_controller_extension.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | module ListControllerExtension 5 | extend ActiveSupport::Concern 6 | 7 | prepended { skip_before_action :ensure_logged_in, only: %i[approval_given approval_pending] } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/discourse_code_review/rake_tasks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | class RakeTasks 5 | def self.define_tasks 6 | Rake::Task.define_task code_review_delete_user_github_access_tokens: :environment do 7 | num_deleted = UserCustomField.where(name: "github user token").delete_all 8 | puts "deleted #{num_deleted} user_custom_fields" 9 | end 10 | 11 | Rake::Task.define_task code_review_tag_commits: :environment do 12 | topics = Topic.joins(:code_review_commit_topic).to_a 13 | 14 | puts "Tagging #{topics.size} topics" 15 | 16 | topics.each do |topic| 17 | DiscourseTagging.tag_topic_by_names( 18 | topic, 19 | Discourse.system_user.guardian, 20 | [SiteSetting.code_review_commit_tag], 21 | append: true, 22 | ) 23 | end 24 | end 25 | 26 | Rake::Task.define_task code_review_full_sha_backfill: :environment do 27 | posts_with_commit = 28 | Post 29 | .joins("INNER JOIN topics ON topics.id = posts.topic_id") 30 | .joins( 31 | "INNER JOIN code_review_commit_topics ON topics.id = code_review_commit_topics.topic_id", 32 | ) 33 | .includes(topic: :code_review_commit_topic) 34 | .where( 35 | " 36 | topics.deleted_at IS NULL AND 37 | posts.deleted_at IS NULL AND 38 | posts.post_number = 1 AND 39 | posts.raw ~ 'sha: [0-9a-f]{6,10}' AND 40 | posts.raw !~ 'sha: [0-9a-f]{11,60}'", 41 | ) 42 | 43 | total = posts_with_commit.count 44 | incr = 0 45 | 46 | puts "Found #{total} posts with a commit sha from the discourse-code-review plugin." 47 | 48 | posts_with_commit.find_each do |post_with_commit| 49 | puts "Replacing sha in post #{post_with_commit.id}..." 50 | 51 | full_git_sha = post_with_commit.topic.code_review_commit_topic.sha 52 | new_raw = post_with_commit.raw.gsub(/sha: [0-9a-f]{6,10}\b/, "sha: #{full_git_sha}") 53 | 54 | if new_raw == post_with_commit.raw 55 | puts "Nothing to change for post #{post_with_commit.id}, continuing. (new raw same as old raw)" 56 | incr += 1 57 | puts "Completed #{incr}/#{total}." 58 | next 59 | end 60 | 61 | post_with_commit.update(raw: new_raw) 62 | post_with_commit.rebake! 63 | 64 | incr += 1 65 | puts "Completed #{incr}/#{total}." 66 | end 67 | 68 | puts "All complete." 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/discourse_code_review/source.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Some things are simple, because they don't touch the DB. 4 | # 5 | # They belong here. 6 | 7 | module DiscourseCodeReview::Source 8 | end 9 | 10 | require File.expand_path("../source/git_repo", __FILE__) 11 | require File.expand_path("../source/github_pr_service", __FILE__) 12 | require File.expand_path("../source/github_pr_querier", __FILE__) 13 | require File.expand_path("../source/github_user_querier", __FILE__) 14 | require File.expand_path("../source/commit_querier.rb", __FILE__) 15 | -------------------------------------------------------------------------------- /lib/discourse_code_review/source/commit_querier.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | ActorWithId = TypedData::TypedStruct.new(login: String, id: TypedData::OrNil[Integer]) 5 | 6 | CommitAuthorInfo = 7 | TypedData::TypedStruct.new( 8 | oid: String, 9 | author: TypedData::OrNil[ActorWithId], 10 | committer: TypedData::OrNil[ActorWithId], 11 | ) 12 | 13 | class Source::CommitQuerier 14 | def initialize(graphql_client) 15 | @graphql_client = graphql_client 16 | end 17 | 18 | def last_commit(owner, name) 19 | response = @graphql_client.execute <<~GRAPHQL 20 | query { 21 | repo: repository(owner: \"#{owner}\", name: \"#{name}\") { 22 | defaultBranchRef { 23 | target { 24 | oid 25 | } 26 | } 27 | } 28 | } 29 | GRAPHQL 30 | 31 | response.dig(:repo, :defaultBranchRef, :target, :oid) 32 | end 33 | 34 | def commits_authors(owner, name, refs) 35 | query = 36 | " 37 | query { 38 | repository(owner: #{owner.to_json}, name: #{name.to_json}) { 39 | #{ 40 | refs 41 | .each_with_index 42 | .map do |ref, i| 43 | " 44 | commit_#{i}: object(expression: #{ref.to_json}) { 45 | ... on Commit { 46 | oid, 47 | author { 48 | user { 49 | login, 50 | id, 51 | } 52 | }, 53 | committer { 54 | user { 55 | login, 56 | id, 57 | } 58 | }, 59 | } 60 | }, 61 | ".lstrip 62 | end 63 | .join 64 | .rstrip 65 | } 66 | } 67 | } 68 | " 69 | 70 | response = @graphql_client.execute(query)[:repository] 71 | 72 | commits = 73 | refs.each_with_index.map do |ref, i| 74 | commit = response[:"commit_#{i}"] 75 | info = 76 | CommitAuthorInfo.new( 77 | oid: commit[:oid], 78 | author: build_actor_with_id(commit[:author][:user]), 79 | committer: build_actor_with_id(commit[:committer][:user]), 80 | ) 81 | 82 | [ref, info] 83 | end 84 | 85 | Hash[commits] 86 | end 87 | 88 | private 89 | 90 | def build_actor_with_id(actor) 91 | ActorWithId.new(login: actor[:login], id: decode_user_id(actor[:id])) if actor 92 | end 93 | 94 | # TODO: 95 | # The ids that github provides are supposed to be treated as opaque. 96 | # 97 | # Unfortunately, we store raw github ids in the DB since they used to be 98 | # exposed in the REST API. This is an interim measure until we switch to 99 | # using the string ids. 100 | def decode_user_id(id) 101 | if id 102 | if m = /^04:User(\d+)$/.match(Base64.decode64(id)) 103 | m[1].to_i 104 | end 105 | end 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /lib/discourse_code_review/source/github_user_querier.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview::Source 4 | class GithubUserQuerier 5 | def initialize(client) 6 | @client = client 7 | end 8 | 9 | def get_user_email(github_login) 10 | client.user(github_login)[:email] 11 | end 12 | 13 | private 14 | 15 | attr_reader :client 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/discourse_code_review/state.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview::State 4 | end 5 | 6 | # Some things are simple, because they only exist to manipulate data in the DB. 7 | # 8 | # They belong here 9 | 10 | require File.expand_path("../state/helpers", __FILE__) 11 | require File.expand_path("../state/commit_approval", __FILE__) 12 | require File.expand_path("../state/commit_topics.rb", __FILE__) 13 | require File.expand_path("../state/github_repo_categories.rb", __FILE__) 14 | -------------------------------------------------------------------------------- /lib/discourse_code_review/state/github_repo_categories.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | module State::GithubRepoCategories 5 | GITHUB_REPO_ID = "GitHub Repo ID" 6 | GITHUB_REPO_NAME = "GitHub Repo Name" 7 | 8 | class << self 9 | def ensure_category(repo_name:, repo_id: nil) 10 | ActiveRecord::Base.transaction(requires_new: true) do 11 | repo_category = GithubRepoCategory.find_by(repo_id: repo_id) if repo_id.present? 12 | repo_category ||= GithubRepoCategory.find_by(name: repo_name) 13 | 14 | category = repo_category&.category 15 | 16 | if !category && repo_id.present? 17 | # create new category 18 | short_name = find_category_name(repo_name.split("/", 2).last) 19 | 20 | category = 21 | Category.new( 22 | name: short_name, 23 | user: Discourse.system_user, 24 | description: 25 | I18n.t("discourse_code_review.category_description", repo_name: repo_name), 26 | ) 27 | 28 | if SiteSetting.code_review_default_parent_category.present? 29 | category.parent_category_id = SiteSetting.code_review_default_parent_category.to_i 30 | end 31 | 32 | category.save! 33 | 34 | if SiteSetting.code_review_default_mute_new_categories 35 | existing_category_ids = 36 | Category.where(id: SiteSetting.default_categories_muted.split("|")).pluck(:id) 37 | SiteSetting.default_categories_muted = 38 | (existing_category_ids << category.id).join("|") 39 | end 40 | end 41 | 42 | if category 43 | repo_category ||= GithubRepoCategory.new 44 | repo_category.category_id = category.id 45 | repo_category.repo_id = repo_id 46 | repo_category.name = repo_name 47 | repo_category.save! if repo_category.changed? 48 | 49 | category.custom_fields[GITHUB_REPO_ID] = repo_id 50 | category.custom_fields[GITHUB_REPO_NAME] = repo_name 51 | category.save_custom_fields 52 | end 53 | 54 | category 55 | end 56 | end 57 | 58 | def each_repo_name(&blk) 59 | GithubRepoCategory.pluck(:name).each(&blk) 60 | end 61 | 62 | def get_repo_name_from_topic(topic) 63 | GithubRepoCategory.where(category_id: topic.category_id).first&.name 64 | end 65 | 66 | private 67 | 68 | def find_category_name(name) 69 | if Category.where(name: name).exists? 70 | name += SecureRandom.hex 71 | else 72 | name 73 | end 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /lib/discourse_code_review/topic_extension.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DiscourseCodeReview 4 | module TopicExtension 5 | extend ActiveSupport::Concern 6 | 7 | prepended { has_one :code_review_commit_topic, class_name: "DiscourseCodeReview::CommitTopic" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/enumerators.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Enumerators 4 | class FlattenMerge 5 | include Enumerable 6 | 7 | def initialize(enumerables, &compare) 8 | @enumerables = enumerables 9 | @compare = compare 10 | end 11 | 12 | def each(&blk) 13 | enumerators = 14 | @enumerables 15 | .map(&:to_enum) 16 | .select do |enumerator| 17 | begin 18 | enumerator.peek 19 | true 20 | rescue StopIteration 21 | false 22 | end 23 | end 24 | 25 | queue = PQueue.new(enumerators) { |a, b| @compare.call(a.peek, b.peek) } 26 | 27 | until queue.empty? 28 | enumerator = queue.pop 29 | blk.call(enumerator.next) 30 | 31 | begin 32 | enumerator.peek 33 | rescue StopIteration 34 | else 35 | queue.push(enumerator) 36 | end 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/graphql_client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class GraphQLClient 4 | class GraphQLError < StandardError 5 | end 6 | 7 | class PaginatedQuery 8 | include Enumerable 9 | 10 | def initialize(client, &query) 11 | @client = client 12 | @query = query 13 | end 14 | 15 | def each(&blk) 16 | cursor = nil 17 | execute_block = client.method(:execute) 18 | 19 | loop do 20 | results, cursor, has_next_page = 21 | query.call(execute_block, cursor).values_at(:items, :cursor, :has_next_page) 22 | 23 | results.each(&blk) 24 | 25 | break unless has_next_page 26 | end 27 | end 28 | 29 | private 30 | 31 | attr_reader :client 32 | attr_reader :query 33 | end 34 | 35 | def initialize(client) 36 | @client = client 37 | end 38 | 39 | def execute(query) 40 | response = client.post("/graphql", { query: query }.to_json) 41 | if response[:errors] 42 | raise GraphQLError, response[:errors].inspect 43 | else 44 | response[:data] 45 | end 46 | end 47 | 48 | def paginated_query(&blk) 49 | PaginatedQuery.new(self, &blk) 50 | end 51 | 52 | private 53 | 54 | attr_reader :client 55 | end 56 | -------------------------------------------------------------------------------- /lib/octokit_rate_limit_retry_mixin.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module OctokitRateLimitRetryMixin 4 | def self.included(base) 5 | base.sidekiq_retry_in do |count, exception| 6 | case exception&.wrapped 7 | when Octokit::TooManyRequests 8 | rate_limit = DiscourseCodeReview.octokit_client.rate_limit 9 | rand(rate_limit.resets_in..(rate_limit.resets_in + 60)) 10 | else 11 | # Retry only once in 30..90 seconds 12 | count == 0 ? rand(30..90) : :discard 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/typed_data.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module TypedData 4 | module TypedStruct 5 | def self.new(base = Object, **attributes, &blk) 6 | ordered_attribute_keys = attributes.keys.sort 7 | 8 | Class.new(base) do 9 | attr_reader *attributes.keys 10 | 11 | define_method(:initialize) do |**opts| 12 | attributes.each do |attr_name, attr_type| 13 | value = opts.fetch(attr_name) 14 | 15 | unless attr_type === value 16 | raise TypeError, 17 | "Expected #{attr_name} to be of type #{attr_type}, got #{value.class}" 18 | end 19 | 20 | instance_variable_set(:"@#{attr_name}", value.freeze) 21 | end 22 | end 23 | 24 | define_method(:hash) { ordered_attribute_keys.map { |key| send(key) }.hash } 25 | 26 | define_method(:eql?) do |other| 27 | return false unless self.class == other.class 28 | 29 | ordered_attribute_keys.all? { |key| send(key).eql?(other.send(key)) } 30 | end 31 | 32 | alias_method(:==, :eql?) 33 | 34 | instance_eval(&blk) if blk 35 | end 36 | end 37 | end 38 | 39 | module TypedTaggedUnion 40 | def self.new(**alternatives) 41 | base = 42 | Class.new do 43 | define_singleton_method(:create) do |name, **attributes| 44 | const_get(name.to_s.camelize.to_sym).new(**attributes) 45 | end 46 | end 47 | 48 | alternatives.each do |tag, attributes| 49 | alternative_klass = 50 | TypedStruct.new(base, **attributes) { define_singleton_method(:tag) { tag } } 51 | 52 | base.const_set(tag.to_s.camelize.to_sym, alternative_klass) 53 | end 54 | 55 | base 56 | end 57 | end 58 | 59 | class Boolean 60 | def ===(other) 61 | TrueClass === other || FalseClass === other 62 | end 63 | end 64 | 65 | module OrNil 66 | def self.[](klass) 67 | Class.new { define_singleton_method(:===) { |other| other.nil? || klass === other } } 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/validators/parent_category_validator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ParentCategoryValidator 4 | def initialize(opts = {}) 5 | @opts = opts 6 | end 7 | 8 | def valid_value?(val) 9 | return true if val.blank? 10 | 11 | @category = Category.find_by(id: val) 12 | @category && @category.height_of_ancestors < SiteSetting.max_category_nesting - 1 13 | end 14 | 15 | def error_message 16 | @category ? I18n.t("category.errors.depth") : I18n.t("category.errors.not_found") 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "@discourse/lint-configs": "2.23.0", 5 | "ember-template-lint": "7.7.0", 6 | "eslint": "9.28.0", 7 | "prettier": "3.5.3", 8 | "stylelint": "16.20.0" 9 | }, 10 | "engines": { 11 | "node": ">= 22", 12 | "npm": "please-use-pnpm", 13 | "yarn": "please-use-pnpm", 14 | "pnpm": "9.x" 15 | }, 16 | "packageManager": "pnpm@9.15.5" 17 | } 18 | -------------------------------------------------------------------------------- /spec/discourse_code_review/lib/github_pr_querier_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | require_relative "../../helpers/integration" 5 | 6 | describe DiscourseCodeReview::Source::GithubPRQuerier, type: :code_review_integration do 7 | let(:pr_querier) do 8 | DiscourseCodeReview::Source::GithubPRQuerier.new(DiscourseCodeReview.graphql_client) 9 | end 10 | 11 | let(:pr) { DiscourseCodeReview::PullRequest.new(owner: "owner", name: "name", issue_number: 100) } 12 | 13 | describe "#associated_pull_requests" do 14 | it "does not error out when the query finds nothing" do 15 | GraphQLClientMock.any_instance.expects(:execute).returns({}) 16 | 17 | expect(pr_querier.associated_pull_requests(anything, anything, anything).to_a).to be_empty 18 | end 19 | end 20 | 21 | describe "#timeline" do 22 | let(:raw_events) do 23 | [ 24 | { 25 | __typename: "PullRequestReview", 26 | id: "PRR_kwDOCTCBxM5NoRuj", 27 | createdAt: "2023-02-16T22:53:41Z", 28 | actor: { 29 | login: "s3lase", 30 | }, 31 | body: "General review comment", 32 | }, 33 | { 34 | __typename: "IssueComment", 35 | id: "IC_kwDOCTCBxM5kaSjN", 36 | createdAt: "2023-08-19T00:47:19Z", 37 | actor: { 38 | login: "s3lase", 39 | }, 40 | body: "And here too", 41 | }, 42 | ] 43 | end 44 | 45 | let(:raw_events_without_body) do 46 | [ 47 | { 48 | __typename: "PullRequestReview", 49 | id: "PRR_kwDOCTCBxM5NoTQO", 50 | createdAt: "2023-02-16T23:00:49Z", 51 | actor: { 52 | login: "s3lase", 53 | }, 54 | body: "", 55 | }, 56 | ] 57 | end 58 | 59 | it "returns all events" do 60 | DiscourseCodeReview::Source::GithubPRQuerier 61 | .any_instance 62 | .expects(:timeline_events_for) 63 | .returns(raw_events) 64 | 65 | timeline = pr_querier.timeline(pr).to_a 66 | first_event, second_event = timeline 67 | 68 | expect(timeline.length).to eq(2) 69 | 70 | expect(first_event[0]).to be_a(DiscourseCodeReview::PullRequestEventInfo) 71 | expect(first_event[0].github_id).to eq("PRR_kwDOCTCBxM5NoRuj") 72 | expect(first_event[1]).to be_a(DiscourseCodeReview::PullRequestEvent::IssueComment) 73 | expect(first_event[1].body).to eq("General review comment") 74 | 75 | expect(second_event[0]).to be_a(DiscourseCodeReview::PullRequestEventInfo) 76 | expect(second_event[0].github_id).to eq("IC_kwDOCTCBxM5kaSjN") 77 | expect(second_event[1]).to be_a(DiscourseCodeReview::PullRequestEvent::IssueComment) 78 | expect(second_event[1].body).to eq("And here too") 79 | end 80 | 81 | it "skips PullRequestReview events without body" do 82 | DiscourseCodeReview::Source::GithubPRQuerier 83 | .any_instance 84 | .expects(:timeline_events_for) 85 | .returns(raw_events + raw_events_without_body) 86 | 87 | timeline = pr_querier.timeline(pr).to_a 88 | 89 | expect(timeline.length).to eq(2) 90 | expect(timeline.map(&:first).map(&:github_id)).not_to include( 91 | raw_events_without_body.map { |e| e[:id] }, 92 | ) 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/discourse_code_review/lib/github_user_syncer_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe DiscourseCodeReview::GithubUserSyncer do 6 | describe "#ensure_user" do 7 | it "uses name for username by default" do 8 | name = "Bill" 9 | email = "billgates@gmail.com" 10 | 11 | user_syncer = DiscourseCodeReview::GithubUserSyncer.new(nil) 12 | user_syncer.ensure_user(name: name, email: email) 13 | 14 | staged_user = User.find_by_email(email) 15 | expect(staged_user.username).to eq(name) 16 | end 17 | 18 | it "doesn't use email for username suggestions by default" do 19 | email = "billgates@gmail.com" 20 | 21 | user_syncer = DiscourseCodeReview::GithubUserSyncer.new(nil) 22 | user_syncer.ensure_user(name: nil, email: email) 23 | 24 | staged_user = User.find_by_email(email) 25 | expect(staged_user.username).to eq("user1") # not "billgates" extracted from billgates@gmail.com 26 | end 27 | 28 | it "uses email for username if enabled and name consists entirely of disallowed characters" do 29 | SiteSetting.use_email_for_username_and_name_suggestions = true 30 | SiteSetting.unicode_usernames = false 31 | name = "άκυρος" 32 | email = "billgates@gmail.com" 33 | 34 | user_syncer = DiscourseCodeReview::GithubUserSyncer.new(nil) 35 | user_syncer.ensure_user(name: name, email: email) 36 | 37 | staged_user = User.find_by_email(email) 38 | expect(staged_user.username).to eq("billgates") 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/discourse_code_review/lib/state/commit_approval_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | module DiscourseCodeReview 6 | describe State::CommitApproval do 7 | fab!(:topic) 8 | fab!(:pr) do 9 | DiscourseCodeReview::PullRequest.new(owner: "owner", name: "name", issue_number: 101) 10 | end 11 | fab!(:approver) { Fabricate(:user) } 12 | fab!(:merged_by) { Fabricate(:user) } 13 | 14 | describe "#ensure_pr_merge_info_post" do 15 | it "does not consider duplicate approvers" do 16 | post = 17 | State::CommitApproval.approve( 18 | topic, 19 | [approver, merged_by] * 2, 20 | pr: pr, 21 | merged_by: merged_by, 22 | ) 23 | expect(post.raw).to eq( 24 | "This commit appears in [#101](https://github.com/owner/name/pull/101) which was approved by #{approver.username} and #{merged_by.username}. It was merged by #{merged_by.username}.", 25 | ) 26 | end 27 | end 28 | 29 | describe "creates notifications upon approval" do 30 | before { SiteSetting.code_review_enabled = true } 31 | 32 | it "doesn't consolidate notifications if they were created more than 6 hours ago" do 33 | second_topic = Fabricate(:topic, user: topic.user) 34 | second_pr = 35 | DiscourseCodeReview::PullRequest.new(owner: "owner", name: "name", issue_number: 102) 36 | 37 | State::CommitApproval.approve(topic, [approver, merged_by], pr: pr, merged_by: merged_by) 38 | first_notification = 39 | Notification.find_by( 40 | user: topic.user, 41 | notification_type: Notification.types[:code_review_commit_approved], 42 | ) 43 | first_notification.update!(created_at: 7.hours.ago) 44 | 45 | State::CommitApproval.approve( 46 | second_topic, 47 | [approver, merged_by], 48 | pr: second_pr, 49 | merged_by: merged_by, 50 | ) 51 | 52 | notifications = 53 | Notification.where( 54 | user: topic.user, 55 | notification_type: Notification.types[:code_review_commit_approved], 56 | ) 57 | expect(notifications.count).to eq(2) 58 | expect(notifications.last.data_hash[:num_approved_commits]).to eq(1) 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/discourse_code_review/lib/state/commit_topics_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | module DiscourseCodeReview 6 | describe State::CommitTopics do 7 | it "has robust sha detection" do 8 | text = (<<~STR).strip 9 | hello abcdf672, a723c123444! 10 | (abc2345662) {abcd87234} [#1209823bc] 11 | ,7862abcdf abcdefg722 12 | abc7827421119a 13 | STR 14 | 15 | shas = State::CommitTopics.detect_shas(text) 16 | 17 | expect(shas).to eq( 18 | %w[abcdf672 a723c123444 abc2345662 abcd87234 1209823bc 7862abcdf abc7827421119a], 19 | ) 20 | end 21 | 22 | describe "#ensure_commit" do 23 | fab!(:user) { Fabricate(:user, refresh_auto_groups: true) } 24 | fab!(:category) 25 | 26 | it "can handle commits without message" do 27 | commit = { 28 | subject: "", 29 | body: "", 30 | email: "re@gis.com", 31 | github_login: "regis", 32 | github_id: "123", 33 | date: 10.day.ago, 34 | diff: "```\nwith a diff", 35 | hash: "1cd4e0bec9ebd50f353a52b9c197f713c0e1f422", 36 | } 37 | 38 | repo = GithubRepo.new("discourse/discourse", Octokit::Client.new, nil, repo_id: 24) 39 | 40 | topic_id = 41 | State::CommitTopics.ensure_commit( 42 | category_id: category.id, 43 | commit: commit, 44 | merged: false, 45 | repo_name: repo.name, 46 | user: user, 47 | followees: [], 48 | ) 49 | 50 | expect(Topic.find_by(id: topic_id).title).to start_with("No message for commit ") 51 | end 52 | 53 | it "can handle deleted topics" do 54 | commit = { 55 | subject: "hello world", 56 | body: "this is the body\nwith an emoji :)", 57 | email: "sam@sam.com", 58 | github_login: "sam", 59 | github_id: "111", 60 | date: 1.day.ago, 61 | diff: "```\nwith a diff", 62 | hash: "154f503d2e99f904356b52f2fae9edcc495708fa", 63 | } 64 | 65 | repo = GithubRepo.new("discourse/discourse", Octokit::Client.new, nil, repo_id: 24) 66 | 67 | topic_id = 68 | State::CommitTopics.ensure_commit( 69 | category_id: category.id, 70 | commit: commit, 71 | merged: false, 72 | repo_name: repo.name, 73 | user: user, 74 | followees: [], 75 | ) 76 | 77 | topic = Topic.find(topic_id) 78 | PostDestroyer.new(Discourse.system_user, topic.first_post).destroy 79 | expect(Topic.find_by(id: topic_id)).to eq(nil) 80 | 81 | topic_id = 82 | State::CommitTopics.ensure_commit( 83 | category_id: category.id, 84 | commit: commit, 85 | merged: false, 86 | repo_name: repo.name, 87 | user: user, 88 | followees: [], 89 | ) 90 | 91 | expect(Topic.find_by(id: topic_id)).not_to eq(nil) 92 | end 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/helpers/github_rest_api_mock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module GithubRestAPIMock 4 | REPO_REQUEST = %r{https://api.github.com/repos/([^/]+)/([^/]+)} 5 | COMMENTS_REQUEST = %r{https://api.github.com/repos/([^/]+)/([^/]+)/commits/([^/]+)/comments} 6 | 7 | class << self 8 | def infos 9 | @infos ||= {} 10 | end 11 | 12 | def comments 13 | @comments ||= 14 | Hash.new { |comments, owner_repo| comments[owner_repo] = Hash.new { |h, sha| h[sha] = [] } } 15 | end 16 | 17 | def declare_repo!(owner:, repo:, default_branch:) 18 | infos[[owner, repo]] = { default_branch: default_branch } 19 | end 20 | 21 | def declare_commit_comment!(owner:, repo:, commit:, comment:) 22 | comments[[owner, repo]][commit] << comment 23 | end 24 | 25 | def setup! 26 | stub_request(:get, REPO_REQUEST) do |match| 27 | _, owner, repo = match.to_a 28 | 29 | { 30 | headers: { 31 | "Content-Type": "application/json", 32 | }, 33 | body: infos.fetch([owner, repo]).to_json, 34 | } 35 | end 36 | 37 | stub_request(:get, COMMENTS_REQUEST) do |match| 38 | _, owner, repo, sha = match.to_a 39 | 40 | { 41 | headers: { 42 | "Content-Type": "application/json", 43 | }, 44 | body: comments[[owner, repo]][sha].to_json, 45 | } 46 | end 47 | end 48 | 49 | private 50 | 51 | def stub_request(method, regex, &blk) 52 | WebMock 53 | .stub_request(:get, regex) 54 | .to_return do |request| 55 | matches = 56 | WebMock::Util::URI 57 | .variations_of_uri_as_strings(request.uri) 58 | .flat_map { |uri| [regex.match(uri)].compact } 59 | 60 | raise unless matches.size == 1 61 | match = matches.first 62 | 63 | blk.call(match) 64 | end 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /spec/helpers/graphql_client_mock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class GraphQLClientMock 4 | module GitObjectType 5 | include GraphQL::Schema::Interface 6 | 7 | definition_methods do 8 | def resolve_type(object, context) 9 | CommitType 10 | end 11 | end 12 | end 13 | 14 | class UserType < GraphQL::Schema::Object 15 | field :login, String, null: false 16 | field :id, String, null: false 17 | 18 | def login 19 | "login" 20 | end 21 | 22 | def id 23 | "id" 24 | end 25 | end 26 | 27 | class GitActorType < GraphQL::Schema::Object 28 | field :user, UserType, null: true 29 | 30 | def user 31 | :user 32 | end 33 | end 34 | 35 | class CommitType < GraphQL::Schema::Object 36 | implements GitObjectType 37 | 38 | field :oid, String, null: false 39 | field :author, GitActorType, null: false 40 | field :committer, GitActorType, null: false 41 | 42 | def oid 43 | "oid" 44 | end 45 | 46 | def author 47 | :author 48 | end 49 | 50 | def committer 51 | :committer 52 | end 53 | end 54 | 55 | class RepositoryType < GraphQL::Schema::Object 56 | field :object, GitObjectType, null: true, resolver_method: :resolve_object do 57 | argument :expression, String, required: true 58 | end 59 | 60 | def resolve_object(expression:) 61 | :commit 62 | end 63 | end 64 | 65 | class QueryType < GraphQL::Schema::Object 66 | field :repository, RepositoryType, null: true do 67 | argument :owner, String, required: true 68 | argument :name, String, required: true 69 | end 70 | 71 | def repository(owner:, name:) 72 | :repo 73 | end 74 | end 75 | 76 | class GithubSchema < GraphQL::Schema 77 | query QueryType 78 | orphan_types CommitType 79 | end 80 | 81 | GraphQLError = GraphQLClient::GraphQLError 82 | PaginatedQuery = GraphQLClient::PaginatedQuery 83 | 84 | def execute(query) 85 | GithubSchema.execute(query).to_h.deep_symbolize_keys[:data] 86 | end 87 | 88 | def paginated_query(&blk) 89 | PaginatedQuery.new(self, &blk) 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /spec/helpers/integration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "remote_mocks" 4 | require_relative "graphql_client_mock" 5 | require_relative "rugged_interceptor" 6 | require_relative "github_rest_api_mock" 7 | 8 | module CodeReviewIntegrationHelpers 9 | def declare_github_repo!(owner:, repo:, default_branch: "main", &blk) 10 | local = RemoteMocks.make_repo 11 | 12 | RuggedInterceptor::Repository.intercept( 13 | "https://github.com/#{owner}/#{repo}.git", 14 | local.workdir, 15 | ) 16 | 17 | GithubRestAPIMock.declare_repo!(owner: owner, repo: repo, default_branch: default_branch) 18 | 19 | blk.call(local) 20 | end 21 | 22 | def declare_github_commit_comment!(**kwargs) 23 | GithubRestAPIMock.declare_commit_comment!(**kwargs) 24 | end 25 | end 26 | 27 | RSpec.configure do |config| 28 | config.include CodeReviewIntegrationHelpers 29 | 30 | config.before(:each, type: :code_review_integration) do 31 | DiscourseCodeReview.reset_state! 32 | 33 | DiscourseCodeReview.stubs(:graphql_client).returns(GraphQLClientMock.new) 34 | 35 | FileUtils.rm_rf("tmp/code-review-repo-#{ENV["TEST_ENV_NUMBER"].presence || "0"}/") 36 | 37 | GithubRestAPIMock.setup! 38 | end 39 | 40 | config.around(type: :code_review_integration) { |example| RuggedInterceptor.use { example.run } } 41 | 42 | config.after(type: :code_review_integration) { RemoteMocks.cleanup! } 43 | end 44 | -------------------------------------------------------------------------------- /spec/helpers/remote_mocks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module RemoteMocks 4 | class << self 5 | include Helpers 6 | 7 | def repos 8 | @repos ||= [] 9 | end 10 | 11 | def make_repo 12 | path = setup_git_repo({}) 13 | repos << path 14 | Rugged::Repository.new(path) 15 | end 16 | 17 | def cleanup! 18 | repos.each { |path| FileUtils.rm_rf(path) } 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/helpers/rugged_interceptor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module RuggedInterceptor 4 | OriginalRugged = ::Rugged 5 | 6 | module Repository 7 | OriginalRepository = ::Rugged::Repository 8 | 9 | class << self 10 | def replacements 11 | @replacements ||= {} 12 | end 13 | 14 | def intercept(url, replacement) 15 | replacements[url] = replacement 16 | end 17 | 18 | def const_missing(name) 19 | OriginalRepository.const_get(name) 20 | end 21 | 22 | def method_missing(method, *args, **kwargs, &blk) 23 | OriginalRepository.send(method, *args, **kwargs, &blk) 24 | end 25 | 26 | def clone_at(url, local_path, options = {}) 27 | OriginalRepository.clone_at(replacements.fetch(url), local_path, options) 28 | end 29 | end 30 | end 31 | 32 | class << self 33 | def const_missing(name) 34 | OriginalRugged.const_get(name) 35 | end 36 | 37 | def method_missing(method, *args, **kwargs, &blk) 38 | OriginalRugged.send(method, *args, **kwargs, &blk) 39 | end 40 | 41 | def use(&blk) 42 | begin 43 | Object.send(:remove_const, :Rugged) 44 | Object.send(:const_set, :Rugged, RuggedInterceptor) 45 | 46 | blk.call 47 | ensure 48 | Object.send(:remove_const, :Rugged) 49 | Object.send(:const_set, :Rugged, OriginalRugged) 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/jobs/code_review_sync_commits_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | require_relative "../helpers/integration" 5 | 6 | describe Jobs::CodeReviewSyncCommits, type: :code_review_integration do 7 | context "with a fake github repo" do 8 | before do 9 | commit = nil 10 | declare_github_repo!( 11 | owner: "10xninjarockstar", 12 | repo: "ultimatetodolist", 13 | default_branch: "main", 14 | ) do |repo| 15 | Dir.chdir(repo.workdir) do 16 | File.write("README.md", <<~EOF) 17 | Just store text files with your todo list items. 18 | EOF 19 | 20 | `git add README.md` 21 | `git commit -m "Initial commit"` 22 | `git branch -m main` 23 | 24 | commit = `git rev-parse HEAD` 25 | end 26 | end 27 | 28 | DiscourseCodeReview::Source::CommitQuerier 29 | .any_instance 30 | .stubs(:last_commit) 31 | .with("10xninjarockstar", "ultimatetodolist") 32 | .returns("abcdef") 33 | 34 | declare_github_commit_comment!( 35 | owner: "10xninjarockstar", 36 | repo: "ultimatetodolist", 37 | commit: commit, 38 | comment: { 39 | }, 40 | ) 41 | 42 | User.set_callback(:create, :after, :ensure_in_trust_level_group) 43 | end 44 | 45 | after { User.skip_callback(:create, :after, :ensure_in_trust_level_group) } 46 | 47 | it "creates a commit topic and a category topic, with a full sha in the first post" do 48 | expect { 49 | described_class.new.execute(repo_name: "10xninjarockstar/ultimatetodolist", repo_id: 24) 50 | }.to change { Topic.count }.by(2) 51 | 52 | topics = Topic.order("id desc").limit(2) 53 | 54 | commit_post = topics.first.first_post 55 | 56 | hash = topics.first.custom_fields[DiscourseCodeReview::COMMIT_HASH] 57 | expect(commit_post.raw).to include("sha: #{hash}") 58 | end 59 | 60 | it "skips if last local and remote commit SHAs match" do 61 | PluginStore.set( 62 | DiscourseCodeReview::PLUGIN_NAME, 63 | DiscourseCodeReview::GithubRepo::LAST_COMMIT + "10xninjarockstar/ultimatetodolist", 64 | "abcdef", 65 | ) 66 | 67 | expect { 68 | described_class.new.execute( 69 | repo_name: "10xninjarockstar/ultimatetodolist", 70 | repo_id: 24, 71 | skip_if_up_to_date: true, 72 | ) 73 | }.not_to change { Topic.count } 74 | end 75 | 76 | it "does not skips if last local and remote commit SHAs mismatch" do 77 | PluginStore.set( 78 | DiscourseCodeReview::PLUGIN_NAME, 79 | DiscourseCodeReview::GithubRepo::LAST_COMMIT + "10xninjarockstar/ultimatetodolist", 80 | "abcdeg", 81 | ) 82 | 83 | expect { 84 | described_class.new.execute( 85 | repo_name: "10xninjarockstar/ultimatetodolist", 86 | repo_id: 24, 87 | skip_if_up_to_date: true, 88 | ) 89 | }.to change { Topic.count }.by(2) 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /spec/jobs/code_review_sync_repos_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | require_relative "../helpers/integration" 5 | 6 | describe Jobs::CodeReviewSyncRepos, type: :code_review_integration do 7 | it "schedules sync jobs for all repos" do 8 | DiscourseCodeReview::State::GithubRepoCategories.ensure_category( 9 | repo_name: "discourse/discourse", 10 | repo_id: 42, 11 | ) 12 | DiscourseCodeReview::State::GithubRepoCategories.ensure_category( 13 | repo_name: "discourse/discourse-code-review", 14 | repo_id: 43, 15 | ) 16 | # Created ... 17 | DiscourseCodeReview::State::GithubRepoCategories.ensure_category( 18 | repo_name: "discourse/discourse-staff-notes", 19 | repo_id: 44, 20 | ) 21 | # ... then moved. 22 | DiscourseCodeReview::State::GithubRepoCategories.ensure_category( 23 | repo_name: "discourse/discourse-staff-notes", 24 | repo_id: nil, 25 | ) 26 | 27 | expect { described_class.new.execute }.to change { Jobs::CodeReviewSyncCommits.jobs.count }.by( 28 | 2, 29 | ) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/lib/enumerators_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe Enumerators::FlattenMerge do 6 | it "should merge a set of enumerators" do 7 | result = Enumerators::FlattenMerge.new([[0], [1]]) { |a, b| a < b }.to_a 8 | 9 | expect(result).to eq([0, 1]) 10 | end 11 | 12 | it "should merge a set of enumerators" do 13 | result = Enumerators::FlattenMerge.new([[0, 1]]) { |a, b| a < b }.to_a 14 | 15 | expect(result).to eq([0, 1]) 16 | end 17 | 18 | it "should merge a set of enumerators" do 19 | result = Enumerators::FlattenMerge.new([[6], [0, 2, 4], [1, 3, 5], []]) { |a, b| a < b }.to_a 20 | 21 | expect(result).to eq([0, 1, 2, 3, 4, 5, 6]) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/lib/github_pr_syncer_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe DiscourseCodeReview::GithubPRSyncer do 6 | it "does nothing if the topic is a PM" do 7 | pm_post = Fabricate(:post, post_number: 2, topic: Fabricate(:private_message_topic)) 8 | 9 | syncer = described_class.new(nil, nil) 10 | 11 | expect(syncer.mirror_pr_post(pm_post)).to be_nil 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/lib/octokit_rate_limit_retry_mixin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe OctokitRateLimitRetryMixin do 6 | describe "sidekiq_retry_in" do 7 | class TestJob < ::Jobs::Base 8 | include OctokitRateLimitRetryMixin 9 | end 10 | 11 | let(:exception) { Jobs::HandledExceptionWrapper.new(Octokit::TooManyRequests.new) } 12 | 13 | before do 14 | stub_request(:get, "https://api.github.com/rate_limit").to_return( 15 | status: 200, 16 | body: "", 17 | headers: { 18 | "X-RateLimit-Limit" => 1000, 19 | "X-RateLimit-Remaining" => 0, 20 | "X-RateLimit-Reset" => 90.minutes.from_now.to_i, 21 | "X-RateLimit-Resource" => "core", 22 | "X-RateLimit-Used" => 0, 23 | }, 24 | ) 25 | end 26 | 27 | it "retries after rate limit expires" do 28 | expect(TestJob.sidekiq_retry_in_block.call(0, exception)).to be >= 3600 29 | end 30 | 31 | it "retries after rate limit expires again" do 32 | expect(TestJob.sidekiq_retry_in_block.call(1, exception)).to be >= 3600 33 | end 34 | 35 | it "retries once for other errors" do 36 | expect(TestJob.sidekiq_retry_in_block.call(0, nil)).to be >= 30 37 | expect(TestJob.sidekiq_retry_in_block.call(0, nil)).to be <= 90 38 | expect(TestJob.sidekiq_retry_in_block.call(1, nil)).to eq(:discard) 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/requests/discourse_code_review/list_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe ListController do 6 | fab!(:user) { Fabricate(:user, username: "t.testeur") } 7 | fab!(:topic) { Fabricate(:topic, user: user) } 8 | fab!(:pr) do 9 | DiscourseCodeReview::PullRequest.new(owner: "owner", name: "name", issue_number: 101) 10 | end 11 | fab!(:approver) { Fabricate(:user, username: "approver-user") } 12 | fab!(:merged_by) { Fabricate(:user) } 13 | fab!(:pending_tag) { Fabricate(:tag, name: "pending") } 14 | fab!(:pending_topic) { Fabricate(:topic, user: user, tags: [pending_tag]) } 15 | 16 | before do 17 | SiteSetting.code_review_enabled = true 18 | sign_in(approver) 19 | 20 | DiscourseCodeReview::State::CommitApproval.approve( 21 | topic, 22 | [approver, merged_by] * 2, 23 | pr: pr, 24 | merged_by: merged_by, 25 | ) 26 | end 27 | 28 | context "for approval-given route" do 29 | it "handles periods in usernames and lists topics authored by this username" do 30 | get "/topics/approval-given/t.testeur.json" 31 | topic_list = response.parsed_body["topic_list"] 32 | expect(topic_list["topics"].size).to eq(1) 33 | expect(topic_list["topics"][0]["id"]).to eq(topic.id) 34 | end 35 | 36 | it "lists only topics authored by the given username" do 37 | get "/topics/approval-given/approver-user.json" 38 | topic_list = response.parsed_body["topic_list"] 39 | expect(topic_list["topics"].size).to eq(0) 40 | end 41 | 42 | it "returns a 404 for non-existing users" do 43 | get "/topics/approval-given/non-existing-user.json" 44 | expect(response.status).to eq(404) 45 | expect(response.parsed_body["errors"]).to eq( 46 | [I18n.t("approval_list.user_not_found", { username: "non-existing-user" })], 47 | ) 48 | end 49 | end 50 | 51 | context "for approval-pending route" do 52 | it "handles periods in usernames and lists topics authored by this username" do 53 | get "/topics/approval-pending/t.testeur.json" 54 | topic_list = response.parsed_body["topic_list"] 55 | expect(topic_list["topics"].size).to eq(1) 56 | expect(topic_list["topics"][0]["id"]).to eq(pending_topic.id) 57 | end 58 | 59 | it "lists only topics authored by the given username" do 60 | get "/topics/approval-pending/approver-user.json" 61 | topic_list = response.parsed_body["topic_list"] 62 | expect(topic_list["topics"].size).to eq(0) 63 | end 64 | 65 | it "returns a 404 for non-existing users" do 66 | get "/topics/approval-pending/non-existing-user.json" 67 | expect(response.status).to eq(404) 68 | expect(response.parsed_body["errors"]).to eq( 69 | [I18n.t("approval_list.user_not_found", { username: "non-existing-user" })], 70 | ) 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /spec/system/core_features_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe "Core features", type: :system do 4 | before { enable_current_plugin } 5 | 6 | it_behaves_like "having working core features" 7 | end 8 | -------------------------------------------------------------------------------- /spec/system/keyboard_shortcuts_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe "Keyboard shortcuts", type: :system do 4 | describe "" do 5 | fab!(:post) 6 | fab!(:current_user) { Fabricate(:admin) } 7 | 8 | let(:topic) { post.topic } 9 | let(:topic_page) { PageObjects::Pages::Topic.new } 10 | let(:tags) { topic.reload.tags.pluck(:name) } 11 | 12 | before do 13 | SiteSetting.code_review_enabled = true 14 | sign_in(current_user) 15 | end 16 | 17 | context "when on a commit topic" do 18 | fab!(:approved_tag) { Fabricate(:tag, name: "approved") } 19 | fab!(:pending_tag) { Fabricate(:tag, name: "pending") } 20 | 21 | context "when the commit is not approved" do 22 | before { topic.tags << pending_tag } 23 | 24 | it "approves the commit" do 25 | topic_page.visit_topic(topic) 26 | send_keys("y") 27 | expect(page).to have_current_path("/") 28 | expect(tags).to include("approved") 29 | end 30 | end 31 | 32 | context "when the commit is already approved" do 33 | before { topic.tags << approved_tag } 34 | 35 | it "does nothing" do 36 | topic_page.visit_topic(topic) 37 | expect { send_keys("y") }.not_to change { topic.reload.tags.pluck(:name) } 38 | expect(page).to have_current_path("/t/#{topic.slug}/#{topic.id}") 39 | end 40 | end 41 | end 42 | 43 | context "when on a normal topic page" do 44 | it "does nothing" do 45 | topic_page.visit_topic(topic) 46 | send_keys("y") 47 | expect(page).to have_current_path("/t/#{topic.slug}/#{topic.id}") 48 | expect(tags).not_to include("approved") 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/tasks/code_review_sha_backfill_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe "tasks/code_review_sha_backfill" do 6 | before do 7 | Rake::Task.clear 8 | Discourse::Application.load_tasks 9 | DiscourseCodeReview::RakeTasks.define_tasks 10 | end 11 | 12 | def raw 13 | <<~RAW 14 | [excerpt] 15 | This is the commit message. 16 | 17 | And some more info. 18 | [/excerpt] 19 | 20 | ```diff 21 | git diff data 22 | @@ -68,10 +68,10 @@ 23 | some code 24 | ``` 25 | [GitHub](https://github.com/discourse/discourse/commit/c187ede3c67f23478bc2d3c20187bd98ac025b9e) 26 | sha: c187ede3 27 | RAW 28 | end 29 | 30 | describe "discourse_code_review:full_sha_backfill" do 31 | let(:topic) { Fabricate(:topic) } 32 | let(:post) { Fabricate(:post, topic: topic, raw: raw) } 33 | 34 | before do 35 | topic.custom_fields[ 36 | DiscourseCodeReview::COMMIT_HASH 37 | ] = "c187ede3c67f23478bc2d3c20187bd98ac025b9e" 38 | topic.save_custom_fields 39 | DiscourseCodeReview::CommitTopic.create!( 40 | topic_id: topic.id, 41 | sha: "c187ede3c67f23478bc2d3c20187bd98ac025b9e", 42 | ) 43 | post.rebake! 44 | Rake::Task["code_review_full_sha_backfill"].reenable 45 | end 46 | 47 | it "updates the post raw with the post revisor to have the full sha" do 48 | original_raw = post.raw 49 | capture_stdout { Rake::Task["code_review_full_sha_backfill"].invoke } 50 | post.reload 51 | 52 | expect(post.raw.chomp).to eq( 53 | original_raw.gsub("sha: c187ede3", "sha: c187ede3c67f23478bc2d3c20187bd98ac025b9e").chomp, 54 | ) 55 | end 56 | 57 | it "is idempotent based on raw not changing and the query not getting longer shas" do 58 | capture_stdout { Rake::Task["code_review_full_sha_backfill"].invoke } 59 | post_baked_at = post.reload.baked_at 60 | Rake::Task["code_review_full_sha_backfill"].reenable 61 | 62 | capture_stdout { Rake::Task["code_review_full_sha_backfill"].invoke } 63 | expect(post.reload.baked_at).to eq_time(post_baked_at) 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /stylelint.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | extends: ["@discourse/lint-configs/stylelint"], 3 | }; 4 | -------------------------------------------------------------------------------- /test/javascripts/acceptance/commit-approved-notifications-test.js: -------------------------------------------------------------------------------- 1 | import { click, visit } from "@ember/test-helpers"; 2 | import { test } from "qunit"; 3 | import { acceptance, queryAll } from "discourse/tests/helpers/qunit-helpers"; 4 | import { i18n } from "discourse-i18n"; 5 | 6 | acceptance("Discourse Code Review - Notifications", function (needs) { 7 | needs.user({ redesigned_user_menu_enabled: true }); 8 | 9 | needs.pretender((server, helper) => { 10 | server.get("/notifications", () => { 11 | return helper.response({ 12 | notifications: [ 13 | { 14 | id: 801, 15 | user_id: 12, 16 | notification_type: 21, // code_review_commit_approved notification type 17 | read: true, 18 | high_priority: false, 19 | created_at: "2001-10-17 15:41:10 UTC", 20 | post_number: 1, 21 | topic_id: 883, 22 | fancy_title: "Osama's commit #1", 23 | slug: "osama-s-commit-1", 24 | data: { 25 | num_approved_commits: 1, 26 | }, 27 | }, 28 | { 29 | id: 389, 30 | user_id: 12, 31 | notification_type: 21, // code_review_commit_approved notification type 32 | read: true, 33 | high_priority: false, 34 | created_at: "2010-11-17 23:01:15 UTC", 35 | post_number: null, 36 | topic_id: null, 37 | fancy_title: null, 38 | slug: null, 39 | data: { 40 | num_approved_commits: 10, 41 | }, 42 | }, 43 | ], 44 | }); 45 | }); 46 | }); 47 | 48 | test("code review commit approved notifications", async function (assert) { 49 | await visit("/"); 50 | await click(".d-header-icons .current-user button"); 51 | 52 | const notifications = queryAll( 53 | "#quick-access-all-notifications ul li.notification a" 54 | ); 55 | assert.strictEqual(notifications.length, 2); 56 | 57 | assert.strictEqual( 58 | notifications[0].textContent.replaceAll(/\s+/g, " ").trim(), 59 | i18n("notifications.code_review.commit_approved.single", { 60 | topicTitle: "Osama's commit #1", 61 | }), 62 | "notification for a single commit approval has the right content" 63 | ); 64 | assert.ok( 65 | notifications[0].href.endsWith("/t/osama-s-commit-1/883"), 66 | "notification for a single commit approval links to the topic" 67 | ); 68 | assert.ok( 69 | notifications[0].querySelector(".d-icon-check"), 70 | "notification for a single commit approval has the right icon" 71 | ); 72 | 73 | assert.strictEqual( 74 | notifications[1].textContent.replaceAll(/\s+/g, " ").trim(), 75 | i18n("notifications.code_review.commit_approved.multiple", { 76 | count: 10, 77 | }), 78 | "notification for multiple commits approval has the right content" 79 | ); 80 | assert.ok( 81 | notifications[1].href.endsWith("/u/eviltrout/activity/approval-given"), 82 | "notification for multiple commits approval links to the user approval-given page" 83 | ); 84 | assert.ok( 85 | notifications[1].querySelector(".d-icon-check"), 86 | "notification for multiple commits approval has the right icon" 87 | ); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /test/javascripts/acceptance/self-approve-desktop-test.js: -------------------------------------------------------------------------------- 1 | import { visit } from "@ember/test-helpers"; 2 | import { test } from "qunit"; 3 | import { cloneJSON } from "discourse/lib/object"; 4 | import topicFixtures from "discourse/tests/fixtures/topic"; 5 | import { 6 | acceptance, 7 | exists, 8 | updateCurrentUser, 9 | } from "discourse/tests/helpers/qunit-helpers"; 10 | 11 | acceptance("review desktop", function (needs) { 12 | needs.user({ 13 | can_review_code: true, 14 | }); 15 | needs.settings({ 16 | code_review_approved_tag: "approved", 17 | code_review_pending_tag: "pending", 18 | code_review_followup_tag: "followup", 19 | }); 20 | needs.pretender((server) => { 21 | const json = cloneJSON(topicFixtures["/t/280/1.json"]); 22 | json.tags = ["pending"]; 23 | 24 | server.get("/t/281.json", () => { 25 | return [200, { "Content-Type": "application/json" }, json]; 26 | }); 27 | }); 28 | 29 | test("shows approve button by default", async (assert) => { 30 | await visit("/t/internationalization-localization/281"); 31 | 32 | assert.ok(exists("#topic-footer-button-approve")); 33 | }); 34 | 35 | test("hides approve button if user is self", async (assert) => { 36 | updateCurrentUser({ id: 1 }); 37 | 38 | await visit("/t/this-is-a-test-topic/9/1"); 39 | 40 | assert.notOk(exists("#topic-footer-button-approve")); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/javascripts/acceptance/self-approve-mobile-test.js: -------------------------------------------------------------------------------- 1 | import { click, visit } from "@ember/test-helpers"; 2 | import { test } from "qunit"; 3 | import { cloneJSON } from "discourse/lib/object"; 4 | import topicFixtures from "discourse/tests/fixtures/topic"; 5 | import { 6 | acceptance, 7 | updateCurrentUser, 8 | } from "discourse/tests/helpers/qunit-helpers"; 9 | 10 | acceptance("review mobile", function (needs) { 11 | needs.user({ can_review_code: true }); 12 | needs.mobileView(); 13 | needs.settings({ 14 | code_review_approved_tag: "approved", 15 | code_review_pending_tag: "pending", 16 | code_review_followup_tag: "followup", 17 | }); 18 | needs.pretender((server) => { 19 | const json = cloneJSON(topicFixtures["/t/280/1.json"]); 20 | json.tags = ["pending"]; 21 | 22 | server.get("/t/281.json", () => { 23 | return [200, { "Content-Type": "application/json" }, json]; 24 | }); 25 | }); 26 | 27 | test("shows approve button by default", async (assert) => { 28 | await visit("/t/internationalization-localization/281"); 29 | await click(".topic-footer-mobile-dropdown-trigger"); 30 | 31 | assert.dom(".approve").exists(); 32 | }); 33 | 34 | test("hides approve button if user is self", async (assert) => { 35 | updateCurrentUser({ id: 1 }); 36 | 37 | await visit("/t/this-is-a-test-topic/9/1"); 38 | 39 | assert.dom(".approve").doesNotExist(); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/javascripts/acceptance/user-activity-approval-given-test.js: -------------------------------------------------------------------------------- 1 | import { visit } from "@ember/test-helpers"; 2 | import { test } from "qunit"; 3 | import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; 4 | import { i18n } from "discourse-i18n"; 5 | 6 | acceptance("User Activity / Approval Given - empty state", function (needs) { 7 | const currentUser = "eviltrout"; 8 | const anotherUser = "charlie"; 9 | needs.user(); 10 | 11 | needs.pretender((server, helper) => { 12 | const emptyResponse = { topic_list: { topics: [] } }; 13 | 14 | server.get(`/topics/approval-given/${currentUser}.json`, () => { 15 | return helper.response(emptyResponse); 16 | }); 17 | 18 | server.get(`/topics/approval-given/${anotherUser}.json`, () => { 19 | return helper.response(emptyResponse); 20 | }); 21 | }); 22 | 23 | test("Shows a blank page placeholder on own page", async function (assert) { 24 | await visit(`/u/${currentUser}/activity/approval-given`); 25 | assert.equal( 26 | query("div.empty-state span.empty-state-title").innerText, 27 | i18n("code_review.approval_given_empty_state_title") 28 | ); 29 | }); 30 | 31 | test("Shows a blank page placeholder on others' page", async function (assert) { 32 | await visit(`/u/${anotherUser}/activity/approval-given`); 33 | assert.equal( 34 | query("div.empty-state span.empty-state-title").innerText, 35 | i18n("code_review.approval_given_empty_state_title_others", { 36 | username: anotherUser, 37 | }) 38 | ); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/javascripts/acceptance/user-activity-approval-pending-test.js: -------------------------------------------------------------------------------- 1 | import { visit } from "@ember/test-helpers"; 2 | import { test } from "qunit"; 3 | import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; 4 | import { i18n } from "discourse-i18n"; 5 | 6 | acceptance("User Activity / Approval Pending - empty state", function (needs) { 7 | const currentUser = "eviltrout"; 8 | const anotherUser = "charlie"; 9 | needs.user(); 10 | 11 | needs.pretender((server, helper) => { 12 | const emptyResponse = { topic_list: { topics: [] } }; 13 | 14 | server.get(`/topics/approval-pending/${currentUser}.json`, () => { 15 | return helper.response(emptyResponse); 16 | }); 17 | 18 | server.get(`/topics/approval-pending/${anotherUser}.json`, () => { 19 | return helper.response(emptyResponse); 20 | }); 21 | }); 22 | 23 | test("Shows a blank page placeholder on own page", async function (assert) { 24 | await visit(`/u/${currentUser}/activity/approval-pending`); 25 | assert.equal( 26 | query("div.empty-state span.empty-state-title").innerText, 27 | i18n("code_review.approval_pending_empty_state_title") 28 | ); 29 | }); 30 | 31 | test("Shows a blank page placeholder on others' page", async function (assert) { 32 | await visit(`/u/${anotherUser}/activity/approval-pending`); 33 | assert.equal( 34 | query("div.empty-state span.empty-state-title").innerText, 35 | i18n("code_review.approval_pending_empty_state_title_others", { 36 | username: anotherUser, 37 | }) 38 | ); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /translator.yml: -------------------------------------------------------------------------------- 1 | # Configuration file for discourse-translator-bot 2 | 3 | files: 4 | - source_path: config/locales/client.en.yml 5 | destination_path: client.yml 6 | - source_path: config/locales/server.en.yml 7 | destination_path: server.yml 8 | --------------------------------------------------------------------------------